bug-cpio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: cpio 2.13: cpio -o --format=ustar broken on BSD UFS


From: Sergey Poznyakoff
Subject: Re: cpio 2.13: cpio -o --format=ustar broken on BSD UFS
Date: Fri, 15 Nov 2019 09:33:01 +0200

Hi Christian,

> (2) cpio, when writing ustar archives, always fills in the devmajor
> and devminor fields, regardless of file type.

I agree with that and have pushed a corresponding fix[1].  However, the
problem is deeper than that.  The same behavior is exhibited for
c_dev_maj and c_dev_min fields in new ascii (newc) archives, for
example.  At least that's what I see on the FreeBSD boxes I have access
to.  The reason is that major() and minor() macros on FreeBSD cast their
return to signed int.  When the value happens to be negative (which it
is most of the time for minor numbers) and is promoted to a wider
unsigned integer (uintmax_t in call to to_ascii or to_oct) it naturally
produces an unsigned number that does not fit in the requested field
width. 

This is fixed by the attached simple patch.  It makes the program work
correctly when major/minor return signed or unsigned int.  I'm not sure
if there exist systems where these macros return an integer wider than 
int.  Just in case, I'll try autodetecting the width and signedness of
their return in configure.ac

Regards,
Sergey

[1] 
http://git.savannah.gnu.org/cgit/cpio.git/commit/?id=df55fb19be545e22d023950263ed5d0756edf81e

diff --git a/src/copyin.c b/src/copyin.c
index 2e7feb1..7079d50 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -1029,8 +1029,8 @@ read_in_old_ascii (struct cpio_file_stat *file_hdr, int 
in_des)
   tape_buffered_read (ascii_header.c_dev, in_des,
                      sizeof ascii_header - sizeof ascii_header.c_magic);
   dev = FROM_OCTAL (ascii_header.c_dev);
-  file_hdr->c_dev_maj = major (dev);
-  file_hdr->c_dev_min = minor (dev);
+  file_hdr->c_dev_maj = cpio_major (dev);
+  file_hdr->c_dev_min = cpio_minor (dev);

   file_hdr->c_ino = FROM_OCTAL (ascii_header.c_ino);
   file_hdr->c_mode = FROM_OCTAL (ascii_header.c_mode);
@@ -1038,8 +1038,8 @@ read_in_old_ascii (struct cpio_file_stat *file_hdr, int 
in_des)
   file_hdr->c_gid = FROM_OCTAL (ascii_header.c_gid);
   file_hdr->c_nlink = FROM_OCTAL (ascii_header.c_nlink);
   dev = FROM_OCTAL (ascii_header.c_rdev);
-  file_hdr->c_rdev_maj = major (dev);
-  file_hdr->c_rdev_min = minor (dev);
+  file_hdr->c_rdev_maj = cpio_major (dev);
+  file_hdr->c_rdev_min = cpio_minor (dev);

   file_hdr->c_mtime = FROM_OCTAL (ascii_header.c_mtime);
   file_hdr->c_filesize = FROM_OCTAL (ascii_header.c_filesize);
@@ -1065,8 +1065,8 @@ read_in_old_ascii (struct cpio_file_stat *file_hdr, int 
in_des)
            && file_hdr->c_rdev_maj == 0
            && file_hdr->c_rdev_min == 1)
          {
-           file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
-           file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+           file_hdr->c_rdev_maj = cpio_major (file_hdr->c_filesize);
+           file_hdr->c_rdev_min = cpio_minor (file_hdr->c_filesize);
            file_hdr->c_filesize = 0;
          }
        break;
@@ -1136,15 +1136,15 @@ read_in_binary (struct cpio_file_stat *file_hdr,
       swab_array ((char *) short_hdr, 13);
     }

-  file_hdr->c_dev_maj = major (short_hdr->c_dev);
-  file_hdr->c_dev_min = minor (short_hdr->c_dev);
+  file_hdr->c_dev_maj = cpio_major (short_hdr->c_dev);
+  file_hdr->c_dev_min = cpio_minor (short_hdr->c_dev);
   file_hdr->c_ino = short_hdr->c_ino;
   file_hdr->c_mode = short_hdr->c_mode;
   file_hdr->c_uid = short_hdr->c_uid;
   file_hdr->c_gid = short_hdr->c_gid;
   file_hdr->c_nlink = short_hdr->c_nlink;
-  file_hdr->c_rdev_maj = major (short_hdr->c_rdev);
-  file_hdr->c_rdev_min = minor (short_hdr->c_rdev);
+  file_hdr->c_rdev_maj = cpio_major (short_hdr->c_rdev);
+  file_hdr->c_rdev_min = cpio_minor (short_hdr->c_rdev);
   file_hdr->c_mtime = (unsigned long) short_hdr->c_mtimes[0] << 16
                       | short_hdr->c_mtimes[1];
   file_hdr->c_filesize = (unsigned long) short_hdr->c_filesizes[0] << 16
@@ -1177,8 +1177,8 @@ read_in_binary (struct cpio_file_stat *file_hdr,
            && file_hdr->c_rdev_maj == 0
            && file_hdr->c_rdev_min == 1)
          {
-           file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
-           file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+           file_hdr->c_rdev_maj = cpio_major (file_hdr->c_filesize);
+           file_hdr->c_rdev_min = cpio_minor (file_hdr->c_filesize);
            file_hdr->c_filesize = 0;
          }
        break;
diff --git a/src/copypass.c b/src/copypass.c
index dc13b5b..76c82cb 100644
--- a/src/copypass.c
+++ b/src/copypass.c
@@ -159,9 +159,9 @@ process_copy_pass ()
                                     input_name.ds_string);
          if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
            link_res = link_to_maj_min_ino (output_name.ds_string,
-                               major (in_file_stat.st_dev),
-                               minor (in_file_stat.st_dev),
-                               in_file_stat.st_ino);
+                                           cpio_major (in_file_stat.st_dev),
+                                           cpio_minor (in_file_stat.st_dev),
+                                           in_file_stat.st_ino);

          /* If the file was not linked, copy contents of file.  */
          if (link_res < 0)
@@ -242,9 +242,9 @@ process_copy_pass ()
                                     input_name.ds_string);
          if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
            link_res = link_to_maj_min_ino (output_name.ds_string,
-                       major (in_file_stat.st_dev),
-                       minor (in_file_stat.st_dev),
-                       in_file_stat.st_ino);
+                                           cpio_major (in_file_stat.st_dev),
+                                           cpio_minor (in_file_stat.st_dev),
+                                           in_file_stat.st_ino);

          if (link_res < 0)
            {
diff --git a/src/cpiohdr.h b/src/cpiohdr.h
index ff5f375..d49aec1 100644
--- a/src/cpiohdr.h
+++ b/src/cpiohdr.h
@@ -130,6 +130,9 @@ struct cpio_file_stat /* Internal representation of a CPIO 
header */
   char const *c_tar_linkname;
 };

+#define cpio_major(d) ((dev_t)major (d))
+#define cpio_minor(d) ((dev_t)minor (d))
+
 #define CPIO_FILE_STAT_INITIALIZER \
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0, NULL }
 void cpio_file_stat_init (struct cpio_file_stat *file_hdr);
diff --git a/src/util.c b/src/util.c
index 2c202b1..21c716d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -763,11 +763,12 @@ get_inode_and_dev (struct cpio_file_stat *hdr, struct 
stat *st)
       if (st->st_nlink > 1)
        {
          struct inode_val *ival = find_inode_val (st->st_ino,
-                                                  major (st->st_dev),
-                                                  minor (st->st_dev));
+                                                  cpio_major (st->st_dev),
+                                                  cpio_minor (st->st_dev));
          if (!ival)
            ival = add_inode (st->st_ino, NULL,
-                             major (st->st_dev), minor (st->st_dev));
+                             cpio_major (st->st_dev),
+                             cpio_minor (st->st_dev));
          hdr->c_ino = ival->trans_inode;
        }
       else
@@ -782,8 +783,8 @@ get_inode_and_dev (struct cpio_file_stat *hdr, struct stat 
*st)
     }
   else
     {
-      hdr->c_dev_maj = major (st->st_dev);
-      hdr->c_dev_min = minor (st->st_dev);
+      hdr->c_dev_maj = cpio_major (st->st_dev);
+      hdr->c_dev_min = cpio_minor (st->st_dev);
     }
 }

@@ -1142,8 +1143,8 @@ stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
   hdr->c_gid = CPIO_GID (st->st_gid);
   if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode))
     {
-      hdr->c_rdev_maj = major (st->st_rdev);
-      hdr->c_rdev_min = minor (st->st_rdev);
+      hdr->c_rdev_maj = cpio_major (st->st_rdev);
+      hdr->c_rdev_min = cpio_minor (st->st_rdev);
     }
   else
     {

reply via email to

[Prev in Thread] Current Thread [Next in Thread]