2 * Syscall wrappers to ensure that nothing gets done in dry_run mode
3 * and to handle system peculiarities.
5 * Copyright (C) 1998 Andrew Tridgell
6 * Copyright (C) 2002 Martin Pool
7 * Copyright (C) 2003-2022 Wayne Davison
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, visit the http://fsf.org website.
25 #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
28 #ifdef HAVE_SYS_ATTR_H
32 #if defined HAVE_SYS_FALLOCATE && !defined HAVE_FALLOCATE
33 #include <sys/syscall.h>
44 extern int preallocate_files
;
45 extern int preserve_perms
;
46 extern int preserve_executability
;
47 extern int open_noatime
;
48 extern int copy_links
;
49 extern int copy_unsafe_links
;
52 # if defined hpux || defined __hpux__ || defined __hpux
53 # define S_BLKSIZE 1024
54 # elif defined _AIX && defined _I386
55 # define S_BLKSIZE 4096
57 # define S_BLKSIZE 512
61 #ifdef SUPPORT_CRTIMES
62 #ifdef HAVE_GETATTRLIST
66 struct timespec crtime
;
69 #elif defined __CYGWIN__
74 #define RETURN_ERROR_IF(x,e) \
82 #define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
84 int do_unlink(const char *path
)
86 if (dry_run
) return 0;
87 RETURN_ERROR_IF_RO_OR_LO
;
92 int do_symlink(const char *lnk
, const char *path
)
94 if (dry_run
) return 0;
95 RETURN_ERROR_IF_RO_OR_LO
;
97 #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
98 /* For --fake-super, we create a normal file with mode 0600
99 * and write the lnk into it. */
101 int ok
, len
= strlen(lnk
);
102 int fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IWUSR
|S_IRUSR
);
105 ok
= write(fd
, lnk
, len
) == len
;
112 return symlink(lnk
, path
);
115 #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
116 ssize_t
do_readlink(const char *path
, char *buf
, size_t bufsiz
)
118 /* For --fake-super, we read the link from the file. */
120 int fd
= do_open_nofollow(path
, O_RDONLY
);
122 int len
= read(fd
, buf
, bufsiz
);
128 /* A real symlink needs to be turned into a fake one on the receiving
129 * side, so tell the generator that the link has no length. */
132 /* Otherwise fall through and let the sender report the real length. */
135 return readlink(path
, buf
, bufsiz
);
140 #if defined HAVE_LINK || defined HAVE_LINKAT
141 int do_link(const char *old_path
, const char *new_path
)
143 if (dry_run
) return 0;
144 RETURN_ERROR_IF_RO_OR_LO
;
146 return linkat(AT_FDCWD
, old_path
, AT_FDCWD
, new_path
, 0);
148 return link(old_path
, new_path
);
153 int do_lchown(const char *path
, uid_t owner
, gid_t group
)
155 if (dry_run
) return 0;
156 RETURN_ERROR_IF_RO_OR_LO
;
160 return lchown(path
, owner
, group
);
163 int do_mknod(const char *pathname
, mode_t mode
, dev_t dev
)
165 if (dry_run
) return 0;
166 RETURN_ERROR_IF_RO_OR_LO
;
168 /* For --fake-super, we create a normal file with mode 0600. */
170 int fd
= open(pathname
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IWUSR
|S_IRUSR
);
171 if (fd
< 0 || close(fd
) < 0)
176 #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
178 return mkfifo(pathname
, mode
);
180 #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
181 if (S_ISSOCK(mode
)) {
183 struct sockaddr_un saddr
;
184 unsigned int len
= strlcpy(saddr
.sun_path
, pathname
, sizeof saddr
.sun_path
);
185 if (len
>= sizeof saddr
.sun_path
) {
186 errno
= ENAMETOOLONG
;
189 #ifdef HAVE_SOCKADDR_UN_LEN
190 saddr
.sun_len
= len
+ 1;
192 saddr
.sun_family
= AF_UNIX
;
194 if ((sock
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0
195 || (unlink(pathname
) < 0 && errno
!= ENOENT
)
196 || (bind(sock
, (struct sockaddr
*)&saddr
, sizeof saddr
)) < 0)
200 return do_chmod(pathname
, mode
);
207 return mknod(pathname
, mode
, dev
);
213 int do_rmdir(const char *pathname
)
215 if (dry_run
) return 0;
216 RETURN_ERROR_IF_RO_OR_LO
;
217 return rmdir(pathname
);
220 int do_open(const char *pathname
, int flags
, mode_t mode
)
222 if (flags
!= O_RDONLY
) {
223 RETURN_ERROR_IF(dry_run
, 0);
224 RETURN_ERROR_IF_RO_OR_LO
;
232 return open(pathname
, flags
| O_BINARY
, mode
);
236 int do_chmod(const char *path
, mode_t mode
)
238 static int switch_step
= 0;
241 if (dry_run
) return 0;
242 RETURN_ERROR_IF_RO_OR_LO
;
244 switch (switch_step
) {
247 if ((code
= lchmod(path
, mode
& CHMOD_BITS
)) == 0)
251 else if (errno
!= ENOTSUP
)
257 # if defined HAVE_SETATTRLIST
258 struct attrlist attrList
;
259 uint32_t m
= mode
& CHMOD_BITS
; /* manpage is wrong: not mode_t! */
261 memset(&attrList
, 0, sizeof attrList
);
262 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
263 attrList
.commonattr
= ATTR_CMN_ACCESSMASK
;
264 if ((code
= setattrlist(path
, &attrList
, &m
, sizeof m
, FSOPT_NOFOLLOW
)) == 0)
266 if (errno
== ENOTSUP
)
272 code
= chmod(path
, mode
& CHMOD_BITS
); /* DISCOURAGED FUNCTION */
275 if (code
!= 0 && (preserve_perms
|| preserve_executability
))
281 int do_rename(const char *old_path
, const char *new_path
)
283 if (dry_run
) return 0;
284 RETURN_ERROR_IF_RO_OR_LO
;
285 return rename(old_path
, new_path
);
288 #ifdef HAVE_FTRUNCATE
289 int do_ftruncate(int fd
, OFF_T size
)
293 if (dry_run
) return 0;
294 RETURN_ERROR_IF_RO_OR_LO
;
297 ret
= ftruncate(fd
, size
);
298 } while (ret
< 0 && errno
== EINTR
);
304 void trim_trailing_slashes(char *name
)
307 /* Some BSD systems cannot make a directory if the name
308 * contains a trailing slash.
309 * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
311 /* Don't change empty string; and also we can't improve on
316 if (name
[--l
] != '/')
322 int do_mkdir(char *path
, mode_t mode
)
324 if (dry_run
) return 0;
325 RETURN_ERROR_IF_RO_OR_LO
;
326 trim_trailing_slashes(path
);
327 return mkdir(path
, mode
);
330 /* like mkstemp but forces permissions */
331 int do_mkstemp(char *template, mode_t perms
)
333 RETURN_ERROR_IF(dry_run
, 0);
334 RETURN_ERROR_IF(read_only
, EROFS
);
337 #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
339 int fd
= mkstemp(template);
342 if (fchmod(fd
, perms
) != 0 && preserve_perms
) {
343 int errno_save
= errno
;
349 #if defined HAVE_SETMODE && O_BINARY
350 setmode(fd
, O_BINARY
);
355 if (!mktemp(template))
357 return do_open(template, O_RDWR
|O_EXCL
|O_CREAT
, perms
);
361 int do_stat(const char *path
, STRUCT_STAT
*st
)
363 #ifdef USE_STAT64_FUNCS
364 return stat64(path
, st
);
366 return stat(path
, st
);
370 int do_lstat(const char *path
, STRUCT_STAT
*st
)
373 # ifdef USE_STAT64_FUNCS
374 return lstat64(path
, st
);
376 return lstat(path
, st
);
379 return do_stat(path
, st
);
383 int do_fstat(int fd
, STRUCT_STAT
*st
)
385 #ifdef USE_STAT64_FUNCS
386 return fstat64(fd
, st
);
388 return fstat(fd
, st
);
392 OFF_T
do_lseek(int fd
, OFF_T offset
, int whence
)
395 return lseek64(fd
, offset
, whence
);
397 return lseek(fd
, offset
, whence
);
401 #ifdef HAVE_SETATTRLIST
402 int do_setattrlist_times(const char *path
, STRUCT_STAT
*stp
)
404 struct attrlist attrList
;
405 struct timespec ts
[2];
407 if (dry_run
) return 0;
408 RETURN_ERROR_IF_RO_OR_LO
;
410 /* Yes, this is in the opposite order of utime and similar. */
411 ts
[0].tv_sec
= stp
->st_mtime
;
412 ts
[0].tv_nsec
= stp
->ST_MTIME_NSEC
;
414 ts
[1].tv_sec
= stp
->st_atime
;
415 ts
[1].tv_nsec
= stp
->ST_ATIME_NSEC
;
417 memset(&attrList
, 0, sizeof attrList
);
418 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
419 attrList
.commonattr
= ATTR_CMN_MODTIME
| ATTR_CMN_ACCTIME
;
420 return setattrlist(path
, &attrList
, ts
, sizeof ts
, FSOPT_NOFOLLOW
);
423 #ifdef SUPPORT_CRTIMES
424 int do_setattrlist_crtime(const char *path
, time_t crtime
)
426 struct attrlist attrList
;
429 if (dry_run
) return 0;
430 RETURN_ERROR_IF_RO_OR_LO
;
435 memset(&attrList
, 0, sizeof attrList
);
436 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
437 attrList
.commonattr
= ATTR_CMN_CRTIME
;
438 return setattrlist(path
, &attrList
, &ts
, sizeof ts
, FSOPT_NOFOLLOW
);
441 #endif /* HAVE_SETATTRLIST */
443 #ifdef SUPPORT_CRTIMES
444 time_t get_create_time(const char *path
, STRUCT_STAT
*stp
)
446 #ifdef HAVE_GETATTRLIST
447 static struct create_time attrBuf
;
448 struct attrlist attrList
;
451 memset(&attrList
, 0, sizeof attrList
);
452 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
453 attrList
.commonattr
= ATTR_CMN_CRTIME
;
454 if (getattrlist(path
, &attrList
, &attrBuf
, sizeof attrBuf
, FSOPT_NOFOLLOW
) < 0)
456 return attrBuf
.crtime
.tv_sec
;
457 #elif defined __CYGWIN__
459 return stp
->st_birthtime
;
461 #error Unknown crtimes implementation
465 #if defined __CYGWIN__
466 int do_SetFileTime(const char *path
, time_t crtime
)
468 if (dry_run
) return 0;
469 RETURN_ERROR_IF_RO_OR_LO
;
471 int cnt
= MultiByteToWideChar(CP_UTF8
, 0, path
, -1, NULL
, 0);
474 WCHAR
*pathw
= new_array(WCHAR
, cnt
);
477 MultiByteToWideChar(CP_UTF8
, 0, path
, -1, pathw
, cnt
);
478 HANDLE handle
= CreateFileW(pathw
, FILE_WRITE_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
479 NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
481 if (handle
== INVALID_HANDLE_VALUE
)
483 int64 temp_time
= Int32x32To64(crtime
, 10000000) + 116444736000000000LL;
485 birth_time
.dwLowDateTime
= (DWORD
)temp_time
;
486 birth_time
.dwHighDateTime
= (DWORD
)(temp_time
>> 32);
487 int ok
= SetFileTime(handle
, &birth_time
, NULL
, NULL
);
492 #endif /* SUPPORT_CRTIMES */
494 #ifdef HAVE_UTIMENSAT
495 int do_utimensat(const char *path
, STRUCT_STAT
*stp
)
497 struct timespec t
[2];
499 if (dry_run
) return 0;
500 RETURN_ERROR_IF_RO_OR_LO
;
502 t
[0].tv_sec
= stp
->st_atime
;
504 t
[0].tv_nsec
= stp
->ST_ATIME_NSEC
;
508 t
[1].tv_sec
= stp
->st_mtime
;
510 t
[1].tv_nsec
= stp
->ST_MTIME_NSEC
;
514 return utimensat(AT_FDCWD
, path
, t
, AT_SYMLINK_NOFOLLOW
);
519 int do_lutimes(const char *path
, STRUCT_STAT
*stp
)
523 if (dry_run
) return 0;
524 RETURN_ERROR_IF_RO_OR_LO
;
526 t
[0].tv_sec
= stp
->st_atime
;
528 t
[0].tv_usec
= stp
->ST_ATIME_NSEC
/ 1000;
532 t
[1].tv_sec
= stp
->st_mtime
;
534 t
[1].tv_usec
= stp
->ST_MTIME_NSEC
/ 1000;
538 return lutimes(path
, t
);
543 int do_utimes(const char *path
, STRUCT_STAT
*stp
)
547 if (dry_run
) return 0;
548 RETURN_ERROR_IF_RO_OR_LO
;
550 t
[0].tv_sec
= stp
->st_atime
;
552 t
[0].tv_usec
= stp
->ST_ATIME_NSEC
/ 1000;
556 t
[1].tv_sec
= stp
->st_mtime
;
558 t
[1].tv_usec
= stp
->ST_MTIME_NSEC
/ 1000;
562 return utimes(path
, t
);
565 #elif defined HAVE_UTIME
566 int do_utime(const char *path
, STRUCT_STAT
*stp
)
568 #ifdef HAVE_STRUCT_UTIMBUF
574 if (dry_run
) return 0;
575 RETURN_ERROR_IF_RO_OR_LO
;
577 # ifdef HAVE_STRUCT_UTIMBUF
578 tbuf
.actime
= stp
->st_atime
;
579 tbuf
.modtime
= stp
->st_mtime
;
580 return utime(path
, &tbuf
);
582 t
[0] = stp
->st_atime
;
583 t
[1] = stp
->st_mtime
;
584 return utime(path
, t
);
589 #error Need utimes or utime function.
592 #ifdef SUPPORT_PREALLOCATION
593 #ifdef FALLOC_FL_KEEP_SIZE
594 #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE
596 #define DO_FALLOC_OPTIONS 0
599 OFF_T
do_fallocate(int fd
, OFF_T offset
, OFF_T length
)
601 int opts
= inplace
|| preallocate_files
? DO_FALLOC_OPTIONS
: 0;
603 RETURN_ERROR_IF(dry_run
, 0);
604 RETURN_ERROR_IF_RO_OR_LO
;
605 if (length
& 1) /* make the length not match the desired length */
609 #if defined HAVE_FALLOCATE
610 ret
= fallocate(fd
, opts
, offset
, length
);
611 #elif defined HAVE_SYS_FALLOCATE
612 ret
= syscall(SYS_fallocate
, fd
, opts
, (loff_t
)offset
, (loff_t
)length
);
613 #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
614 ret
= posix_fallocate(fd
, offset
, length
);
616 #error Coding error in SUPPORT_PREALLOCATION logic.
622 if (do_fstat(fd
, &st
) < 0)
624 return st
.st_blocks
* S_BLKSIZE
;
630 /* Punch a hole at pos for len bytes. The current file position must be at pos and will be
631 * changed to be at pos + len. */
632 int do_punch_hole(int fd
, OFF_T pos
, OFF_T len
)
634 #ifdef HAVE_FALLOCATE
635 # ifdef HAVE_FALLOC_FL_PUNCH_HOLE
636 if (fallocate(fd
, FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_KEEP_SIZE
, pos
, len
) == 0) {
637 if (do_lseek(fd
, len
, SEEK_CUR
) != pos
+ len
)
642 # ifdef HAVE_FALLOC_FL_ZERO_RANGE
643 if (fallocate(fd
, FALLOC_FL_ZERO_RANGE
, pos
, len
) == 0) {
644 if (do_lseek(fd
, len
, SEEK_CUR
) != pos
+ len
)
654 memset(zeros
, 0, sizeof zeros
);
656 int chunk
= len
> (int)sizeof zeros
? (int)sizeof zeros
: len
;
657 int wrote
= write(fd
, zeros
, chunk
);
659 if (wrote
< 0 && errno
== EINTR
)
669 int do_open_nofollow(const char *pathname
, int flags
)
672 STRUCT_STAT f_st
, l_st
;
676 if (flags
!= O_RDONLY
) {
677 RETURN_ERROR_IF(dry_run
, 0);
678 RETURN_ERROR_IF_RO_OR_LO
;
680 /* This function doesn't support write attempts w/o O_NOFOLLOW. */
687 fd
= open(pathname
, flags
|O_NOFOLLOW
);
689 if (do_lstat(pathname
, &l_st
) < 0)
691 if (S_ISLNK(l_st
.st_mode
)) {
695 if ((fd
= open(pathname
, flags
)) < 0)
697 if (do_fstat(fd
, &f_st
) < 0) {
698 close_and_return_error
:
700 int save_errno
= errno
;
706 if (l_st
.st_dev
!= f_st
.st_dev
|| l_st
.st_ino
!= f_st
.st_ino
) {
708 goto close_and_return_error
;
716 open a file relative to a base directory. The basedir can be NULL,
717 in which case the current working directory is used. The relpath
718 must be a relative path, and the relpath must not contain any
719 elements in the path which follow symlinks (ie. like O_NOFOLLOW, but
720 applies to all path components, not just the last component)
722 The relpath must also not contain any ../ elements in the path
724 int secure_relative_open(const char *basedir
, const char *relpath
, int flags
, mode_t mode
)
726 if (!relpath
|| relpath
[0] == '/') {
727 // must be a relative path
731 if (strncmp(relpath
, "../", 3) == 0 || strstr(relpath
, "/../")) {
732 // no ../ elements allowed in the relpath
737 #if !defined(O_NOFOLLOW) || !defined(O_DIRECTORY) || !defined(AT_FDCWD)
738 // really old system, all we can do is live with the risks
740 return open(relpath
, flags
, mode
);
742 char fullpath
[MAXPATHLEN
];
743 pathjoin(fullpath
, sizeof fullpath
, basedir
, relpath
);
744 return open(fullpath
, flags
, mode
);
746 int dirfd
= AT_FDCWD
;
747 if (basedir
!= NULL
) {
748 dirfd
= openat(AT_FDCWD
, basedir
, O_RDONLY
| O_DIRECTORY
);
755 char *path_copy
= my_strdup(relpath
, __FILE__
, __LINE__
);
760 for (const char *part
= strtok(path_copy
, "/");
762 part
= strtok(NULL
, "/"))
764 int next_fd
= openat(dirfd
, part
, O_RDONLY
| O_DIRECTORY
| O_NOFOLLOW
);
765 if (next_fd
== -1 && errno
== ENOTDIR
) {
766 if (strtok(NULL
, "/") != NULL
) {
767 // this is not the last component of the path
771 // this could be the last component of the path, try as a file
772 retfd
= openat(dirfd
, part
, flags
| O_NOFOLLOW
, mode
);
778 if (dirfd
!= AT_FDCWD
) close(dirfd
);
782 // the path must be a directory
787 if (dirfd
!= AT_FDCWD
) {
791 #endif // O_NOFOLLOW, O_DIRECTORY
795 varient of do_open/do_open_nofollow which does do_open() if the
796 copy_links or copy_unsafe_links options are set and does
797 do_open_nofollow() otherwise
799 This is used to prevent a race condition where an attacker could be
800 switching a file between being a symlink and being a normal file
802 The open is always done with O_RDONLY flags
804 int do_open_checklinks(const char *pathname
)
806 if (copy_links
|| copy_unsafe_links
) {
807 return do_open(pathname
, O_RDONLY
, 0);
809 return do_open_nofollow(pathname
, O_RDONLY
);