🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.utils.bug
Article #19

tar enhancement.

#19
From: Jeff Moskow
Date: Thu, 29 Oct 1992 13:55
249 lines
7181 bytes
On SYSV systems, it is not possible to easily detect sparse files, yet
they do exist and it would be nice to tar/untar them efficiently.  Here
is a patch which implements --sparse-file and --sparse-list commands to
allow users to tell tar which files to treat as "sparse".  It seems to
meet most of our needs and you may want to include it in tar 1.12

Jeff Moskow
jeff@rtr.com

Here's the patch:

-------------------------cut here--------------------------------------
*** create.c.orig	Mon Sep 14 17:19:28 1992
--- create.c	Wed Oct 28 12:58:36 1992
***************
*** 373,379 ****
  		
  		header_moved = 0;
  
- #ifdef BSD42
  		if (f_sparse_files) {
  		/*
  	 	 * JK - This is the test for sparseness: whether the
--- 373,378 ----
***************
*** 384,393 ****
  		 * at least one of those records in the file is just
  		 * a useless hole.
  		 */
  #ifdef hpux	/* Nice of HPUX to gratuitiously change it, huh?  - mib */
! 		        if (hstat.st_size - (hstat.st_blocks * 1024) > 1024 )
  #else
! 			if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE)
  #endif
  			  {
  				int	filesize = hstat.st_size;
--- 383,398 ----
  		 * at least one of those records in the file is just
  		 * a useless hole.
  		 */
+ #ifdef BSD42
  #ifdef hpux	/* Nice of HPUX to gratuitiously change it, huh?  - mib */
! 		        if (hstat.st_size - (hstat.st_blocks * 1024) > 1024 
! #else
! 			if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE
! #endif
!                             || check_sparse(p))
  #else
!                         if (check_sparse(p))
! 
  #endif
  			  {
  				int	filesize = hstat.st_size;
***************
*** 455,463 ****
--- 460,470 ----
  					
  			}
  		}
+ /*
  #else
  		upperbound=SPARSE_IN_HDR-1;
  #endif
+ */
  		
  		sizeleft = hstat.st_size;
  		/* Don't bother opening empty, world readable files. */
*** tar.c.orig	Mon Sep 14 17:31:38 1992
--- tar.c	Wed Oct 28 13:33:15 1992
***************
*** 92,97 ****
--- 92,100 ----
  
  extern FILE *msg_file;
  
+ int	check_sparse();
+ void	add_sparse();
+ void	add_sparse_file();
  int	check_exclude();
  void	add_exclude();
  void	add_exclude_file();
***************
*** 184,189 ****
--- 187,194 ----
  	{"portability",		0,	0,			'o'},
  	{"compress",		0,	&f_compress,		1},
  	{"compress-block",	0,	&f_compress,		2},
+ 	{"sparse-list",		1,	0,			18},
+ 	{"sparse-file",		1,	0,			19},
  	{"sparse",		0,	&f_sparse_files,	1},
  	{"tape-length",		1,	0,			'L'},
  	{"remove-files",	0,	&f_remove_files,	1},
***************
*** 358,363 ****
--- 363,378 ----
  			f_volno_file = optarg;
  			break;
  			
+ 		case 18:
+ 			f_sparse_files++;
+ 			add_sparse_file(optarg);
+ 			break;
+ 			
+ 		case 19:
+ 			f_sparse_files++;
+ 			add_sparse(optarg);
+ 			break;
+ 			
  		case 'g':	/* We are making a GNU dump; save
  				   directories at the beginning of
  				   the archive, and include in each
***************
*** 704,709 ****
--- 719,726 ----
      --preserve-order	list of names to extract is sorted to match archive\n\
  --same-owner		create extracted files with the same ownership \n\
  -S, --sparse		handle sparse files efficiently\n\
+ --sparse-file FILE	treat FILE as sparse (implicit -S as well)\n\
+ --sparse-list FILE	treat files listed in FILE as sparse (implicit -S)\n\
  -T, --files-from F	get names to extract or create from file F\n\
  --null			-T reads null-terminated names, disable -C\n\
  --totals			print total bytes written with --create\n\
***************
*** 1394,1399 ****
--- 1411,1534 ----
  		if(   (str=strstr(name,exclude[n]))
   		   && (str==name || str[-1]=='/')
  		   && str[strlen(exclude[n])]=='\0')
+ 			return 1;
+ 	}
+ 	return 0;
+ }
+ 
+ char *s_buffer = 0;
+ int size_s_buffer;
+ int free_s_buffer;
+ 
+ char **sparse = 0;
+ int size_sparse = 0;
+ int free_sparse = 0;
+ 
+ char **re_sparse = 0;
+ int size_re_sparse = 0;
+ int free_re_sparse = 0;
+ 
+ void
+ add_sparse(name)
+ char *name;
+ {
+ /*	char *rname;*/
+ /*	char **tmp_ptr;*/
+ 	int size_buf;
+ 
+ 	un_quote_string(name);
+ 	size_buf = strlen(name);
+ 
+ 	if(s_buffer==0) {
+ 		s_buffer = (char *)ck_malloc(size_buf+1024);
+ 		free_s_buffer=1024;
+ 	} else if(free_s_buffer<=size_buf) {
+ 		char *old_s_buffer;
+ 		char **tmp_ptr;
+ 
+ 		old_s_buffer = s_buffer;
+ 		s_buffer = (char *)ck_realloc(s_buffer,size_s_buffer+1024);
+ 		free_s_buffer = 1024;
+ 		for(tmp_ptr=sparse;tmp_ptr<sparse+size_sparse;tmp_ptr++)
+ 			*tmp_ptr= s_buffer + ((*tmp_ptr) - old_s_buffer);
+ 		for(tmp_ptr=re_sparse;tmp_ptr<re_sparse+size_re_sparse;tmp_ptr++)
+ 			*tmp_ptr= s_buffer + ((*tmp_ptr) - old_s_buffer);
+ 	}
+ 
+ 	if(is_regex(name)) {
+ 		if(free_re_sparse==0) {
+ 			re_sparse= (char **)(re_sparse ? ck_realloc(re_sparse,(size_re_sparse+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32));
+ 			free_re_sparse+=32;
+ 		}
+ 		re_sparse[size_re_sparse]=s_buffer+size_s_buffer;
+ 		size_re_sparse++;
+ 		free_re_sparse--;
+ 	} else {
+ 		if(free_sparse==0) {
+ 			sparse=(char **)(sparse ? ck_realloc(sparse,(size_sparse+32)*sizeof(char *)) : ck_malloc(sizeof(char *)*32));
+ 			free_sparse+=32;
+ 		}
+ 		sparse[size_sparse]=s_buffer+size_s_buffer;
+ 		size_sparse++;
+ 		free_sparse--;
+ 	}
+ 	strcpy(s_buffer+size_s_buffer,name);
+ 	size_s_buffer+=size_buf+1;
+ 	free_s_buffer-=size_buf+1;
+ }
+ 
+ void
+ add_sparse_file(file)
+ char *file;
+ {
+ 	FILE *fp;
+ 	char buf[1024];
+ 
+ 	if(strcmp(file, "-"))
+ 		fp=fopen(file,"r");
+ 	else
+ 		/* Let's hope the person knows what they're doing. */
+ 		/* Using -X - -T - -f - will get you *REALLY* strange
+ 		   results. . . */
+ 		fp=stdin;
+ 
+ 	if(!fp) {
+ 		msg_perror("can't open %s",file);
+ 		exit(2);
+ 	}
+ 	while(fgets(buf,1024,fp)) {
+ /*		int size_buf;*/
+ 		char *end_str;
+ 
+ 		end_str=rindex(buf,'\n');
+ 		if(end_str)
+ 			*end_str='\0';
+ 		add_sparse(buf);
+ 
+ 	}
+ 	fclose(fp);
+ }
+ 
+ /* Returns non-zero if the file 'name' should be treated as sparse */
+ int
+ check_sparse(name)
+ char *name;
+ {
+ 	int n;
+ 	char *str;
+ 	extern char *strstr();
+ 
+ 	for(n=0;n<size_re_sparse;n++) {
+ 		if(fnmatch(re_sparse[n], name, FNM_TARPATH) == 0)
+ 			return 1;
+ 	}
+ 	for(n=0;n<size_sparse;n++) {
+ 		/* Accept the output from strstr only if it is the last
+ 		   part of the string.  There is certainly a faster way to
+ 		   do this. . . */
+ 		if(   (str=strstr(name,sparse[n]))
+  		   && (str==name || str[-1]=='/')
+ 		   && str[strlen(sparse[n])]=='\0')
  			return 1;
  	}
  	return 0;
Technical Details
Message-ID: <9210291355.AA04618@mousse.rtr.COM>
Path: arc1-ca.pugleaf.net!sparky!uunet!ogicse!uwm.edu!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!cis.ohio-state.edu!mousse.rtr.COM!jeff

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!ogicse!uwm.edu!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!cis.ohio-state.edu!mousse.rtr.COM!jeff
From: jeff@mousse.rtr.COM (Jeff Moskow)
Newsgroups: gnu.utils.bug
Subject: tar enhancement.
Message-ID: <9210291355.AA04618@mousse.rtr.COM>
Date: 29 Oct 92 13:55:35 GMT
Article-I.D.: mousse.9210291355.AA04618
Sender: gnulists@ai.mit.edu
Distribution: gnu
Organization: Gnus Not Usenet
Lines: 249
Approved: bug-gnu-utils@prep.ai.mit.edu