1 /* GNU dump extensions to tar.
2 Copyright (C) 1988, 1992 Free Software Foundation
4 This file is part of GNU Tar.
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 #include <sys/types.h>
33 #if defined(_POSIX_VERSION) || defined(DIRENT)
39 #define DP_NAMELEN(x) strlen((x)->d_name)
40 #endif /* _POSIX_VERSION or DIRENT */
41 #if !defined(_POSIX_VERSION) && !defined(DIRENT) && defined(BSD42)
43 #define DP_NAMELEN(x) (x)->d_namlen
44 #endif /* not _POSIX_VERSION and BSD42 */
47 #define DP_NAMELEN(x) (x)->d_namlen
50 #if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT)
52 #define DP_NAMELEN(x) strlen((x)->d_name)
53 #endif /* USG and not _POSIX_VERSION and not DIRENT */
59 extern time_t new_time;
60 extern FILE *msg_file;
64 extern PTR ck_malloc();
65 extern PTR ck_realloc();
67 extern PTR init_buffer();
68 extern char *get_buffer();
69 int is_dot_or_dotdot();
70 extern void add_buffer();
71 extern void flush_buffer();
73 int recursively_delete();
75 char *un_quote_string();
77 extern char *new_name();
79 static void add_dir_name();
89 static struct dirname *dir_list;
90 static time_t this_time;
93 add_dir(name,dev,ino,text)
101 dp=(struct dirname *)malloc(sizeof(struct dirname));
108 dp->name=malloc(strlen(name)+1);
109 strcpy(dp->name,name);
122 static char *path = 0;
125 path = ck_malloc(PATH_MAX);
127 if(gnu_dumpfile[0]!='/') {
128 #if defined(__MSDOS__) || defined(USG) || defined(_POSIX_VERSION)
129 if(!getcwd(path,PATH_MAX))
130 msg("Couldn't get current directory.");
136 msg("Couldn't get current directory: %s",path);
140 /* If this doesn't fit, we're in serious trouble */
142 strcat(path,gnu_dumpfile);
145 fp=fopen(gnu_dumpfile,"r");
146 if(fp==0 && errno!=ENOENT) {
147 msg_perror("Can't open %s",gnu_dumpfile);
152 fgets(buf,sizeof(buf),fp);
157 while(fgets(buf,sizeof(buf),fp)) {
158 strp= &buf[strlen(buf)];
163 while(isdigit(*strp))
166 while(isspace(*strp))
168 while(isdigit(*strp))
171 add_dir(un_quote_string(strp),dev,ino,(char *)0);
182 extern char *quote_copy_string();
184 fp=fopen(gnu_dumpfile,"w");
186 msg_perror("Can't write to %s",gnu_dumpfile);
189 fprintf(fp,"%lu\n",this_time);
190 for(dp=dir_list;dp;dp=dp->next) {
193 str=quote_copy_string(dp->name);
195 fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str);
198 fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name);
209 for(dp=dir_list;dp;dp=dp->next) {
210 if(!strcmp(dp->name,name))
217 /* Collect all the names from argv[] (or whatever), then expand them into
218 a directory tree, and put all the directories at the beginning. */
220 collect_and_sort_names()
222 struct name *n,*n_next;
232 if(!namelist) addname(".");
233 for(n=namelist;n;n=n_next) {
235 if(n->found || n->dir_contents)
237 if(n->regexp) /* FIXME just skip regexps for now */
240 if(chdir(n->change_dir)<0) {
241 msg_perror("can't chdir to %s",n->change_dir);
246 if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN|STX_LINK))
248 if(lstat(n->name,&statbuf)<0)
251 msg_perror("can't stat %s",n->name);
254 if(S_ISDIR(statbuf.st_mode)) {
256 add_dir_name(n->name,statbuf.st_dev);
261 for(n=namelist;n;n=n->next)
263 namelist=(struct name *)merge_sort((PTR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp);
265 for(n=namelist;n;n=n->next) {
278 return strcmp(n1->name,n2->name);
284 return strcmp(n1->name,n2->name);
294 frst= (*(char **)p1)+1;
295 scnd= (*(char **)p2)+1;
297 return strcmp(frst,scnd);
301 get_dir_contents(p,device)
306 register struct direct *d;
322 bufsiz=strlen(p)+NAMSIZ;
323 namebuf=ck_malloc(bufsiz+2);
326 msg_perror("can't open directory %s",p);
328 msg("error opening directory %s",p);
335 all_children= dp ? dp->allnew : 0;
336 (void) strcpy(namebuf,p);
337 if(p[strlen(p)-1]!='/')
338 (void) strcat(namebuf,"/");
341 the_buffer=init_buffer();
342 while(d=readdir(dirp)) {
346 if(is_dot_or_dotdot(d->d_name))
348 if(DP_NAMELEN(d) + len >=bufsiz) {
350 namebuf=ck_realloc(namebuf,bufsiz+2);
352 (void) strcpy(namebuf+len,d->d_name);
354 if (0 != f_follow_links?
355 statx(namebuf, &hs, STATSIZE, STX_HIDDEN):
356 statx(namebuf, &hs, STATSIZE, STX_HIDDEN|STX_LINK))
358 if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs))
361 msg_perror("can't stat %s",namebuf);
364 if( (f_local_filesys && device!=hs.st_dev)
365 || (f_exclude && check_exclude(namebuf)))
366 add_buffer(the_buffer,"N",1);
368 else if (S_ISHIDDEN (hs.st_mode)) {
369 add_buffer (the_buffer, "D", 1);
370 strcat (d->d_name, "A");
374 else if(S_ISDIR(hs.st_mode)) {
375 if(dp=get_dir(namebuf)) {
376 if( dp->dev!=hs.st_dev
377 || dp->ino!=hs.st_ino) {
379 msg("directory %s has been renamed.",namebuf);
387 msg("Directory %s is new",namebuf);
388 add_dir(namebuf,hs.st_dev,hs.st_ino,"");
395 add_buffer(the_buffer,"D",1);
396 } else if( !all_children
398 && new_time>hs.st_mtime
400 || new_time>hs.st_ctime))
401 add_buffer(the_buffer,"N",1);
403 add_buffer(the_buffer,"Y",1);
404 add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
406 add_buffer(the_buffer,"\000\000",2);
409 /* Well, we've read in the contents of the dir, now sort them */
410 buf=get_buffer(the_buffer);
412 flush_buffer(the_buffer);
416 for(p_buf=buf;*p_buf;) {
423 vec=(char **)malloc(sizeof(char *)*(n_strs+1));
424 for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1)
427 qsort((PTR)vec,n_strs,sizeof(char *),dirent_cmp);
428 new_buf=(char *)malloc(p_buf-buf+2);
429 for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) {
432 for(p_tmp= *p_vec;*p_buf++= *p_tmp++;)
437 flush_buffer(the_buffer);
444 /* p is a directory. Add all the files in P to the namelist. If any of the
445 files is a directory, recurse on the subdirectory. . . */
447 add_dir_name(p,device)
462 /* char **vec,**p_vec;*/
463 /* int n_strs,n_size;*/
469 new_buf=get_dir_contents(p,device);
471 for(n=namelist;n;n=n->next) {
472 if(!strcmp(n->name,p)) {
473 n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
481 buflen= NAMSIZ<=len ? len + NAMSIZ : NAMSIZ;
482 namebuf= ck_malloc(buflen+1);
484 (void)strcpy(namebuf,p);
485 if(namebuf[len-1]!='/') {
489 for(p_buf=new_buf;*p_buf;p_buf+=sublen+1) {
490 sublen=strlen(p_buf);
492 if(len+sublen>=buflen) {
494 namebuf= ck_realloc(namebuf,buflen+1);
496 (void)strcpy(namebuf+len,p_buf+1);
498 add_dir_name(namebuf,device);
505 /* Returns non-zero if p is . or .. This could be a macro for speed. */
510 return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0')));
519 gnu_restore(skipcrud)
523 /* int current_dir_length; */
526 /* int archive_dir_length; */
532 extern struct stat hstat; /* Stat struct corresponding */
535 extern union record *head;
537 dirp=opendir(skipcrud+head->header.name);
540 /* The directory doesn't exist now. It'll be created.
541 In any case, we don't have to delete any files out
543 skip_file((long)hstat.st_size);
547 the_buffer=init_buffer();
548 while(d=readdir(dirp)) {
549 if(is_dot_or_dotdot(d->d_name))
552 add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
555 add_buffer(the_buffer,"",1);
557 current_dir=get_buffer(the_buffer);
558 archive_dir=(char *)malloc(hstat.st_size);
560 msg("Can't allocate %d bytes for restore",hstat.st_size);
561 skip_file((long)hstat.st_size);
565 for(size=hstat.st_size;size>0;size-=copied) {
566 from=findrec()->charptr;
568 msg("Unexpected EOF in archive\n");
571 copied=endofrecs()->charptr - from;
574 bcopy((PTR)from,(PTR)to,(int)copied);
576 userec((union record *)(from+copied-1));
579 for(cur=current_dir;*cur;cur+=strlen(cur)+1) {
580 for(arc=archive_dir;*arc;arc+=strlen(arc)+1) {
586 p=new_name(skipcrud+head->header.name,cur);
587 if(f_confirm && !confirm("delete",p)) {
592 fprintf(msg_file,"%s: deleting %s\n",tar,p);
593 if(recursively_delete(p)) {
594 msg("%s: Error while deleting %s\n",tar,p);
600 flush_buffer(the_buffer);
605 recursively_delete(path)
615 if(lstat(path,&sbuf)<0)
617 if(S_ISDIR(sbuf.st_mode)) {
619 /* path_len=strlen(path); */
623 while(dp=readdir(dirp)) {
624 if(is_dot_or_dotdot(dp->d_name))
626 path_buf=new_name(path,dp->d_name);
627 if(recursively_delete(path_buf)) {