diff options
author | obrien <obrien@FreeBSD.org> | 1997-03-30 10:34:16 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1997-03-30 10:34:16 +0000 |
commit | 3bca94d06ee39468414ff052f3006666d3f60089 (patch) | |
tree | 15891b26306c4326f54d661a4ac09d2cb56b21a2 /contrib/cpio | |
parent | 3fecf166e7ad99cb6a69e3bdf653e4cfcc5ca8d5 (diff) | |
download | FreeBSD-src-3bca94d06ee39468414ff052f3006666d3f60089.zip FreeBSD-src-3bca94d06ee39468414ff052f3006666d3f60089.tar.gz |
Output a zero rdev except for bdevs, cdevs, fifos and sockets. This
stops regular files with unrepresentable rdevs from being rejected
and makes the output independent of unpreservable metadata.
Don't output a file if the major, minor or totality of its rdev would be
truncated. Print a message about the skipped files to stderr but don't
report the error in the exit status. cpio's abysmal error handling doesn't
allow continuing after an error, and the rdev checks had to be misplaced
to avoid the problem of returning an error code from routines that return
void.
Minor numbers are limited to 21 bits in pax's ustar format and to 18
bits in archives created by gnu tar (gnu tar wastes 3 bits for padding).
pax's and cpio's ustar format is incompatible with gnu tar's ustar
format for other reasons (see cpio/README).
Submitted by: bde via old gnu/usr.bin/cpio v2.3.
Diffstat (limited to 'contrib/cpio')
-rw-r--r-- | contrib/cpio/copyout.c | 142 |
1 files changed, 140 insertions, 2 deletions
diff --git a/contrib/cpio/copyout.c b/contrib/cpio/copyout.c index 22e9a0c..39890b0 100644 --- a/contrib/cpio/copyout.c +++ b/contrib/cpio/copyout.c @@ -35,6 +35,7 @@ static void add_link_defer (); static void writeout_other_defers (); static void writeout_final_defers(); static void writeout_defered_file (); +static int check_rdev (); /* Write out header FILE_HDR, including the file name, to file descriptor OUT_DES. */ @@ -293,8 +294,32 @@ process_copy_out () file_hdr.c_uid = file_stat.st_uid; file_hdr.c_gid = file_stat.st_gid; file_hdr.c_nlink = file_stat.st_nlink; - file_hdr.c_rdev_maj = major (file_stat.st_rdev); - file_hdr.c_rdev_min = minor (file_stat.st_rdev); + + /* The rdev is meaningless except for block and character + special files (POSIX standard) and perhaps fifos and + sockets. Clear it for other types of files so that + check_rdev() doesn't reject files just because stat() + put garbage in st_rdev and so that the output doesn't + depend on the garbage. */ + switch (file_hdr.c_mode & CP_IFMT) + { + case CP_IFBLK: + case CP_IFCHR: +#ifdef CP_IFIFO + case CP_IFIFO: +#endif +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif + file_hdr.c_rdev_maj = major (file_stat.st_rdev); + file_hdr.c_rdev_min = minor (file_stat.st_rdev); + break; + default: + file_hdr.c_rdev_maj = 0; + file_hdr.c_rdev_min = 0; + break; + } + file_hdr.c_mtime = file_stat.st_mtime; file_hdr.c_filesize = file_stat.st_size; file_hdr.c_chksum = 0; @@ -338,6 +363,23 @@ process_copy_out () continue; } + switch (check_rdev (&file_hdr)) + { + case 1: + error (0, 0, "%s not dumped: major number would be truncated", + file_hdr.c_name); + continue; + case 2: + error (0, 0, "%s not dumped: minor number would be truncated", + file_hdr.c_name); + continue; + case 4: + error (0, 0, "%s not dumped: device number would be truncated", + file_hdr.c_name); + continue; + } + + /* Copy the named file to the output. */ switch (file_hdr.c_mode & CP_IFMT) { @@ -805,3 +847,99 @@ writeout_defered_file (header, out_file_des) } return; } + + +static int +check_rdev (file_hdr) + struct new_cpio_header *file_hdr; +{ + if (archive_format == arf_newascii || archive_format == arf_crcascii) + { + if ((file_hdr->c_rdev_maj & 0xFFFFFFFF) != file_hdr->c_rdev_maj) + return 1; + if ((file_hdr->c_rdev_min & 0xFFFFFFFF) != file_hdr->c_rdev_min) + return 2; + } + else if (archive_format == arf_oldascii || archive_format == arf_hpoldascii) + { +#ifndef __MSDOS__ + dev_t rdev; + + rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + if (archive_format == arf_oldascii) + { + if ((rdev & 0xFFFF) != rdev) + return 4; + } + else + { + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + /* We could handle one more bit if longs are >= 33 bits. */ + if ((rdev & 037777777777) != rdev) + return 4; + break; + default: + if ((rdev & 0xFFFF) != rdev) + return 4; + break; + } + } +#endif + } + else if (archive_format == arf_tar || archive_format == arf_ustar) + { + /* The major and minor formats are limited to 7 octal digits in ustar + format, and to_oct () adds a gratuitous trailing blank to further + limit the format to 6 octal digits. */ + if ((file_hdr->c_rdev_maj & 0777777) != file_hdr->c_rdev_maj) + return 1; + if ((file_hdr->c_rdev_min & 0777777) != file_hdr->c_rdev_min) + return 2; + } + else + { +#ifndef __MSDOS__ + dev_t rdev; + + rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min); + if (archive_format != arf_hpbinary) + { + if ((rdev & 0xFFFF) != rdev) + return 4; + } + else + { + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFCHR: + case CP_IFBLK: +#ifdef CP_IFSOCK + case CP_IFSOCK: +#endif +#ifdef CP_IFIFO + case CP_IFIFO: +#endif + if ((rdev & 0xFFFFFFFF) != rdev) + return 4; + file_hdr->c_filesize = rdev; + rdev = makedev (0, 1); + break; + default: + if ((rdev & 0xFFFF) != rdev) + return 4; + break; + } + } +#endif + } + return 0; +} |