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 {