summaryrefslogtreecommitdiffstats
path: root/usr.bin/cpio/cpio.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2009-04-17 04:04:57 +0000
committerkientzle <kientzle@FreeBSD.org>2009-04-17 04:04:57 +0000
commit5853643ce6ecab17fd51492c41fe5a44599637b2 (patch)
tree71b1033c9249ea051e5e93acaad8389233a40909 /usr.bin/cpio/cpio.c
parent4e8cb50d8bef897f785cb884230eb42be06c0541 (diff)
downloadFreeBSD-src-5853643ce6ecab17fd51492c41fe5a44599637b2.zip
FreeBSD-src-5853643ce6ecab17fd51492c41fe5a44599637b2.tar.gz
Merge from libarchive.googlecode.com:
* Lots of new tests. * New -n / --numeric-uid-gid option * More sanity-checking of arguments * Various Windows portability improvements * Sync up version number to 2.7.0
Diffstat (limited to 'usr.bin/cpio/cpio.c')
-rw-r--r--usr.bin/cpio/cpio.c156
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",
OpenPOWER on IntegriCloud