From nobody@FreeBSD.org  Tue Dec  8 15:02:16 2009
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id C6CAE1065676
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  8 Dec 2009 15:02:16 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 9C7338FC1B
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  8 Dec 2009 15:02:16 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id nB8F2G4Y033738
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 8 Dec 2009 15:02:16 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id nB8F2GwR033737;
	Tue, 8 Dec 2009 15:02:16 GMT
	(envelope-from nobody)
Message-Id: <200912081502.nB8F2GwR033737@www.freebsd.org>
Date: Tue, 8 Dec 2009 15:02:16 GMT
From: yamayan <yamayan@wind.sannet.ne.jp>
To: freebsd-gnats-submit@FreeBSD.org
Subject: unzip(1) option -p NOT quiet
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         141280
>Category:       bin
>Synopsis:       unzip(1) option -p NOT quiet
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Dec 08 15:10:02 UTC 2009
>Closed-Date:    Tue Dec 22 15:32:53 UTC 2009
>Last-Modified:  Tue May  4 19:20:00 UTC 2010
>Originator:     yamayan
>Release:        9.0-CURRENT
>Organization:
>Environment:
FreeBSD genius 9.0-CURRENT FreeBSD 9.0-CURRENT #0: Mon Dec  7 00:04:53 JST 2009     root@genius:/usr/obj/usr/src/sys/NYANCO  amd64
>Description:
unzip(1) option -p NOT quiet!

> unzip -p ANY.zip
Archive:  ANY.zip
[unzipped ANY.zip]

First line MUST NOT output.
>How-To-Repeat:
> echo FreeBSD > ANY.txt
> zip ANY.zip ANY.txt
> unzip -p ANY.zip
Archive:  ANY.zip
FreeBSD

>Fix:
/usr/src/usr.bin/unzip/unzip.c
line 817: printf("Archive:  %s\n", fn);
add if-expression, ex. if(!p_opt)

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Mon Dec 21 17:31:27 UTC 2009 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=141280 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/141280: commit references a PR
Date: Tue, 22 Dec 2009 15:13:30 +0000 (UTC)

 Author: jh
 Date: Tue Dec 22 15:13:16 2009
 New Revision: 200844
 URL: http://svn.freebsd.org/changeset/base/200844
 
 Log:
   Don't print the archive name with -p and -q options.
   
   PR:		bin/141280
   Approved by:	des, trasz (mentor)
 
 Modified:
   head/usr.bin/unzip/unzip.c
 
 Modified: head/usr.bin/unzip/unzip.c
 ==============================================================================
 --- head/usr.bin/unzip/unzip.c	Tue Dec 22 15:08:06 2009	(r200843)
 +++ head/usr.bin/unzip/unzip.c	Tue Dec 22 15:13:16 2009	(r200844)
 @@ -814,7 +814,8 @@ unzip(const char *fn)
  	ac(archive_read_support_format_zip(a));
  	ac(archive_read_open_fd(a, fd, 8192));
  
 -	printf("Archive:  %s\n", fn);
 +	if (!p_opt && !q_opt)
 +		printf("Archive:  %s\n", fn);
  	if (v_opt == 1) {
  		printf("  Length     Date   Time    Name\n");
  		printf(" --------    ----   ----    ----\n");
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: jh 
State-Changed-When: Tue Dec 22 15:32:51 UTC 2009 
State-Changed-Why:  
Fixed in head (r200844). Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=141280 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/141280: commit references a PR
Date: Tue,  4 May 2010 19:18:10 +0000 (UTC)

 Author: delphij
 Date: Tue May  4 19:18:00 2010
 New Revision: 207629
 URL: http://svn.freebsd.org/changeset/base/207629
 
 Log:
   MFC r196981, r200844, r201630, r203977, r203978, r204352:
   
   r196981 (rdivacky):
   
   Add C/c/f/p/v switches plus a bunch of minor fixes and cleanups.
   
   Obtained from:	NetBSD
   
   r200844 (jh):
   
   Don't print the archive name with -p and -q options.
   
   PR:		bin/141280
   
   r201630 (kientzle):
   
   When restoring files, use the mode for the mode.
   
   Thanks to: Jun Kuriyama for pointing this out
   
   r203977 (gavin):
   
   Implement the rename query, for when a file with the same name as the one
   about to be extracted already exists.  The question, and interpretation
   of the response is deliberately compatible with Info-Zip.
   
   This change was originally obtained from NetBSD, but has three changes:
    - better compatibility with Info-Zip in the handling of ^D
    - Use getdelim() rather than getline()
    - bug fix: != changed to == in the "file rename" code
   
   I suspect the latter is also a bug in NetBSD, but I can't easily confirm
   this.
   
   PR:		bin/143307
   Reviewed by:	rdivacky (change to unzip.c only)
   Obtained from:	NetBSD src/usr.bin/unzip/unzip.c 1.8
   
   r203978 (gavin):
   
   Bump .Dd for r203977
   
   r204352 (ru):
   
   Fixed static linkage.
   
   ==
   
   Requested by:	Alex Kozlov <spam rm-rf kiev ua>
 
 Modified:
   stable/8/usr.bin/unzip/Makefile
   stable/8/usr.bin/unzip/unzip.1
   stable/8/usr.bin/unzip/unzip.c
 Directory Properties:
   stable/8/usr.bin/unzip/   (props changed)
 
 Modified: stable/8/usr.bin/unzip/Makefile
 ==============================================================================
 --- stable/8/usr.bin/unzip/Makefile	Tue May  4 19:04:51 2010	(r207628)
 +++ stable/8/usr.bin/unzip/Makefile	Tue May  4 19:18:00 2010	(r207629)
 @@ -3,7 +3,7 @@
  PROG = unzip
  WARNS ?= 6
  CSTD = c99
 -DPADD = ${LIBARCHIVE}
 -LDADD = -larchive
 +DPADD = ${LIBARCHIVE} ${LIBZ}
 +LDADD = -larchive -lz
  
  .include <bsd.prog.mk>
 
 Modified: stable/8/usr.bin/unzip/unzip.1
 ==============================================================================
 --- stable/8/usr.bin/unzip/unzip.1	Tue May  4 19:04:51 2010	(r207628)
 +++ stable/8/usr.bin/unzip/unzip.1	Tue May  4 19:18:00 2010	(r207629)
 @@ -25,7 +25,7 @@
  .\"
  .\" $FreeBSD$
  .\"
 -.Dd June 30, 2008
 +.Dd February 16, 2010
  .Dt UNZIP 1
  .Os
  .Sh NAME
 @@ -33,7 +33,7 @@
  .Nd extract files from a ZIP archive
  .Sh SYNOPSIS
  .Nm
 -.Op Fl ajLlnoqtu
 +.Op Fl aCcfjLlnopqtuv
  .Op Fl d Ar dir
  .Ar zipfile
  .Sh DESCRIPTION
 @@ -44,9 +44,22 @@ The following options are available:
  .It Fl a
  When extracting a text file, convert DOS-style line endings to
  Unix-style line endings.
 +.It Fl C
 +Match file names case-insensitively.
 +.It Fl c
 +Extract to stdout/screen.
 +When extracting files from the zipfile, they are written to stdout.
 +This is similar to
 +.Fl p ,
 +but doesn't suppress normal output.
  .It Fl d Ar dir
  Extract files into the specified directory rather than the current
  directory.
 +.It Fl f
 +Update existing.
 +Extract only files from the zipfile if a file with the same name
 +already exists on disk and is older than the former.
 +Otherwise, the file is silently skipped.
  .It Fl j
  Ignore directories stored in the zipfile; instead, extract all files
  directly into the extraction directory.
 @@ -56,13 +69,19 @@ Convert the names of the extracted files
  List, rather than extract, the contents of the zipfile.
  .It Fl n
  No overwrite.
 -When extacting a file from the zipfile, if a file with the same name
 +When extracting a file from the zipfile, if a file with the same name
  already exists on disk, the file is silently skipped.
  .It Fl o
  Overwrite.
 -When extacting a file from the zipfile, if a file with the same name
 +When extracting a file from the zipfile, if a file with the same name
  already exists on disk, the existing file is replaced with the file
  from the zipfile.
 +.It Fl p
 +Extract to stdout.
 +When extracting files from the zipfile, they are written to stdout.
 +The normal output is suppressed as if
 +.Fl q
 +was specified.
  .It Fl q
  Quiet: print less information while extracting.
  .It Fl t
 @@ -70,15 +89,25 @@ Test: do not extract anything, but verif
  in the archive.
  .It Fl u
  Update.
 -When extacting a file from the zipfile, if a file with the same name
 +When extracting a file from the zipfile, if a file with the same name
  already exists on disk, the existing file is replaced with the file
  from the zipfile if and only if the latter is newer than the former.
  Otherwise, the file is silently skipped.
 +.It Fl v
 +List verbosely, rather than extract, the contents of the zipfile.
 +This differs from
 +.Fl l
 +by using the long listing.
 +Note that most of the data is currently fake and does not reflect the
 +content of the archive.
 +.It Fl x Ar pattern
 +Exclude files matching the pattern
 +.Ar pattern .
  .El
  .Pp
  Note that only one of
  .Fl n ,
 -.Fl o
 +.Fl o ,
  and
  .Fl u
  may be specified.
 @@ -129,17 +158,6 @@ utility is only able to process ZIP arch
  Depending on the installed version of
  .Xr libarchive ,
  this may or may not include self-extracting archives.
 -.Sh BUGS
 -The
 -.Nm
 -utility currently does not support asking the user whether to
 -overwrite or skip a file that already exists on disk.
 -To be on the safe side, it will fail if it encounters a file that
 -already exists and neither the
 -.Fl n
 -nor the
 -.Fl o
 -command line option was specified.
  .Sh SEE ALSO
  .Xr libarchive 3
  .Sh HISTORY
 
 Modified: stable/8/usr.bin/unzip/unzip.c
 ==============================================================================
 --- stable/8/usr.bin/unzip/unzip.c	Tue May  4 19:04:51 2010	(r207628)
 +++ stable/8/usr.bin/unzip/unzip.c	Tue May  4 19:18:00 2010	(r207629)
 @@ -1,4 +1,5 @@
  /*-
 + * Copyright (c) 2009 Joerg Sonnenberger <joerg@NetBSD.org>
   * Copyright (c) 2007-2008 Dag-Erling Codan Smrgrav
   * All rights reserved.
   *
 @@ -51,15 +52,19 @@
  
  /* command-line options */
  static int		 a_opt;		/* convert EOL */
 +static int		 C_opt;		/* match case-insensitively */
 +static int		 c_opt;		/* extract to stdout */
  static const char	*d_arg;		/* directory */
 +static int		 f_opt;		/* update existing files only */
  static int		 j_opt;		/* junk directories */
  static int		 L_opt;		/* lowercase names */
 -static int		 l_opt;		/* list */
  static int		 n_opt;		/* never overwrite */
  static int		 o_opt;		/* always overwrite */
 +static int		 p_opt;		/* extract to stdout, quiet */
  static int		 q_opt;		/* quiet */
  static int		 t_opt;		/* test */
  static int		 u_opt;		/* update */
 +static int		 v_opt;		/* verbose/list */
  
  /* time when unzip started */
  static time_t		 now;
 @@ -70,9 +75,6 @@ static int		 unzip_debug;
  /* running on tty? */
  static int		 tty;
  
 -/* error flag for -t */
 -static int		 test_failed;
 -
  /* convenience macro */
  /* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */
  #define ac(call)						\
 @@ -162,7 +164,6 @@ static void
  info(const char *fmt, ...)
  {
  	va_list ap;
 -	int i;
  
  	if (q_opt && !unzip_debug)
  		return;
 @@ -171,9 +172,10 @@ info(const char *fmt, ...)
  	va_end(ap);
  	fflush(stdout);
  
 -	for (i = 0; fmt[i] != '\0'; ++i)
 -		/* nothing */ ;
 -	noeol = !(i && fmt[i - 1] == '\n');
 +	if (*fmt == '\0')
 +		noeol = 1;
 +	else
 +		noeol = fmt[strlen(fmt) - 1] != '\n';
  }
  
  /* debug message (if unzip_debug) */
 @@ -181,7 +183,6 @@ static void
  debug(const char *fmt, ...)
  {
  	va_list ap;
 -	int i;
  
  	if (!unzip_debug)
  		return;
 @@ -190,9 +191,10 @@ debug(const char *fmt, ...)
  	va_end(ap);
  	fflush(stderr);
  
 -	for (i = 0; fmt[i] != '\0'; ++i)
 -		/* nothing */ ;
 -	noeol = !(i && fmt[i - 1] == '\n');
 +	if (*fmt == '\0')
 +		noeol = 1;
 +	else
 +		noeol = fmt[strlen(fmt) - 1] != '\n';
  }
  
  /* duplicate a path name, possibly converting to lower case */
 @@ -200,7 +202,7 @@ static char *
  pathdup(const char *path)
  {
  	char *str;
 -	int len;
 +	size_t i, len;
  
  	len = strlen(path);
  	while (len && path[len - 1] == '/')
 @@ -209,8 +211,12 @@ pathdup(const char *path)
  		errno = ENOMEM;
  		error("malloc()");
  	}
 -	for (int i = 0; i < len; ++i)
 -		str[i] = L_opt ? tolower(path[i]) : path[i];
 +	if (L_opt) {
 +		for (i = 0; i < len; ++i)
 +			str[i] = tolower((unsigned char)path[i]);
 +	} else {
 +		memcpy(str, path, len);
 +	}
  	str[len] = '\0';
  
  	return (str);
 @@ -221,7 +227,7 @@ static char *
  pathcat(const char *prefix, const char *path)
  {
  	char *str;
 -	int prelen, len;
 +	size_t prelen, len;
  
  	prelen = prefix ? strlen(prefix) + 1 : 0;
  	len = strlen(path) + 1;
 @@ -257,7 +263,7 @@ static void
  add_pattern(struct pattern_list *list, const char *pattern)
  {
  	struct pattern *entry;
 -	int len;
 +	size_t len;
  
  	debug("adding pattern '%s'\n", pattern);
  	len = strlen(pattern);
 @@ -265,7 +271,6 @@ add_pattern(struct pattern_list *list, c
  		errno = ENOMEM;
  		error("malloc()");
  	}
 -	memset(&entry->link, 0, sizeof entry->link);
  	memcpy(entry->pattern, pattern, len + 1);
  	STAILQ_INSERT_TAIL(list, entry, link);
  }
 @@ -279,7 +284,7 @@ match_pattern(struct pattern_list *list,
  	struct pattern *entry;
  
  	STAILQ_FOREACH(entry, list, link) {
 -		if (fnmatch(entry->pattern, str, 0) == 0)
 +		if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0)
  			return (1);
  	}
  	return (0);
 @@ -378,7 +383,7 @@ extract_dir(struct archive *a, struct ar
  {
  	int mode;
  
 -	mode = archive_entry_filetype(e) & 0777;
 +	mode = archive_entry_mode(e) & 0777;
  	if (mode == 0)
  		mode = 0755;
  
 @@ -406,49 +411,104 @@ extract_dir(struct archive *a, struct ar
  static unsigned char buffer[8192];
  static char spinner[] = { '|', '/', '-', '\\' };
  
 +static int
 +handle_existing_file(char **path)
 +{
 +	size_t alen;
 +	ssize_t len;
 +	char buf[4];
 +
 +	for (;;) {
 +		fprintf(stderr,
 +		    "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
 +		    *path);
 +		if (fgets(buf, sizeof(buf), stdin) == 0) {
 +			clearerr(stdin);
 +			printf("NULL\n(EOF or read error, "
 +			    "treating as \"[N]one\"...)\n");
 +			n_opt = 1;
 +			return -1;
 +		}
 +		switch (*buf) {
 +		case 'A':
 +			o_opt = 1;
 +			/* FALLTHROUGH */
 +		case 'y':
 +		case 'Y':
 +			(void)unlink(*path);
 +			return 1;
 +		case 'N':
 +			n_opt = 1;			
 +			/* FALLTHROUGH */
 +		case 'n':
 +			return -1;
 +		case 'r':
 +		case 'R':
 +			printf("New name: ");
 +			fflush(stdout);
 +			free(*path);
 +			*path = NULL;
 +			alen = 0;
 +			len = getdelim(path, &alen, '\n', stdin);
 +			if ((*path)[len - 1] == '\n')
 +				(*path)[len - 1] = '\0';
 +			return 0;
 +		default:
 +			break;
 +		}
 +	}
 +}
 +
  /*
   * Extract a regular file.
   */
  static void
 -extract_file(struct archive *a, struct archive_entry *e, const char *path)
 +extract_file(struct archive *a, struct archive_entry *e, char **path)
  {
  	int mode;
  	time_t mtime;
  	struct stat sb;
  	struct timeval tv[2];
 -	int cr, fd, text, warn;
 +	int cr, fd, text, warn, check;
  	ssize_t len;
  	unsigned char *p, *q, *end;
  
 -	mode = archive_entry_filetype(e) & 0777;
 +	mode = archive_entry_mode(e) & 0777;
  	if (mode == 0)
  		mode = 0644;
  	mtime = archive_entry_mtime(e);
  
  	/* look for existing file of same name */
 -	if (lstat(path, &sb) == 0) {
 -		if (u_opt) {
 +recheck:
 +	if (lstat(*path, &sb) == 0) {
 +		if (u_opt || f_opt) {
  			/* check if up-to-date */
 -			if (S_ISREG(sb.st_mode) && sb.st_mtime > mtime)
 +			if (S_ISREG(sb.st_mode) && sb.st_mtime >= mtime)
  				return;
 -			(void)unlink(path);
 +			(void)unlink(*path);
  		} else if (o_opt) {
  			/* overwrite */
 -			(void)unlink(path);
 +			(void)unlink(*path);
  		} else if (n_opt) {
  			/* do not overwrite */
  			return;
  		} else {
 -			/* XXX ask user */
 -			errorx("not implemented");
 +			check = handle_existing_file(path);
 +			if (check == 0)
 +				goto recheck;
 +			if (check == -1)
 +				return; /* do not overwrite */
  		}
 +	} else {
 +		if (f_opt)
 +			return;
  	}
  
 -	if ((fd = open(path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
 -		error("open('%s')", path);
 +	if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
 +		error("open('%s')", *path);
  
  	/* loop over file contents and write to disk */
 -	info("x %s", path);
 +	info(" extracting: %s", *path);
  	text = a_opt;
  	warn = 0;
  	cr = 0;
 @@ -465,7 +525,7 @@ extract_file(struct archive *a, struct a
  		if (a_opt && cr) {
  			if (len == 0 || buffer[0] != '\n')
  				if (write(fd, "\r", 1) != 1)
 -					error("write('%s')", path);
 +					error("write('%s')", *path);
  			cr = 0;
  		}
  
 @@ -496,7 +556,7 @@ extract_file(struct archive *a, struct a
  		/* simple case */
  		if (!a_opt || !text) {
  			if (write(fd, buffer, len) != len)
 -				error("write('%s')", path);
 +				error("write('%s')", *path);
  			continue;
  		}
  
 @@ -506,7 +566,7 @@ extract_file(struct archive *a, struct a
  				if (!warn && !isascii(*q)) {
  					warningx("%s may be corrupted due"
  					    " to weak text file detection"
 -					    " heuristic", path);
 +					    " heuristic", *path);
  					warn = 1;
  				}
  				if (q[0] != '\r')
 @@ -519,7 +579,7 @@ extract_file(struct archive *a, struct a
  					break;
  			}
  			if (write(fd, p, q - p) != q - p)
 -				error("write('%s')", path);
 +				error("write('%s')", *path);
  		}
  	}
  	if (tty)
 @@ -534,9 +594,9 @@ extract_file(struct archive *a, struct a
  	tv[1].tv_sec = mtime;
  	tv[1].tv_usec = 0;
  	if (futimes(fd, tv) != 0)
 -		error("utimes('%s')", path);
 +		error("utimes('%s')", *path);
  	if (close(fd) != 0)
 -		error("close('%s')", path);
 +		error("close('%s')", *path);
  }
  
  /*
 @@ -612,46 +672,178 @@ extract(struct archive *a, struct archiv
  	if (S_ISDIR(filetype))
  		extract_dir(a, e, realpathname);
  	else
 -		extract_file(a, e, realpathname);
 +		extract_file(a, e, &realpathname);
  
  	free(realpathname);
  	free(pathname);
  }
  
 +static void
 +extract_stdout(struct archive *a, struct archive_entry *e)
 +{
 +	char *pathname;
 +	mode_t filetype;
 +	int cr, text, warn;
 +	ssize_t len;
 +	unsigned char *p, *q, *end;
 +
 +	pathname = pathdup(archive_entry_pathname(e));
 +	filetype = archive_entry_filetype(e);
 +
 +	/* I don't think this can happen in a zipfile.. */
 +	if (!S_ISDIR(filetype) && !S_ISREG(filetype)) {
 +		warningx("skipping non-regular entry '%s'", pathname);
 +		ac(archive_read_data_skip(a));
 +		free(pathname);
 +		return;
 +	}
 +
 +	/* skip directories in -j case */
 +	if (S_ISDIR(filetype)) {
 +		ac(archive_read_data_skip(a));
 +		free(pathname);
 +		return;
 +	}
 +
 +	/* apply include / exclude patterns */
 +	if (!accept_pathname(pathname)) {
 +		ac(archive_read_data_skip(a));
 +		free(pathname);
 +		return;
 +	}
 +
 +	if (c_opt)
 +		info("x %s\n", pathname);
 +
 +	text = a_opt;
 +	warn = 0;
 +	cr = 0;
 +	for (int n = 0; ; n++) {
 +		len = archive_read_data(a, buffer, sizeof buffer);
 +
 +		if (len < 0)
 +			ac(len);
 +
 +		/* left over CR from previous buffer */
 +		if (a_opt && cr) {
 +			if (len == 0 || buffer[0] != '\n') {
 +				if (fwrite("\r", 1, 1, stderr) != 1)
 +					error("write('%s')", pathname);
 +			}
 +			cr = 0;
 +		}
 +
 +		/* EOF */
 +		if (len == 0)
 +			break;
 +		end = buffer + len;
 +
 +		/*
 +		 * Detect whether this is a text file.  The correct way to
 +		 * do this is to check the least significant bit of the
 +		 * "internal file attributes" field of the corresponding
 +		 * file header in the central directory, but libarchive
 +		 * does not read the central directory, so we have to
 +		 * guess by looking for non-ASCII characters in the
 +		 * buffer.  Hopefully we won't guess wrong.  If we do
 +		 * guess wrong, we print a warning message later.
 +		 */
 +		if (a_opt && n == 0) {
 +			for (p = buffer; p < end; ++p) {
 +				if (!isascii((unsigned char)*p)) {
 +					text = 0;
 +					break;
 +				}
 +			}
 +		}
 +
 +		/* simple case */
 +		if (!a_opt || !text) {
 +			if (fwrite(buffer, 1, len, stdout) != (size_t)len)
 +				error("write('%s')", pathname);
 +			continue;
 +		}
 +
 +		/* hard case: convert \r\n to \n (sigh...) */
 +		for (p = buffer; p < end; p = q + 1) {
 +			for (q = p; q < end; q++) {
 +				if (!warn && !isascii(*q)) {
 +					warningx("%s may be corrupted due"
 +					    " to weak text file detection"
 +					    " heuristic", pathname);
 +					warn = 1;
 +				}
 +				if (q[0] != '\r')
 +					continue;
 +				if (&q[1] == end) {
 +					cr = 1;
 +					break;
 +				}
 +				if (q[1] == '\n')
 +					break;
 +			}
 +			if (fwrite(p, 1, q - p, stdout) != (size_t)(q - p))
 +				error("write('%s')", pathname);
 +		}
 +	}
 +
 +	free(pathname);
 +}
 +
  /*
   * Print the name of an entry to stdout.
   */
  static void
  list(struct archive *a, struct archive_entry *e)
  {
 +	char buf[20];
 +	time_t mtime;
  
 -	printf("%s\n", archive_entry_pathname(e));
 +	mtime = archive_entry_mtime(e);
 +	strftime(buf, sizeof(buf), "%m-%d-%g %R", localtime(&mtime));
 +
 +	if (v_opt == 1) {
 +		printf(" %8ju  %s   %s\n",
 +		    (uintmax_t)archive_entry_size(e),
 +		    buf, archive_entry_pathname(e));
 +	} else if (v_opt == 2) {
 +		printf("%8ju  Stored  %7ju   0%%  %s  %08x  %s\n",
 +		    (uintmax_t)archive_entry_size(e),
 +		    (uintmax_t)archive_entry_size(e),
 +		    buf,
 +		    0U,
 +		    archive_entry_pathname(e));
 +	}
  	ac(archive_read_data_skip(a));
  }
  
  /*
   * Extract to memory to check CRC
   */
 -static void
 +static int
  test(struct archive *a, struct archive_entry *e)
  {
  	ssize_t len;
 +	int error_count;
  
 +	error_count = 0;
  	if (S_ISDIR(archive_entry_filetype(e)))
 -		return;
 +		return 0;
  
 -	info("%s ", archive_entry_pathname(e));
 +	info("    testing: %s\t", archive_entry_pathname(e));
  	while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0)
  		/* nothing */;
  	if (len < 0) {
 -		info("%s\n", archive_error_string(a));
 -		++test_failed;
 +		info(" %s\n", archive_error_string(a));
 +		++error_count;
  	} else {
 -		info("OK\n");
 +		info(" OK\n");
  	}
  
  	/* shouldn't be necessary, but it doesn't hurt */
  	ac(archive_read_data_skip(a));
 +
 +	return error_count;
  }
  
  
 @@ -665,6 +857,7 @@ unzip(const char *fn)
  	struct archive *a;
  	struct archive_entry *e;
  	int fd, ret;
 +	uintmax_t total_size, file_count, error_count;
  
  	if ((fd = open(fn, O_RDONLY)) < 0)
  		error("%s", fn);
 @@ -673,33 +866,70 @@ unzip(const char *fn)
  	ac(archive_read_support_format_zip(a));
  	ac(archive_read_open_fd(a, fd, 8192));
  
 +	if (!p_opt && !q_opt)
 +		printf("Archive:  %s\n", fn);
 +	if (v_opt == 1) {
 +		printf("  Length     Date   Time    Name\n");
 +		printf(" --------    ----   ----    ----\n");
 +	} else if (v_opt == 2) {
 +		printf(" Length   Method    Size  Ratio   Date   Time   CRC-32    Name\n");
 +		printf("--------  ------  ------- -----   ----   ----   ------    ----\n");
 +	}
 +
 +	total_size = 0;
 +	file_count = 0;
 +	error_count = 0;
  	for (;;) {
  		ret = archive_read_next_header(a, &e);
  		if (ret == ARCHIVE_EOF)
  			break;
  		ac(ret);
  		if (t_opt)
 -			test(a, e);
 -		else if (l_opt)
 +			error_count += test(a, e);
 +		else if (v_opt)
  			list(a, e);
 +		else if (p_opt || c_opt)
 +			extract_stdout(a, e);
  		else
  			extract(a, e);
 +
 +		total_size += archive_entry_size(e);
 +		++file_count;
 +	}
 +
 +	if (v_opt == 1) {
 +		printf(" --------                   -------\n");
 +		printf(" %8ju                   %ju file%s\n",
 +		    total_size, file_count, file_count != 1 ? "s" : "");
 +	} else if (v_opt == 2) {
 +		printf("--------          -------  ---                            -------\n");
 +		printf("%8ju          %7ju   0%%                            %ju file%s\n",
 +		    total_size, total_size, file_count,
 +		    file_count != 1 ? "s" : "");
  	}
  
  	ac(archive_read_close(a));
  	(void)archive_read_finish(a);
 +
  	if (close(fd) != 0)
  		error("%s", fn);
  
 -	if (t_opt && test_failed)
 -		errorx("%d checksum error(s) found.", test_failed);
 +	if (t_opt) {
 +		if (error_count > 0) {
 +			errorx("%d checksum error(s) found.", error_count);
 +		}
 +		else {
 +			printf("No errors detected in compressed data of %s.\n",
 +			       fn);
 +		}
 +	}
  }
  
  static void
  usage(void)
  {
  
 -	fprintf(stderr, "usage: unzip [-ajLlnoqtu] [-d dir] zipfile\n");
 +	fprintf(stderr, "usage: unzip [-aCcfjLlnopqtuv] [-d dir] [-x pattern] zipfile\n");
  	exit(1);
  }
  
 @@ -709,14 +939,23 @@ getopts(int argc, char *argv[])
  	int opt;
  
  	optreset = optind = 1;
 -	while ((opt = getopt(argc, argv, "ad:jLlnoqtux:")) != -1)
 +	while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:")) != -1)
  		switch (opt) {
  		case 'a':
  			a_opt = 1;
  			break;
 +		case 'C':
 +			C_opt = 1;
 +			break;
 +		case 'c':
 +			c_opt = 1;
 +			break;
  		case 'd':
  			d_arg = optarg;
  			break;
 +		case 'f':
 +			f_opt = 1;
 +			break;
  		case 'j':
  			j_opt = 1;
  			break;
 @@ -724,13 +963,18 @@ getopts(int argc, char *argv[])
  			L_opt = 1;
  			break;
  		case 'l':
 -			l_opt = 1;
 +			if (v_opt == 0)
 +				v_opt = 1;
  			break;
  		case 'n':
  			n_opt = 1;
  			break;
  		case 'o':
  			o_opt = 1;
 +			q_opt = 1;
 +			break;
 +		case 'p':
 +			p_opt = 1;
  			break;
  		case 'q':
  			q_opt = 1;
 @@ -741,6 +985,9 @@ getopts(int argc, char *argv[])
  		case 'u':
  			u_opt = 1;
  			break;
 +		case 'v':
 +			v_opt = 2;
 +			break;
  		case 'x':
  			add_pattern(&exclude, optarg);
  			break;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
