Annotation of embedaddon/rsync/syscall.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:  * Syscall wrappers to ensure that nothing gets done in dry_run mode
                      3:  * and to handle system peculiarities.
                      4:  *
                      5:  * Copyright (C) 1998 Andrew Tridgell
                      6:  * Copyright (C) 2002 Martin Pool
1.1.1.4 ! misho       7:  * Copyright (C) 2003-2020 Wayne Davison
1.1       misho       8:  *
                      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.
                     13:  *
                     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.
                     18:  *
                     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.
                     21:  */
                     22: 
                     23: #include "rsync.h"
                     24: 
                     25: #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
                     26: #include <sys/un.h>
                     27: #endif
                     28: #ifdef HAVE_SYS_ATTR_H
                     29: #include <sys/attr.h>
                     30: #endif
                     31: 
1.1.1.2   misho      32: #if defined HAVE_SYS_FALLOCATE && !defined HAVE_FALLOCATE
                     33: #include <sys/syscall.h>
                     34: #endif
                     35: 
1.1       misho      36: extern int dry_run;
                     37: extern int am_root;
1.1.1.2   misho      38: extern int am_sender;
1.1       misho      39: extern int read_only;
                     40: extern int list_only;
1.1.1.4 ! misho      41: extern int force_change;
        !            42: extern int inplace;
        !            43: extern int preallocate_files;
1.1       misho      44: extern int preserve_perms;
                     45: extern int preserve_executability;
1.1.1.4 ! misho      46: extern int open_noatime;
        !            47: 
        !            48: int direct_io = 0;
        !            49: 
        !            50: #ifndef S_BLKSIZE
        !            51: # if defined hpux || defined __hpux__ || defined __hpux
        !            52: #  define S_BLKSIZE 1024
        !            53: # elif defined _AIX && defined _I386
        !            54: #  define S_BLKSIZE 4096
        !            55: # else
        !            56: #  define S_BLKSIZE 512
        !            57: # endif
        !            58: #endif
        !            59: 
        !            60: #ifdef SUPPORT_CRTIMES
        !            61: #pragma pack(push, 4)
        !            62: struct create_time {
        !            63:        uint32 length;
        !            64:        struct timespec crtime;
        !            65: };
        !            66: #pragma pack(pop)
        !            67: #endif
1.1       misho      68: 
                     69: #define RETURN_ERROR_IF(x,e) \
                     70:        do { \
                     71:                if (x) { \
                     72:                        errno = (e); \
                     73:                        return -1; \
                     74:                } \
                     75:        } while (0)
                     76: 
                     77: #define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
                     78: 
                     79: int do_unlink(const char *fname)
                     80: {
                     81:        if (dry_run) return 0;
                     82:        RETURN_ERROR_IF_RO_OR_LO;
1.1.1.4 ! misho      83:        if (unlink(fname) == 0)
        !            84:                return 0;
        !            85: #ifdef SUPPORT_FORCE_CHANGE
        !            86:        if (force_change && errno == EPERM) {
        !            87:                STRUCT_STAT st;
        !            88: 
        !            89:                if (x_lstat(fname, &st, NULL) == 0
        !            90:                 && make_mutable(fname, st.st_mode, st.st_flags, force_change) > 0) {
        !            91:                        if (unlink(fname) == 0)
        !            92:                                return 0;
        !            93:                        undo_make_mutable(fname, st.st_flags);
        !            94:                }
        !            95:                /* TODO: handle immutable directories */
        !            96:                errno = EPERM;
        !            97:        }
        !            98: #endif
        !            99:        return -1;
1.1       misho     100: }
                    101: 
1.1.1.2   misho     102: #ifdef SUPPORT_LINKS
                    103: int do_symlink(const char *lnk, const char *fname)
1.1       misho     104: {
                    105:        if (dry_run) return 0;
                    106:        RETURN_ERROR_IF_RO_OR_LO;
1.1.1.2   misho     107: 
                    108: #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
                    109:        /* For --fake-super, we create a normal file with mode 0600
                    110:         * and write the lnk into it. */
                    111:        if (am_root < 0) {
                    112:                int ok, len = strlen(lnk);
1.1.1.4 ! misho     113:                int flags = O_WRONLY|O_CREAT|O_TRUNC;
        !           114: 
        !           115:                if (direct_io)
        !           116:                        flags |= O_DIRECT;
        !           117: 
        !           118:                int fd = open(fname, flags, S_IWUSR|S_IRUSR);
1.1.1.2   misho     119:                if (fd < 0)
                    120:                        return -1;
                    121:                ok = write(fd, lnk, len) == len;
                    122:                if (close(fd) < 0)
                    123:                        ok = 0;
                    124:                return ok ? 0 : -1;
                    125:        }
                    126: #endif
                    127: 
                    128:        return symlink(lnk, fname);
1.1       misho     129: }
                    130: 
1.1.1.2   misho     131: #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
                    132: ssize_t do_readlink(const char *path, char *buf, size_t bufsiz)
                    133: {
                    134:        /* For --fake-super, we read the link from the file. */
                    135:        if (am_root < 0) {
                    136:                int fd = do_open_nofollow(path, O_RDONLY);
                    137:                if (fd >= 0) {
                    138:                        int len = read(fd, buf, bufsiz);
                    139:                        close(fd);
                    140:                        return len;
                    141:                }
                    142:                if (errno != ELOOP)
                    143:                        return -1;
                    144:                /* A real symlink needs to be turned into a fake one on the receiving
                    145:                 * side, so tell the generator that the link has no length. */
                    146:                if (!am_sender)
                    147:                        return 0;
                    148:                /* Otherwise fall through and let the sender report the real length. */
                    149:        }
                    150: 
                    151:        return readlink(path, buf, bufsiz);
                    152: }
                    153: #endif
                    154: #endif
                    155: 
1.1.1.4 ! misho     156: #if defined HAVE_LINK || defined HAVE_LINKAT
        !           157: int do_link(const char *old_path, const char *new_path)
1.1       misho     158: {
1.1.1.4 ! misho     159:        int st;
        !           160: 
1.1       misho     161:        if (dry_run) return 0;
                    162:        RETURN_ERROR_IF_RO_OR_LO;
1.1.1.4 ! misho     163: #ifdef HAVE_LINKAT
        !           164:        st = linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0);
        !           165: #else
        !           166:        st = link(old_path, new_path);
        !           167: #endif
        !           168:        if (/*soften_links &&*/ st != 0 && errno == EXDEV)
        !           169:                st = symlink(old_path, new_path);
        !           170:        return st;
1.1       misho     171: }
                    172: #endif
                    173: 
1.1.1.4 ! misho     174: int do_clone(const char *old_path, const char *new_path, mode_t mode)
        !           175: {
        !           176: #ifdef FICLONE
        !           177:        int ifd, ofd, ret, save_errno;
        !           178: 
        !           179:        if (dry_run) return 0;
        !           180:        RETURN_ERROR_IF_RO_OR_LO;
        !           181: 
        !           182:        if ((ifd = do_open(old_path, O_RDONLY, 0)) < 0) {
        !           183:                save_errno = errno;
        !           184:                rsyserr(FERROR_XFER, errno, "open %s", full_fname(old_path));
        !           185:                errno = save_errno;
        !           186:                return -1;
        !           187:        }
        !           188: 
        !           189:        if (robust_unlink(new_path) && errno != ENOENT) {
        !           190:                save_errno = errno;
        !           191:                rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(new_path));
        !           192:                close(ifd);
        !           193:                errno = save_errno;
        !           194:                return -1;
        !           195:        }
        !           196: 
        !           197:        mode &= INITACCESSPERMS;
        !           198:        if ((ofd = do_open(new_path, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
        !           199:                save_errno = errno;
        !           200:                rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(new_path));
        !           201:                close(ifd);
        !           202:                errno = save_errno;
        !           203:                return -1;
        !           204:        }
        !           205: 
        !           206:        ret = ioctl(ofd, FICLONE, ifd);
        !           207:        save_errno = errno;
        !           208:        close(ifd);
        !           209:        close(ofd);
        !           210:        if (ret < 0)
        !           211:                unlink(new_path);
        !           212:        errno = save_errno;
        !           213:        return ret;
        !           214: #else
        !           215:        (void)old_path;
        !           216:        (void)new_path;
        !           217:        errno = ENOTSUP;
        !           218:        return -1;
        !           219: #endif
        !           220: }
        !           221: 
        !           222: int do_lchown(const char *path, uid_t owner, gid_t group, UNUSED(mode_t mode), UNUSED(uint32 fileflags))
1.1       misho     223: {
                    224:        if (dry_run) return 0;
                    225:        RETURN_ERROR_IF_RO_OR_LO;
                    226: #ifndef HAVE_LCHOWN
                    227: #define lchown chown
                    228: #endif
1.1.1.4 ! misho     229:        if (lchown(path, owner, group) == 0)
        !           230:                return 0;
        !           231: #ifdef SUPPORT_FORCE_CHANGE
        !           232:        if (force_change && errno == EPERM) {
        !           233:                if (fileflags == NO_FFLAGS) {
        !           234:                        STRUCT_STAT st;
        !           235:                        if (x_lstat(path, &st, NULL) == 0) {
        !           236:                                mode = st.st_mode;
        !           237:                                fileflags = st.st_flags;
        !           238:                        }
        !           239:                }
        !           240:                if (fileflags != NO_FFLAGS
        !           241:                 && make_mutable(path, mode, fileflags, force_change) > 0) {
        !           242:                        int ret = lchown(path, owner, group);
        !           243:                        undo_make_mutable(path, fileflags);
        !           244:                        if (ret == 0)
        !           245:                                return 0;
        !           246:                }
        !           247:                errno = EPERM;
        !           248:        }
        !           249: #endif
        !           250:        return -1;
1.1       misho     251: }
                    252: 
                    253: int do_mknod(const char *pathname, mode_t mode, dev_t dev)
                    254: {
                    255:        if (dry_run) return 0;
                    256:        RETURN_ERROR_IF_RO_OR_LO;
                    257: 
                    258:        /* For --fake-super, we create a normal file with mode 0600. */
                    259:        if (am_root < 0) {
                    260:                int fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
                    261:                if (fd < 0 || close(fd) < 0)
                    262:                        return -1;
                    263:                return 0;
                    264:        }
                    265: 
                    266: #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
                    267:        if (S_ISFIFO(mode))
                    268:                return mkfifo(pathname, mode);
                    269: #endif
                    270: #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
                    271:        if (S_ISSOCK(mode)) {
                    272:                int sock;
                    273:                struct sockaddr_un saddr;
1.1.1.3   misho     274:                unsigned int len = strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
                    275:                if (len >= sizeof saddr.sun_path) {
                    276:                        errno = ENAMETOOLONG;
                    277:                        return -1;
                    278:                }
1.1       misho     279: #ifdef HAVE_SOCKADDR_UN_LEN
1.1.1.3   misho     280:                saddr.sun_len = len + 1;
1.1       misho     281: #endif
                    282:                saddr.sun_family = AF_UNIX;
                    283: 
                    284:                if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0
1.1.1.4 ! misho     285:                 || (unlink(pathname) < 0 && errno != ENOENT)
        !           286:                 || (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0)
1.1       misho     287:                        return -1;
                    288:                close(sock);
                    289: #ifdef HAVE_CHMOD
1.1.1.4 ! misho     290:                return do_chmod(pathname, mode, 0);
1.1       misho     291: #else
                    292:                return 0;
                    293: #endif
                    294:        }
                    295: #endif
                    296: #ifdef HAVE_MKNOD
                    297:        return mknod(pathname, mode, dev);
                    298: #else
                    299:        return -1;
                    300: #endif
                    301: }
                    302: 
                    303: int do_rmdir(const char *pathname)
                    304: {
                    305:        if (dry_run) return 0;
                    306:        RETURN_ERROR_IF_RO_OR_LO;
1.1.1.4 ! misho     307:        if (rmdir(pathname) == 0)
        !           308:                return 0;
        !           309: #ifdef SUPPORT_FORCE_CHANGE
        !           310:        if (force_change && errno == EPERM) {
        !           311:                STRUCT_STAT st;
        !           312: 
        !           313:                if (x_lstat(pathname, &st, NULL) == 0
        !           314:                 && make_mutable(pathname, st.st_mode, st.st_flags, force_change) > 0) {
        !           315:                        if (rmdir(pathname) == 0)
        !           316:                                return 0;
        !           317:                        undo_make_mutable(pathname, st.st_flags);
        !           318:                }
        !           319:                errno = EPERM;
        !           320:        }
        !           321: #endif
        !           322:        return -1;
1.1       misho     323: }
                    324: 
                    325: int do_open(const char *pathname, int flags, mode_t mode)
                    326: {
                    327:        if (flags != O_RDONLY) {
                    328:                RETURN_ERROR_IF(dry_run, 0);
                    329:                RETURN_ERROR_IF_RO_OR_LO;
                    330:        }
                    331: 
1.1.1.4 ! misho     332: #ifdef O_NOATIME
        !           333:        if (open_noatime)
        !           334:                flags |= O_NOATIME;
        !           335: #endif
        !           336:        if (direct_io)
        !           337:                flags |= O_DIRECT;
        !           338: 
1.1       misho     339:        return open(pathname, flags | O_BINARY, mode);
                    340: }
                    341: 
                    342: #ifdef HAVE_CHMOD
1.1.1.4 ! misho     343: int do_chmod(const char *path, mode_t mode, UNUSED(uint32 fileflags))
1.1       misho     344: {
                    345:        int code;
                    346:        if (dry_run) return 0;
                    347:        RETURN_ERROR_IF_RO_OR_LO;
                    348: #ifdef HAVE_LCHMOD
                    349:        code = lchmod(path, mode & CHMOD_BITS);
                    350: #else
                    351:        if (S_ISLNK(mode)) {
                    352: # if defined HAVE_SETATTRLIST
                    353:                struct attrlist attrList;
                    354:                uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */
                    355: 
                    356:                memset(&attrList, 0, sizeof attrList);
                    357:                attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
                    358:                attrList.commonattr = ATTR_CMN_ACCESSMASK;
                    359:                code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW);
                    360: # else
                    361:                code = 1;
                    362: # endif
                    363:        } else
                    364:                code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
                    365: #endif /* !HAVE_LCHMOD */
1.1.1.4 ! misho     366: #ifdef SUPPORT_FORCE_CHANGE
        !           367:        if (code < 0 && force_change && errno == EPERM && !S_ISLNK(mode)) {
        !           368:                if (fileflags == NO_FFLAGS) {
        !           369:                        STRUCT_STAT st;
        !           370:                        if (x_lstat(path, &st, NULL) == 0)
        !           371:                                fileflags = st.st_flags;
        !           372:                }
        !           373:                if (fileflags != NO_FFLAGS
        !           374:                 && make_mutable(path, mode, fileflags, force_change) > 0) {
        !           375:                        code = chmod(path, mode & CHMOD_BITS);
        !           376:                        undo_make_mutable(path, fileflags);
        !           377:                        if (code == 0)
        !           378:                                return 0;
        !           379:                }
        !           380:                errno = EPERM;
        !           381:        }
        !           382: #endif
1.1       misho     383:        if (code != 0 && (preserve_perms || preserve_executability))
                    384:                return code;
                    385:        return 0;
                    386: }
                    387: #endif
                    388: 
1.1.1.4 ! misho     389: #ifdef HAVE_CHFLAGS
        !           390: int do_chflags(const char *path, uint32 fileflags)
1.1       misho     391: {
                    392:        if (dry_run) return 0;
                    393:        RETURN_ERROR_IF_RO_OR_LO;
1.1.1.4 ! misho     394:        return chflags(path, fileflags);
        !           395: }
        !           396: #endif
        !           397: 
        !           398: int do_rename(const char *old_path, const char *new_path)
        !           399: {
        !           400:        if (dry_run) return 0;
        !           401:        RETURN_ERROR_IF_RO_OR_LO;
        !           402:        if (rename(old_path, new_path) == 0)
        !           403:                return 0;
        !           404: #ifdef SUPPORT_FORCE_CHANGE
        !           405:        if (force_change && errno == EPERM) {
        !           406:                STRUCT_STAT st1, st2;
        !           407:                int became_mutable;
        !           408: 
        !           409:                if (x_lstat(old_path, &st1, NULL) != 0)
        !           410:                        goto failed;
        !           411:                became_mutable = make_mutable(old_path, st1.st_mode, st1.st_flags, force_change) > 0;
        !           412:                if (became_mutable && rename(old_path, new_path) == 0)
        !           413:                        goto success;
        !           414:                if (x_lstat(new_path, &st2, NULL) == 0
        !           415:                 && make_mutable(new_path, st2.st_mode, st2.st_flags, force_change) > 0) {
        !           416:                        if (rename(old_path, new_path) == 0) {
        !           417:                          success:
        !           418:                                if (became_mutable) /* Yes, use new_path and st1! */
        !           419:                                        undo_make_mutable(new_path, st1.st_flags);
        !           420:                                return 0;
        !           421:                        }
        !           422:                        undo_make_mutable(new_path, st2.st_flags);
        !           423:                }
        !           424:                /* TODO: handle immutable directories */
        !           425:                if (became_mutable)
        !           426:                        undo_make_mutable(old_path, st1.st_flags);
        !           427:          failed:
        !           428:                errno = EPERM;
        !           429:        }
        !           430: #endif
        !           431:        return -1;
1.1       misho     432: }
                    433: 
                    434: #ifdef HAVE_FTRUNCATE
                    435: int do_ftruncate(int fd, OFF_T size)
                    436: {
                    437:        int ret;
                    438: 
                    439:        if (dry_run) return 0;
                    440:        RETURN_ERROR_IF_RO_OR_LO;
                    441: 
                    442:        do {
                    443:                ret = ftruncate(fd, size);
                    444:        } while (ret < 0 && errno == EINTR);
                    445: 
                    446:        return ret;
                    447: }
                    448: #endif
                    449: 
                    450: void trim_trailing_slashes(char *name)
                    451: {
                    452:        int l;
                    453:        /* Some BSD systems cannot make a directory if the name
                    454:         * contains a trailing slash.
                    455:         * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
                    456: 
                    457:        /* Don't change empty string; and also we can't improve on
                    458:         * "/" */
                    459: 
                    460:        l = strlen(name);
                    461:        while (l > 1) {
                    462:                if (name[--l] != '/')
                    463:                        break;
                    464:                name[l] = '\0';
                    465:        }
                    466: }
                    467: 
                    468: int do_mkdir(char *fname, mode_t mode)
                    469: {
                    470:        if (dry_run) return 0;
                    471:        RETURN_ERROR_IF_RO_OR_LO;
                    472:        trim_trailing_slashes(fname);
                    473:        return mkdir(fname, mode);
                    474: }
                    475: 
                    476: /* like mkstemp but forces permissions */
                    477: int do_mkstemp(char *template, mode_t perms)
                    478: {
                    479:        RETURN_ERROR_IF(dry_run, 0);
                    480:        RETURN_ERROR_IF(read_only, EROFS);
                    481:        perms |= S_IWUSR;
                    482: 
                    483: #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
                    484:        {
                    485:                int fd = mkstemp(template);
                    486:                if (fd == -1)
                    487:                        return -1;
                    488:                if (fchmod(fd, perms) != 0 && preserve_perms) {
                    489:                        int errno_save = errno;
                    490:                        close(fd);
                    491:                        unlink(template);
                    492:                        errno = errno_save;
                    493:                        return -1;
                    494:                }
                    495: #if defined HAVE_SETMODE && O_BINARY
                    496:                setmode(fd, O_BINARY);
                    497: #endif
                    498:                return fd;
                    499:        }
                    500: #else
                    501:        if (!mktemp(template))
                    502:                return -1;
                    503:        return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
                    504: #endif
                    505: }
                    506: 
                    507: int do_stat(const char *fname, STRUCT_STAT *st)
                    508: {
                    509: #ifdef USE_STAT64_FUNCS
                    510:        return stat64(fname, st);
                    511: #else
                    512:        return stat(fname, st);
                    513: #endif
                    514: }
                    515: 
                    516: int do_lstat(const char *fname, STRUCT_STAT *st)
                    517: {
                    518: #ifdef SUPPORT_LINKS
                    519: # ifdef USE_STAT64_FUNCS
                    520:        return lstat64(fname, st);
                    521: # else
                    522:        return lstat(fname, st);
                    523: # endif
                    524: #else
                    525:        return do_stat(fname, st);
                    526: #endif
                    527: }
                    528: 
                    529: int do_fstat(int fd, STRUCT_STAT *st)
                    530: {
                    531: #ifdef USE_STAT64_FUNCS
                    532:        return fstat64(fd, st);
                    533: #else
                    534:        return fstat(fd, st);
                    535: #endif
                    536: }
                    537: 
                    538: OFF_T do_lseek(int fd, OFF_T offset, int whence)
                    539: {
                    540: #ifdef HAVE_LSEEK64
                    541: #if !SIZEOF_OFF64_T
                    542:        OFF_T lseek64();
                    543: #else
                    544:        off64_t lseek64();
                    545: #endif
                    546:        return lseek64(fd, offset, whence);
                    547: #else
                    548:        return lseek(fd, offset, whence);
                    549: #endif
                    550: }
                    551: 
1.1.1.4 ! misho     552: #ifdef HAVE_SETATTRLIST
        !           553: int do_setattrlist_times(const char *fname, STRUCT_STAT *stp)
        !           554: {
        !           555:        struct attrlist attrList;
        !           556:        struct timespec ts;
        !           557: 
        !           558:        if (dry_run) return 0;
        !           559:        RETURN_ERROR_IF_RO_OR_LO;
        !           560: 
        !           561:        ts.tv_sec = stp->st_mtime;
        !           562:        ts.tv_nsec = stp->ST_MTIME_NSEC;
        !           563: 
        !           564:        memset(&attrList, 0, sizeof attrList);
        !           565:        attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
        !           566:        attrList.commonattr = ATTR_CMN_MODTIME;
        !           567:        return setattrlist(fname, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
        !           568: }
        !           569: #endif
        !           570: 
        !           571: #ifdef SUPPORT_CRTIMES
        !           572: time_t get_create_time(const char *path)
        !           573: {
        !           574:        static struct create_time attrBuf;
        !           575:        struct attrlist attrList;
        !           576: 
        !           577:        memset(&attrList, 0, sizeof attrList);
        !           578:        attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
        !           579:        attrList.commonattr = ATTR_CMN_CRTIME;
        !           580:        if (getattrlist(path, &attrList, &attrBuf, sizeof attrBuf, FSOPT_NOFOLLOW) < 0)
        !           581:                return 0;
        !           582:        return attrBuf.crtime.tv_sec;
        !           583: }
        !           584: #endif
        !           585: 
        !           586: #ifdef SUPPORT_CRTIMES
        !           587: int set_create_time(const char *path, time_t crtime)
        !           588: {
        !           589:        struct attrlist attrList;
        !           590:        struct timespec ts;
        !           591: 
        !           592:        if (dry_run) return 0;
        !           593:        RETURN_ERROR_IF_RO_OR_LO;
        !           594: 
        !           595:        ts.tv_sec = crtime;
        !           596:        ts.tv_nsec = 0;
        !           597: 
        !           598:        memset(&attrList, 0, sizeof attrList);
        !           599:        attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
        !           600:        attrList.commonattr = ATTR_CMN_CRTIME;
        !           601:        return setattrlist(path, &attrList, &ts, sizeof ts, FSOPT_NOFOLLOW);
        !           602: }
        !           603: #endif
        !           604: 
1.1       misho     605: #ifdef HAVE_UTIMENSAT
1.1.1.4 ! misho     606: int do_utimensat(const char *fname, STRUCT_STAT *stp)
1.1       misho     607: {
                    608:        struct timespec t[2];
                    609: 
                    610:        if (dry_run) return 0;
                    611:        RETURN_ERROR_IF_RO_OR_LO;
                    612: 
1.1.1.4 ! misho     613:        t[0].tv_sec = stp->st_atime;
        !           614: #ifdef ST_ATIME_NSEC
        !           615:        t[0].tv_nsec = stp->ST_ATIME_NSEC;
        !           616: #else
        !           617:        t[0].tv_nsec = 0;
        !           618: #endif
        !           619:        t[1].tv_sec = stp->st_mtime;
        !           620: #ifdef ST_MTIME_NSEC
        !           621:        t[1].tv_nsec = stp->ST_MTIME_NSEC;
        !           622: #else
        !           623:        t[1].tv_nsec = 0;
        !           624: #endif
1.1       misho     625:        return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW);
                    626: }
                    627: #endif
                    628: 
                    629: #ifdef HAVE_LUTIMES
1.1.1.4 ! misho     630: int do_lutimes(const char *fname, STRUCT_STAT *stp)
1.1       misho     631: {
                    632:        struct timeval t[2];
                    633: 
                    634:        if (dry_run) return 0;
                    635:        RETURN_ERROR_IF_RO_OR_LO;
                    636: 
1.1.1.4 ! misho     637:        t[0].tv_sec = stp->st_atime;
        !           638: #ifdef ST_ATIME_NSEC
        !           639:        t[0].tv_usec = stp->ST_ATIME_NSEC / 1000;
        !           640: #else
1.1       misho     641:        t[0].tv_usec = 0;
1.1.1.4 ! misho     642: #endif
        !           643:        t[1].tv_sec = stp->st_mtime;
        !           644: #ifdef ST_MTIME_NSEC
        !           645:        t[1].tv_usec = stp->ST_MTIME_NSEC / 1000;
        !           646: #else
        !           647:        t[1].tv_usec = 0;
        !           648: #endif
1.1       misho     649:        return lutimes(fname, t);
                    650: }
                    651: #endif
                    652: 
                    653: #ifdef HAVE_UTIMES
1.1.1.4 ! misho     654: int do_utimes(const char *fname, STRUCT_STAT *stp)
1.1       misho     655: {
                    656:        struct timeval t[2];
                    657: 
                    658:        if (dry_run) return 0;
                    659:        RETURN_ERROR_IF_RO_OR_LO;
                    660: 
1.1.1.4 ! misho     661:        t[0].tv_sec = stp->st_atime;
        !           662: #ifdef ST_ATIME_NSEC
        !           663:        t[0].tv_usec = stp->ST_ATIME_NSEC / 1000;
        !           664: #else
1.1       misho     665:        t[0].tv_usec = 0;
1.1.1.4 ! misho     666: #endif
        !           667:        t[1].tv_sec = stp->st_mtime;
        !           668: #ifdef ST_MTIME_NSEC
        !           669:        t[1].tv_usec = stp->ST_MTIME_NSEC / 1000;
        !           670: #else
        !           671:        t[1].tv_usec = 0;
        !           672: #endif
1.1       misho     673:        return utimes(fname, t);
                    674: }
                    675: 
                    676: #elif defined HAVE_UTIME
1.1.1.4 ! misho     677: int do_utime(const char *fname, STRUCT_STAT *stp)
1.1       misho     678: {
                    679: #ifdef HAVE_STRUCT_UTIMBUF
                    680:        struct utimbuf tbuf;
                    681: #else
                    682:        time_t t[2];
                    683: #endif
                    684: 
                    685:        if (dry_run) return 0;
                    686:        RETURN_ERROR_IF_RO_OR_LO;
                    687: 
                    688: # ifdef HAVE_STRUCT_UTIMBUF
1.1.1.4 ! misho     689:        tbuf.actime = stp->st_atime;
        !           690:        tbuf.modtime = stp->st_mtime;
1.1       misho     691:        return utime(fname, &tbuf);
                    692: # else
1.1.1.4 ! misho     693:        t[0] = stp->st_atime;
        !           694:        t[1] = stp->st_mtime;
1.1       misho     695:        return utime(fname, t);
                    696: # endif
                    697: }
                    698: 
                    699: #else
                    700: #error Need utimes or utime function.
                    701: #endif
1.1.1.2   misho     702: 
                    703: #ifdef SUPPORT_PREALLOCATION
                    704: #ifdef FALLOC_FL_KEEP_SIZE
                    705: #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE
                    706: #else
                    707: #define DO_FALLOC_OPTIONS 0
                    708: #endif
1.1.1.4 ! misho     709: 
        !           710: OFF_T do_fallocate(int fd, OFF_T offset, OFF_T length)
        !           711: {
        !           712:        int opts = inplace || preallocate_files ? DO_FALLOC_OPTIONS : 0;
        !           713:        int ret;
1.1.1.2   misho     714:        RETURN_ERROR_IF(dry_run, 0);
                    715:        RETURN_ERROR_IF_RO_OR_LO;
1.1.1.4 ! misho     716:        if (length & 1) /* make the length not match the desired length */
        !           717:                length++;
        !           718:        else
        !           719:                length--;
1.1.1.2   misho     720: #if defined HAVE_FALLOCATE
1.1.1.4 ! misho     721:        ret = fallocate(fd, opts, offset, length);
1.1.1.2   misho     722: #elif defined HAVE_SYS_FALLOCATE
1.1.1.4 ! misho     723:        ret = syscall(SYS_fallocate, fd, opts, (loff_t)offset, (loff_t)length);
1.1.1.2   misho     724: #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
1.1.1.4 ! misho     725:        ret = posix_fallocate(fd, offset, length);
1.1.1.2   misho     726: #else
                    727: #error Coding error in SUPPORT_PREALLOCATION logic.
                    728: #endif
1.1.1.4 ! misho     729:        if (ret < 0)
        !           730:                return ret;
        !           731:        if (opts == 0) {
        !           732:                STRUCT_STAT st;
        !           733:                if (do_fstat(fd, &st) < 0)
        !           734:                        return length;
        !           735:                return st.st_blocks * S_BLKSIZE;
        !           736:        }
        !           737:        return 0;
1.1.1.2   misho     738: }
                    739: #endif
                    740: 
1.1.1.4 ! misho     741: /* Punch a hole at pos for len bytes. The current file position must be at pos and will be
        !           742:  * changed to be at pos + len. */
        !           743: int do_punch_hole(int fd, OFF_T pos, OFF_T len)
        !           744: {
        !           745: #ifdef HAVE_FALLOCATE
        !           746: # ifdef HAVE_FALLOC_FL_PUNCH_HOLE
        !           747:        if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, pos, len) == 0) {
        !           748:                if (do_lseek(fd, len, SEEK_CUR) != pos + len)
        !           749:                        return -1;
        !           750:                return 0;
        !           751:        }
        !           752: # endif
        !           753: # ifdef HAVE_FALLOC_FL_ZERO_RANGE
        !           754:        if (fallocate(fd, FALLOC_FL_ZERO_RANGE, pos, len) == 0) {
        !           755:                if (do_lseek(fd, len, SEEK_CUR) != pos + len)
        !           756:                        return -1;
        !           757:                return 0;
        !           758:        }
        !           759: # endif
        !           760: #else
        !           761:        (void)pos;
        !           762: #endif
        !           763:        {
        !           764:                char zeros[4096];
        !           765:                memset(zeros, 0, sizeof zeros);
        !           766:                while (len > 0) {
        !           767:                        int chunk = len > (int)sizeof zeros ? (int)sizeof zeros : len;
        !           768:                        int wrote = write(fd, zeros, chunk);
        !           769:                        if (wrote <= 0) {
        !           770:                                if (wrote < 0 && errno == EINTR)
        !           771:                                        continue;
        !           772:                                return -1;
        !           773:                        }
        !           774:                        len -= wrote;
        !           775:                }
        !           776:        }
        !           777:        return 0;
        !           778: }
        !           779: 
1.1.1.2   misho     780: int do_open_nofollow(const char *pathname, int flags)
                    781: {
                    782: #ifndef O_NOFOLLOW
                    783:        STRUCT_STAT f_st, l_st;
                    784: #endif
                    785:        int fd;
                    786: 
                    787:        if (flags != O_RDONLY) {
                    788:                RETURN_ERROR_IF(dry_run, 0);
                    789:                RETURN_ERROR_IF_RO_OR_LO;
                    790: #ifndef O_NOFOLLOW
                    791:                /* This function doesn't support write attempts w/o O_NOFOLLOW. */
                    792:                errno = EINVAL;
                    793:                return -1;
                    794: #endif
                    795:        }
                    796: 
1.1.1.4 ! misho     797:        if (direct_io)
        !           798:                flags |= O_DIRECT;
        !           799: 
1.1.1.2   misho     800: #ifdef O_NOFOLLOW
                    801:        fd = open(pathname, flags|O_NOFOLLOW);
                    802: #else
                    803:        if (do_lstat(pathname, &l_st) < 0)
                    804:                return -1;
                    805:        if (S_ISLNK(l_st.st_mode)) {
                    806:                errno = ELOOP;
                    807:                return -1;
                    808:        }
                    809:        if ((fd = open(pathname, flags)) < 0)
                    810:                return fd;
                    811:        if (do_fstat(fd, &f_st) < 0) {
                    812:          close_and_return_error:
                    813:                {
                    814:                        int save_errno = errno;
                    815:                        close(fd);
                    816:                        errno = save_errno;
                    817:                }
                    818:                return -1;
                    819:        }
                    820:        if (l_st.st_dev != f_st.st_dev || l_st.st_ino != f_st.st_ino) {
                    821:                errno = EINVAL;
                    822:                goto close_and_return_error;
                    823:        }
                    824: #endif
                    825: 
                    826:        return fd;
                    827: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>