File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / syscall.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    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
    7:  * Copyright (C) 2003-2020 Wayne Davison
    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: 
   32: #if defined HAVE_SYS_FALLOCATE && !defined HAVE_FALLOCATE
   33: #include <sys/syscall.h>
   34: #endif
   35: 
   36: extern int dry_run;
   37: extern int am_root;
   38: extern int am_sender;
   39: extern int read_only;
   40: extern int list_only;
   41: extern int force_change;
   42: extern int inplace;
   43: extern int preallocate_files;
   44: extern int preserve_perms;
   45: extern int preserve_executability;
   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
   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;
   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;
  100: }
  101: 
  102: #ifdef SUPPORT_LINKS
  103: int do_symlink(const char *lnk, const char *fname)
  104: {
  105: 	if (dry_run) return 0;
  106: 	RETURN_ERROR_IF_RO_OR_LO;
  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);
  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);
  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);
  129: }
  130: 
  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: 
  156: #if defined HAVE_LINK || defined HAVE_LINKAT
  157: int do_link(const char *old_path, const char *new_path)
  158: {
  159: 	int st;
  160: 
  161: 	if (dry_run) return 0;
  162: 	RETURN_ERROR_IF_RO_OR_LO;
  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;
  171: }
  172: #endif
  173: 
  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))
  223: {
  224: 	if (dry_run) return 0;
  225: 	RETURN_ERROR_IF_RO_OR_LO;
  226: #ifndef HAVE_LCHOWN
  227: #define lchown chown
  228: #endif
  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;
  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;
  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: 		}
  279: #ifdef HAVE_SOCKADDR_UN_LEN
  280: 		saddr.sun_len = len + 1;
  281: #endif
  282: 		saddr.sun_family = AF_UNIX;
  283: 
  284: 		if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0
  285: 		 || (unlink(pathname) < 0 && errno != ENOENT)
  286: 		 || (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0)
  287: 			return -1;
  288: 		close(sock);
  289: #ifdef HAVE_CHMOD
  290: 		return do_chmod(pathname, mode, 0);
  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;
  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;
  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: 
  332: #ifdef O_NOATIME
  333: 	if (open_noatime)
  334: 		flags |= O_NOATIME;
  335: #endif
  336: 	if (direct_io)
  337: 		flags |= O_DIRECT;
  338: 
  339: 	return open(pathname, flags | O_BINARY, mode);
  340: }
  341: 
  342: #ifdef HAVE_CHMOD
  343: int do_chmod(const char *path, mode_t mode, UNUSED(uint32 fileflags))
  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 */
  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
  383: 	if (code != 0 && (preserve_perms || preserve_executability))
  384: 		return code;
  385: 	return 0;
  386: }
  387: #endif
  388: 
  389: #ifdef HAVE_CHFLAGS
  390: int do_chflags(const char *path, uint32 fileflags)
  391: {
  392: 	if (dry_run) return 0;
  393: 	RETURN_ERROR_IF_RO_OR_LO;
  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;
  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: 
  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: 
  605: #ifdef HAVE_UTIMENSAT
  606: int do_utimensat(const char *fname, STRUCT_STAT *stp)
  607: {
  608: 	struct timespec t[2];
  609: 
  610: 	if (dry_run) return 0;
  611: 	RETURN_ERROR_IF_RO_OR_LO;
  612: 
  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
  625: 	return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW);
  626: }
  627: #endif
  628: 
  629: #ifdef HAVE_LUTIMES
  630: int do_lutimes(const char *fname, STRUCT_STAT *stp)
  631: {
  632: 	struct timeval t[2];
  633: 
  634: 	if (dry_run) return 0;
  635: 	RETURN_ERROR_IF_RO_OR_LO;
  636: 
  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
  641: 	t[0].tv_usec = 0;
  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
  649: 	return lutimes(fname, t);
  650: }
  651: #endif
  652: 
  653: #ifdef HAVE_UTIMES
  654: int do_utimes(const char *fname, STRUCT_STAT *stp)
  655: {
  656: 	struct timeval t[2];
  657: 
  658: 	if (dry_run) return 0;
  659: 	RETURN_ERROR_IF_RO_OR_LO;
  660: 
  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
  665: 	t[0].tv_usec = 0;
  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
  673: 	return utimes(fname, t);
  674: }
  675: 
  676: #elif defined HAVE_UTIME
  677: int do_utime(const char *fname, STRUCT_STAT *stp)
  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
  689: 	tbuf.actime = stp->st_atime;
  690: 	tbuf.modtime = stp->st_mtime;
  691: 	return utime(fname, &tbuf);
  692: # else
  693: 	t[0] = stp->st_atime;
  694: 	t[1] = stp->st_mtime;
  695: 	return utime(fname, t);
  696: # endif
  697: }
  698: 
  699: #else
  700: #error Need utimes or utime function.
  701: #endif
  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
  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;
  714: 	RETURN_ERROR_IF(dry_run, 0);
  715: 	RETURN_ERROR_IF_RO_OR_LO;
  716: 	if (length & 1) /* make the length not match the desired length */
  717: 		length++;
  718: 	else
  719: 		length--;
  720: #if defined HAVE_FALLOCATE
  721: 	ret = fallocate(fd, opts, offset, length);
  722: #elif defined HAVE_SYS_FALLOCATE
  723: 	ret = syscall(SYS_fallocate, fd, opts, (loff_t)offset, (loff_t)length);
  724: #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
  725: 	ret = posix_fallocate(fd, offset, length);
  726: #else
  727: #error Coding error in SUPPORT_PREALLOCATION logic.
  728: #endif
  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;
  738: }
  739: #endif
  740: 
  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: 
  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: 
  797: 	if (direct_io)
  798: 		flags |= O_DIRECT;
  799: 
  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>