(apply_attributes): New function.
authorJim Meyering <jim@meyering.net>
Thu, 3 Jul 1997 12:16:41 +0000 (12:16 +0000)
committerJim Meyering <jim@meyering.net>
Thu, 3 Jul 1997 12:16:41 +0000 (12:16 +0000)
(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.

src/mv.c

index 9f30e517855b42f4c3d92bfdf8cb7472c8cc23f2..0d21c9ef03b4b080f4e40f596507994e37d672ca 100644 (file)
--- a/src/mv.c
+++ b/src/mv.c
 # 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;