summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1997-07-03 12:16:41 +0000
committerJim Meyering <jim@meyering.net>1997-07-03 12:16:41 +0000
commit22ff29fe3e30ae72079b3aa0ec952c7351173fa7 (patch)
tree01faeaf3f98c6f0378fff012984f9e7f25a6627f /src
parentab171ee6b54986f31a62a6eef11c5daa3dd3ff05 (diff)
downloadcoreutils-22ff29fe3e30ae72079b3aa0ec952c7351173fa7.tar.xz
(apply_attributes): New function.
(copy_reg): Use apply_attributes instead of open-coding the pieces. Now, failure to preserve file attributes does not cause mv to change its exit status, and such failures elicit warning diagnostics. This behavior is required by POSIX. Before, failure to preserve ownership due to insufficient access was diagnosed only for root. Prompted by a report from Bengt Martensson.
Diffstat (limited to 'src')
-rw-r--r--src/mv.c86
1 files changed, 48 insertions, 38 deletions
diff --git a/src/mv.c b/src/mv.c
index 9f30e5178..0d21c9ef0 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -55,10 +55,6 @@
# define chown(PATH, OWNER, GROUP) lchown(PATH, OWNER, GROUP)
#endif
-#ifndef _POSIX_VERSION
-uid_t geteuid ();
-#endif
-
char *base_name ();
enum backup_type get_version ();
int isdir ();
@@ -87,9 +83,6 @@ static int verbose;
/* If nonzero, stdin is a tty. */
static int stdin_tty;
-/* This process's effective user ID. */
-static uid_t myeuid;
-
/* If nonzero, display usage information and exit. */
static int show_help;
@@ -120,6 +113,50 @@ is_real_dir (const char *path)
return lstat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
}
+/* Apply as many of the file attributes (the struct stat fields: st_atime,
+ st_mtime, st_uid, st_gid, st_mode) of ATTR to FILE as possible.
+ Return non-zero if any operation failed; return zero otherwise. */
+
+static int
+apply_attributes (const char *file, const struct stat *attr)
+{
+ struct utimbuf tv;
+ mode_t mode = attr->st_mode;
+ int fail = 0;
+
+ /* Try to apply the modtime and access time. */
+ tv.actime = attr->st_atime;
+ tv.modtime = attr->st_mtime;
+ if (utime (file, &tv))
+ {
+ error (0, errno, "%s: unable to restore file times", file);
+ fail = 1;
+ }
+
+ /* chown would turn off set[ug]id bits for non-root, so do the
+ chown before the chmod. */
+
+ /* Try to apply group ID and owner ID. */
+ if (chown (file, attr->st_uid, attr->st_gid))
+ {
+ error (0, errno, "%s: unable to restore owner and group IDs", file);
+
+ /* If the owner and group cannot be preserved, then mask off
+ any setgid and setuid bits. */
+ mode &= (~(S_ISUID | S_ISGID));
+ fail = 1;
+ }
+
+ /* Try to apply file mode. */
+ if (chmod (file, mode & 07777))
+ {
+ error (0, errno, "%s: unable to restore file mode", file);
+ fail = 1;
+ }
+
+ return fail;
+}
+
/* Copy regular file SOURCE onto file DEST. SOURCE_STATS must be
the result of calling lstat on SOURCE.
Return 1 if an error occurred, 0 if successful. */
@@ -192,36 +229,10 @@ copy_reg (const char *source, const char *dest, const struct stat *source_stats)
return 1;
}
- /* chown turns off set[ug]id bits for non-root,
- so do the chmod last. */
-
- /* Try to copy the old file's modtime and access time. */
- {
- struct utimbuf tv;
-
- tv.actime = source_stats->st_atime;
- tv.modtime = source_stats->st_mtime;
- if (utime (dest, &tv))
- {
- error (0, errno, "%s", dest);
- return 1;
- }
- }
-
- /* Try to preserve ownership. For non-root it might fail, but that's ok.
- But root probably wants to know, e.g. if NFS disallows it. */
- if (chown (dest, source_stats->st_uid, source_stats->st_gid)
- && (errno != EPERM || myeuid == 0))
- {
- error (0, errno, "%s", dest);
- return 1;
- }
-
- if (chmod (dest, source_stats->st_mode & 07777))
- {
- error (0, errno, "%s", dest);
- return 1;
- }
+ /* Try to apply the attributes of SOURCE to DEST.
+ Each failure gets a diagnostic, but POSIX requires that failure
+ to preserve attributes not change mv's exit status. */
+ apply_attributes (dest, source_stats);
return 0;
}
@@ -455,7 +466,6 @@ main (int argc, char **argv)
simple_backup_suffix = version;
version = getenv ("VERSION_CONTROL");
- myeuid = geteuid ();
interactive = override_mode = verbose = update = 0;
errors = 0;