home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 May / Chip_2000-05_cd2.bin / dosutils / gtar109 / gnu.c < prev    next >
C/C++ Source or Header  |  1991-01-14  |  11KB  |  563 lines

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <ctype.h>
  5.  
  6. #ifdef BSD42
  7. #include <sys/dir.h>
  8. #else
  9. #ifdef MSDOS
  10. #include <sys/dir.h>
  11. #else
  12. #ifdef USG
  13. #ifdef NDIR
  14. #include <ndir.h>
  15. #else
  16. #include <dirent.h>
  17. #endif
  18. #ifndef DIRECT
  19. #define direct dirent
  20. #endif
  21. #define DP_NAMELEN(x) strlen((x)->d_name)
  22. #else
  23. /*
  24.  * FIXME: On other systems there is no standard place for the header file
  25.  * for the portable directory access routines.  Change the #include line
  26.  * below to bring it in from wherever it is.
  27.  */
  28. #include "ndir.h"
  29. #endif
  30. #endif
  31. #endif
  32.  
  33. #ifndef S_IFLNK
  34. #define lstat stat
  35. #endif
  36.  
  37. #ifndef DP_NAMELEN
  38. #define DP_NAMELEN(x)    (x)->d_namlen
  39. #endif
  40.  
  41. #ifdef __STDC__
  42. #define VOIDSTAR void *
  43. #else
  44. #define VOIDSTAR char *
  45. #endif
  46.  
  47. extern VOIDSTAR malloc();
  48.  
  49. #include "tar.h"
  50.  
  51. extern time_t new_time;
  52. extern FILE *msg_file;
  53.  
  54. extern VOIDSTAR init_buffer();
  55. extern char *get_buffer();
  56. extern void add_buffer();
  57. extern void flush_buffer();
  58.  
  59. extern char *new_name();
  60.  
  61. struct stat statbuf;
  62.  
  63. struct dirname {
  64.     struct dirname *next;
  65.     char *name;
  66.     char *dir_text;
  67.     int dev;
  68.     int ino;
  69. };
  70. struct dirname *dir_list;
  71. time_t this_time;
  72.  
  73. void
  74. add_dir(name,dev,ino,text)
  75. char *name;
  76. char *text;
  77. {
  78.     struct dirname *dp;
  79.  
  80.     dp=(struct dirname *)malloc(sizeof(struct dirname));
  81.     if(!dp)
  82.         abort();
  83.     dp->next=dir_list;
  84.     dir_list=dp;
  85.     dp->dev=dev;
  86.     dp->ino=ino;
  87.     dp->name=malloc(strlen(name)+1);
  88.     strcpy(dp->name,name);
  89.     dp->dir_text=text;
  90. }
  91.  
  92. void
  93. read_dir_file(name)
  94. char *name;
  95. {
  96.     int dev;
  97.     int ino;
  98.     char *strp;
  99.     FILE *fp;
  100.     char buf[512];
  101.  
  102.     time(&this_time);
  103.     fp=fopen(name,"r");
  104.     if(fp==0) {
  105.         msg_perror("Can't open %s",name);
  106.         return;
  107.     }
  108.     fgets(buf,sizeof(buf),fp);
  109.     if(!f_new_files) {
  110.         f_new_files++;
  111.         new_time=atol(buf);
  112.     }
  113.     while(fgets(buf,sizeof(buf),fp)) {
  114.         strp= &buf[strlen(buf)];
  115.         if(strp[-1]=='\n')
  116.             strp[-1]='\0';
  117.         strp=buf;
  118.         dev=atol(strp);
  119.         while(isdigit(*strp))
  120.             strp++;
  121.         ino=atol(strp);
  122.         while(isspace(*strp))
  123.             strp++;
  124.         while(isdigit(*strp))
  125.             strp++;
  126.         strp++;
  127.         add_dir(un_quote_string(strp),dev,ino,(char *)0);
  128.     }
  129.     fclose(fp);
  130. }
  131.  
  132. void
  133. write_dir_file(name)
  134. char *name;
  135. {
  136.     FILE *fp;
  137.     struct dirname *dp;
  138.     char *str;
  139.     extern char *quote_copy_string();
  140.  
  141.     fp=fopen(name,"w");
  142.     if(fp==0) {
  143.         msg_perror("Can't write to %s",name);
  144.         return;
  145.     }
  146.     fprintf(fp,"%lu\n",this_time);
  147.     for(dp=dir_list;dp;dp=dp->next) {
  148.         if(!dp->dir_text)
  149.             continue;
  150.         str=quote_copy_string(dp->name);
  151.         if(str) {
  152.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str);
  153.             free(str);
  154.         } else
  155.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name);
  156.     }
  157.     fclose(fp);
  158. }
  159.  
  160. struct dirname *
  161. get_dir(name)
  162. char *name;
  163. {
  164.     struct dirname *dp;
  165.  
  166.     for(dp=dir_list;dp;dp=dp->next) {
  167.         if(!strcmp(dp->name,name))
  168.             return dp;
  169.     }
  170.     return 0;
  171. }
  172.  
  173.  
  174. static void add_dir_name();
  175.  
  176. /* Collect all the names from argv[] (or whatever), then expand them into
  177.    a directory tree, and put all the directories at the beginning. */
  178. collect_and_sort_names()
  179. {
  180.     struct name *n,*n_next;
  181.     int num_names;
  182.     int name_cmp();
  183.     char *merge_sort();
  184.  
  185.     name_gather();
  186.  
  187.     if(gnu_dumpfile)
  188.         read_dir_file(gnu_dumpfile);
  189.     if(!namelist) addname(".");
  190.     for(n=namelist;n;n=n_next) {
  191.         n_next=n->next;
  192.         if(n->found || n->dir_contents)
  193.             continue;
  194.         if(n->regexp)        /* FIXME just skip regexps for now */
  195.             continue;
  196.         if(n->change_dir)
  197.             if(chdir(n->change_dir)<0) {
  198.                 msg_perror("can't chdir to %s",n->change_dir);
  199.                 continue;
  200.             }
  201.  
  202.         if(lstat(n->name,&statbuf)<0) {
  203.             msg_perror("can't stat %s",n->name);
  204.             continue;
  205.         }
  206.         if((statbuf.st_mode&S_IFMT)==S_IFDIR) {
  207.             n->found++;
  208.             add_dir_name(n->name,statbuf.st_dev);
  209.         }
  210.     }
  211.  
  212.     num_names=0;
  213.     for(n=namelist;n;n=n->next)
  214.         num_names++;
  215.     namelist=(struct name *)merge_sort((VOIDSTAR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp);
  216.  
  217.     for(n=namelist;n;n=n->next) {
  218.         n->found=0;
  219.     }
  220.     if(gnu_dumpfile)
  221.         write_dir_file(gnu_dumpfile);
  222. }
  223.  
  224. int
  225. name_cmp(n1,n2)
  226. struct name *n1,*n2;
  227. {
  228.     if(n1->found) {
  229.         if(n2->found)
  230.             return strcmp(n1->name,n2->name);
  231.         else
  232.             return -1;
  233.     } else if(n2->found)
  234.         return 1;
  235.     else
  236.         return strcmp(n1->name,n2->name);
  237. }
  238.  
  239. int
  240. dirent_cmp(p1,p2)
  241. char **p1,**p2;
  242. {
  243.     char *frst,*scnd;
  244.  
  245.     frst= (*p1)+1;
  246.     scnd= (*p2)+1;
  247.  
  248.     return strcmp(frst,scnd);
  249. }
  250.  
  251. char *
  252. get_dir_contents(p,device)
  253. char *p;
  254. int device;
  255. {
  256.     DIR *dirp;
  257.     register struct direct *d;
  258.     char *new_buf;
  259.     char namebuf[NAMSIZ+2];
  260.     int len;
  261.     VOIDSTAR the_buffer;
  262.     char *buf;
  263.     int n_strs;
  264.     int n_size;
  265.     char *p_buf;
  266.     char **vec,**p_vec;
  267.     int all_children = 0;
  268.  
  269.     extern int errno;
  270.  
  271.     errno=0;
  272.     dirp=opendir(p);
  273.     if(!dirp) {
  274.         if(errno)
  275.             msg_perror("can't open directory %s",p);
  276.         else
  277.             msg("error opening directory %s",p);
  278.         new_buf="\0\0\0\0";
  279.     } else {
  280.         (void) strcpy(namebuf,p);
  281.         if(p[strlen(p)-1]!='/')
  282.             (void) strcat(namebuf,"/");
  283.         len=strlen(namebuf);
  284.  
  285.         the_buffer=init_buffer();
  286.         while(d=readdir(dirp)) {
  287.             struct stat hs;
  288.  
  289.             /* Skip . and .. */
  290.             if(is_dot_or_dotdot(d->d_name))
  291.                 continue;
  292.             if(DP_NAMELEN(d) + len >=NAMSIZ) {
  293.                 msg("%s%s name too long: skipped",namebuf,d->d_name);
  294.                 continue;
  295.             }
  296.             (void) strcpy(namebuf+len,d->d_name);
  297.             if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs)) {
  298.                 msg_perror("can't stat %s",namebuf);
  299.                 continue;
  300.             }
  301.             if(   (f_local_filesys && device!=hs.st_dev)
  302.                || (f_exclude && check_exclude(namebuf)))
  303.                 add_buffer(the_buffer,"N",1);
  304.             else if((hs.st_mode&S_IFMT)==S_IFDIR) {
  305.                 struct dirname *dp;
  306.  
  307.                 if(dp=get_dir(namebuf)) {
  308.                     if(   dp->dev!=hs.st_dev
  309.                         || dp->ino!=hs.st_ino) {
  310.                            if(f_verbose)
  311.                             msg("directory %s has been renamed.",namebuf);
  312.                         all_children++;
  313.                         dp->dev=hs.st_dev;
  314.                         dp->ino=hs.st_ino;
  315.                     }
  316.                     dp->dir_text="";
  317.                 } else {
  318.                     if(f_verbose)
  319.                         msg("Directory %s is new",namebuf);
  320.                     add_dir(namebuf,hs.st_dev,hs.st_ino,"");
  321.                     all_children++;
  322.                 }
  323.  
  324.                 add_buffer(the_buffer,"D",1);
  325.             } else if(   !all_children
  326.                    && f_new_files
  327.                  && new_time>hs.st_mtime
  328.                 && (   f_new_files>1
  329.                      || new_time>hs.st_ctime))
  330.                 add_buffer(the_buffer,"N",1);
  331.             else
  332.                 add_buffer(the_buffer,"Y",1);
  333.             add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  334.         }
  335.         add_buffer(the_buffer,"\000\000",2);
  336.         closedir(dirp);
  337.  
  338.         /* Well, we've read in the contents of the dir, now sort them */
  339.         buf=get_buffer(the_buffer);
  340.         if(buf[0]=='\0') {
  341.             flush_buffer(the_buffer);
  342.             new_buf="\0\0\0\0";
  343.         } else {
  344.             n_strs=0;
  345.             for(p_buf=buf;*p_buf;) {
  346.                 int tmp;
  347.  
  348.                 tmp=strlen(p_buf)+1;
  349.                 n_strs++;
  350.                 p_buf+=tmp;
  351.             }
  352.             vec=(char **)malloc(sizeof(char *)*(n_strs+1));
  353.             for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1)
  354.                 *p_vec++= p_buf;
  355.             *p_vec= 0;
  356.             qsort((VOIDSTAR)vec,n_strs,sizeof(char *),dirent_cmp);
  357.             new_buf=(char *)malloc(p_buf-buf+2);
  358.             for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) {
  359.                 char *p_tmp;
  360.  
  361.                 for(p_tmp= *p_vec;*p_buf++= *p_tmp++;)
  362.                     ;
  363.             }
  364.             *p_buf++='\0';
  365.             free(vec);
  366.             flush_buffer(the_buffer);
  367.         }
  368.     }
  369.     return new_buf;
  370. }
  371.  
  372. /* p is a directory.  Add all the files in P to the namelist.  If any of the
  373.    files is a directory, recurse on the subdirectory. . . */
  374. static void
  375. add_dir_name(p,device)
  376. char *p;
  377. int device;
  378. {
  379.     char *new_buf;
  380.     char *p_buf;
  381.  
  382.     char namebuf[NAMSIZ+2];
  383.     register int len;
  384.  
  385.     VOIDSTAR the_buffer;
  386.  
  387.     char *buf;
  388.     char **vec,**p_vec;
  389.     int n_strs,n_size;
  390.  
  391.     struct name *n;
  392.  
  393.     int dirent_cmp();
  394.  
  395.     new_buf=get_dir_contents(p,device);
  396.  
  397. /*    add_dir_to_name(p,new_buf);
  398. add_dir_to_name(name,dirc)
  399. char *name;
  400. char *dirc;
  401. { */
  402.  
  403.     for(n=namelist;n;n=n->next) {
  404.         if(!strcmp(n->name,p)) {
  405.             n->dir_contents = new_buf;
  406.             break;
  407.         }
  408.     }
  409. /* } */
  410.  
  411.  
  412.     (void)strcpy(namebuf,p);
  413.     len=strlen(namebuf);
  414.     if(namebuf[len-1]!='/') {
  415.         namebuf[len++]='/';
  416.         namebuf[len]='\0';
  417.     }
  418.     for(p_buf=new_buf;*p_buf;p_buf+=strlen(p_buf)+1) {
  419.         if(*p_buf=='D') {
  420.             (void)strcpy(namebuf+len,p_buf+1);
  421.             addname(namebuf);
  422.             add_dir_name(namebuf,device);
  423.         }
  424.     }
  425. }
  426.  
  427. /* Returns non-zero if p is . or ..   This could be a macro for speed. */
  428. is_dot_or_dotdot(p)
  429. char *p;
  430. {
  431.     return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0')));
  432. }
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439. gnu_restore(skipcrud)
  440. int skipcrud;
  441. {
  442.     char *current_dir;
  443. /*    int current_dir_length; */
  444.  
  445.     char *archive_dir;
  446. /*    int archive_dir_length; */
  447.     VOIDSTAR the_buffer;
  448.     char    *p;
  449.     DIR    *dirp;
  450.     struct direct *d;
  451.     char *cur,*arc;
  452.     extern struct stat hstat;        /* Stat struct corresponding */
  453.     long size,copied;
  454.     char *from,*to;
  455.     extern union record *head;
  456.  
  457.     dirp=opendir(skipcrud+head->header.name);
  458.  
  459.     if(!dirp) {
  460.             /* The directory doesn't exist now.  It'll be created.
  461.                In any case, we don't have to delete any files out
  462.                of it */
  463.         skip_file((long)hstat.st_size);
  464.         return;
  465.     }
  466.  
  467.     the_buffer=init_buffer();
  468.     while(d=readdir(dirp)) {
  469.         if(is_dot_or_dotdot(d->d_name))
  470.             continue;
  471.  
  472.         add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  473.     }
  474.     closedir(dirp);
  475.     add_buffer(the_buffer,"",1);
  476.  
  477.     current_dir=get_buffer(the_buffer);
  478.     archive_dir=(char *)malloc(hstat.st_size);
  479.     if(archive_dir==0) {
  480.         msg("Can't allocate %d bytes for restore",hstat.st_size);
  481.         skip_file((long)hstat.st_size);
  482.         return;
  483.     }
  484.     to=archive_dir;
  485.     for(size=hstat.st_size;size>0;size-=copied) {
  486.         from=findrec()->charptr;
  487.         if(!from) {
  488.             msg("Unexpected EOF in archive\n");
  489.             break;
  490.         }
  491.         copied=endofrecs()->charptr - from;
  492.         if(copied>size)
  493.             copied=size;
  494.         bcopy((VOIDSTAR)from,(VOIDSTAR)to,(int)copied);
  495.         to+=copied;
  496.         userec((union record *)(from+copied-1));
  497.     }
  498.  
  499.     for(cur=current_dir;*cur;cur+=strlen(cur)+1) {
  500.         for(arc=archive_dir;*arc;arc+=strlen(arc)+1) {
  501.             arc++;
  502.             if(!strcmp(arc,cur))
  503.                 break;
  504.         }
  505.         if(*arc=='\0') {
  506.             p=new_name(skipcrud+head->header.name,cur);
  507.             if(f_confirm && !confirm("delete",p)) {
  508.                 free(p);
  509.                 continue;
  510.             }
  511.             if(f_verbose)
  512.                 fprintf(msg_file,"%s: deleting %s\n",tar,p);
  513.             if(recursively_delete(p)) {
  514.                 msg("%s: Error while deleting %s\n",tar,p);
  515.             }
  516.             free(p);
  517.         }
  518.  
  519.     }
  520.     flush_buffer(the_buffer);
  521.     free(archive_dir);
  522. }
  523.  
  524. recursively_delete(path)
  525. char *path;
  526. {
  527.     struct stat sbuf;
  528.     DIR *dirp;
  529.     struct direct *dp;
  530.     char *path_buf;
  531.     /* int path_len; */
  532.  
  533.  
  534.     if(lstat(path,&sbuf)<0)
  535.         return 1;
  536.     if((sbuf.st_mode &S_IFMT)==S_IFDIR) {
  537.  
  538.         /* path_len=strlen(path); */
  539.         dirp=opendir(path);
  540.         if(dirp==0)
  541.             return 1;
  542.         while(dp=readdir(dirp)) {
  543.             if(is_dot_or_dotdot(dp->d_name))
  544.                 continue;
  545.             path_buf=new_name(path,dp->d_name);
  546.             if(recursively_delete(path_buf)) {
  547.                 free(path_buf);
  548.                 closedir(dirp);
  549.                 return 1;
  550.             }
  551.             free(path_buf);
  552.         }
  553.         closedir(dirp);
  554.  
  555.         if(rmdir(path)<0)
  556.             return 1;
  557.         return 0;
  558.     }
  559.     if(unlink(path)<0)
  560.         return 1;
  561.     return 0;
  562. }
  563.