示例#1
0
文件: util.c 项目: empeg/rsync
/* Copy a file.  If ofd < 0, copy_file unlinks and opens the "dest" file.
 * Otherwise, it just writes to and closes the provided file descriptor.
 * In either case, if --xattrs are being preserved, the dest file will
 * have its xattrs set from the source file.
 *
 * This is used in conjunction with the --temp-dir, --backup, and
 * --copy-dest options. */
int copy_file(const char *source, const char *dest, int ofd, mode_t mode)
{
	int ifd;
	char buf[1024 * 8];
	int len;   /* Number of bytes read into `buf'. */
#ifdef PREALLOCATE_NEEDS_TRUNCATE
	OFF_T preallocated_len = 0, offset = 0;
#endif

	if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
		int save_errno = errno;
		rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
		errno = save_errno;
		return -1;
	}

	if (ofd < 0) {
		if (robust_unlink(dest) && errno != ENOENT) {
			int save_errno = errno;
			rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
			errno = save_errno;
			return -1;
		}

#ifdef SUPPORT_XATTRS
		if (preserve_xattrs)
			mode |= S_IWUSR;
#endif
		mode &= INITACCESSPERMS;
		if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
			int save_errno = errno;
			rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
			close(ifd);
			errno = save_errno;
			return -1;
		}
	}

#ifdef SUPPORT_PREALLOCATION
	if (preallocate_files) {
		STRUCT_STAT srcst;

		/* Try to preallocate enough space for file's eventual length.  Can
		 * reduce fragmentation on filesystems like ext4, xfs, and NTFS. */
		if (do_fstat(ifd, &srcst) < 0)
			rsyserr(FWARNING, errno, "fstat %s", full_fname(source));
		else if (srcst.st_size > 0) {
			if (do_fallocate(ofd, 0, srcst.st_size) == 0) {
#ifdef PREALLOCATE_NEEDS_TRUNCATE
				preallocated_len = srcst.st_size;
#endif
			} else
				rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest));
		}
	}
#endif

	while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
		if (full_write(ofd, buf, len) < 0) {
			int save_errno = errno;
			rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
			close(ifd);
			close(ofd);
			errno = save_errno;
			return -1;
		}
#ifdef PREALLOCATE_NEEDS_TRUNCATE
		offset += len;
#endif
	}

	if (len < 0) {
		int save_errno = errno;
		rsyserr(FERROR_XFER, errno, "read %s", full_fname(source));
		close(ifd);
		close(ofd);
		errno = save_errno;
		return -1;
	}

	if (close(ifd) < 0) {
		rsyserr(FWARNING, errno, "close failed on %s",
			full_fname(source));
	}

#ifdef PREALLOCATE_NEEDS_TRUNCATE
	/* Source file might have shrunk since we fstatted it.
	 * Cut off any extra preallocated zeros from dest file. */
	if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) {
		/* If we fail to truncate, the dest file may be wrong, so we
		 * must trigger the "partial transfer" error. */
		rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest));
	}
#endif

	if (close(ofd) < 0) {
		int save_errno = errno;
		rsyserr(FERROR_XFER, errno, "close failed on %s",
			full_fname(dest));
		errno = save_errno;
		return -1;
	}

#ifdef SUPPORT_XATTRS
	if (preserve_xattrs)
		copy_xattrs(source, dest);
#endif

	return 0;
}
示例#2
0
int create_parent_dirs(int dir_id, const char *path)
{
	mhdd_debug(MHDD_DEBUG,
		"create_parent_dirs: dir_id=%d, path=%s\n", dir_id, path);
	char *parent=get_parent_path(path);
	if (!parent) return 0;

	char *exists=find_path(parent);
	if (!exists) { free(parent); errno=EFAULT; return -errno; }


	char *path_parent=create_path(mhdd.dirs[dir_id], parent);
	struct stat st;

	// already exists
	if (stat(path_parent, &st)==0)
	{
		free(exists);
		free(path_parent);
		free(parent);
		return 0;
	}

	// create parent dirs
	int res=create_parent_dirs(dir_id, parent);

	if (res!=0)
	{
		free(path_parent);
		free(parent);
		free(exists);
		return res;
	}

	// get stat from exists dir
	if (stat(exists, &st)!=0)
	{
		free(exists);
		free(path_parent);
		free(parent);
		return -errno;
	}
	res=mkdir(path_parent, st.st_mode);
	if (res==0)
	{
		chown(path_parent, st.st_uid, st.st_gid);
		chmod(path_parent, st.st_mode);
	}
	else
	{
		res=-errno;
		mhdd_debug(MHDD_DEBUG,
			"create_parent_dirs: can not create dir %s: %s\n",
			path_parent,
			strerror(errno));
	}

#ifndef WITHOUT_XATTR
        // copy extended attributes of parent dir
        if (copy_xattrs(exists, path_parent) == -1)
            mhdd_debug(MHDD_MSG,
                    "copy_xattrs: error copying xattrs from %s to %s\n",
                    exists, path_parent);
#endif

	free(exists);
	free(path_parent);
	free(parent);
	return res;
}
示例#3
0
int
do_copy_attributes (const char *src, const char *dest, int all, int mode, int xattributes, int ownership)
{
  int r;
  struct stat srcstat, deststat;

  static const unsigned int file_mask = 07777;

  /* If it was specified to copy everything, manually enable all the flags
   * not manually specified to avoid checking for flag || all everytime.
   */
  if (all) {
    if (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_MODE_BITMASK))
      mode = 1;
    if (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_XATTRIBUTES_BITMASK))
      xattributes = 1;
    if (!(optargs_bitmask & GUESTFS_COPY_ATTRIBUTES_OWNERSHIP_BITMASK))
      ownership = 1;
  }

  CHROOT_IN;
  r = stat (src, &srcstat);
  CHROOT_OUT;

  if (r == -1) {
    reply_with_perror ("stat: %s", src);
    return -1;
  }

  CHROOT_IN;
  r = stat (dest, &deststat);
  CHROOT_OUT;

  if (r == -1) {
    reply_with_perror ("stat: %s", dest);
    return -1;
  }

  if (mode &&
      ((srcstat.st_mode & file_mask) != (deststat.st_mode & file_mask))) {
    CHROOT_IN;
    r = chmod (dest, (srcstat.st_mode & file_mask));
    CHROOT_OUT;

    if (r == -1) {
      reply_with_perror ("chmod: %s", dest);
      return -1;
    }
  }

  if (ownership &&
      (srcstat.st_uid != deststat.st_uid || srcstat.st_gid != deststat.st_gid)) {
    CHROOT_IN;
    r = chown (dest, srcstat.st_uid, srcstat.st_gid);
    CHROOT_OUT;

    if (r == -1) {
      reply_with_perror ("chown: %s", dest);
      return -1;
    }
  }

  if (xattributes && optgroup_linuxxattrs_available ()) {
    if (!copy_xattrs (src, dest))
      /* copy_xattrs replies with an error already. */
      return -1;
  }

  return 0;
}
示例#4
0
int move_file(struct flist * file, off_t wsize)
{
	char *from, *to, *buf;
	off_t size;
	FILE *input, *output;
	int ret, dir_id;
	struct utimbuf ftime = {0};
	struct statvfs svf;
	fsblkcnt_t space;
	struct stat st;

	mhdd_debug(MHDD_MSG, "move_file: %s\n", file->real_name);

	/* TODO: it would be nice to contrive something alter */
	flist_wrlock_locked();
	from=file->real_name;

	/* We need to check if already moved */
	if (statvfs(from, &svf) != 0)
		return -errno;
	space = svf.f_bsize;
	space *= svf.f_bavail;

	/* get file size */
	if (fstat(file->fh, &st) != 0) {
		mhdd_debug(MHDD_MSG, "move_file: error stat %s: %s\n",
			from, strerror(errno));
		return -errno;
	}

        /* Hard link support is limited to a single device, and files with
           >1 hardlinks cannot be moved between devices since this would
           (a) result in partial files on the source device (b) not free
           the space from the source device during unlink. */
	if (st.st_nlink > 1) {
		mhdd_debug(MHDD_MSG, "move_file: cannot move "
			"files with >1 hardlinks\n");
		return -ENOTSUP;
	}

	size = st.st_size;
	if (size < wsize) size=wsize;

	if (space > size) {
		mhdd_debug(MHDD_MSG, "move_file: we have enough space\n");
		return 0;
	}

	if ((dir_id=find_free_space(size)) == -1) {
		mhdd_debug(MHDD_MSG, "move_file: can not find space\n");
		return -1;
	}

	if (!(input = fopen(from, "r")))
		return -errno;

	create_parent_dirs(dir_id, file->name);

	to = create_path(mhdd.dirs[dir_id], file->name);
	if (!(output = fopen(to, "w+"))) {
		ret = -errno;
		mhdd_debug(MHDD_MSG, "move_file: error create %s: %s\n",
				to, strerror(errno));
		free(to);
		fclose(input);
		return(ret);
	}

	mhdd_debug(MHDD_MSG, "move_file: move %s to %s\n", from, to);

	// move data
	buf=(char *)calloc(sizeof(char), MOVE_BLOCK_SIZE);
	while((size = fread(buf, sizeof(char), MOVE_BLOCK_SIZE, input))) {
		if (size != fwrite(buf, sizeof(char), size, output)) {
			mhdd_debug(MHDD_MSG,
				"move_file: error move data to %s: %s\n",
				to, strerror(errno));
			fclose(output);
			fclose(input);
			free(buf);
			unlink(to);
			free(to);
			return -1;
		}
	}
	free(buf);

	mhdd_debug(MHDD_MSG, "move_file: done move data\n");
	fclose(input);

	// owner/group/permissions
	fchmod(fileno(output), st.st_mode);
	fchown(fileno(output), st.st_uid, st.st_gid);
	fclose(output);

	// time
	ftime.actime = st.st_atime;
	ftime.modtime = st.st_mtime;
	utime(to, &ftime);

#ifndef WITHOUT_XATTR
        // extended attributes
        if (copy_xattrs(from, to) == -1)
            mhdd_debug(MHDD_MSG,
                    "copy_xattrs: error copying xattrs from %s to %s\n",
                    from, to);
#endif


	from = strdup(from);
	if ((ret = reopen_files(file, to)) == 0)
		unlink(from);
	else
		unlink(to);

	mhdd_debug(MHDD_MSG, "move_file: %s -> %s: done, code=%d\n",
		from, to, ret);
	free(to);
	free(from);
	return ret;
}
示例#5
0
/* Copy a file.  If ofd < 0, copy_file unlinks and opens the "dest" file.
 * Otherwise, it just writes to and closes the provided file descriptor.
 * In either case, if --xattrs are being preserved, the dest file will
 * have its xattrs set from the source file.
 *
 * This is used in conjunction with the --temp-dir, --backup, and
 * --copy-dest options. */
int copy_file(const char *source, const char *dest, int ofd,
	      mode_t mode, int create_bak_dir)
{
	int ifd;
	char buf[1024 * 8];
	int len;   /* Number of bytes read into `buf'. */

	if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
		int save_errno = errno;
		rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
		errno = save_errno;
		return -1;
	}

	if (ofd < 0) {
		if (robust_unlink(dest) && errno != ENOENT) {
			int save_errno = errno;
			rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
			errno = save_errno;
			return -1;
		}

		if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
			int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
			if (create_bak_dir && errno == ENOENT && make_bak_dir(dest) == 0) {
				if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)
					save_errno = errno ? errno : save_errno;
				else
					save_errno = 0;
			}
			if (save_errno) {
				rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
				close(ifd);
				errno = save_errno;
				return -1;
			}
		}
	}

	while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
		if (full_write(ofd, buf, len) < 0) {
			int save_errno = errno;
			rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
			close(ifd);
			close(ofd);
			errno = save_errno;
			return -1;
		}
	}

	if (len < 0) {
		int save_errno = errno;
		rsyserr(FERROR_XFER, errno, "read %s", full_fname(source));
		close(ifd);
		close(ofd);
		errno = save_errno;
		return -1;
	}

	if (close(ifd) < 0) {
		rsyserr(FWARNING, errno, "close failed on %s",
			full_fname(source));
	}

	if (close(ofd) < 0) {
		int save_errno = errno;
		rsyserr(FERROR_XFER, errno, "close failed on %s",
			full_fname(dest));
		errno = save_errno;
		return -1;
	}

#ifdef SUPPORT_XATTRS
	if (preserve_xattrs)
		copy_xattrs(source, dest);
#endif

	return 0;
}