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-2020 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 #define RETURN_ERROR_IF(x,e) \
65 #define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
67 int do_unlink(const char *fname
)
69 if (dry_run
) return 0;
70 RETURN_ERROR_IF_RO_OR_LO
;
75 int do_symlink(const char *lnk
, const char *fname
)
77 if (dry_run
) return 0;
78 RETURN_ERROR_IF_RO_OR_LO
;
80 #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
81 /* For --fake-super, we create a normal file with mode 0600
82 * and write the lnk into it. */
84 int ok
, len
= strlen(lnk
);
85 int fd
= open(fname
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IWUSR
|S_IRUSR
);
88 ok
= write(fd
, lnk
, len
) == len
;
95 return symlink(lnk
, fname
);
98 #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
99 ssize_t
do_readlink(const char *path
, char *buf
, size_t bufsiz
)
101 /* For --fake-super, we read the link from the file. */
103 int fd
= do_open_nofollow(path
, O_RDONLY
);
105 int len
= read(fd
, buf
, bufsiz
);
111 /* A real symlink needs to be turned into a fake one on the receiving
112 * side, so tell the generator that the link has no length. */
115 /* Otherwise fall through and let the sender report the real length. */
118 return readlink(path
, buf
, bufsiz
);
124 int do_link(const char *old_path
, const char *new_path
)
126 if (dry_run
) return 0;
127 RETURN_ERROR_IF_RO_OR_LO
;
128 return link(old_path
, new_path
);
132 int do_lchown(const char *path
, uid_t owner
, gid_t group
)
134 if (dry_run
) return 0;
135 RETURN_ERROR_IF_RO_OR_LO
;
139 return lchown(path
, owner
, group
);
142 int do_mknod(const char *pathname
, mode_t mode
, dev_t dev
)
144 if (dry_run
) return 0;
145 RETURN_ERROR_IF_RO_OR_LO
;
147 /* For --fake-super, we create a normal file with mode 0600. */
149 int fd
= open(pathname
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IWUSR
|S_IRUSR
);
150 if (fd
< 0 || close(fd
) < 0)
155 #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
157 return mkfifo(pathname
, mode
);
159 #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
160 if (S_ISSOCK(mode
)) {
162 struct sockaddr_un saddr
;
163 unsigned int len
= strlcpy(saddr
.sun_path
, pathname
, sizeof saddr
.sun_path
);
164 if (len
>= sizeof saddr
.sun_path
) {
165 errno
= ENAMETOOLONG
;
168 #ifdef HAVE_SOCKADDR_UN_LEN
169 saddr
.sun_len
= len
+ 1;
171 saddr
.sun_family
= AF_UNIX
;
173 if ((sock
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0
174 || (unlink(pathname
) < 0 && errno
!= ENOENT
)
175 || (bind(sock
, (struct sockaddr
*)&saddr
, sizeof saddr
)) < 0)
179 return do_chmod(pathname
, mode
);
186 return mknod(pathname
, mode
, dev
);
192 int do_rmdir(const char *pathname
)
194 if (dry_run
) return 0;
195 RETURN_ERROR_IF_RO_OR_LO
;
196 return rmdir(pathname
);
199 int do_open(const char *pathname
, int flags
, mode_t mode
)
201 if (flags
!= O_RDONLY
) {
202 RETURN_ERROR_IF(dry_run
, 0);
203 RETURN_ERROR_IF_RO_OR_LO
;
211 return open(pathname
, flags
| O_BINARY
, mode
);
215 int do_chmod(const char *path
, mode_t mode
)
218 if (dry_run
) return 0;
219 RETURN_ERROR_IF_RO_OR_LO
;
221 code
= lchmod(path
, mode
& CHMOD_BITS
);
224 # if defined HAVE_SETATTRLIST
225 struct attrlist attrList
;
226 uint32_t m
= mode
& CHMOD_BITS
; /* manpage is wrong: not mode_t! */
228 memset(&attrList
, 0, sizeof attrList
);
229 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
230 attrList
.commonattr
= ATTR_CMN_ACCESSMASK
;
231 code
= setattrlist(path
, &attrList
, &m
, sizeof m
, FSOPT_NOFOLLOW
);
236 code
= chmod(path
, mode
& CHMOD_BITS
); /* DISCOURAGED FUNCTION */
237 #endif /* !HAVE_LCHMOD */
238 if (code
!= 0 && (preserve_perms
|| preserve_executability
))
244 int do_rename(const char *old_path
, const char *new_path
)
246 if (dry_run
) return 0;
247 RETURN_ERROR_IF_RO_OR_LO
;
248 return rename(old_path
, new_path
);
251 #ifdef HAVE_FTRUNCATE
252 int do_ftruncate(int fd
, OFF_T size
)
256 if (dry_run
) return 0;
257 RETURN_ERROR_IF_RO_OR_LO
;
260 ret
= ftruncate(fd
, size
);
261 } while (ret
< 0 && errno
== EINTR
);
267 void trim_trailing_slashes(char *name
)
270 /* Some BSD systems cannot make a directory if the name
271 * contains a trailing slash.
272 * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
274 /* Don't change empty string; and also we can't improve on
279 if (name
[--l
] != '/')
285 int do_mkdir(char *fname
, mode_t mode
)
287 if (dry_run
) return 0;
288 RETURN_ERROR_IF_RO_OR_LO
;
289 trim_trailing_slashes(fname
);
290 return mkdir(fname
, mode
);
293 /* like mkstemp but forces permissions */
294 int do_mkstemp(char *template, mode_t perms
)
296 RETURN_ERROR_IF(dry_run
, 0);
297 RETURN_ERROR_IF(read_only
, EROFS
);
300 #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
302 int fd
= mkstemp(template);
305 if (fchmod(fd
, perms
) != 0 && preserve_perms
) {
306 int errno_save
= errno
;
312 #if defined HAVE_SETMODE && O_BINARY
313 setmode(fd
, O_BINARY
);
318 if (!mktemp(template))
320 return do_open(template, O_RDWR
|O_EXCL
|O_CREAT
, perms
);
324 int do_stat(const char *fname
, STRUCT_STAT
*st
)
326 #ifdef USE_STAT64_FUNCS
327 return stat64(fname
, st
);
329 return stat(fname
, st
);
333 int do_lstat(const char *fname
, STRUCT_STAT
*st
)
336 # ifdef USE_STAT64_FUNCS
337 return lstat64(fname
, st
);
339 return lstat(fname
, st
);
342 return do_stat(fname
, st
);
346 int do_fstat(int fd
, STRUCT_STAT
*st
)
348 #ifdef USE_STAT64_FUNCS
349 return fstat64(fd
, st
);
351 return fstat(fd
, st
);
355 OFF_T
do_lseek(int fd
, OFF_T offset
, int whence
)
363 return lseek64(fd
, offset
, whence
);
365 return lseek(fd
, offset
, whence
);
369 #ifdef HAVE_SETATTRLIST
370 int do_setattrlist_times(const char *fname
, STRUCT_STAT
*stp
)
372 struct attrlist attrList
;
375 if (dry_run
) return 0;
376 RETURN_ERROR_IF_RO_OR_LO
;
378 ts
.tv_sec
= stp
->st_mtime
;
379 ts
.tv_nsec
= stp
->ST_MTIME_NSEC
;
381 memset(&attrList
, 0, sizeof attrList
);
382 attrList
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
383 attrList
.commonattr
= ATTR_CMN_MODTIME
;
384 return setattrlist(fname
, &attrList
, &ts
, sizeof ts
, FSOPT_NOFOLLOW
);
388 #ifdef HAVE_UTIMENSAT
389 int do_utimensat(const char *fname
, STRUCT_STAT
*stp
)
391 struct timespec t
[2];
393 if (dry_run
) return 0;
394 RETURN_ERROR_IF_RO_OR_LO
;
396 t
[0].tv_sec
= stp
->st_atime
;
398 t
[0].tv_nsec
= stp
->ST_ATIME_NSEC
;
402 t
[1].tv_sec
= stp
->st_mtime
;
404 t
[1].tv_nsec
= stp
->ST_MTIME_NSEC
;
408 return utimensat(AT_FDCWD
, fname
, t
, AT_SYMLINK_NOFOLLOW
);
413 int do_lutimes(const char *fname
, STRUCT_STAT
*stp
)
417 if (dry_run
) return 0;
418 RETURN_ERROR_IF_RO_OR_LO
;
420 t
[0].tv_sec
= stp
->st_atime
;
422 t
[0].tv_usec
= stp
->ST_ATIME_NSEC
/ 1000;
426 t
[1].tv_sec
= stp
->st_mtime
;
428 t
[1].tv_usec
= stp
->ST_MTIME_NSEC
/ 1000;
432 return lutimes(fname
, t
);
437 int do_utimes(const char *fname
, STRUCT_STAT
*stp
)
441 if (dry_run
) return 0;
442 RETURN_ERROR_IF_RO_OR_LO
;
444 t
[0].tv_sec
= stp
->st_atime
;
446 t
[0].tv_usec
= stp
->ST_ATIME_NSEC
/ 1000;
450 t
[1].tv_sec
= stp
->st_mtime
;
452 t
[1].tv_usec
= stp
->ST_MTIME_NSEC
/ 1000;
456 return utimes(fname
, t
);
459 #elif defined HAVE_UTIME
460 int do_utime(const char *fname
, STRUCT_STAT
*stp
)
462 #ifdef HAVE_STRUCT_UTIMBUF
468 if (dry_run
) return 0;
469 RETURN_ERROR_IF_RO_OR_LO
;
471 # ifdef HAVE_STRUCT_UTIMBUF
472 tbuf
.actime
= stp
->st_atime
;
473 tbuf
.modtime
= stp
->st_mtime
;
474 return utime(fname
, &tbuf
);
476 t
[0] = stp
->st_atime
;
477 t
[1] = stp
->st_mtime
;
478 return utime(fname
, t
);
483 #error Need utimes or utime function.
486 #ifdef SUPPORT_PREALLOCATION
487 #ifdef FALLOC_FL_KEEP_SIZE
488 #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE
490 #define DO_FALLOC_OPTIONS 0
493 OFF_T
do_fallocate(int fd
, OFF_T offset
, OFF_T length
)
495 int opts
= inplace
|| preallocate_files
? DO_FALLOC_OPTIONS
: 0;
497 RETURN_ERROR_IF(dry_run
, 0);
498 RETURN_ERROR_IF_RO_OR_LO
;
499 if (length
& 1) /* make the length not match the desired length */
503 #if defined HAVE_FALLOCATE
504 ret
= fallocate(fd
, opts
, offset
, length
);
505 #elif defined HAVE_SYS_FALLOCATE
506 ret
= syscall(SYS_fallocate
, fd
, opts
, (loff_t
)offset
, (loff_t
)length
);
507 #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
508 ret
= posix_fallocate(fd
, offset
, length
);
510 #error Coding error in SUPPORT_PREALLOCATION logic.
516 if (do_fstat(fd
, &st
) < 0)
518 return st
.st_blocks
* S_BLKSIZE
;
524 /* Punch a hole at pos for len bytes. The current file position must be at pos and will be
525 * changed to be at pos + len. */
526 int do_punch_hole(int fd
, UNUSED(OFF_T pos
), OFF_T len
)
528 #ifdef HAVE_FALLOCATE
529 # ifdef HAVE_FALLOC_FL_PUNCH_HOLE
530 if (fallocate(fd
, FALLOC_FL_PUNCH_HOLE
| FALLOC_FL_KEEP_SIZE
, pos
, len
) == 0) {
531 if (do_lseek(fd
, len
, SEEK_CUR
) != pos
+ len
)
536 # ifdef HAVE_FALLOC_FL_ZERO_RANGE
537 if (fallocate(fd
, FALLOC_FL_ZERO_RANGE
, pos
, len
) == 0) {
538 if (do_lseek(fd
, len
, SEEK_CUR
) != pos
+ len
)
546 memset(zeros
, 0, sizeof zeros
);
548 int chunk
= len
> (int)sizeof zeros
? (int)sizeof zeros
: len
;
549 int wrote
= write(fd
, zeros
, chunk
);
551 if (wrote
< 0 && errno
== EINTR
)
561 int do_open_nofollow(const char *pathname
, int flags
)
564 STRUCT_STAT f_st
, l_st
;
568 if (flags
!= O_RDONLY
) {
569 RETURN_ERROR_IF(dry_run
, 0);
570 RETURN_ERROR_IF_RO_OR_LO
;
572 /* This function doesn't support write attempts w/o O_NOFOLLOW. */
579 fd
= open(pathname
, flags
|O_NOFOLLOW
);
581 if (do_lstat(pathname
, &l_st
) < 0)
583 if (S_ISLNK(l_st
.st_mode
)) {
587 if ((fd
= open(pathname
, flags
)) < 0)
589 if (do_fstat(fd
, &f_st
) < 0) {
590 close_and_return_error
:
592 int save_errno
= errno
;
598 if (l_st
.st_dev
!= f_st
.st_dev
|| l_st
.st_ino
!= f_st
.st_ino
) {
600 goto close_and_return_error
;