diff options
author | Pádraig Brady <P@draigBrady.com> | 2009-09-21 08:43:03 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2010-07-01 14:33:27 +0100 |
commit | 1af81dfb4d24d104777b8917544d81097db0deab (patch) | |
tree | 3030f158798f4246a3b7d38ba9262adb57705849 /src | |
parent | 8aa15b2be2bd2ab4b76d197a279abf8b9091680a (diff) | |
download | coreutils-1af81dfb4d24d104777b8917544d81097db0deab.tar.xz |
cp: add an option to only copy the file attributes
* src/copy.c (copy_attr): A new function which merges copy_attr_by_fd
and copy_attr_by_name. Also display all errors when --attributes-only
* src/copy.c (copy_reg): Skip copying the file contents if specified.
Refactor the SELinux error handling code a little and display all
SELinux errors when only copying attributes.
* src/copy.h (struct cp_options): Add a data_copy_required boolean
* src/cp.c (main): Default to copying data but don't if specified
* src/install.c: Default to copying data
* src/mv.c: Likewise
tests/cp/reflink-perm: Add a test to check that --attributes-only
does not copy data
* tests/cp/acl: Likewise. Also refactor to remove redundant
acl manipulation
* doc/coreutils.texi (cp invocation): Describe the new option
* NEWS: Mention the new feature
Diffstat (limited to 'src')
-rw-r--r-- | src/copy.c | 84 | ||||
-rw-r--r-- | src/copy.h | 4 | ||||
-rw-r--r-- | src/cp.c | 10 | ||||
-rw-r--r-- | src/install.c | 1 | ||||
-rw-r--r-- | src/mv.c | 1 |
5 files changed, 52 insertions, 48 deletions
diff --git a/src/copy.c b/src/copy.c index 171499c47..6d11ed868 100644 --- a/src/copy.c +++ b/src/copy.c @@ -177,11 +177,11 @@ static void copy_attr_error (struct error_context *ctx ATTRIBUTE_UNUSED, char const *fmt, ...) { - int err = errno; - va_list ap; - if (!errno_unsupported (errno)) { + int err = errno; + va_list ap; + /* use verror module to print error message */ va_start (ap, fmt); verror (0, err, fmt, ap); @@ -214,51 +214,39 @@ copy_attr_free (struct error_context *ctx ATTRIBUTE_UNUSED, { } -static bool -copy_attr_by_fd (char const *src_path, int src_fd, - char const *dst_path, int dst_fd, const struct cp_options *x) -{ - struct error_context ctx = - { - .error = x->require_preserve_xattr ? copy_attr_allerror : copy_attr_error, - .quote = copy_attr_quote, - .quote_free = copy_attr_free - }; - return 0 == attr_copy_fd (src_path, src_fd, dst_path, dst_fd, 0, - (x->reduce_diagnostics - && !x->require_preserve_xattr)? NULL : &ctx); -} +/* If positive SRC_FD and DST_FD descriptors are passed, + then copy by fd, otherwise copy by name. */ static bool -copy_attr_by_name (char const *src_path, char const *dst_path, - const struct cp_options *x) +copy_attr (char const *src_path, int src_fd, + char const *dst_path, int dst_fd, struct cp_options const *x) { + int ret; + bool all_errors = (!x->data_copy_required || x->require_preserve_xattr); + bool some_errors = (!all_errors && !x->reduce_diagnostics); struct error_context ctx = { - .error = x->require_preserve_xattr ? copy_attr_allerror : copy_attr_error, + .error = all_errors ? copy_attr_allerror : copy_attr_error, .quote = copy_attr_quote, .quote_free = copy_attr_free }; - return 0 == attr_copy_file (src_path, dst_path, 0, - (x-> reduce_diagnostics - && !x->require_preserve_xattr) ? NULL : &ctx); -} -#else /* USE_XATTR */ + if (0 <= src_fd && 0 <= dst_fd) + ret = attr_copy_fd (src_path, src_fd, dst_path, dst_fd, 0, + (all_errors || some_errors ? &ctx : NULL)); + else + ret = attr_copy_file (src_path, dst_path, 0, + (all_errors || some_errors ? &ctx : NULL)); -static bool -copy_attr_by_fd (char const *src_path ATTRIBUTE_UNUSED, - int src_fd ATTRIBUTE_UNUSED, - char const *dst_path ATTRIBUTE_UNUSED, - int dst_fd ATTRIBUTE_UNUSED, - const struct cp_options *x ATTRIBUTE_UNUSED) -{ - return true; + return ret == 0; } +#else /* USE_XATTR */ static bool -copy_attr_by_name (char const *src_path ATTRIBUTE_UNUSED, - char const *dst_path ATTRIBUTE_UNUSED, - const struct cp_options *x ATTRIBUTE_UNUSED) +copy_attr (char const *src_path ATTRIBUTE_UNUSED, + int src_fd ATTRIBUTE_UNUSED, + char const *dst_path ATTRIBUTE_UNUSED, + int dst_fd ATTRIBUTE_UNUSED, + struct cp_options const *x ATTRIBUTE_UNUSED) { return true; } @@ -483,7 +471,7 @@ copy_reg (char const *src_name, char const *dst_name, struct stat sb; struct stat src_open_sb; bool return_val = true; - bool data_copy_required = true; + bool data_copy_required = x->data_copy_required; source_desc = open (src_name, (O_RDONLY | O_BINARY @@ -526,11 +514,14 @@ copy_reg (char const *src_name, char const *dst_name, that is used when the destination file doesn't already exist. */ if (x->preserve_security_context && 0 <= dest_desc) { + bool all_errors = (!x->data_copy_required + || x->require_preserve_context); + bool some_errors = !all_errors && !x->reduce_diagnostics; security_context_t con = NULL; + if (getfscreatecon (&con) < 0) { - if (x->require_preserve_context || - (!x->reduce_diagnostics && !errno_unsupported (errno))) + if (all_errors || (some_errors && !errno_unsupported (errno))) error (0, errno, _("failed to get file system create context")); if (x->require_preserve_context) { @@ -543,8 +534,7 @@ copy_reg (char const *src_name, char const *dst_name, { if (fsetfilecon (dest_desc, con) < 0) { - if (x->require_preserve_context || - (!x->reduce_diagnostics && !errno_unsupported (errno))) + if (all_errors || (some_errors && !errno_unsupported (errno))) error (0, errno, _("failed to set the security context of %s to %s"), quote_n (0, dst_name), quote_n (1, con)); @@ -850,7 +840,7 @@ copy_reg (char const *src_name, char const *dst_name, if (!(sb.st_mode & S_IWUSR) && geteuid () != 0) access_changed = fchmod_or_lchmod (dest_desc, dst_name, 0600) == 0; - if (!copy_attr_by_fd (src_name, source_desc, dst_name, dest_desc, x) + if (!copy_attr (src_name, source_desc, dst_name, dest_desc, x) && x->require_preserve_xattr) return_val = false; @@ -1821,14 +1811,15 @@ copy_internal (char const *src_name, char const *dst_name, if (x->preserve_security_context) { + bool all_errors = !x->data_copy_required || x->require_preserve_context; + bool some_errors = !all_errors && !x->reduce_diagnostics; security_context_t con; if (0 <= lgetfilecon (src_name, &con)) { if (setfscreatecon (con) < 0) { - if (x->require_preserve_context || - (!x->reduce_diagnostics && !errno_unsupported (errno))) + if (all_errors || (some_errors && !errno_unsupported (errno))) error (0, errno, _("failed to set default file creation context to %s"), quote (con)); @@ -1842,8 +1833,7 @@ copy_internal (char const *src_name, char const *dst_name, } else { - if (x->require_preserve_context || - (!x->reduce_diagnostics && !errno_unsupported (errno))) + if (all_errors || (some_errors && !errno_unsupported (errno))) { error (0, errno, _("failed to get security context of %s"), @@ -2168,7 +2158,7 @@ copy_internal (char const *src_name, char const *dst_name, set_author (dst_name, -1, &src_sb); - if (x->preserve_xattr && ! copy_attr_by_name (src_name, dst_name, x) + if (x->preserve_xattr && ! copy_attr (src_name, -1, dst_name, -1, x) && x->require_preserve_xattr) return false; diff --git a/src/copy.h b/src/copy.h index 59e29f53b..7c7e3f312 100644 --- a/src/copy.h +++ b/src/copy.h @@ -170,6 +170,10 @@ struct cp_options will be hard links to the same file (a copy of F). */ bool preserve_links; + /* Optionally don't copy the data, either with CoW reflink files or + explicitly with the --attributes-only option. */ + bool data_copy_required; + /* If true and any of the above (for preserve) file attributes cannot be applied to a destination file, treat it as a failure and return nonzero immediately. E.g. for cp -p this must be true, for mv it @@ -72,7 +72,8 @@ struct dir_attr non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - COPY_CONTENTS_OPTION = CHAR_MAX + 1, + ATTRIBUTES_ONLY_OPTION = CHAR_MAX + 1, + COPY_CONTENTS_OPTION, NO_PRESERVE_ATTRIBUTES_OPTION, PARENTS_OPTION, PRESERVE_ATTRIBUTES_OPTION, @@ -115,6 +116,7 @@ ARGMATCH_VERIFY (reflink_type_string, reflink_type); static struct option const long_opts[] = { {"archive", no_argument, NULL, 'a'}, + {"attributes-only", no_argument, NULL, ATTRIBUTES_ONLY_OPTION}, {"backup", optional_argument, NULL, 'b'}, {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, {"dereference", no_argument, NULL, 'L'}, @@ -167,6 +169,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); fputs (_("\ -a, --archive same as -dR --preserve=all\n\ + --attributes-only don't copy the file data, just the attributes\n\ --backup[=CONTROL] make a backup of each existing destination file\n\ -b like --backup but does not accept an argument\n\ --copy-contents copy contents of special files when recursive\n\ @@ -781,6 +784,7 @@ cp_option_init (struct cp_options *x) x->reduce_diagnostics = false; x->require_preserve_xattr = false; + x->data_copy_required = true; x->require_preserve = false; x->recursive = false; x->sparse_mode = SPARSE_AUTO; @@ -962,6 +966,10 @@ main (int argc, char **argv) version_control_string = optarg; break; + case ATTRIBUTES_ONLY_OPTION: + x.data_copy_required = false; + break; + case COPY_CONTENTS_OPTION: copy_contents = true; break; diff --git a/src/install.c b/src/install.c index 038e86976..97029140c 100644 --- a/src/install.c +++ b/src/install.c @@ -280,6 +280,7 @@ cp_option_init (struct cp_options *x) x->preserve_mode = false; x->preserve_timestamps = false; x->reduce_diagnostics=false; + x->data_copy_required = true; x->require_preserve = false; x->require_preserve_context = false; x->require_preserve_xattr = false; @@ -119,6 +119,7 @@ cp_option_init (struct cp_options *x) x->preserve_timestamps = true; x->preserve_security_context = selinux_enabled; x->reduce_diagnostics = false; + x->data_copy_required = true; x->require_preserve = false; /* FIXME: maybe make this an option */ x->require_preserve_context = false; x->preserve_xattr = true; |