]> Dogcows Code - chaz/tar/blob - src/gnu.c
*** empty log message ***
[chaz/tar] / src / gnu.c
1 /* GNU dump extensions to tar.
2 Copyright (C) 1988, 1992 Free Software Foundation
3
4 This file is part of GNU Tar.
5
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)
9 any later version.
10
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.
15
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. */
19
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #ifndef STDC_HEADERS
25 extern int errno;
26 #endif
27 #include <time.h>
28 time_t time();
29
30 #include "tar.h"
31 #include "port.h"
32
33 #if defined(_POSIX_VERSION) || defined(DIRENT)
34 #include <dirent.h>
35 #ifdef direct
36 #undef direct
37 #endif /* direct */
38 #define direct 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)
42 #include <sys/dir.h>
43 #define DP_NAMELEN(x) (x)->d_namlen
44 #endif /* not _POSIX_VERSION and BSD42 */
45 #ifdef __MSDOS__
46 #include "msd_dir.h"
47 #define DP_NAMELEN(x) (x)->d_namlen
48 #define direct dirent
49 #endif
50 #if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT)
51 #include <ndir.h>
52 #define DP_NAMELEN(x) strlen((x)->d_name)
53 #endif /* USG and not _POSIX_VERSION and not DIRENT */
54
55 #ifndef S_ISLNK
56 #define lstat stat
57 #endif
58
59 extern time_t new_time;
60 extern FILE *msg_file;
61
62 void addname();
63 int check_exclude();
64 extern PTR ck_malloc();
65 extern PTR ck_realloc();
66 int confirm();
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();
72 void name_gather();
73 int recursively_delete();
74 void skip_file();
75 char *un_quote_string();
76
77 extern char *new_name();
78
79 static void add_dir_name();
80
81 struct dirname {
82 struct dirname *next;
83 char *name;
84 char *dir_text;
85 int dev;
86 int ino;
87 int allnew;
88 };
89 static struct dirname *dir_list;
90 static time_t this_time;
91
92 void
93 add_dir(name,dev,ino,text)
94 char *name;
95 char *text;
96 dev_t dev;
97 ino_t ino;
98 {
99 struct dirname *dp;
100
101 dp=(struct dirname *)malloc(sizeof(struct dirname));
102 if(!dp)
103 abort();
104 dp->next=dir_list;
105 dir_list=dp;
106 dp->dev=dev;
107 dp->ino=ino;
108 dp->name=malloc(strlen(name)+1);
109 strcpy(dp->name,name);
110 dp->dir_text=text;
111 dp->allnew=0;
112 }
113
114 void
115 read_dir_file()
116 {
117 int dev;
118 int ino;
119 char *strp;
120 FILE *fp;
121 char buf[512];
122 static char *path = 0;
123
124 if (path == 0)
125 path = ck_malloc(PATH_MAX);
126 time(&this_time);
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.");
131 exit(EX_SYSTEM);
132 #else
133 char *getwd();
134
135 if(!getwd(path)) {
136 msg("Couldn't get current directory: %s",path);
137 exit(EX_SYSTEM);
138 }
139 #endif
140 /* If this doesn't fit, we're in serious trouble */
141 strcat(path,"/");
142 strcat(path,gnu_dumpfile);
143 gnu_dumpfile=path;
144 }
145 fp=fopen(gnu_dumpfile,"r");
146 if(fp==0 && errno!=ENOENT) {
147 msg_perror("Can't open %s",gnu_dumpfile);
148 return;
149 }
150 if(!fp)
151 return;
152 fgets(buf,sizeof(buf),fp);
153 if(!f_new_files) {
154 f_new_files++;
155 new_time=atol(buf);
156 }
157 while(fgets(buf,sizeof(buf),fp)) {
158 strp= &buf[strlen(buf)];
159 if(strp[-1]=='\n')
160 strp[-1]='\0';
161 strp=buf;
162 dev=atol(strp);
163 while(isdigit(*strp))
164 strp++;
165 ino=atol(strp);
166 while(isspace(*strp))
167 strp++;
168 while(isdigit(*strp))
169 strp++;
170 strp++;
171 add_dir(un_quote_string(strp),dev,ino,(char *)0);
172 }
173 fclose(fp);
174 }
175
176 void
177 write_dir_file()
178 {
179 FILE *fp;
180 struct dirname *dp;
181 char *str;
182 extern char *quote_copy_string();
183
184 fp=fopen(gnu_dumpfile,"w");
185 if(fp==0) {
186 msg_perror("Can't write to %s",gnu_dumpfile);
187 return;
188 }
189 fprintf(fp,"%lu\n",this_time);
190 for(dp=dir_list;dp;dp=dp->next) {
191 if(!dp->dir_text)
192 continue;
193 str=quote_copy_string(dp->name);
194 if(str) {
195 fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str);
196 free(str);
197 } else
198 fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name);
199 }
200 fclose(fp);
201 }
202
203 struct dirname *
204 get_dir(name)
205 char *name;
206 {
207 struct dirname *dp;
208
209 for(dp=dir_list;dp;dp=dp->next) {
210 if(!strcmp(dp->name,name))
211 return dp;
212 }
213 return 0;
214 }
215
216
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. */
219 void
220 collect_and_sort_names()
221 {
222 struct name *n,*n_next;
223 int num_names;
224 struct stat statbuf;
225 int name_cmp();
226 char *merge_sort();
227
228 name_gather();
229
230 if(gnu_dumpfile)
231 read_dir_file();
232 if(!namelist) addname(".");
233 for(n=namelist;n;n=n_next) {
234 n_next=n->next;
235 if(n->found || n->dir_contents)
236 continue;
237 if(n->regexp) /* FIXME just skip regexps for now */
238 continue;
239 if(n->change_dir)
240 if(chdir(n->change_dir)<0) {
241 msg_perror("can't chdir to %s",n->change_dir);
242 continue;
243 }
244
245 #ifdef AIX
246 if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN|STX_LINK))
247 #else
248 if(lstat(n->name,&statbuf)<0)
249 #endif /* AIX */
250 {
251 msg_perror("can't stat %s",n->name);
252 continue;
253 }
254 if(S_ISDIR(statbuf.st_mode)) {
255 n->found++;
256 add_dir_name(n->name,statbuf.st_dev);
257 }
258 }
259
260 num_names=0;
261 for(n=namelist;n;n=n->next)
262 num_names++;
263 namelist=(struct name *)merge_sort((PTR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp);
264
265 for(n=namelist;n;n=n->next) {
266 n->found=0;
267 }
268 if(gnu_dumpfile)
269 write_dir_file(gnu_dumpfile);
270 }
271
272 int
273 name_cmp(n1,n2)
274 struct name *n1,*n2;
275 {
276 if(n1->found) {
277 if(n2->found)
278 return strcmp(n1->name,n2->name);
279 else
280 return -1;
281 } else if(n2->found)
282 return 1;
283 else
284 return strcmp(n1->name,n2->name);
285 }
286
287 int
288 dirent_cmp(p1,p2)
289 const PTR p1;
290 const PTR p2;
291 {
292 char *frst,*scnd;
293
294 frst= (*(char **)p1)+1;
295 scnd= (*(char **)p2)+1;
296
297 return strcmp(frst,scnd);
298 }
299
300 char *
301 get_dir_contents(p,device)
302 char *p;
303 int device;
304 {
305 DIR *dirp;
306 register struct direct *d;
307 char *new_buf;
308 char *namebuf;
309 int bufsiz;
310 int len;
311 PTR the_buffer;
312 char *buf;
313 size_t n_strs;
314 /* int n_size;*/
315 char *p_buf;
316 char **vec,**p_vec;
317
318 extern int errno;
319
320 errno=0;
321 dirp=opendir(p);
322 bufsiz=strlen(p)+NAMSIZ;
323 namebuf=ck_malloc(bufsiz+2);
324 if(!dirp) {
325 if(errno)
326 msg_perror("can't open directory %s",p);
327 else
328 msg("error opening directory %s",p);
329 new_buf=NULL;
330 } else {
331 struct dirname *dp;
332 int all_children;
333
334 dp=get_dir(p);
335 all_children= dp ? dp->allnew : 0;
336 (void) strcpy(namebuf,p);
337 if(p[strlen(p)-1]!='/')
338 (void) strcat(namebuf,"/");
339 len=strlen(namebuf);
340
341 the_buffer=init_buffer();
342 while(d=readdir(dirp)) {
343 struct stat hs;
344
345 /* Skip . and .. */
346 if(is_dot_or_dotdot(d->d_name))
347 continue;
348 if(DP_NAMELEN(d) + len >=bufsiz) {
349 bufsiz+=NAMSIZ;
350 namebuf=ck_realloc(namebuf,bufsiz+2);
351 }
352 (void) strcpy(namebuf+len,d->d_name);
353 #ifdef AIX
354 if (0 != f_follow_links?
355 statx(namebuf, &hs, STATSIZE, STX_HIDDEN):
356 statx(namebuf, &hs, STATSIZE, STX_HIDDEN|STX_LINK))
357 #else
358 if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs))
359 #endif
360 {
361 msg_perror("can't stat %s",namebuf);
362 continue;
363 }
364 if( (f_local_filesys && device!=hs.st_dev)
365 || (f_exclude && check_exclude(namebuf)))
366 add_buffer(the_buffer,"N",1);
367 #ifdef AIX
368 else if (S_ISHIDDEN (hs.st_mode)) {
369 add_buffer (the_buffer, "D", 1);
370 strcat (d->d_name, "A");
371 d->d_namlen++;
372 }
373 #endif /* AIX */
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) {
378 if(f_verbose)
379 msg("directory %s has been renamed.",namebuf);
380 dp->allnew=1;
381 dp->dev=hs.st_dev;
382 dp->ino=hs.st_ino;
383 }
384 dp->dir_text="";
385 } else {
386 if(f_verbose)
387 msg("Directory %s is new",namebuf);
388 add_dir(namebuf,hs.st_dev,hs.st_ino,"");
389 dp=get_dir(namebuf);
390 dp->allnew=1;
391 }
392 if(all_children)
393 dp->allnew=1;
394
395 add_buffer(the_buffer,"D",1);
396 } else if( !all_children
397 && f_new_files
398 && new_time>hs.st_mtime
399 && ( f_new_files>1
400 || new_time>hs.st_ctime))
401 add_buffer(the_buffer,"N",1);
402 else
403 add_buffer(the_buffer,"Y",1);
404 add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
405 }
406 add_buffer(the_buffer,"\000\000",2);
407 closedir(dirp);
408
409 /* Well, we've read in the contents of the dir, now sort them */
410 buf=get_buffer(the_buffer);
411 if(buf[0]=='\0') {
412 flush_buffer(the_buffer);
413 new_buf=NULL;
414 } else {
415 n_strs=0;
416 for(p_buf=buf;*p_buf;) {
417 int tmp;
418
419 tmp=strlen(p_buf)+1;
420 n_strs++;
421 p_buf+=tmp;
422 }
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)
425 *p_vec++= p_buf;
426 *p_vec= 0;
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++) {
430 char *p_tmp;
431
432 for(p_tmp= *p_vec;*p_buf++= *p_tmp++;)
433 ;
434 }
435 *p_buf++='\0';
436 free(vec);
437 flush_buffer(the_buffer);
438 }
439 }
440 free(namebuf);
441 return new_buf;
442 }
443
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. . . */
446 static void
447 add_dir_name(p,device)
448 char *p;
449 int device;
450 {
451 char *new_buf;
452 char *p_buf;
453
454 char *namebuf;
455 int buflen;
456 register int len;
457 int sublen;
458
459 /* PTR the_buffer;*/
460
461 /* char *buf;*/
462 /* char **vec,**p_vec;*/
463 /* int n_strs,n_size;*/
464
465 struct name *n;
466
467 int dirent_cmp();
468
469 new_buf=get_dir_contents(p,device);
470
471 for(n=namelist;n;n=n->next) {
472 if(!strcmp(n->name,p)) {
473 n->dir_contents = new_buf;
474 break;
475 }
476 }
477
478 if (new_buf)
479 {
480 len=strlen(p);
481 buflen= NAMSIZ<=len ? len + NAMSIZ : NAMSIZ;
482 namebuf= ck_malloc(buflen+1);
483
484 (void)strcpy(namebuf,p);
485 if(namebuf[len-1]!='/') {
486 namebuf[len++]='/';
487 namebuf[len]='\0';
488 }
489 for(p_buf=new_buf;*p_buf;p_buf+=sublen+1) {
490 sublen=strlen(p_buf);
491 if(*p_buf=='D') {
492 if(len+sublen>=buflen) {
493 buflen+=NAMSIZ;
494 namebuf= ck_realloc(namebuf,buflen+1);
495 }
496 (void)strcpy(namebuf+len,p_buf+1);
497 addname(namebuf);
498 add_dir_name(namebuf,device);
499 }
500 }
501 free(namebuf);
502 }
503 }
504
505 /* Returns non-zero if p is . or .. This could be a macro for speed. */
506 int
507 is_dot_or_dotdot(p)
508 char *p;
509 {
510 return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0')));
511 }
512
513
514
515
516
517
518 void
519 gnu_restore(skipcrud)
520 int skipcrud;
521 {
522 char *current_dir;
523 /* int current_dir_length; */
524
525 char *archive_dir;
526 /* int archive_dir_length; */
527 PTR the_buffer;
528 char *p;
529 DIR *dirp;
530 struct direct *d;
531 char *cur,*arc;
532 extern struct stat hstat; /* Stat struct corresponding */
533 long size,copied;
534 char *from,*to;
535 extern union record *head;
536
537 dirp=opendir(skipcrud+head->header.name);
538
539 if(!dirp) {
540 /* The directory doesn't exist now. It'll be created.
541 In any case, we don't have to delete any files out
542 of it */
543 skip_file((long)hstat.st_size);
544 return;
545 }
546
547 the_buffer=init_buffer();
548 while(d=readdir(dirp)) {
549 if(is_dot_or_dotdot(d->d_name))
550 continue;
551
552 add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
553 }
554 closedir(dirp);
555 add_buffer(the_buffer,"",1);
556
557 current_dir=get_buffer(the_buffer);
558 archive_dir=(char *)malloc(hstat.st_size);
559 if(archive_dir==0) {
560 msg("Can't allocate %d bytes for restore",hstat.st_size);
561 skip_file((long)hstat.st_size);
562 return;
563 }
564 to=archive_dir;
565 for(size=hstat.st_size;size>0;size-=copied) {
566 from=findrec()->charptr;
567 if(!from) {
568 msg("Unexpected EOF in archive\n");
569 break;
570 }
571 copied=endofrecs()->charptr - from;
572 if(copied>size)
573 copied=size;
574 bcopy((PTR)from,(PTR)to,(int)copied);
575 to+=copied;
576 userec((union record *)(from+copied-1));
577 }
578
579 for(cur=current_dir;*cur;cur+=strlen(cur)+1) {
580 for(arc=archive_dir;*arc;arc+=strlen(arc)+1) {
581 arc++;
582 if(!strcmp(arc,cur))
583 break;
584 }
585 if(*arc=='\0') {
586 p=new_name(skipcrud+head->header.name,cur);
587 if(f_confirm && !confirm("delete",p)) {
588 free(p);
589 continue;
590 }
591 if(f_verbose)
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);
595 }
596 free(p);
597 }
598
599 }
600 flush_buffer(the_buffer);
601 free(archive_dir);
602 }
603
604 int
605 recursively_delete(path)
606 char *path;
607 {
608 struct stat sbuf;
609 DIR *dirp;
610 struct direct *dp;
611 char *path_buf;
612 /* int path_len; */
613
614
615 if(lstat(path,&sbuf)<0)
616 return 1;
617 if(S_ISDIR(sbuf.st_mode)) {
618
619 /* path_len=strlen(path); */
620 dirp=opendir(path);
621 if(dirp==0)
622 return 1;
623 while(dp=readdir(dirp)) {
624 if(is_dot_or_dotdot(dp->d_name))
625 continue;
626 path_buf=new_name(path,dp->d_name);
627 if(recursively_delete(path_buf)) {
628 free(path_buf);
629 closedir(dirp);
630 return 1;
631 }
632 free(path_buf);
633 }
634 closedir(dirp);
635
636 if(rmdir(path)<0)
637 return 1;
638 return 0;
639 }
640 if(unlink(path)<0)
641 return 1;
642 return 0;
643 }
644
This page took 0.064115 seconds and 4 git commands to generate.