home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gtak212.zip / 1.10 / gnu.c < prev    next >
C/C++ Source or Header  |  1993-01-10  |  16KB  |  725 lines

  1. /*****************************************************************************
  2.  * $Id: gnu.c,v 1.11 1993/01/10 11:19:45 ak Exp $
  3.  *****************************************************************************
  4.  * $Log: gnu.c,v $
  5.  * Revision 1.11  1993/01/10  11:19:45  ak
  6.  * J.R.: Bugfix: f_gnudump='f' sicherte doppelt.
  7.  *
  8.  * Revision 1.10  1992/12/13  09:39:40  ak
  9.  * K.U.R: f_archive/f_reset_archive added to support the "archived" bit.
  10.  *
  11.  * Revision 1.9  1992/10/31  06:55:09  ak
  12.  * Modified -G (again) to specify the generation of increment.
  13.  *
  14.  * Revision 1.8  1992/10/29  10:00:03  ak
  15.  * -G for incremental backups like -g, but w/o writing the dumpfile.
  16.  *
  17.  * Revision 1.7  1992/09/29  09:55:42  ak
  18.  * K.U.R., once again :-)
  19.  * - removed a dup() in buffer.c
  20.  * - EMX opendir with hidden/system test in gnu.c (...dotdot)
  21.  *
  22.  * Revision 1.6  1992/09/26  08:31:50  ak
  23.  * *** empty log message ***
  24.  *
  25.  * Revision 1.5  1992/09/20  17:50:30  ak
  26.  * EMX 0.8 stat() returns random inode numbers. As a result, TAR -g
  27.  * archived every single directory. ifdef'ed out this code.
  28.  *
  29.  * Revision 1.4  1992/09/20  07:47:06  ak
  30.  * Fixes from Kai Uwe Rommel
  31.  *   --checkpoints instead of --semi-verbose (1.11)
  32.  *   -g filenames
  33.  *
  34.  * Revision 1.3  1992/09/12  15:57:30  ak
  35.  * - Usenet patches for GNU TAR 1.10
  36.  * - Bugfixes and patches of Kai Uwe Rommel:
  37.  *         filename conversion for FAT
  38.  *         EMX 0.8e
  39.  *         -0..1 alias for a: b:
  40.  *         -2..7 alias for +++TAPE$x
  41.  *
  42.  * Revision 1.2  1992/09/02  20:08:10  ak
  43.  * Version AK200
  44.  * - Tape access
  45.  * - Quick file access
  46.  * - OS/2 extended attributes
  47.  * - Some OS/2 fixes
  48.  * - Some fixes of Kai Uwe Rommel
  49.  *
  50.  * Revision 1.1.1.1  1992/09/02  19:21:41  ak
  51.  * Original GNU Tar 1.10 with some filenames changed for FAT compatibility.
  52.  *
  53.  * Revision 1.1  1992/09/02  19:21:40  ak
  54.  * Initial revision
  55.  *
  56.  *****************************************************************************/
  57.  
  58. static char *rcsid = "$Id: gnu.c,v 1.11 1993/01/10 11:19:45 ak Exp $";
  59.  
  60. /*
  61.  * Modified by Andreas Kaiser July 92.
  62.  * See CHANGES.AK for info.
  63.  */
  64.  
  65. #include <stdio.h>
  66. #include <sys/types.h>
  67. #include <sys/stat.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70.  
  71. #ifdef BSD42
  72.  #include <sys/dir.h>
  73. #else
  74.  #ifdef __MSDOS__
  75.   #include "msd_dir.h"
  76.  #else
  77.   #ifdef USG
  78.    #ifdef NDIR
  79.     #include <ndir.h>
  80.    #else
  81.     #include <dirent.h>
  82.    #endif
  83.    #ifndef DIRECT
  84.     #define direct dirent
  85.    #endif
  86.    #define DP_NAMELEN(x) strlen((x)->d_name)
  87.   #else
  88.    /*
  89.     * FIXME: On other systems there is no standard place for the header file
  90.     * for the portable directory access routines.  Change the #include line
  91.     * below to bring it in from wherever it is.
  92.     */
  93.    #ifdef OS2
  94.     #include "dirent.h"
  95.     #define direct dirent
  96.     #define DP_NAMELEN(x) strlen((x)->d_name)
  97.    #else
  98.     #include "ndir.h"
  99.    #endif
  100.   #endif
  101.  #endif
  102. #endif
  103.  
  104. #ifndef DP_NAMELEN
  105. #define DP_NAMELEN(x)    (x)->d_namlen
  106. #endif
  107.  
  108. #ifndef MAXPATHLEN
  109. #define MAXPATHLEN 1024
  110. #endif
  111.  
  112. /*
  113.  * If there are no symbolic links, there is no lstat().  Use stat().
  114.  */
  115. #ifndef S_IFLNK
  116. #define lstat stat
  117. #endif
  118.  
  119. #ifdef __STDC__
  120. #define VOIDSTAR void *
  121. #else
  122. #define VOIDSTAR char *
  123. #endif
  124. extern VOIDSTAR ck_malloc();
  125. extern VOIDSTAR ck_realloc();
  126.  
  127. #ifndef S_IFLNK
  128. #define lstat stat
  129. #endif
  130.  
  131. extern VOIDSTAR malloc();
  132.  
  133. #include "tar.h"
  134. #include "port.h"
  135.  
  136. extern time_t new_time;
  137. extern FILE *msg_file;
  138.  
  139. extern VOIDSTAR init_buffer();
  140. extern char *get_buffer();
  141. extern void add_buffer();
  142. extern void flush_buffer();
  143.  
  144. extern char *new_name();
  145.  
  146. static void add_dir_name();
  147.  
  148. struct dirname {
  149.     struct dirname *next;
  150.     char *name;
  151.     char *dir_text;
  152.     int dev;
  153.     int ino;
  154.     int allnew;
  155. };
  156. static struct dirname *dir_list;
  157. static time_t this_time;
  158.  
  159. void
  160. add_dir(name,dev,ino,text)
  161. char *name;
  162. char *text;
  163. {
  164.     struct dirname *dp;
  165.  
  166.     dp=(struct dirname *)malloc(sizeof(struct dirname));
  167.     if(!dp)
  168.         abort();
  169.     dp->next=dir_list;
  170.     dir_list=dp;
  171.     dp->dev=dev;
  172.     dp->ino=ino;
  173.     dp->name=malloc(strlen(name)+1);
  174.     strcpy(dp->name,name);
  175.     dp->dir_text=text;
  176.     dp->allnew=0;
  177. }
  178.  
  179. void
  180. read_dir_file()
  181. {
  182.     int dev;
  183.     int ino;
  184.     char *strp;
  185.     FILE *fp;
  186.     char buf[512];
  187.     extern int errno;
  188.     static char path[MAXPATHLEN];
  189.  
  190.     if (!gnu_dumpfile)
  191.         return;
  192.     time(&this_time);
  193. #ifdef MSDOS
  194.     if(gnu_dumpfile[0]!='/' && (!isalpha(gnu_dumpfile[0]) || 
  195.                     gnu_dumpfile[1]!=':' || 
  196.                     gnu_dumpfile[2]!='/')) {
  197.         _fullpath(path,gnu_dumpfile,MAXPATHLEN);
  198.         gnu_dumpfile=path;
  199.     }
  200. #else
  201.     if(gnu_dumpfile[0]!='/') {
  202. #ifdef USG
  203.             int getcwd();
  204.             if(!getcwd(path,MAXPATHLEN)) {
  205.                 msg("Couldn't get current directory.");
  206.                 exit(EX_SYSTEM);
  207.             }
  208. #else
  209.             char *getwd();
  210.  
  211.             if(!getwd(path)) {
  212.                 msg("Couldn't get current directory: %s",path);
  213.                 exit(EX_SYSTEM);
  214.             }
  215. #endif
  216.         /* If this doesn't fit, we're in serious trouble */
  217.         strcat(path,"/");
  218.         strcat(path,gnu_dumpfile);
  219.         gnu_dumpfile=path;
  220.     }
  221. #endif
  222.  
  223.     if (f_gnudump == 'f')
  224.         return;
  225.  
  226.     fp=fopen(gnu_dumpfile,"r");
  227.     if(fp==0 && errno!=ENOENT) {
  228.         msg_perror("Can't open %s",gnu_dumpfile);
  229.         return;
  230.     }
  231.     if(!fp)
  232.         return;
  233.     fgets(buf,sizeof(buf),fp);
  234.     if(!f_new_files) {
  235.         f_new_files++;
  236.         new_time=atol(buf);
  237.     }
  238.     while(fgets(buf,sizeof(buf),fp)) {
  239.         strp= &buf[strlen(buf)];
  240.         if(strp[-1]=='\n')
  241.             strp[-1]='\0';
  242.         strp=buf;
  243.         dev=atol(strp);
  244.         while(isdigit(*strp))
  245.             strp++;
  246.         ino=atol(strp);
  247.         while(isspace(*strp))
  248.             strp++;
  249.         while(isdigit(*strp))
  250.             strp++;
  251.         strp++;
  252.         add_dir(un_quote_string(strp),dev,ino,(char *)0);
  253.     }
  254.     fclose(fp);
  255. }
  256.  
  257. void
  258. write_dir_file()
  259. {
  260.     FILE *fp;
  261.     struct dirname *dp;
  262.     char *str;
  263.     extern char *quote_copy_string();
  264.  
  265.     if (!gnu_dumpfile || f_gnudump == 's')
  266.         return;
  267.     fp=fopen(gnu_dumpfile,"w");
  268.     if(fp==0) {
  269.         msg_perror("Can't write to %s",gnu_dumpfile);
  270.         return;
  271.     }
  272.     fprintf(fp,"%lu\n",this_time);
  273.     for(dp=dir_list;dp;dp=dp->next) {
  274.         if(!dp->dir_text)
  275.             continue;
  276.         str=quote_copy_string(dp->name);
  277.         if(str) {
  278.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str);
  279.             free(str);
  280.         } else
  281.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name);
  282.     }
  283.     fclose(fp);
  284. }
  285.  
  286. struct dirname *
  287. get_dir(name)
  288. char *name;
  289. {
  290.     struct dirname *dp;
  291.  
  292.     for(dp=dir_list;dp;dp=dp->next) {
  293.         if(!strcmp(dp->name,name))
  294.             return dp;
  295.     }
  296.     return 0;
  297. }
  298.  
  299.  
  300. /* Collect all the names from argv[] (or whatever), then expand them into
  301.    a directory tree, and put all the directories at the beginning. */
  302. collect_and_sort_names()
  303. {
  304.     struct name *n,*n_next;
  305.     int num_names;
  306.     struct stat statbuf;
  307.     int name_cmp();
  308.     char *merge_sort();
  309.  
  310.     name_gather();
  311.  
  312.     read_dir_file();
  313.     if(!namelist) addname(".");
  314.     for(n=namelist;n;n=n_next) {
  315.         n_next=n->next;
  316.         if(n->found || n->dir_contents)
  317.             continue;
  318.         if(n->regexp)        /* FIXME just skip regexps for now */
  319.             continue;
  320.         if(n->change_dir)
  321.             if(chdir(n->change_dir)<0) {
  322.                 msg_perror("can't chdir to %s",n->change_dir);
  323.                 continue;
  324.             }
  325.  
  326. #ifdef AIX
  327.         if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN|STX_LINK))
  328. #else
  329.         if(lstat(n->name,&statbuf)<0) {
  330. #endif /* AIX */
  331.             msg_perror("can't stat %s",n->name);
  332.             continue;
  333.         }
  334.         if((statbuf.st_mode&S_IFMT)==S_IFDIR) {
  335.             n->found++;
  336.             add_dir_name(n->name,statbuf.st_dev);
  337.         }
  338.     }
  339.  
  340.     num_names=0;
  341.     for(n=namelist;n;n=n->next)
  342.         num_names++;
  343.     namelist=(struct name *)merge_sort((VOIDSTAR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp);
  344.  
  345.     for(n=namelist;n;n=n->next) {
  346.         n->found=0;
  347.     }
  348. }
  349.  
  350. int
  351. name_cmp(n1,n2)
  352. struct name *n1,*n2;
  353. {
  354.     if(n1->found) {
  355.         if(n2->found)
  356.             return strcmp(n1->name,n2->name);
  357.         else
  358.             return -1;
  359.     } else if(n2->found)
  360.         return 1;
  361.     else
  362.         return strcmp(n1->name,n2->name);
  363. }
  364.  
  365. int
  366. dirent_cmp(p1,p2)
  367. char **p1,**p2;
  368. {
  369.     char *frst,*scnd;
  370.  
  371.     frst= (*p1)+1;
  372.     scnd= (*p2)+1;
  373.  
  374.     return strcmp(frst,scnd);
  375. }
  376.  
  377. char *
  378. get_dir_contents(p,device)
  379. char *p;
  380. int device;
  381. {
  382.     DIR *dirp;
  383.     register struct direct *d;
  384.     char *new_buf;
  385.     char *namebuf;
  386.     int bufsiz;
  387.     int len;
  388.     VOIDSTAR the_buffer;
  389.     char *buf;
  390.     int n_strs;
  391.     int n_size;
  392.     char *p_buf;
  393.     char **vec,**p_vec;
  394.  
  395.     extern int errno;
  396.  
  397.     errno=0;
  398.     dirp=opendir(p);
  399.     bufsiz=strlen(p)+NAMSIZ;
  400.     namebuf=ck_malloc(bufsiz+2);
  401.     if(!dirp) {
  402.         if(errno)
  403.             msg_perror("can't open directory %s",p);
  404.         else
  405.             msg("error opening directory %s",p);
  406.         new_buf=NULL;
  407.     } else {
  408.         struct dirname *dp;
  409.         int all_children;
  410.  
  411.         dp=get_dir(p);
  412.         all_children= dp ? dp->allnew : 0;
  413.         (void) strcpy(namebuf,p);
  414.         if(p[strlen(p)-1]!='/')
  415.             (void) strcat(namebuf,"/");
  416.         len=strlen(namebuf);
  417.  
  418.         the_buffer=init_buffer();
  419.         while(d=readdir(dirp)) {
  420.             struct stat hs;
  421.  
  422.             /* Skip . and .. */
  423.             if(is_dot_or_dotdot(d))
  424.                 continue;
  425.             if(DP_NAMELEN(d) + len >=bufsiz) {
  426.                 bufsiz+=NAMSIZ;
  427.                 namebuf=ck_realloc(namebuf,bufsiz+2);
  428.             }
  429.             (void) strcpy(namebuf+len,d->d_name);
  430. #ifdef AIX
  431.             if (0 != f_follow_links?
  432.                 statx(namebuf, &hs, STATSIZE, STX_HIDDEN):
  433.                 statx(namebuf, &hs, STATSIZE, STX_HIDDEN|STX_LINK))
  434. #else
  435.             if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs))
  436. #endif
  437.             {
  438.                 msg_perror("can't stat %s",namebuf);
  439.                 continue;
  440.             }
  441.             if(   (f_local_filesys && device!=hs.st_dev)
  442.                || (f_exclude && check_exclude(namebuf)))
  443.                 add_buffer(the_buffer,"N",1);
  444. #ifdef AIX
  445.             else if (S_ISHIDDEN (hs.st_mode)) {
  446.                 add_buffer (the_buffer, "D", 1);
  447.                 strcat (d->d_name, "A");
  448.                 d->d_namlen++;
  449.             }    
  450. #endif /* AIX */
  451.             else if((hs.st_mode&S_IFMT)==S_IFDIR) {
  452.                 if(dp=get_dir(namebuf)) {
  453. #ifndef OS2
  454.                     if(   dp->dev!=hs.st_dev
  455.                         || dp->ino!=hs.st_ino) {
  456.                            if(f_verbose)
  457.                             msg("directory %s has been renamed.",namebuf);
  458.                         dp->allnew=1;
  459.                         dp->dev=hs.st_dev;
  460.                         dp->ino=hs.st_ino;
  461.                     }
  462. #endif
  463.                     dp->dir_text="";
  464.                 } else {
  465.                     if(f_verbose)
  466.                         msg("Directory %s is new",namebuf);
  467.                     add_dir(namebuf,hs.st_dev,hs.st_ino,"");
  468.                     dp=get_dir(namebuf);
  469.                     dp->allnew=1;
  470.                 }
  471.                 if(all_children)
  472.                     dp->allnew=1;
  473.  
  474.                 add_buffer(the_buffer,"D",1);
  475.             } else if(   !all_children
  476.                    && f_new_files
  477.                  && new_time>hs.st_mtime
  478.                 && (   f_new_files>1
  479.                      || new_time>hs.st_ctime))
  480.                 add_buffer(the_buffer,"N",1);
  481.             else
  482.                 add_buffer(the_buffer,"Y",1);
  483.             add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  484.         }
  485.         add_buffer(the_buffer,"\000\000",2);
  486.         closedir(dirp);
  487.  
  488.         /* Well, we've read in the contents of the dir, now sort them */
  489.         buf=get_buffer(the_buffer);
  490.         if(buf[0]=='\0') {
  491.             flush_buffer(the_buffer);
  492.             new_buf=NULL;
  493.         } else {
  494.             n_strs=0;
  495.             for(p_buf=buf;*p_buf;) {
  496.                 int tmp;
  497.  
  498.                 tmp=strlen(p_buf)+1;
  499.                 n_strs++;
  500.                 p_buf+=tmp;
  501.             }
  502.             vec=(char **)malloc(sizeof(char *)*(n_strs+1));
  503.             for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1)
  504.                 *p_vec++= p_buf;
  505.             *p_vec= 0;
  506.             qsort((VOIDSTAR)vec,n_strs,sizeof(char *),dirent_cmp);
  507.             new_buf=(char *)malloc(p_buf-buf+2);
  508.             for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) {
  509.                 char *p_tmp;
  510.  
  511.                 for(p_tmp= *p_vec;*p_buf++= *p_tmp++;)
  512.                     ;
  513.             }
  514.             *p_buf++='\0';
  515.             free(vec);
  516.             flush_buffer(the_buffer);
  517.         }
  518.     }
  519.     free(namebuf);
  520.     return new_buf;
  521. }
  522.  
  523. /* p is a directory.  Add all the files in P to the namelist.  If any of the
  524.    files is a directory, recurse on the subdirectory. . . */
  525. static void
  526. add_dir_name(p,device)
  527. char *p;
  528. int device;
  529. {
  530.     char *new_buf;
  531.     char *p_buf;
  532.  
  533.     char *namebuf;
  534.     int buflen;
  535.     register int len;
  536.     int sublen;
  537.  
  538.     VOIDSTAR the_buffer;
  539.  
  540.     char *buf;
  541.     char **vec,**p_vec;
  542.     int n_strs,n_size;
  543.  
  544.     struct name *n;
  545.  
  546.     int dirent_cmp();
  547.  
  548.     new_buf=get_dir_contents(p,device);
  549.  
  550.     for(n=namelist;n;n=n->next) {
  551.         if(!strcmp(n->name,p)) {
  552.             n->dir_contents = new_buf;
  553.             break;
  554.         }
  555.     }
  556.  
  557.     len=strlen(p);
  558.     buflen= NAMSIZ<=len ? len + NAMSIZ : NAMSIZ;
  559.     namebuf= ck_malloc(buflen+1);
  560.  
  561.     (void)strcpy(namebuf,p);
  562.     if(namebuf[len-1]!='/') {
  563.         namebuf[len++]='/';
  564.         namebuf[len]='\0';
  565.     }
  566.     for(p_buf=new_buf;p_buf && *p_buf;p_buf+=sublen+1) {
  567.         sublen=strlen(p_buf);
  568.         if(*p_buf=='D') {
  569.             if(len+sublen>=buflen) {
  570.                 buflen+=NAMSIZ;
  571.                 namebuf= ck_realloc(namebuf,buflen+1);
  572.             }
  573.             (void)strcpy(namebuf+len,p_buf+1);
  574.             addname(namebuf);
  575.             add_dir_name(namebuf,device);
  576.         }
  577.     }
  578.     free(namebuf);
  579. }
  580.  
  581. /* Returns non-zero if p is . or ..   This could be a macro for speed. */
  582. is_dot_or_dotdot(d)
  583. struct dirent *d;
  584. {
  585.       char *p = d->d_name;
  586. #ifdef MSDOS
  587.         if(!f_use_protection && (d->d_mode & (A_HIDDEN|A_SYSTEM)) != 0)
  588.           return 1;
  589.         if(f_archive && (d->d_mode & (A_ARCHIVE|A_DIR)) == 0)
  590.           return 1;
  591. #endif
  592.     return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0')));
  593. }
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600. gnu_restore(skipcrud)
  601. int skipcrud;
  602. {
  603.     char *current_dir;
  604. /*    int current_dir_length; */
  605.  
  606.     char *archive_dir;
  607. /*    int archive_dir_length; */
  608.     VOIDSTAR the_buffer;
  609.     char    *p;
  610.     DIR    *dirp;
  611.     struct direct *d;
  612.     char *cur,*arc;
  613.     extern struct stat hstat;        /* Stat struct corresponding */
  614.     long size,copied;
  615.     char *from,*to;
  616.     extern union record *head;
  617.  
  618.     dirp=opendir(skipcrud+head->header.name);
  619.  
  620.     if(!dirp) {
  621.             /* The directory doesn't exist now.  It'll be created.
  622.                In any case, we don't have to delete any files out
  623.                of it */
  624.         skip_file((long)hstat.st_size);
  625.         return;
  626.     }
  627.  
  628.     the_buffer=init_buffer();
  629.     while(d=readdir(dirp)) {
  630.         if(is_dot_or_dotdot(d))
  631.             continue;
  632.  
  633.         add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  634.     }
  635.     closedir(dirp);
  636.     add_buffer(the_buffer,"",1);
  637.  
  638.     current_dir=get_buffer(the_buffer);
  639.     archive_dir=(char *)malloc(hstat.st_size);
  640.     if(archive_dir==0) {
  641.         msg("Can't allocate %d bytes for restore",hstat.st_size);
  642.         skip_file((long)hstat.st_size);
  643.         return;
  644.     }
  645.     to=archive_dir;
  646.     for(size=hstat.st_size;size>0;size-=copied) {
  647.         from=findrec()->charptr;
  648.         if(!from) {
  649.             msg("Unexpected EOF in archive\n");
  650.             break;
  651.         }
  652.         copied=endofrecs()->charptr - from;
  653.         if(copied>size)
  654.             copied=size;
  655.         bcopy((VOIDSTAR)from,(VOIDSTAR)to,(int)copied);
  656.         to+=copied;
  657.         userec((union record *)(from+copied-1));
  658.     }
  659.  
  660.     for(cur=current_dir;*cur;cur+=strlen(cur)+1) {
  661.         for(arc=archive_dir;*arc;arc+=strlen(arc)+1) {
  662.             arc++;
  663.             if(!strcmp(arc,cur))
  664.                 break;
  665.         }
  666.         if(*arc=='\0') {
  667.             p=new_name(skipcrud+head->header.name,cur);
  668.             if(f_confirm && !confirm("delete",p)) {
  669.                 free(p);
  670.                 continue;
  671.             }
  672.             if(f_verbose)
  673.                 fprintf(msg_file,"%s: deleting %s\n",tar,p);
  674.             if(recursively_delete(p)) {
  675.                 msg("%s: Error while deleting %s\n",tar,p);
  676.             }
  677.             free(p);
  678.         }
  679.  
  680.     }
  681.     flush_buffer(the_buffer);
  682.     free(archive_dir);
  683. }
  684.  
  685. recursively_delete(path)
  686. char *path;
  687. {
  688.     struct stat sbuf;
  689.     DIR *dirp;
  690.     struct direct *dp;
  691.     char *path_buf;
  692.     /* int path_len; */
  693.  
  694.  
  695.     if(lstat(path,&sbuf)<0)
  696.         return 1;
  697.     if((sbuf.st_mode &S_IFMT)==S_IFDIR) {
  698.  
  699.         /* path_len=strlen(path); */
  700.         dirp=opendir(path);
  701.         if(dirp==0)
  702.             return 1;
  703.         while(dp=readdir(dirp)) {
  704.             if(is_dot_or_dotdot(dp))
  705.                 continue;
  706.             path_buf=new_name(path,dp->d_name);
  707.             if(recursively_delete(path_buf)) {
  708.                 free(path_buf);
  709.                 closedir(dirp);
  710.                 return 1;
  711.             }
  712.             free(path_buf);
  713.         }
  714.         closedir(dirp);
  715.  
  716.         if(rmdir(path)<0)
  717.             return 1;
  718.         return 0;
  719.     }
  720.     if(unlink(path)<0)
  721.         return 1;
  722.     return 0;
  723. }
  724.  
  725.