[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
{