diff options
Diffstat (limited to 'usr.bin/cpio/cpio.c')
-rw-r--r-- | usr.bin/cpio/cpio.c | 156 |
1 files changed, 135 insertions, 21 deletions
diff --git a/usr.bin/cpio/cpio.c b/usr.bin/cpio/cpio.c index f7f64eb..be68616 100644 --- a/usr.bin/cpio/cpio.c +++ b/usr.bin/cpio/cpio.c @@ -32,9 +32,15 @@ __FBSDID("$FreeBSD$"); #include <archive.h> #include <archive_entry.h> +#ifdef HAVE_SYS_MKDEV_H +#include <sys/mkdev.h> +#endif #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif #ifdef HAVE_ERRNO_H #include <errno.h> #endif @@ -60,6 +66,12 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif #include "cpio.h" #include "matching.h" @@ -94,7 +106,7 @@ static void mode_in(struct cpio *); static void mode_list(struct cpio *); static void mode_out(struct cpio *); static void mode_pass(struct cpio *, const char *); -static void restore_time(struct cpio *, struct archive_entry *, +static int restore_time(struct cpio *, struct archive_entry *, const char *, int fd); static void usage(void); static void version(void); @@ -112,12 +124,22 @@ main(int argc, char *argv[]) memset(cpio, 0, sizeof(*cpio)); cpio->buff = buff; cpio->buff_size = sizeof(buff); +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure open() function will be used with a binary mode. */ + /* on cygwin, we need something similar, but instead link against */ + /* a special startup object, binmode.o */ + _set_fmode(_O_BINARY); +#endif /* Need cpio_progname before calling cpio_warnc. */ if (*argv == NULL) cpio_progname = "bsdcpio"; else { +#if defined(_WIN32) && !defined(__CYGWIN__) + cpio_progname = strrchr(*argv, '\\'); +#else cpio_progname = strrchr(*argv, '/'); +#endif if (cpio_progname != NULL) cpio_progname++; else @@ -132,8 +154,6 @@ main(int argc, char *argv[]) cpio->mode = '\0'; cpio->verbose = 0; cpio->compress = '\0'; - /* TODO: Implement old binary format in libarchive, use that here. */ - cpio->format = "odc"; /* Default format */ cpio->extract_flags = ARCHIVE_EXTRACT_NO_AUTODIR; cpio->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS; @@ -141,7 +161,11 @@ main(int argc, char *argv[]) cpio->extract_flags |= ARCHIVE_EXTRACT_PERM; cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; cpio->extract_flags |= ARCHIVE_EXTRACT_ACL; +#if defined(_WIN32) || defined(__CYGWIN__) + if (bsdcpio_is_privileged()) +#else if (geteuid() == 0) +#endif cpio->extract_flags |= ARCHIVE_EXTRACT_OWNER; cpio->bytes_per_block = 512; cpio->filename = NULL; @@ -190,6 +214,9 @@ main(int argc, char *argv[]) cpio->filename = cpio->optarg; break; case 'i': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -i and -%c", cpio->mode); cpio->mode = opt; break; case OPTION_INSECURE: @@ -205,6 +232,9 @@ main(int argc, char *argv[]) case 'm': /* POSIX 1997 */ cpio->extract_flags |= ARCHIVE_EXTRACT_TIME; break; + case 'n': /* GNU cpio */ + cpio->option_numeric_uid_gid = 1; + break; case OPTION_NO_PRESERVE_OWNER: /* GNU cpio */ cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; break; @@ -212,9 +242,15 @@ main(int argc, char *argv[]) cpio->filename = cpio->optarg; break; case 'o': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -o and -%c", cpio->mode); cpio->mode = opt; break; case 'p': /* POSIX 1997 */ + if (cpio->mode != '\0') + cpio_errc(1, 0, + "Cannot use both -p and -%c", cpio->mode); cpio->mode = opt; cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT; break; @@ -254,23 +290,56 @@ main(int argc, char *argv[]) break; #endif case 'y': /* tar convention */ +#if HAVE_LIBBZ2 cpio->compress = opt; +#else + cpio_warnc(0, "bzip2 compression not supported by " + "this version of bsdcpio"); +#endif break; case 'Z': /* tar convention */ cpio->compress = opt; break; case 'z': /* tar convention */ +#if HAVE_LIBZ cpio->compress = opt; +#else + cpio_warnc(0, "gzip compression not supported by " + "this version of bsdcpio"); +#endif break; default: usage(); } } - /* TODO: Sanity-check args, error out on nonsensical combinations. */ + /* + * Sanity-check args, error out on nonsensical combinations. + */ + /* -t implies -i if no mode was specified. */ + if (cpio->option_list && cpio->mode == '\0') + cpio->mode = 'i'; + /* -t requires -i */ + if (cpio->option_list && cpio->mode != 'i') + cpio_errc(1, 0, "Option -t requires -i", cpio->mode); + /* -n requires -it */ + if (cpio->option_numeric_uid_gid && !cpio->option_list) + cpio_errc(1, 0, "Option -n requires -it"); + /* Can only specify format when writing */ + if (cpio->format != NULL && cpio->mode != 'o') + cpio_errc(1, 0, "Option --format requires -o"); + /* -l requires -p */ + if (cpio->option_link && cpio->mode != 'p') + cpio_errc(1, 0, "Option -l requires -p"); + /* TODO: Flag other nonsensical combinations. */ switch (cpio->mode) { case 'o': + /* TODO: Implement old binary format in libarchive, + use that here. */ + if (cpio->format == NULL) + cpio->format = "odc"; /* Default format */ + mode_out(cpio); break; case 'i': @@ -321,7 +390,12 @@ static const char *long_help_msg = "Common Options:\n" " -v Verbose\n" "Create: %p -o [options] < [list of files] > [archive]\n" - " -z, -y Compress archive with gzip/bzip2\n" +#ifdef HAVE_BZLIB_H + " -y Compress archive with bzip2\n" +#endif +#ifdef HAVE_ZLIB_H + " -z Compress archive with gzip\n" +#endif " --format {odc|newc|ustar} Select archive format\n" "List: %p -it < [archive]\n" "Extract: %p -i [options] < [archive]\n"; @@ -387,12 +461,16 @@ mode_out(struct cpio *cpio) if (cpio->archive == NULL) cpio_errc(1, 0, "Failed to allocate archive object"); switch (cpio->compress) { +#ifdef HAVE_BZLIB_H case 'j': case 'y': archive_write_set_compression_bzip2(cpio->archive); break; +#endif +#ifdef HAVE_ZLIB_H case 'z': archive_write_set_compression_gzip(cpio->archive); break; +#endif case 'Z': archive_write_set_compression_compress(cpio->archive); break; @@ -455,11 +533,15 @@ file_to_archive(struct cpio *cpio, const char *srcpath) struct archive_entry *entry, *spare; size_t len; const char *p; +#if !defined(_WIN32) || defined(__CYGWIN__) int lnklen; +#endif int r; /* * Create an archive_entry describing the source file. + * + * XXX TODO: rework to use archive_read_disk_entry_from_file() */ entry = archive_entry_new(); if (entry == NULL) @@ -483,6 +565,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath) st.st_gid = cpio->uid_override; archive_entry_copy_stat(entry, &st); +#if !defined(_WIN32) || defined(__CYGWIN__) /* If its a symlink, pull the target. */ if (S_ISLNK(st.st_mode)) { lnklen = readlink(srcpath, cpio->buff, cpio->buff_size); @@ -495,6 +578,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath) cpio->buff[lnklen] = 0; archive_entry_set_symlink(entry, cpio->buff); } +#endif /* * Generate a destination path for this entry. @@ -625,7 +709,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) if (r != ARCHIVE_OK) cpio_warnc(archive_errno(cpio->archive), "%s: %s", - destpath, + srcpath, archive_error_string(cpio->archive)); if (r == ARCHIVE_FATAL) @@ -647,7 +731,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry) } } - restore_time(cpio, entry, srcpath, fd); + fd = restore_time(cpio, entry, srcpath, fd); cleanup: if (cpio->verbose) @@ -657,7 +741,7 @@ cleanup: return (0); } -static void +static int restore_time(struct cpio *cpio, struct archive_entry *entry, const char *name, int fd) { @@ -667,17 +751,20 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, (void)cpio; /* UNUSED */ (void)entry; /* UNUSED */ (void)name; /* UNUSED */ - (void)fd; /* UNUSED */ if (!warned) cpio_warnc(0, "Can't restore access times on this platform"); warned = 1; - return; + return (fd); +#else +#if defined(_WIN32) && !defined(__CYGWIN__) + struct __timeval times[2]; #else struct timeval times[2]; +#endif if (!cpio->option_atime_restore) - return; + return (fd); times[1].tv_sec = archive_entry_mtime(entry); times[1].tv_usec = archive_entry_mtime_nsec(entry) / 1000; @@ -687,8 +774,16 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, #ifdef HAVE_FUTIMES if (fd >= 0 && futimes(fd, times) == 0) - return; + return (fd); #endif + /* + * Some platform cannot restore access times if the file descriptor + * is still opened. + */ + if (fd >= 0) { + close(fd); + fd = -1; + } #ifdef HAVE_LUTIMES if (lutimes(name, times) != 0) @@ -697,6 +792,7 @@ restore_time(struct cpio *cpio, struct archive_entry *entry, #endif cpio_warnc(errno, "Can't update time for %s", name); #endif + return (fd); } @@ -858,6 +954,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) { char size[32]; char date[32]; + char uids[16], gids[16]; const char *uname, *gname; FILE *out = stdout; const struct stat *st; @@ -870,15 +967,24 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) if (!now) time(&now); - /* Use uname if it's present, else uid. */ - uname = archive_entry_uname(entry); - if (uname == NULL) - uname = lookup_uname(cpio, archive_entry_uid(entry)); - - /* Use gname if it's present, else gid. */ - gname = archive_entry_gname(entry); - if (gname == NULL) - gname = lookup_gname(cpio, archive_entry_gid(entry)); + if (cpio->option_numeric_uid_gid) { + /* Format numeric uid/gid for display. */ + snprintf(uids, sizeof(uids), "%jd", + (intmax_t)archive_entry_uid(entry)); + uname = uids; + snprintf(gids, sizeof(gids), "%jd", + (intmax_t)archive_entry_gid(entry)); + gname = gids; + } else { + /* Use uname if it's present, else lookup name from uid. */ + uname = archive_entry_uname(entry); + if (uname == NULL) + uname = lookup_uname(cpio, archive_entry_uid(entry)); + /* Use gname if it's present, else lookup name from gid. */ + gname = archive_entry_gname(entry); + if (gname == NULL) + gname = lookup_gname(cpio, archive_entry_gid(entry)); + } /* Print device number or file size. */ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) { @@ -892,10 +998,18 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry) /* Format the time using 'ls -l' conventions. */ tim = (time_t)st->st_mtime; +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Windows' strftime function does not support %e format. */ + if (abs(tim - now) > (365/2)*86400) + fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y"; + else + fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M"; +#else if (abs(tim - now) > (365/2)*86400) fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y"; else fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M"; +#endif strftime(date, sizeof(date), fmt, localtime(&tim)); fprintf(out, "%s%3d %-8s %-8s %8s %12s %s", |