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>
42 extern int preallocate_files
;
43 extern int preserve_perms
;
44 extern int preserve_executability
;
45 extern int open_noatime
;
48 # if defined hpux || defined __hpux__ || defined __hpux
49 # define S_BLKSIZE 1024
50 # elif defined _AIX && defined _I386
51 # define S_BLKSIZE 4096
53 # define S_BLKSIZE 512
57 #ifdef SUPPORT_CRTIMES
58 #ifdef HAVE_GETATTRLIST
62 struct timespec crtime
;
65 #elif defined __CYGWIN__
70 #define RETURN_ERROR_IF(x,e) \
78 #define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
80 int do_unlink(const char *path
)
82 if (dry_run
) return 0;
83 RETURN_ERROR_IF_RO_OR_LO
;
88 int do_symlink(const char *lnk
, const char *path
)
90 if (dry_run
) return 0;
91 RETURN_ERROR_IF_RO_OR_LO
;
93 #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
94 /* For --fake-super, we create a normal file with mode 0600
95 * and write the lnk into it. */
97 int ok
, len
= strlen(lnk
);
98 int fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IWUSR
|S_IRUSR
);
101 ok
= write(fd
, lnk
, len
) == len
;
108 return symlink(lnk
, path
);
111 #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
112 ssize_t
do_readlink(const char *path
, char *buf
, size_t bufsiz
)
114 /* For --fake-super, we read the link from the file. */
116 int fd
= do_open_nofollow(path
, O_RDONLY
);
118 int len
= read(fd
, buf
, bufsiz
);
124 /* A real symlink needs to be turned into a fake one on the receiving
125 * side, so tell the generator that the link has no length. */
128 /* Otherwise fall through and let the sender report the real length. */
131 return readlink(path
, buf
, bufsiz
);
136 #if defined HAVE_LINK || defined HAVE_LINKAT
137 int do_link(const char *old_path
, const char *new_path
)
139 if (dry_run
) return 0;
140 RETURN_ERROR_IF_RO_OR_LO
;
142 return linkat(AT_FDCWD
, old_path
, AT_FDCWD
, new_path
, 0);
144 return link(old_path
, new_path
);
149 int do_lchown(const char *path
, uid_t owner
, gid_t group
)
151 if (dry_run
) return 0;
152 RETURN_ERROR_IF_RO_OR_LO
;
156 return lchown(path
, owner
, group
);
159 int do_mknod(const char *pathname
, mode_t mode
, dev_t dev
)
161 if (dry_run
) return 0;
162 RETURN_ERROR_IF_RO_OR_LO
;
164 /* For --fake-super, we create a normal file with mode 0600. */
166 int fd
= open(pathname
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IWUSR
|S_IRUSR
);
167 if (fd
< 0 || close(fd
) < 0)
172 #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
174 return mkfifo(pathname
, mode
);
176 #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
177 if (S_ISSOCK(mode
)) {
179 struct sockaddr_un saddr
;
180 unsigned int len
= strlcpy(saddr
.sun_path
, pathname
, sizeof saddr
.sun_path
);
181 if (len
>= sizeof saddr
.sun_path
) {
182 errno
= ENAMETOOLONG
;
185 #ifdef HAVE_SOCKADDR_UN_LEN
186 saddr
.sun_len
= len
+ 1;
188 saddr
.sun_family
= AF_UNIX
;
190 if ((sock
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0
191 || (unlink(pathname
) < 0 && errno
!= ENOENT
)
192 || (bind(sock
, (struct sockaddr
*)&saddr
, sizeof saddr
)) < 0)
196 return do_chmod(pathname
, mode
);
203 return mknod(pathname
, mode
, dev
);
209 int do_rmdir(const char *pathname
)
211 if (dry_run
) return 0;
212 RETURN_ERROR_IF_RO_OR_LO
;
213 return rmdir(pathname
);
216 int do_open(const char *pathname
, int flags
, mode_t mode
)
218 if (flags
!= O_RDONLY
) {
219 RETURN_ERROR_IF(dry_run
, 0);
220 RETURN_ERROR_IF_RO_OR_LO
;
228 return open(pathname
, flags
| O_BINARY
, mode
);
232 int do_chmod(const char *path
, mode_t mode
)
234 static int switch_step
= 0;
237 if (dry_run
) return 0;
238 RETURN_ERROR_IF_RO_OR_LO
;
240 switch (switch_step
) {
243 if ((code
= lchmod(path
, mode
& CHMOD_BITS
)) == 0)
247 else if (errno
!= ENOTSUP
)
253 # if defined HAVE_SETATTRLIST
254 struct attrlist attrList
;
255 uint32_t m
= mode
& CHMOD_BITS
; /* manpage is wrong: not mode_t! */
257 memset(&attrList
, 0, sizeof attrList
);
258 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
259 attrList
.commonattr
= ATTR_CMN_ACCESSMASK
;
260 if ((code
= setattrlist(path
, &attrList
, &m
, sizeof m
, FSOPT_NOFOLLOW
)) == 0)
262 if (errno
== ENOTSUP
)
268 code
= chmod(path
, mode
& CHMOD_BITS
); /* DISCOURAGED FUNCTION */
271 if (code
!= 0 && (preserve_perms
|| preserve_executability
))
277 int do_rename(const char *old_path
, const char *new_path
)
279 if (dry_run
) return 0;
280 RETURN_ERROR_IF_RO_OR_LO
;
281 return rename(old_path
, new_path
);
284 #ifdef HAVE_FTRUNCATE
285 int do_ftruncate(int fd
, OFF_T size
)
289 if (dry_run
) return 0;
290 RETURN_ERROR_IF_RO_OR_LO
;
293 ret
= ftruncate(fd
, size
);
294 } while (ret
< 0 && errno
== EINTR
);
300 void trim_trailing_slashes(char *name
)
303 /* Some BSD systems cannot make a directory if the name
304 * contains a trailing slash.
305 * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
307 /* Don't change empty string; and also we can't improve on
312 if (name
[--l
] != '/')
318 int do_mkdir(char *path
, mode_t mode
)
320 if (dry_run
) return 0;
321 RETURN_ERROR_IF_RO_OR_LO
;
322 trim_trailing_slashes(path
);
323 return mkdir(path
, mode
);
326 /* like mkstemp but forces permissions */
327 int do_mkstemp(char *template, mode_t perms
)
329 RETURN_ERROR_IF(dry_run
, 0);
330 RETURN_ERROR_IF(read_only
, EROFS
);
333 #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
335 int fd
= mkstemp(template);
338 if (fchmod(fd
, perms
) != 0 && preserve_perms
) {
339 int errno_save
= errno
;
345 #if defined HAVE_SETMODE && O_BINARY
346 setmode(fd
, O_BINARY
);
351 if (!mktemp(template))
353 return do_open(template, O_RDWR
|O_EXCL
|O_CREAT
, perms
);
357 int do_stat(const char *path
, STRUCT_STAT
*st
)
359 #ifdef USE_STAT64_FUNCS
360 return stat64(path
, st
);
362 return stat(path
, st
);
366 int do_lstat(const char *path
, STRUCT_STAT
*st
)
369 # ifdef USE_STAT64_FUNCS
370 return lstat64(path
, st
);
372 return lstat(path
, st
);
375 return do_stat(path
, st
);
379 int do_fstat(int fd
, STRUCT_STAT
*st
)
381 #ifdef USE_STAT64_FUNCS
382 return fstat64(fd
, st
);
384 return fstat(fd
, st
);
388 OFF_T
do_lseek(int fd
, OFF_T offset
, int whence
)
396 return lseek64(fd
, offset
, whence
);
398 return lseek(fd
, offset
, whence
);
402 #ifdef HAVE_SETATTRLIST
403 int do_setattrlist_times(const char *path
, STRUCT_STAT
*stp
)
405 struct attrlist attrList
;
406 struct timespec ts
[2];
408 if (dry_run
) return 0;
409 RETURN_ERROR_IF_RO_OR_LO
;
411 /* Yes, this is in the opposite order of utime and similar. */
412 ts
[0].tv_sec
= stp
->st_mtime
;
413 ts
[0].tv_nsec
= stp
->ST_MTIME_NSEC
;
415 ts
[1].tv_sec
= stp
->st_atime
;
416 ts
[1].tv_nsec
= stp
->ST_ATIME_NSEC
;
418 memset(&attrList
, 0, sizeof attrList
);
419 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
420 attrList
.commonattr
= ATTR_CMN_MODTIME
| ATTR_CMN_ACCTIME
;
421 return setattrlist(path
, &attrList
, ts
, sizeof ts
, FSOPT_NOFOLLOW
);
424 #ifdef SUPPORT_CRTIMES
425 int do_setattrlist_crtime(const char *path
, time_t crtime
)
427 struct attrlist attrList
;
430 if (dry_run
) return 0;
431 RETURN_ERROR_IF_RO_OR_LO
;
436 memset(&attrList
, 0, sizeof attrList
);
437 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
438 attrList
.commonattr
= ATTR_CMN_CRTIME
;
439 return setattrlist(path
, &attrList
, &ts
, sizeof ts
, FSOPT_NOFOLLOW
);
442 #endif /* HAVE_SETATTRLIST */
444 #ifdef SUPPORT_CRTIMES
445 time_t get_create_time(const char *path
, STRUCT_STAT
*stp
)
447 #ifdef HAVE_GETATTRLIST
448 static struct create_time attrBuf
;
449 struct attrlist attrList
;
452 memset(&attrList
, 0, sizeof attrList
);
453 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
454 attrList
.commonattr
= ATTR_CMN_CRTIME
;
455 if (getattrlist(path
, &attrList
, &attrBuf
, sizeof attrBuf
, FSOPT_NOFOLLOW
) < 0)
457 return attrBuf
.crtime
.tv_sec
;
458 #elif defined __CYGWIN__
460 return stp
->st_birthtime
;
462 #error Unknown crtimes implementation
466 #if defined __CYGWIN__
467 int do_SetFileTime(const char *path
, time_t crtime
)
469 if (dry_run
) return 0;
470 RETURN_ERROR_IF_RO_OR_LO
;
472 int cnt
= MultiByteToWideChar(CP_UTF8
, 0, path
, -1, NULL
, 0);
475 WCHAR
*pathw
= new_array(WCHAR
, cnt
);
478 MultiByteToWideChar(CP_UTF8
, 0, path
, -1, pathw
, cnt
);
479 HANDLE handle
= CreateFileW(pathw
, FILE_WRITE_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
480 NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, NULL
);
482 if (handle
== INVALID_HANDLE_VALUE
)
484 int64 temp_time
= Int32x32To64(crtime
, 10000000) + 116444736000000000LL;
486 birth_time
.dwLowDateTime
= (DWORD
)temp_time
;
487 birth_time
.dwHighDateTime
= (DWORD
)(temp_time
>> 32);
488 int ok
= SetFileTime(handle
, &birth_time
, NULL
, NULL
);
493 #endif /* SUPPORT_CRTIMES */
495 #ifdef HAVE_UTIMENSAT
496 int do_utimensat(const char *path
, STRUCT_STAT
*stp
)
498 struct timespec t
[2];
500 if (dry_run
) return 0;
501 RETURN_ERROR_IF_RO_OR_LO
;
503 t
[0].tv_sec
= stp
->st_atime
;
505 t
[0].tv_nsec
= stp
->ST_ATIME_NSEC
;
509 t
[1].tv_sec
= stp
->st_mtime
;
511 t
[1].tv_nsec
= stp
->ST_MTIME_NSEC
;
515 return utimensat(AT_FDCWD
, path
, t
, AT_SYMLINK_NOFOLLOW
);
520 int do_lutimes(const char *path
, STRUCT_STAT
*stp
)
524 if (dry_run
) return 0;
525 RETURN_ERROR_IF_RO_OR_LO
;
527 t
[0].tv_sec
= stp
->st_atime
;
529 t
[0].tv_usec
= stp
->ST_ATIME_NSEC
/ 1000;
533 t
[1].tv_sec
= stp
->st_mtime
;
535 t
[1].tv_usec
= stp
->ST_MTIME_NSEC
/ 1000;
539 return lutimes(path
, t
);
544 int do_utimes(const char *path
, STRUCT_STAT
*stp
)
548 if (dry_run
) return 0;
549 RETURN_ERROR_IF_RO_OR_LO
;
551 t
[0].tv_sec
= stp
->st_atime
;
553 t
[0].tv_usec
= stp
->ST_ATIME_NSEC
/ 1000;
557 t
[1].tv_sec
= stp
->st_mtime
;
559 t
[1].tv_usec
= stp
->ST_MTIME_NSEC
/ 1000;
563 return utimes(path
, t
);
566 #elif defined HAVE_UTIME
567 int do_utime(const char *path
, STRUCT_STAT
*stp
)
569 #ifdef HAVE_STRUCT_UTIMBUF
575 if (dry_run
) return 0;
576 RETURN_ERROR_IF_RO_OR_LO
;
578 # ifdef HAVE_STRUCT_UTIMBUF
579 tbuf
.actime
= stp
->st_atime
;
580 tbuf
.modtime
= stp
->st_mtime
;
581 return utime(path
, &tbuf
);
583 t
[0] = stp
->st_atime
;
584 t
[1] = stp
->st_mtime
;
585 return utime(path
, t
);
590 #error Need utimes or utime function.
593 #ifdef SUPPORT_PREALLOCATION
594 #ifdef FALLOC_FL_KEEP_SIZE
595 #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE
597 #define DO_FALLOC_OPTIONS 0
600 OFF_T
do_fallocate(int fd
, OFF_T offset
, OFF_T length
)
602 int opts
= inplace
|| preallocate_files
? DO_FALLOC_OPTIONS
: 0;
604 RETURN_ERROR_IF(dry_run
, 0);
605 RETURN_ERROR_IF_RO_OR_LO
;
606 if (length
& 1) /* make the length not match the desired length */
610 #if defined HAVE_FALLOCATE
611 ret
= fallocate(fd
, opts
, offset
, length
);
612 #elif defined HAVE_SYS_FALLOCATE
613 ret
= syscall(SYS_fallocate
, fd
, opts
, (loff_t
)offset
, (loff_t
)length
);
614 #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
615 ret
= posix_fallocate(fd
, offset
, length
);
617 #error Coding error in SUPPORT_PREALLOCATION logic.
623 if (do_fstat(fd
, &st
) < 0)
625 return st
.st_blocks
* S_BLKSIZE
;
631 /* Punch a hole at pos for len bytes. The current file position must be at pos and will be
632 * changed to be at pos + len. */
633 int do_punch_hole(int fd
, OFF_T pos
, OFF_T len
)
635 #ifdef HAVE_FALLOCATE
636 # ifdef HAVE_FALLOC_FL_PUNCH_HOLE
637 if (fallocate(fd
, FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_KEEP_SIZE
, pos
, len
) == 0) {
638 if (do_lseek(fd
, len
, SEEK_CUR
) != pos
+ len
)
643 # ifdef HAVE_FALLOC_FL_ZERO_RANGE
644 if (fallocate(fd
, FALLOC_FL_ZERO_RANGE
, pos
, len
) == 0) {
645 if (do_lseek(fd
, len
, SEEK_CUR
) != pos
+ len
)
655 memset(zeros
, 0, sizeof zeros
);
657 int chunk
= len
> (int)sizeof zeros
? (int)sizeof zeros
: len
;
658 int wrote
= write(fd
, zeros
, chunk
);
660 if (wrote
< 0 && errno
== EINTR
)
670 int do_open_nofollow(const char *pathname
, int flags
)
673 STRUCT_STAT f_st
, l_st
;
677 if (flags
!= O_RDONLY
) {
678 RETURN_ERROR_IF(dry_run
, 0);
679 RETURN_ERROR_IF_RO_OR_LO
;
681 /* This function doesn't support write attempts w/o O_NOFOLLOW. */
688 fd
= open(pathname
, flags
|O_NOFOLLOW
);
690 if (do_lstat(pathname
, &l_st
) < 0)
692 if (S_ISLNK(l_st
.st_mode
)) {
696 if ((fd
= open(pathname
, flags
)) < 0)
698 if (do_fstat(fd
, &f_st
) < 0) {
699 close_and_return_error
:
701 int save_errno
= errno
;
707 if (l_st
.st_dev
!= f_st
.st_dev
|| l_st
.st_ino
!= f_st
.st_ino
) {
709 goto close_and_return_error
;