Subject: bin/3177: add --fastread to tar to read only what's necessary
To: None <gnats-bugs@gnats.netbsd.org>
From: Hubert Feyrer <feyrer@rfhs8012.fh-regensburg.de>
List: netbsd-bugs
Date: 02/01/1997 22:58:58
>Number:         3177
>Category:       bin
>Synopsis:       add --fastread to tar to read only what's necessary
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Feb  1 21:50:01 1997
>Last-Modified:
>Originator:     Hubert Feyrer
>Organization:
Hubert Feyrer <hubert.feyrer@rz.uni-regensburg.de>
>Release:        1.2
>Environment:
	
System: NetBSD miyu 1.2 NetBSD 1.2 (MIYU) #8: Sun Jan 26 20:34:03 MET 1997 feyrer@miyu:/usr/disk1/src12/sys/arch/i386/compile/MIYU i386


>Description:
	The patch below is to make NetBSD's tar-command recognize
	the --fast-read switch. It can be used to read only as much
	of a tar file as needed to extract e.g. the first file without
	scanning to the EOF.

	This has been borrowed from FreeBSD, it's used in the ports
	system there.


>How-To-Repeat:
	tar -xf largefile.tar firstfile	
	-> scans the whole largefile.tar after extracting firstfile,
	   slow

	tar --fast-read -xf -largefile.tar firstfile
	-> aborts after extracting firstfile -> fast.


>Fix:


Patch against NetBSD V1.2's tar command to make it recognize
the --fast-read option. Borrowed from FreeBSD.


diff -crNb /usr/src/gnu/usr.bin/tar/tar.1 tar-NetBSD/tar.1
*** /usr/src/gnu/usr.bin/tar/tar.1	Wed Mar 13 14:55:00 1996
--- tar-NetBSD/tar.1	Sat Feb  1 22:03:50 1997
***************
*** 158,163 ****
--- 158,166 ----
  .It Fl -new-volume-script Ar file
  Run a script at the end of each archive volume (implies
  .Fl M ) .
+ .It Fl -fast-read
+ Stop after all non-wildcard extraction targets have been found
+ in the archive.
  .It Fl G
  .It Fl -incremental
  Create/list/extract old GNU-format incremental backup.
diff -crNb /usr/src/gnu/usr.bin/tar/tar.c tar-NetBSD/tar.c
*** /usr/src/gnu/usr.bin/tar/tar.c	Thu Mar 21 18:35:51 1996
--- tar-NetBSD/tar.c	Sat Feb  1 21:59:29 1997
***************
*** 88,93 ****
--- 88,94 ----
  void name_init ();
  void options ();
  char *un_quote_string ();
+ int nlpsfreed = 0;
  
  #ifndef S_ISLNK
  #define lstat stat
***************
*** 187,192 ****
--- 188,194 ----
  
    {"norecurse", 0, &f_norecurse, 1},
    {"unlink", 0, &f_unlink, 1},
+   {"fast-read", 0, &f_fast_read, 1},
  
    {0, 0, 0, 0}
  };
***************
*** 766,771 ****
--- 768,774 ----
  -[0-7][lmh]		specify drive and density\n\
  --norecurse		don't recurse into subdirectories when creating\n\
  --unlink		unlink files before creating them\n\
+ --fast-read 		stop after desired names in archive have been found\n\
  ", stdout);
  }
  
***************
*** 1127,1132 ****
--- 1130,1136 ----
       register char *p;
  {
    register struct name *nlp;
+   struct name *tmpnlp;
    register int len;
  
  again:
***************
*** 1135,1141 ****
    if (nlp->fake)
      {
        if (nlp->change_dir && chdir (nlp->change_dir))
! 	msg_perror ("Can't change to directory %d", nlp->change_dir);
        namelist = 0;
        return 1;
      }
--- 1139,1145 ----
    if (nlp->fake)
      {
        if (nlp->change_dir && chdir (nlp->change_dir))
! 	msg_perror ("Can't change to directory %s", nlp->change_dir);
        namelist = 0;
        return 1;
      }
***************
*** 1178,1183 ****
--- 1182,1215 ----
  	    }
  	  if (nlp->change_dir && chdir (nlp->change_dir))
  	    msg_perror ("Can't change to directory %s", nlp->change_dir);
+ 	  if (f_fast_read) {
+ 	      if (strcmp(p, nlp->name) == 0) {
+ 		  /* remove the current entry, since we found a match */
+ 		  /* use brute force, this code is a mess anyway */
+ 		  if (namelist->next == NULL) {
+ 		      /* the list contains one element */
+ 		      free(namelist);
+ 		      namelist = NULL;
+ 		  } else {
+ 		      if (nlp == namelist) {
+ 			  /* the first element is the one */
+ 			  tmpnlp = namelist->next;
+ 			  free(namelist);
+ 			  namelist = tmpnlp;
+ 		      } else {
+ 			  tmpnlp = namelist;
+ 			  while (tmpnlp->next != nlp) {
+ 			      tmpnlp = tmpnlp->next;
+ 			  }
+ 			  tmpnlp->next = nlp->next;
+ 			  free(nlp);
+ 		      }
+ 		  }
+ 		  /* set a boolean to decide wether we started with a  */
+ 		  /* non-empty  namelist, that was emptied */
+ 		  nlpsfreed = 1;
+ 	      }
+ 	  }
  	  return 1;		/* We got a match */
  	}
      }
diff -crNb /usr/src/gnu/usr.bin/tar/tar.h tar-NetBSD/tar.h
*** /usr/src/gnu/usr.bin/tar/tar.h	Sat Aug  7 07:42:55 1993
--- tar-NetBSD/tar.h	Sat Feb  1 22:01:34 1997
***************
*** 236,241 ****
--- 236,242 ----
  TAR_EXTERN int f_compress_block; /* --compress-block */
  TAR_EXTERN int f_norecurse;	/* --norecurse */
  TAR_EXTERN int f_unlink;	/* --unlink */
+ TAR_EXTERN int f_fast_read;	/* --fast-read */
  
  /*
   * We default to Unix Standard format rather than 4.2BSD tar format.
***************
*** 278,283 ****
--- 279,288 ----
   */
  TAR_EXTERN char read_error_flag;
  
+ /*
+  * global boolean, see name_match in tar.c
+  */
+ extern int	nlpsfreed;
  
  /*
   * Declarations of functions available to the world.
>Audit-Trail:
>Unformatted: