File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / syscall.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:51:14 2013 UTC (10 years, 8 months ago) by misho
Branches: rsync, MAIN
CVS tags: RSYNC3_1_0, HEAD
v 3.1.0

    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-2013 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 preserve_perms;
   42: extern int preserve_executability;
   43: 
   44: #define RETURN_ERROR_IF(x,e) \
   45: 	do { \
   46: 		if (x) { \
   47: 			errno = (e); \
   48: 			return -1; \
   49: 		} \
   50: 	} while (0)
   51: 
   52: #define RETURN_ERROR_IF_RO_OR_LO RETURN_ERROR_IF(read_only || list_only, EROFS)
   53: 
   54: int do_unlink(const char *fname)
   55: {
   56: 	if (dry_run) return 0;
   57: 	RETURN_ERROR_IF_RO_OR_LO;
   58: 	return unlink(fname);
   59: }
   60: 
   61: #ifdef SUPPORT_LINKS
   62: int do_symlink(const char *lnk, const char *fname)
   63: {
   64: 	if (dry_run) return 0;
   65: 	RETURN_ERROR_IF_RO_OR_LO;
   66: 
   67: #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
   68: 	/* For --fake-super, we create a normal file with mode 0600
   69: 	 * and write the lnk into it. */
   70: 	if (am_root < 0) {
   71: 		int ok, len = strlen(lnk);
   72: 		int fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
   73: 		if (fd < 0)
   74: 			return -1;
   75: 		ok = write(fd, lnk, len) == len;
   76: 		if (close(fd) < 0)
   77: 			ok = 0;
   78: 		return ok ? 0 : -1;
   79: 	}
   80: #endif
   81: 
   82: 	return symlink(lnk, fname);
   83: }
   84: 
   85: #if defined NO_SYMLINK_XATTRS || defined NO_SYMLINK_USER_XATTRS
   86: ssize_t do_readlink(const char *path, char *buf, size_t bufsiz)
   87: {
   88: 	/* For --fake-super, we read the link from the file. */
   89: 	if (am_root < 0) {
   90: 		int fd = do_open_nofollow(path, O_RDONLY);
   91: 		if (fd >= 0) {
   92: 			int len = read(fd, buf, bufsiz);
   93: 			close(fd);
   94: 			return len;
   95: 		}
   96: 		if (errno != ELOOP)
   97: 			return -1;
   98: 		/* A real symlink needs to be turned into a fake one on the receiving
   99: 		 * side, so tell the generator that the link has no length. */
  100: 		if (!am_sender)
  101: 			return 0;
  102: 		/* Otherwise fall through and let the sender report the real length. */
  103: 	}
  104: 
  105: 	return readlink(path, buf, bufsiz);
  106: }
  107: #endif
  108: #endif
  109: 
  110: #ifdef HAVE_LINK
  111: int do_link(const char *fname1, const char *fname2)
  112: {
  113: 	if (dry_run) return 0;
  114: 	RETURN_ERROR_IF_RO_OR_LO;
  115: 	return link(fname1, fname2);
  116: }
  117: #endif
  118: 
  119: int do_lchown(const char *path, uid_t owner, gid_t group)
  120: {
  121: 	if (dry_run) return 0;
  122: 	RETURN_ERROR_IF_RO_OR_LO;
  123: #ifndef HAVE_LCHOWN
  124: #define lchown chown
  125: #endif
  126: 	return lchown(path, owner, group);
  127: }
  128: 
  129: int do_mknod(const char *pathname, mode_t mode, dev_t dev)
  130: {
  131: 	if (dry_run) return 0;
  132: 	RETURN_ERROR_IF_RO_OR_LO;
  133: 
  134: 	/* For --fake-super, we create a normal file with mode 0600. */
  135: 	if (am_root < 0) {
  136: 		int fd = open(pathname, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
  137: 		if (fd < 0 || close(fd) < 0)
  138: 			return -1;
  139: 		return 0;
  140: 	}
  141: 
  142: #if !defined MKNOD_CREATES_FIFOS && defined HAVE_MKFIFO
  143: 	if (S_ISFIFO(mode))
  144: 		return mkfifo(pathname, mode);
  145: #endif
  146: #if !defined MKNOD_CREATES_SOCKETS && defined HAVE_SYS_UN_H
  147: 	if (S_ISSOCK(mode)) {
  148: 		int sock;
  149: 		struct sockaddr_un saddr;
  150: #ifdef HAVE_SOCKADDR_UN_LEN
  151: 		unsigned int len =
  152: #endif
  153: 		    strlcpy(saddr.sun_path, pathname, sizeof saddr.sun_path);
  154: #ifdef HAVE_SOCKADDR_UN_LEN
  155: 		saddr.sun_len = len >= sizeof saddr.sun_path
  156: 			      ? sizeof saddr.sun_path : len + 1;
  157: #endif
  158: 		saddr.sun_family = AF_UNIX;
  159: 
  160: 		if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0
  161: 		    || (unlink(pathname) < 0 && errno != ENOENT)
  162: 		    || (bind(sock, (struct sockaddr*)&saddr, sizeof saddr)) < 0)
  163: 			return -1;
  164: 		close(sock);
  165: #ifdef HAVE_CHMOD
  166: 		return do_chmod(pathname, mode);
  167: #else
  168: 		return 0;
  169: #endif
  170: 	}
  171: #endif
  172: #ifdef HAVE_MKNOD
  173: 	return mknod(pathname, mode, dev);
  174: #else
  175: 	return -1;
  176: #endif
  177: }
  178: 
  179: int do_rmdir(const char *pathname)
  180: {
  181: 	if (dry_run) return 0;
  182: 	RETURN_ERROR_IF_RO_OR_LO;
  183: 	return rmdir(pathname);
  184: }
  185: 
  186: int do_open(const char *pathname, int flags, mode_t mode)
  187: {
  188: 	if (flags != O_RDONLY) {
  189: 		RETURN_ERROR_IF(dry_run, 0);
  190: 		RETURN_ERROR_IF_RO_OR_LO;
  191: 	}
  192: 
  193: 	return open(pathname, flags | O_BINARY, mode);
  194: }
  195: 
  196: #ifdef HAVE_CHMOD
  197: int do_chmod(const char *path, mode_t mode)
  198: {
  199: 	int code;
  200: 	if (dry_run) return 0;
  201: 	RETURN_ERROR_IF_RO_OR_LO;
  202: #ifdef HAVE_LCHMOD
  203: 	code = lchmod(path, mode & CHMOD_BITS);
  204: #else
  205: 	if (S_ISLNK(mode)) {
  206: # if defined HAVE_SETATTRLIST
  207: 		struct attrlist attrList;
  208: 		uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */
  209: 
  210: 		memset(&attrList, 0, sizeof attrList);
  211: 		attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
  212: 		attrList.commonattr = ATTR_CMN_ACCESSMASK;
  213: 		code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW);
  214: # else
  215: 		code = 1;
  216: # endif
  217: 	} else
  218: 		code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
  219: #endif /* !HAVE_LCHMOD */
  220: 	if (code != 0 && (preserve_perms || preserve_executability))
  221: 		return code;
  222: 	return 0;
  223: }
  224: #endif
  225: 
  226: int do_rename(const char *fname1, const char *fname2)
  227: {
  228: 	if (dry_run) return 0;
  229: 	RETURN_ERROR_IF_RO_OR_LO;
  230: 	return rename(fname1, fname2);
  231: }
  232: 
  233: #ifdef HAVE_FTRUNCATE
  234: int do_ftruncate(int fd, OFF_T size)
  235: {
  236: 	int ret;
  237: 
  238: 	if (dry_run) return 0;
  239: 	RETURN_ERROR_IF_RO_OR_LO;
  240: 
  241: 	do {
  242: 		ret = ftruncate(fd, size);
  243: 	} while (ret < 0 && errno == EINTR);
  244: 
  245: 	return ret;
  246: }
  247: #endif
  248: 
  249: void trim_trailing_slashes(char *name)
  250: {
  251: 	int l;
  252: 	/* Some BSD systems cannot make a directory if the name
  253: 	 * contains a trailing slash.
  254: 	 * <http://www.opensource.apple.com/bugs/X/BSD%20Kernel/2734739.html> */
  255: 
  256: 	/* Don't change empty string; and also we can't improve on
  257: 	 * "/" */
  258: 
  259: 	l = strlen(name);
  260: 	while (l > 1) {
  261: 		if (name[--l] != '/')
  262: 			break;
  263: 		name[l] = '\0';
  264: 	}
  265: }
  266: 
  267: int do_mkdir(char *fname, mode_t mode)
  268: {
  269: 	if (dry_run) return 0;
  270: 	RETURN_ERROR_IF_RO_OR_LO;
  271: 	trim_trailing_slashes(fname);
  272: 	return mkdir(fname, mode);
  273: }
  274: 
  275: /* like mkstemp but forces permissions */
  276: int do_mkstemp(char *template, mode_t perms)
  277: {
  278: 	RETURN_ERROR_IF(dry_run, 0);
  279: 	RETURN_ERROR_IF(read_only, EROFS);
  280: 	perms |= S_IWUSR;
  281: 
  282: #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
  283: 	{
  284: 		int fd = mkstemp(template);
  285: 		if (fd == -1)
  286: 			return -1;
  287: 		if (fchmod(fd, perms) != 0 && preserve_perms) {
  288: 			int errno_save = errno;
  289: 			close(fd);
  290: 			unlink(template);
  291: 			errno = errno_save;
  292: 			return -1;
  293: 		}
  294: #if defined HAVE_SETMODE && O_BINARY
  295: 		setmode(fd, O_BINARY);
  296: #endif
  297: 		return fd;
  298: 	}
  299: #else
  300: 	if (!mktemp(template))
  301: 		return -1;
  302: 	return do_open(template, O_RDWR|O_EXCL|O_CREAT, perms);
  303: #endif
  304: }
  305: 
  306: int do_stat(const char *fname, STRUCT_STAT *st)
  307: {
  308: #ifdef USE_STAT64_FUNCS
  309: 	return stat64(fname, st);
  310: #else
  311: 	return stat(fname, st);
  312: #endif
  313: }
  314: 
  315: int do_lstat(const char *fname, STRUCT_STAT *st)
  316: {
  317: #ifdef SUPPORT_LINKS
  318: # ifdef USE_STAT64_FUNCS
  319: 	return lstat64(fname, st);
  320: # else
  321: 	return lstat(fname, st);
  322: # endif
  323: #else
  324: 	return do_stat(fname, st);
  325: #endif
  326: }
  327: 
  328: int do_fstat(int fd, STRUCT_STAT *st)
  329: {
  330: #ifdef USE_STAT64_FUNCS
  331: 	return fstat64(fd, st);
  332: #else
  333: 	return fstat(fd, st);
  334: #endif
  335: }
  336: 
  337: OFF_T do_lseek(int fd, OFF_T offset, int whence)
  338: {
  339: #ifdef HAVE_LSEEK64
  340: #if !SIZEOF_OFF64_T
  341: 	OFF_T lseek64();
  342: #else
  343: 	off64_t lseek64();
  344: #endif
  345: 	return lseek64(fd, offset, whence);
  346: #else
  347: 	return lseek(fd, offset, whence);
  348: #endif
  349: }
  350: 
  351: #ifdef HAVE_UTIMENSAT
  352: int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec)
  353: {
  354: 	struct timespec t[2];
  355: 
  356: 	if (dry_run) return 0;
  357: 	RETURN_ERROR_IF_RO_OR_LO;
  358: 
  359: 	t[0].tv_sec = 0;
  360: 	t[0].tv_nsec = UTIME_NOW;
  361: 	t[1].tv_sec = modtime;
  362: 	t[1].tv_nsec = mod_nsec;
  363: 	return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW);
  364: }
  365: #endif
  366: 
  367: #ifdef HAVE_LUTIMES
  368: int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec)
  369: {
  370: 	struct timeval t[2];
  371: 
  372: 	if (dry_run) return 0;
  373: 	RETURN_ERROR_IF_RO_OR_LO;
  374: 
  375: 	t[0].tv_sec = time(NULL);
  376: 	t[0].tv_usec = 0;
  377: 	t[1].tv_sec = modtime;
  378: 	t[1].tv_usec = mod_nsec / 1000;
  379: 	return lutimes(fname, t);
  380: }
  381: #endif
  382: 
  383: #ifdef HAVE_UTIMES
  384: int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec)
  385: {
  386: 	struct timeval t[2];
  387: 
  388: 	if (dry_run) return 0;
  389: 	RETURN_ERROR_IF_RO_OR_LO;
  390: 
  391: 	t[0].tv_sec = time(NULL);
  392: 	t[0].tv_usec = 0;
  393: 	t[1].tv_sec = modtime;
  394: 	t[1].tv_usec = mod_nsec / 1000;
  395: 	return utimes(fname, t);
  396: }
  397: 
  398: #elif defined HAVE_UTIME
  399: int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec))
  400: {
  401: #ifdef HAVE_STRUCT_UTIMBUF
  402: 	struct utimbuf tbuf;
  403: #else
  404: 	time_t t[2];
  405: #endif
  406: 
  407: 	if (dry_run) return 0;
  408: 	RETURN_ERROR_IF_RO_OR_LO;
  409: 
  410: # ifdef HAVE_STRUCT_UTIMBUF
  411: 	tbuf.actime = time(NULL);
  412: 	tbuf.modtime = modtime;
  413: 	return utime(fname, &tbuf);
  414: # else
  415: 	t[0] = time(NULL);
  416: 	t[1] = modtime;
  417: 	return utime(fname, t);
  418: # endif
  419: }
  420: 
  421: #else
  422: #error Need utimes or utime function.
  423: #endif
  424: 
  425: #ifdef SUPPORT_PREALLOCATION
  426: int do_fallocate(int fd, OFF_T offset, OFF_T length)
  427: {
  428: #ifdef FALLOC_FL_KEEP_SIZE
  429: #define DO_FALLOC_OPTIONS FALLOC_FL_KEEP_SIZE
  430: #else
  431: #define DO_FALLOC_OPTIONS 0
  432: #endif
  433: 	RETURN_ERROR_IF(dry_run, 0);
  434: 	RETURN_ERROR_IF_RO_OR_LO;
  435: #if defined HAVE_FALLOCATE
  436: 	return fallocate(fd, DO_FALLOC_OPTIONS, offset, length);
  437: #elif defined HAVE_SYS_FALLOCATE
  438: 	return syscall(SYS_fallocate, fd, DO_FALLOC_OPTIONS, (loff_t)offset, (loff_t)length);
  439: #elif defined HAVE_EFFICIENT_POSIX_FALLOCATE
  440: 	return posix_fallocate(fd, offset, length);
  441: #else
  442: #error Coding error in SUPPORT_PREALLOCATION logic.
  443: #endif
  444: }
  445: #endif
  446: 
  447: int do_open_nofollow(const char *pathname, int flags)
  448: {
  449: #ifndef O_NOFOLLOW
  450: 	STRUCT_STAT f_st, l_st;
  451: #endif
  452: 	int fd;
  453: 
  454: 	if (flags != O_RDONLY) {
  455: 		RETURN_ERROR_IF(dry_run, 0);
  456: 		RETURN_ERROR_IF_RO_OR_LO;
  457: #ifndef O_NOFOLLOW
  458: 		/* This function doesn't support write attempts w/o O_NOFOLLOW. */
  459: 		errno = EINVAL;
  460: 		return -1;
  461: #endif
  462: 	}
  463: 
  464: #ifdef O_NOFOLLOW
  465: 	fd = open(pathname, flags|O_NOFOLLOW);
  466: #else
  467: 	if (do_lstat(pathname, &l_st) < 0)
  468: 		return -1;
  469: 	if (S_ISLNK(l_st.st_mode)) {
  470: 		errno = ELOOP;
  471: 		return -1;
  472: 	}
  473: 	if ((fd = open(pathname, flags)) < 0)
  474: 		return fd;
  475: 	if (do_fstat(fd, &f_st) < 0) {
  476: 	  close_and_return_error:
  477: 		{
  478: 			int save_errno = errno;
  479: 			close(fd);
  480: 			errno = save_errno;
  481: 		}
  482: 		return -1;
  483: 	}
  484: 	if (l_st.st_dev != f_st.st_dev || l_st.st_ino != f_st.st_ino) {
  485: 		errno = EINVAL;
  486: 		goto close_and_return_error;
  487: 	}
  488: #endif
  489: 
  490: 	return fd;
  491: }

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