Exemplo n.º 1
0
int do_rename(const char *fname1, const char *fname2)
{
	if (dry_run) return 0;
	RETURN_ERROR_IF_RO_OR_LO;
	if (rename(fname1, fname2) == 0)
		return 0;
#ifdef SUPPORT_FORCE_CHANGE
	if (force_change && errno == EPERM) {
		STRUCT_STAT st1, st2;
		int became_mutable;

		if (x_lstat(fname1, &st1, NULL) != 0)
			goto failed;
		became_mutable = make_mutable(fname1, st1.st_mode, st1.st_flags, force_change) > 0;
		if (became_mutable && rename(fname1, fname2) == 0)
			goto success;
		if (x_lstat(fname2, &st2, NULL) == 0
		 && make_mutable(fname2, st2.st_mode, st2.st_flags, force_change) > 0) {
			if (rename(fname1, fname2) == 0) {
			  success:
				if (became_mutable) /* Yes, use fname2 and st1! */
					undo_make_mutable(fname2, st1.st_flags);
				return 0;
			}
			undo_make_mutable(fname2, st2.st_flags);
		}
		/* TODO: handle immutable directories */
		if (became_mutable)
			undo_make_mutable(fname1, st1.st_flags);
	  failed:
		errno = EPERM;
	}
#endif
	return -1;
}
Exemplo n.º 2
0
int do_lchown(const char *path, uid_t owner, gid_t group, mode_t mode, uint32 fileflags)
{
	if (dry_run) return 0;
	RETURN_ERROR_IF_RO_OR_LO;
#ifndef HAVE_LCHOWN
#define lchown chown
#endif
	if (lchown(path, owner, group) == 0)
		return 0;
#ifdef SUPPORT_FORCE_CHANGE
	if (force_change && errno == EPERM) {
		if (fileflags == NO_FFLAGS) {
			STRUCT_STAT st;
			if (x_lstat(path, &st, NULL) == 0) {
				mode = st.st_mode;
				fileflags = st.st_flags;
			}
		}
		if (fileflags != NO_FFLAGS
		 && make_mutable(path, mode, fileflags, force_change) > 0) {
			int ret = lchown(path, owner, group);
			undo_make_mutable(path, fileflags);
			if (ret == 0)
				return 0;
		}
		errno = EPERM;
	}
#else
	mode = fileflags = 0; /* avoid compiler warning */
#endif
	return -1;
}
Exemplo n.º 3
0
int do_chmod(const char *path, mode_t mode, uint32 fileflags)
{
	int code;
	if (dry_run) return 0;
	RETURN_ERROR_IF_RO_OR_LO;
#ifdef HAVE_LCHMOD
	code = lchmod(path, mode & CHMOD_BITS);
#else
	if (S_ISLNK(mode)) {
# if defined HAVE_SETATTRLIST
		struct attrlist attrList;
		uint32_t m = mode & CHMOD_BITS; /* manpage is wrong: not mode_t! */

		memset(&attrList, 0, sizeof attrList);
		attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
		attrList.commonattr = ATTR_CMN_ACCESSMASK;
		code = setattrlist(path, &attrList, &m, sizeof m, FSOPT_NOFOLLOW);
# else
		code = 1;
# endif
	} else
		code = chmod(path, mode & CHMOD_BITS); /* DISCOURAGED FUNCTION */
#endif /* !HAVE_LCHMOD */
#ifdef SUPPORT_FORCE_CHANGE
	if (code < 0 && force_change && errno == EPERM && !S_ISLNK(mode)) {
		if (fileflags == NO_FFLAGS) {
			STRUCT_STAT st;
			if (x_lstat(path, &st, NULL) == 0)
				fileflags = st.st_flags;
		}
		if (fileflags != NO_FFLAGS
		 && make_mutable(path, mode, fileflags, force_change) > 0) {
			code = chmod(path, mode & CHMOD_BITS);
			undo_make_mutable(path, fileflags);
			if (code == 0)
				return 0;
		}
		errno = EPERM;
	}
#else
	fileflags = 0; /* avoid compiler warning */
#endif
	if (code != 0 && (preserve_perms || preserve_executability))
		return code;
	return 0;
}
Exemplo n.º 4
0
int do_rmdir(const char *pathname)
{
	if (dry_run) return 0;
	RETURN_ERROR_IF_RO_OR_LO;
	if (rmdir(pathname) == 0)
		return 0;
#ifdef SUPPORT_FORCE_CHANGE
	if (force_change && errno == EPERM) {
		STRUCT_STAT st;

		if (x_lstat(pathname, &st, NULL) == 0
		 && make_mutable(pathname, st.st_mode, st.st_flags, force_change) > 0) {
			if (rmdir(pathname) == 0)
				return 0;
			undo_make_mutable(pathname, st.st_flags);
		}
		errno = EPERM;
	}
#endif
	return -1;
}
Exemplo n.º 5
0
int do_unlink(const char *fname)
{
	if (dry_run) return 0;
	RETURN_ERROR_IF_RO_OR_LO;
	if (unlink(fname) == 0)
		return 0;
#ifdef SUPPORT_FORCE_CHANGE
	if (force_change && errno == EPERM) {
		STRUCT_STAT st;

		if (x_lstat(fname, &st, NULL) == 0
		 && make_mutable(fname, st.st_mode, st.st_flags, force_change) > 0) {
			if (unlink(fname) == 0)
				return 0;
			undo_make_mutable(fname, st.st_flags);
		}
		/* TODO: handle immutable directories */
		errno = EPERM;
	}
#endif
	return -1;
}
Exemplo n.º 6
0
/* If we have a --backup-dir, then we get here from make_backup().
 * We will move the file to be deleted into a parallel directory tree. */
static int keep_backup(const char *fname)
{
	stat_x sx;
	struct file_struct *file;
	char *buf;
	int save_preserve_xattrs = preserve_xattrs;
	int kept = 0;
	int ret_code;

	/* return if no file to keep */
	if (x_lstat(fname, &sx.st, NULL) < 0)
		return 1;
#ifdef SUPPORT_ACLS
	sx.acc_acl = sx.def_acl = NULL;
#endif
#ifdef SUPPORT_XATTRS
	sx.xattr = NULL;
#endif

	if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
		return 1; /* the file could have disappeared */

	if (!(buf = get_backup_name(fname))) {
		unmake_file(file);
#ifdef SUPPORT_ACLS
		uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
		uncache_tmp_xattrs();
#endif
		return 0;
	}

#ifdef SUPPORT_ACLS
	if (preserve_acls && !S_ISLNK(file->mode)) {
		get_acl(fname, &sx);
		cache_tmp_acl(file, &sx);
		free_acl(&sx);
	}
#endif
#ifdef SUPPORT_XATTRS
	if (preserve_xattrs) {
		get_xattr(fname, &sx);
		cache_tmp_xattr(file, &sx);
		free_xattr(&sx);
	}
#endif

	/* Check to see if this is a device file, or link */
	if ((am_root && preserve_devices && IS_DEVICE(file->mode))
	 || (preserve_specials && IS_SPECIAL(file->mode))) {
		int save_errno;
		do_unlink(buf);
		if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) {
			save_errno = errno ? errno : EINVAL; /* 0 paranoia */
			if (errno == ENOENT && make_bak_dir(buf) == 0) {
				if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
					save_errno = errno ? errno : save_errno;
				else
					save_errno = 0;
			}
			if (save_errno) {
				rsyserr(FERROR, save_errno, "mknod %s failed",
					full_fname(buf));
			}
		} else
			save_errno = 0;
		if (verbose > 2 && save_errno == 0) {
			rprintf(FINFO, "make_backup: DEVICE %s successful.\n",
				fname);
		}
		kept = 1;
		do_unlink(fname);
	}

	if (!kept && S_ISDIR(file->mode)) {
		/* make an empty directory */
		if (do_mkdir(buf, file->mode) < 0) {
			int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
			if (errno == ENOENT && make_bak_dir(buf) == 0) {
				if (do_mkdir(buf, file->mode) < 0)
					save_errno = errno ? errno : save_errno;
				else
					save_errno = 0;
			}
			if (save_errno) {
				rsyserr(FINFO, save_errno, "mkdir %s failed",
					full_fname(buf));
			}
		}

		ret_code = do_rmdir(fname);
		if (verbose > 2) {
			rprintf(FINFO, "make_backup: RMDIR %s returns %i\n",
				full_fname(fname), ret_code);
		}
		kept = 1;
	}

#ifdef SUPPORT_LINKS
	if (!kept && preserve_links && S_ISLNK(file->mode)) {
		const char *sl = F_SYMLINK(file);
		if (safe_symlinks && unsafe_symlink(sl, fname)) {
			if (verbose) {
				rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n",
					full_fname(buf), sl);
			}
			kept = 1;
		} else {
			do_unlink(buf);
			if (do_symlink(sl, buf) < 0) {
				int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
				if (errno == ENOENT && make_bak_dir(buf) == 0) {
					if (do_symlink(sl, buf) < 0)
						save_errno = errno ? errno : save_errno;
					else
						save_errno = 0;
				}
				if (save_errno) {
					rsyserr(FERROR, save_errno, "link %s -> \"%s\"",
						full_fname(buf), sl);
				}
			}
			do_unlink(fname);
			kept = 1;
		}
	}
#endif

	if (!kept && !S_ISREG(file->mode)) {
		rprintf(FINFO, "make_bak: skipping non-regular file %s\n",
			fname);
		unmake_file(file);
#ifdef SUPPORT_ACLS
		uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
		uncache_tmp_xattrs();
#endif
		return 1;
	}

	/* move to keep tree if a file */
	if (!kept) {
		if (robust_move(fname, buf) != 0) {
			rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
				full_fname(fname), buf);
		} else if (sx.st.st_nlink > 1) {
			/* If someone has hard-linked the file into the backup
			 * dir, rename() might return success but do nothing! */
			robust_unlink(fname); /* Just in case... */
		}
	}
	preserve_xattrs = 0;
	set_file_attrs(buf, file, NULL, fname, 0);
	preserve_xattrs = save_preserve_xattrs;
	unmake_file(file);
#ifdef SUPPORT_ACLS
	uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
	uncache_tmp_xattrs();
#endif

	if (verbose > 1) {
		rprintf(FINFO, "backed up %s to %s\n",
			fname, buf);
	}
	return 1;
}
Exemplo n.º 7
0
/* Hard-link, rename, or copy an item to the backup name.  Returns 0 for
 * failure, 1 if item was moved, 2 if item was duplicated or hard linked
 * into backup area, or 3 if item doesn't exist or isn't a regular file. */
int make_backup(const char *fname, BOOL prefer_rename)
{
	stat_x sx;
	struct file_struct *file;
	int save_preserve_xattrs;
	char *buf;
	int ret = 0;

	init_stat_x(&sx);
	/* Return success if no file to keep. */
	if (x_lstat(fname, &sx.st, NULL) < 0)
		return 3;

	if (!(buf = get_backup_name(fname)))
		return 0;

	/* Try a hard-link or a rename first.  Using rename is not atomic, but
	 * is more efficient than forcing a copy for larger files when no hard-
	 * linking is possible. */
	if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
		goto success;
	if (errno == EEXIST || errno == EISDIR) {
		STRUCT_STAT bakst;
		if (do_lstat(buf, &bakst) == 0) {
			int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
			if (delete_item(buf, bakst.st_mode, flags) != 0)
				return 0;
		}
		if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
			goto success;
	}

	/* Fall back to making a copy. */
	if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS)))
		return 3; /* the file could have disappeared */

#ifdef SUPPORT_ACLS
	if (preserve_acls && !S_ISLNK(file->mode)) {
		get_acl(fname, &sx);
		cache_tmp_acl(file, &sx);
		free_acl(&sx);
	}
#endif
#ifdef SUPPORT_XATTRS
	if (preserve_xattrs) {
		get_xattr(fname, &sx);
		cache_tmp_xattr(file, &sx);
		free_xattr(&sx);
	}
#endif

	/* Check to see if this is a device file, or link */
	if ((am_root && preserve_devices && IS_DEVICE(file->mode))
	 || (preserve_specials && IS_SPECIAL(file->mode))) {
		if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0)
			rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf));
		else if (DEBUG_GTE(BACKUP, 1))
			rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname);
		ret = 2;
	}

#ifdef SUPPORT_LINKS
	if (!ret && preserve_links && S_ISLNK(file->mode)) {
		const char *sl = F_SYMLINK(file);
		if (safe_symlinks && unsafe_symlink(sl, fname)) {
			if (INFO_GTE(SYMSAFE, 1)) {
				rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n",
					fname, sl);
			}
			ret = 2;
		} else {
			if (do_symlink(sl, buf) < 0)
				rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl);
			else if (DEBUG_GTE(BACKUP, 1))
				rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname);
			ret = 2;
		}
	}
#endif

	if (!ret && !S_ISREG(file->mode)) {
		rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname);
		unmake_file(file);
#ifdef SUPPORT_ACLS
		uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
		uncache_tmp_xattrs();
#endif
		return 3;
	}

	/* Copy to backup tree if a file. */
	if (!ret) {
		if (copy_file(fname, buf, -1, file->mode) < 0) {
			rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
				full_fname(fname), buf);
			unmake_file(file);
#ifdef SUPPORT_ACLS
			uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
			uncache_tmp_xattrs();
#endif
			return 0;
		}
		if (DEBUG_GTE(BACKUP, 1))
			rprintf(FINFO, "make_backup: COPY %s successful.\n", fname);
		ret = 2;
	}

	save_preserve_xattrs = preserve_xattrs;
	preserve_xattrs = 0;
	set_file_attrs(buf, file, NULL, fname, ATTRS_SET_NANO);
	preserve_xattrs = save_preserve_xattrs;

	unmake_file(file);
#ifdef SUPPORT_ACLS
	uncache_tmp_acls();
#endif
#ifdef SUPPORT_XATTRS
	uncache_tmp_xattrs();
#endif

  success:
	if (INFO_GTE(BACKUP, 1))
		rprintf(FINFO, "backed up %s to %s\n", fname, buf);
	return ret;
}