瀏覽代碼

(mode_to_oct): Do not assume internal mode_t and external octal modes
have the same bit patterns.
(start_header): Do not assume mode bits have traditional Unix values.
(finish_sparse_file): Use lseek whence macros instead of integers.
(dump_file): Do not assume mode bits have traditional Unix values.
Do not invoke finish_sparse_file on a negative file descriptor.

Paul Eggert 26 年之前
父節點
當前提交
66e89f0fa5
共有 1 個文件被更改,包括 31 次插入7 次删除
  1. 31 7
      src/create.c

+ 31 - 7
src/create.c

@@ -141,7 +141,29 @@ minor_to_oct (minor_t v, char *p, size_t s)
 void
 mode_to_oct (mode_t v, char *p, size_t s)
 {
-  to_oct ((uintmax_t) v, (uintmax_t) 0, p, s, "mode_t");
+  /* In the common case where the internal and external mode bits are the same,
+     propagate all unknown bits to the external mode.
+     This matches historical practice.
+     Otherwise, just copy the bits we know about.  */
+  uintmax_t u =
+    ((S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
+      && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
+      && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
+      && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC)
+     ? v
+     : ((v & S_ISUID ? TSUID : 0)
+	| (v & S_ISGID ? TSGID : 0)
+	| (v & S_ISVTX ? TSVTX : 0)
+	| (v & S_IRUSR ? TUREAD : 0)
+	| (v & S_IWUSR ? TUWRITE : 0)
+	| (v & S_IXUSR ? TUEXEC : 0)
+	| (v & S_IRGRP ? TGREAD : 0)
+	| (v & S_IWGRP ? TGWRITE : 0)
+	| (v & S_IXGRP ? TGEXEC : 0)
+	| (v & S_IROTH ? TOREAD : 0)
+	| (v & S_IWOTH ? TOWRITE : 0)
+	| (v & S_IXOTH ? TOEXEC : 0)));
+  to_oct (u, (uintmax_t) 0, p, s, "mode_t");
 }
 void
 off_to_oct (off_t v, char *p, size_t s)
@@ -332,7 +354,7 @@ Removing leading `/' from absolute path names in the archive")));
      acceptor for Paul's test.  */
 
   if (archive_format == V7_FORMAT)
-    MODE_TO_OCT (st->st_mode & 07777, header->header.mode);
+    MODE_TO_OCT (st->st_mode & MODE_ALL, header->header.mode);
   else
     MODE_TO_OCT (st->st_mode, header->header.mode);
 
@@ -404,8 +426,8 @@ finish_header (union block *header)
   /* Fill in the checksum field.  It's formatted differently from the
      other fields: it has [6] digits, a null, then a space -- rather than
      digits, then a null.  We use to_oct.
-     The final space is already there, from checksumming,
-     and to_oct doesn't modify it.
+     The final space is already there, from
+     checksumming, and to_oct doesn't modify it.
 
      This is a fast way to do:
 
@@ -620,7 +642,7 @@ finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
 	  break;
 	}
 
-      if (lseek (file, sparsearray[sparse_index++].offset, 0) < 0)
+      if (lseek (file, sparsearray[sparse_index++].offset, SEEK_SET) < 0)
 	{
 	  char buf[UINTMAX_STRSIZE_BOUND];
 	  ERROR ((0, errno, _("lseek error at byte %s in file %s"),
@@ -1061,7 +1083,8 @@ Removing leading `/' from absolute links")));
 	 files when archive is meant for /dev/null.  */
 
       if (dev_null_output
-	  || (sizeleft == 0 && 0444 == (0444 & current_stat.st_mode)))
+	  || (sizeleft == 0
+	      && MODE_R == (MODE_R & current_stat.st_mode)))
 	f = -1;
       else
 	{
@@ -1144,7 +1167,8 @@ Removing leading `/' from absolute links")));
 	}
       if (save_typeflag == GNUTYPE_SPARSE)
 	{
-	  if (finish_sparse_file (f, &sizeleft, current_stat.st_size, p))
+	  if (f < 0
+	      || finish_sparse_file (f, &sizeleft, current_stat.st_size, p))
 	    goto padit;
 	}
       else