From 10b4901399a867671f09cf2dbf4316a71ccc5fbc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Pinard?= Date: Wed, 16 Nov 1994 02:48:44 +0000 Subject: [PATCH] *** empty log message *** --- scripts/level-0 | 2 +- scripts/level-1 | 117 +++++---- src/gnu.c | 644 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 710 insertions(+), 53 deletions(-) create mode 100644 src/gnu.c diff --git a/scripts/level-0 b/scripts/level-0 index 4e1ffe4..a693ef7 100644 --- a/scripts/level-0 +++ b/scripts/level-0 @@ -86,7 +86,7 @@ LOGFILE="log-`date | sed -ne ' localhost="`hostname | sed -e 's/\..*//'`" -TAR_PART1="/usr/local/bin/tar -c --multi-volume --one-file-system --block=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}" +TAR_PART1="${TAR} -c --multi-volume --one-file-system --block=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}" # Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then diff --git a/scripts/level-1 b/scripts/level-1 index 474e36f..d3bc385 100644 --- a/scripts/level-1 +++ b/scripts/level-1 @@ -21,11 +21,11 @@ fi # Maybe sleep until around specified or default hour. # -if [ "$1" != "now" ]; then - if [ "$1"x != x ]; then - spec=$1 +if [ "${1}" != "now" ]; then + if [ "${1}"x != x ]; then + spec=${1} else - spec=$BACKUP_HOUR + spec=${BACKUP_HOUR} fi pausetime=`date | awk '{hr=substr($4,1,2);\\ mn=substr($4,4,2);\\ @@ -35,7 +35,7 @@ if [ "$1" != "now" ]; then print 3600*(spec+(24-hr))-60*mn; }' spec=$spec` clear cat ./dont_touch - sleep $pausetime + sleep ${pausetime} fi # start doing things @@ -43,105 +43,118 @@ fi here=`pwd` LOGFILE=log-`date | awk '{print $2 "-" $3 "-" $6}'`-level-1 HOST=`hostname | sed 's/\..*//'` -TAR_PART1="/usr/local/bin/tar -c --multi-volume --one-file-system --block=$BLOCKING --sparse --volno-file=$VOLNO_FILE" +TAR_PART1="/usr/local/bin/tar -c --multi-volume --one-file-system --block=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}" + +# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs +if [ x != "x${DUMP_REMIND_SCRIPT}" ]; then + TAR_PART1="${TAR_PART1} --info-script=${DUMP_REMIND_SCRIPT}" +fi # Make sure the log file did not already exist. Create it. -if [ -f $LOGFILE ] ; then - echo Log file $LOGFILE already exists. +if [ -f ${LOGFILE} ] ; then + echo Log file ${LOGFILE} already exists. exit 1 else - touch $LOGFILE + touch ${LOGFILE} fi -mt -f $TAPE_FILE rewind -rm $VOLNO_FILE +mt -f ${TAPE_FILE} rewind +rm ${VOLNO_FILE} -set $BACKUP_DIRS +set ${BACKUP_DIRS} while [ $# -ne 0 ] ; do - host=`echo $1 | sed 's/:.*$//'` - fs=`echo $1 | sed 's/^.*://'` + host=`echo ${1} | sed 's/:.*$//'` + fs=`echo ${1} | sed 's/^.*://'` date=`date` - fsname=`echo $1 | sed 's/\//:/g'` + fsname=`echo ${1} | sed 's/\//:/g'` # This filename must be absolute; it is opened on the machine that runs tar. TAR_PART2="--listed=/etc/tar-backup/temp.level-1" - TAR_PART3="--label='level 1 backup of $fs on $host at $date' -C $fs ." + TAR_PART3="--label='level 1 backup of ${fs} on ${host} at ${date}' -C ${fs} ." - echo Backing up $1 at $date | tee -a $LOGFILE - echo Last full dump on this filesystem: | tee -a $LOGFILE + echo Backing up ${1} at ${date} | tee -a ${LOGFILE} + echo Last full dump on this filesystem: | tee -a ${LOGFILE} - if [ $HOST != $host ] ; then - rsh $host "ls -l /etc/tar-backup/$fsname.level-0; \ - cp /etc/tar-backup/$fsname.level-0 /etc/tar-backup/temp.level-1" \ - 2>&1 | tee -a $LOGFILE + if [ ${HOST} != ${host} ] ; then + rsh ${host} "ls -l /etc/tar-backup/${fsname}.level-0; \ + cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1" \ + 2>&1 | tee -a ${LOGFILE} else - ls -l /etc/tar-backup/$fsname.level-0 2>&1 | tee -a $LOGFILE - cp /etc/tar-backup/$fsname.level-0 /etc/tar-backup/temp.level-1 2>&1 | tee -a $LOGFILE + ls -l /etc/tar-backup/${fsname}.level-0 2>&1 | tee -a ${LOGFILE} + cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1 2>&1 | tee -a ${LOGFILE} fi # Actually back things up. - if [ $HOST != $host ] ; then - rsh $host $TAR_PART1 -f $HOST:$TAPE_FILE $TAR_PART2 $TAR_PART3 2>&1 | tee -a $LOGFILE + if [ ${HOST} != ${host} ] ; then + rsh ${host} ${TAR_PART1} -f ${HOST}:${TAPE_FILE} ${TAR_PART2} ${TAR_PART3} 2>&1 | tee -a ${LOGFILE} else # Using `sh -c exec' causes nested quoting and shell substitution # to be handled here in the same way rsh handles it. - sh -c "exec $TAR_PART1 -f $TAPE_FILE $TAR_PART2 $TAR_PART3" 2>&1 | tee -a $LOGFILE + sh -c "exec ${TAR_PART1} -f ${TAPE_FILE} ${TAR_PART2} ${TAR_PART3}" 2>&1 | tee -a ${LOGFILE} fi + # This doesn't presently work, of course, because $? is set to the exit + # status of the last thing in the pipeline of the previous command, + # namely `tee'. We really want the exit status of the sh command + # running tar, but getting this seems to be nontrivial. --friedman if [ $? -ne 0 ] ; then - echo Backup of $1 failed. | tee -a $LOGFILE + echo Backup of ${1} failed. | tee -a ${LOGFILE} # I'm assuming that the tar will have written an empty # file to the tape, otherwise I should do a cat here. else - if [ $HOST != $host ] ; then - rsh $host mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/$fsname.level-1 2>&1 | tee -a $LOGFILE + if [ ${HOST} != ${host} ] ; then + rsh ${host} mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/${fsname}.level-1 2>&1 | tee -a ${LOGFILE} else - mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/$fsname.level-1 2>&1 | tee -a $LOGFILE + mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/${fsname}.level-1 2>&1 | tee -a ${LOGFILE} fi fi - $TAPE_STATUS | tee -a $LOGFILE + ${TAPE_STATUS} | tee -a ${LOGFILE} sleep 60 shift done # Dump any individual files requested. -if [ x != "x$BACKUP_FILES" ] ; then +if [ x != "x${BACKUP_FILES}" ] ; then date=`date` TAR_PART2="--listed=/etc/tar-backup/temp.level-1" - TAR_PART3="--label='Incremental backup of miscellaneous files at $date'" + TAR_PART3="--label='Incremental backup of miscellaneous files at ${date}'" - echo Backing up miscellaneous files at $date | tee -a $LOGFILE - echo Last full dump of these files: | tee -a $LOGFILE - ls -l /etc/tar-backup/misc.level-0 2>&1 | tee -a $LOGFILE + echo Backing up miscellaneous files at ${date} | tee -a ${LOGFILE} + echo Last full dump of these files: | tee -a ${LOGFILE} + ls -l /etc/tar-backup/misc.level-0 2>&1 | tee -a ${LOGFILE} - rm -f /etc/tar-backup/temp.level-1 2>&1 | tee -a $LOGFILE - cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1 2>&1 | tee -a $LOGFILE + rm -f /etc/tar-backup/temp.level-1 2>&1 | tee -a ${LOGFILE} + cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1 2>&1 | tee -a ${LOGFILE} - echo Backing up miscellaneous files at $date | tee -a $LOGFILE + echo Backing up miscellaneous files at ${date} | tee -a ${LOGFILE} # Using `sh -c exec' causes nested quoting and shell substitution # to be handled here in the same way rsh handles it. - sh -c "exec $TAR_PART1 -f $TAPE_FILE $TAR_PART2 $TAR_PART3 \ - $BACKUP_FILES" 2>&1 | tee -a $LOGFILE + sh -c "exec ${TAR_PART1} -f ${TAPE_FILE} ${TAR_PART2} ${TAR_PART3} \ + ${BACKUP_FILES}" 2>&1 | tee -a ${LOGFILE} + # This doesn't presently work, of course, because $? is set to the exit + # status of the last thing in the pipeline of the previous command, + # namely `tee'. We really want the exit status of the sh command + # running tar, but getting this seems to be nontrivial. --friedman if [ $? -ne 0 ] ; then - echo Backup of miscellaneous files failed. | tee -a $LOGFILE + echo Backup of miscellaneous files failed. | tee -a ${LOGFILE} # I'm assuming that the tar will have written an empty # file to the tape, otherwise I should do a cat here. else - mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1 2>&1 | tee -a $LOGFILE + mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1 2>&1 | tee -a ${LOGFILE} fi - $TAPE_STATUS | tee -a $LOGFILE + ${TAPE_STATUS} | tee -a ${LOGFILE} else - echo No miscellaneous files specified | tee -a $LOGFILE + echo No miscellaneous files specified | tee -a ${LOGFILE} false fi -mt -f $TAPE_FILE rewind -mt -f $TAPE_FILE offl +mt -f ${TAPE_FILE} rewind +mt -f ${TAPE_FILE} offl -echo Sending the dump log to $ADMINISTRATOR -cat $LOGFILE | sed -f logfile.sed > $LOGFILE.tmp -/usr/ucb/mail -s "Results of backup on `date`" $ADMINISTRATOR < $LOGFILE.tmp -rm -f $LOGFILE.tmp +echo Sending the dump log to ${ADMINISTRATOR} +cat ${LOGFILE} | sed -f logfile.sed > ${LOGFILE}.tmp +/usr/ucb/mail -s "Results of backup on `date`" ${ADMINISTRATOR} < ${LOGFILE}.tmp +rm -f ${LOGFILE}.tmp diff --git a/src/gnu.c b/src/gnu.c new file mode 100644 index 0000000..ba4253f --- /dev/null +++ b/src/gnu.c @@ -0,0 +1,644 @@ +/* GNU dump extensions to tar. + Copyright (C) 1988, 1992 Free Software Foundation + +This file is part of GNU Tar. + +GNU Tar is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Tar is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Tar; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#ifndef STDC_HEADERS +extern int errno; +#endif +#include +time_t time(); + +#include "tar.h" +#include "port.h" + +#if defined(_POSIX_VERSION) || defined(DIRENT) +#include +#ifdef direct +#undef direct +#endif /* direct */ +#define direct dirent +#define DP_NAMELEN(x) strlen((x)->d_name) +#endif /* _POSIX_VERSION or DIRENT */ +#if !defined(_POSIX_VERSION) && !defined(DIRENT) && defined(BSD42) +#include +#define DP_NAMELEN(x) (x)->d_namlen +#endif /* not _POSIX_VERSION and BSD42 */ +#ifdef __MSDOS__ +#include "msd_dir.h" +#define DP_NAMELEN(x) (x)->d_namlen +#define direct dirent +#endif +#if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT) +#include +#define DP_NAMELEN(x) strlen((x)->d_name) +#endif /* USG and not _POSIX_VERSION and not DIRENT */ + +#ifndef S_ISLNK +#define lstat stat +#endif + +extern time_t new_time; +extern FILE *msg_file; + +void addname(); +int check_exclude(); +extern PTR ck_malloc(); +extern PTR ck_realloc(); +int confirm(); +extern PTR init_buffer(); +extern char *get_buffer(); +int is_dot_or_dotdot(); +extern void add_buffer(); +extern void flush_buffer(); +void name_gather(); +int recursively_delete(); +void skip_file(); +char *un_quote_string(); + +extern char *new_name(); + +static void add_dir_name(); + +struct dirname { + struct dirname *next; + char *name; + char *dir_text; + int dev; + int ino; + int allnew; +}; +static struct dirname *dir_list; +static time_t this_time; + +void +add_dir(name,dev,ino,text) +char *name; +char *text; +dev_t dev; +ino_t ino; +{ + struct dirname *dp; + + dp=(struct dirname *)malloc(sizeof(struct dirname)); + if(!dp) + abort(); + dp->next=dir_list; + dir_list=dp; + dp->dev=dev; + dp->ino=ino; + dp->name=malloc(strlen(name)+1); + strcpy(dp->name,name); + dp->dir_text=text; + dp->allnew=0; +} + +void +read_dir_file() +{ + int dev; + int ino; + char *strp; + FILE *fp; + char buf[512]; + static char *path = 0; + + if (path == 0) + path = ck_malloc(PATH_MAX); + time(&this_time); + if(gnu_dumpfile[0]!='/') { +#if defined(__MSDOS__) || defined(USG) || defined(_POSIX_VERSION) + if(!getcwd(path,PATH_MAX)) + msg("Couldn't get current directory."); + exit(EX_SYSTEM); +#else + char *getwd(); + + if(!getwd(path)) { + msg("Couldn't get current directory: %s",path); + exit(EX_SYSTEM); + } +#endif + /* If this doesn't fit, we're in serious trouble */ + strcat(path,"/"); + strcat(path,gnu_dumpfile); + gnu_dumpfile=path; + } + fp=fopen(gnu_dumpfile,"r"); + if(fp==0 && errno!=ENOENT) { + msg_perror("Can't open %s",gnu_dumpfile); + return; + } + if(!fp) + return; + fgets(buf,sizeof(buf),fp); + if(!f_new_files) { + f_new_files++; + new_time=atol(buf); + } + while(fgets(buf,sizeof(buf),fp)) { + strp= &buf[strlen(buf)]; + if(strp[-1]=='\n') + strp[-1]='\0'; + strp=buf; + dev=atol(strp); + while(isdigit(*strp)) + strp++; + ino=atol(strp); + while(isspace(*strp)) + strp++; + while(isdigit(*strp)) + strp++; + strp++; + add_dir(un_quote_string(strp),dev,ino,(char *)0); + } + fclose(fp); +} + +void +write_dir_file() +{ + FILE *fp; + struct dirname *dp; + char *str; + extern char *quote_copy_string(); + + fp=fopen(gnu_dumpfile,"w"); + if(fp==0) { + msg_perror("Can't write to %s",gnu_dumpfile); + return; + } + fprintf(fp,"%lu\n",this_time); + for(dp=dir_list;dp;dp=dp->next) { + if(!dp->dir_text) + continue; + str=quote_copy_string(dp->name); + if(str) { + fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str); + free(str); + } else + fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name); + } + fclose(fp); +} + +struct dirname * +get_dir(name) +char *name; +{ + struct dirname *dp; + + for(dp=dir_list;dp;dp=dp->next) { + if(!strcmp(dp->name,name)) + return dp; + } + return 0; +} + + +/* Collect all the names from argv[] (or whatever), then expand them into + a directory tree, and put all the directories at the beginning. */ +void +collect_and_sort_names() +{ + struct name *n,*n_next; + int num_names; + struct stat statbuf; + int name_cmp(); + char *merge_sort(); + + name_gather(); + + if(gnu_dumpfile) + read_dir_file(); + if(!namelist) addname("."); + for(n=namelist;n;n=n_next) { + n_next=n->next; + if(n->found || n->dir_contents) + continue; + if(n->regexp) /* FIXME just skip regexps for now */ + continue; + if(n->change_dir) + if(chdir(n->change_dir)<0) { + msg_perror("can't chdir to %s",n->change_dir); + continue; + } + +#ifdef AIX + if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN|STX_LINK)) +#else + if(lstat(n->name,&statbuf)<0) +#endif /* AIX */ + { + msg_perror("can't stat %s",n->name); + continue; + } + if(S_ISDIR(statbuf.st_mode)) { + n->found++; + add_dir_name(n->name,statbuf.st_dev); + } + } + + num_names=0; + for(n=namelist;n;n=n->next) + num_names++; + namelist=(struct name *)merge_sort((PTR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp); + + for(n=namelist;n;n=n->next) { + n->found=0; + } + if(gnu_dumpfile) + write_dir_file(gnu_dumpfile); +} + +int +name_cmp(n1,n2) +struct name *n1,*n2; +{ + if(n1->found) { + if(n2->found) + return strcmp(n1->name,n2->name); + else + return -1; + } else if(n2->found) + return 1; + else + return strcmp(n1->name,n2->name); +} + +int +dirent_cmp(p1,p2) +const PTR p1; +const PTR p2; +{ + char *frst,*scnd; + + frst= (*(char **)p1)+1; + scnd= (*(char **)p2)+1; + + return strcmp(frst,scnd); +} + +char * +get_dir_contents(p,device) +char *p; +int device; +{ + DIR *dirp; + register struct direct *d; + char *new_buf; + char *namebuf; + int bufsiz; + int len; + PTR the_buffer; + char *buf; + size_t n_strs; +/* int n_size;*/ + char *p_buf; + char **vec,**p_vec; + + extern int errno; + + errno=0; + dirp=opendir(p); + bufsiz=strlen(p)+NAMSIZ; + namebuf=ck_malloc(bufsiz+2); + if(!dirp) { + if(errno) + msg_perror("can't open directory %s",p); + else + msg("error opening directory %s",p); + new_buf=NULL; + } else { + struct dirname *dp; + int all_children; + + dp=get_dir(p); + all_children= dp ? dp->allnew : 0; + (void) strcpy(namebuf,p); + if(p[strlen(p)-1]!='/') + (void) strcat(namebuf,"/"); + len=strlen(namebuf); + + the_buffer=init_buffer(); + while(d=readdir(dirp)) { + struct stat hs; + + /* Skip . and .. */ + if(is_dot_or_dotdot(d->d_name)) + continue; + if(DP_NAMELEN(d) + len >=bufsiz) { + bufsiz+=NAMSIZ; + namebuf=ck_realloc(namebuf,bufsiz+2); + } + (void) strcpy(namebuf+len,d->d_name); +#ifdef AIX + if (0 != f_follow_links? + statx(namebuf, &hs, STATSIZE, STX_HIDDEN): + statx(namebuf, &hs, STATSIZE, STX_HIDDEN|STX_LINK)) +#else + if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs)) +#endif + { + msg_perror("can't stat %s",namebuf); + continue; + } + if( (f_local_filesys && device!=hs.st_dev) + || (f_exclude && check_exclude(namebuf))) + add_buffer(the_buffer,"N",1); +#ifdef AIX + else if (S_ISHIDDEN (hs.st_mode)) { + add_buffer (the_buffer, "D", 1); + strcat (d->d_name, "A"); + d->d_namlen++; + } +#endif /* AIX */ + else if(S_ISDIR(hs.st_mode)) { + if(dp=get_dir(namebuf)) { + if( dp->dev!=hs.st_dev + || dp->ino!=hs.st_ino) { + if(f_verbose) + msg("directory %s has been renamed.",namebuf); + dp->allnew=1; + dp->dev=hs.st_dev; + dp->ino=hs.st_ino; + } + dp->dir_text=""; + } else { + if(f_verbose) + msg("Directory %s is new",namebuf); + add_dir(namebuf,hs.st_dev,hs.st_ino,""); + dp=get_dir(namebuf); + dp->allnew=1; + } + if(all_children) + dp->allnew=1; + + add_buffer(the_buffer,"D",1); + } else if( !all_children + && f_new_files + && new_time>hs.st_mtime + && ( f_new_files>1 + || new_time>hs.st_ctime)) + add_buffer(the_buffer,"N",1); + else + add_buffer(the_buffer,"Y",1); + add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1)); + } + add_buffer(the_buffer,"\000\000",2); + closedir(dirp); + + /* Well, we've read in the contents of the dir, now sort them */ + buf=get_buffer(the_buffer); + if(buf[0]=='\0') { + flush_buffer(the_buffer); + new_buf=NULL; + } else { + n_strs=0; + for(p_buf=buf;*p_buf;) { + int tmp; + + tmp=strlen(p_buf)+1; + n_strs++; + p_buf+=tmp; + } + vec=(char **)malloc(sizeof(char *)*(n_strs+1)); + for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1) + *p_vec++= p_buf; + *p_vec= 0; + qsort((PTR)vec,n_strs,sizeof(char *),dirent_cmp); + new_buf=(char *)malloc(p_buf-buf+2); + for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) { + char *p_tmp; + + for(p_tmp= *p_vec;*p_buf++= *p_tmp++;) + ; + } + *p_buf++='\0'; + free(vec); + flush_buffer(the_buffer); + } + } + free(namebuf); + return new_buf; +} + +/* p is a directory. Add all the files in P to the namelist. If any of the + files is a directory, recurse on the subdirectory. . . */ +static void +add_dir_name(p,device) +char *p; +int device; +{ + char *new_buf; + char *p_buf; + + char *namebuf; + int buflen; + register int len; + int sublen; + +/* PTR the_buffer;*/ + +/* char *buf;*/ +/* char **vec,**p_vec;*/ +/* int n_strs,n_size;*/ + + struct name *n; + + int dirent_cmp(); + + new_buf=get_dir_contents(p,device); + + for(n=namelist;n;n=n->next) { + if(!strcmp(n->name,p)) { + n->dir_contents = new_buf; + break; + } + } + + if (new_buf) + { + len=strlen(p); + buflen= NAMSIZ<=len ? len + NAMSIZ : NAMSIZ; + namebuf= ck_malloc(buflen+1); + + (void)strcpy(namebuf,p); + if(namebuf[len-1]!='/') { + namebuf[len++]='/'; + namebuf[len]='\0'; + } + for(p_buf=new_buf;*p_buf;p_buf+=sublen+1) { + sublen=strlen(p_buf); + if(*p_buf=='D') { + if(len+sublen>=buflen) { + buflen+=NAMSIZ; + namebuf= ck_realloc(namebuf,buflen+1); + } + (void)strcpy(namebuf+len,p_buf+1); + addname(namebuf); + add_dir_name(namebuf,device); + } + } + free(namebuf); + } +} + +/* Returns non-zero if p is . or .. This could be a macro for speed. */ +int +is_dot_or_dotdot(p) +char *p; +{ + return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0'))); +} + + + + + + +void +gnu_restore(skipcrud) +int skipcrud; +{ + char *current_dir; +/* int current_dir_length; */ + + char *archive_dir; +/* int archive_dir_length; */ + PTR the_buffer; + char *p; + DIR *dirp; + struct direct *d; + char *cur,*arc; + extern struct stat hstat; /* Stat struct corresponding */ + long size,copied; + char *from,*to; + extern union record *head; + + dirp=opendir(skipcrud+head->header.name); + + if(!dirp) { + /* The directory doesn't exist now. It'll be created. + In any case, we don't have to delete any files out + of it */ + skip_file((long)hstat.st_size); + return; + } + + the_buffer=init_buffer(); + while(d=readdir(dirp)) { + if(is_dot_or_dotdot(d->d_name)) + continue; + + add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1)); + } + closedir(dirp); + add_buffer(the_buffer,"",1); + + current_dir=get_buffer(the_buffer); + archive_dir=(char *)malloc(hstat.st_size); + if(archive_dir==0) { + msg("Can't allocate %d bytes for restore",hstat.st_size); + skip_file((long)hstat.st_size); + return; + } + to=archive_dir; + for(size=hstat.st_size;size>0;size-=copied) { + from=findrec()->charptr; + if(!from) { + msg("Unexpected EOF in archive\n"); + break; + } + copied=endofrecs()->charptr - from; + if(copied>size) + copied=size; + bcopy((PTR)from,(PTR)to,(int)copied); + to+=copied; + userec((union record *)(from+copied-1)); + } + + for(cur=current_dir;*cur;cur+=strlen(cur)+1) { + for(arc=archive_dir;*arc;arc+=strlen(arc)+1) { + arc++; + if(!strcmp(arc,cur)) + break; + } + if(*arc=='\0') { + p=new_name(skipcrud+head->header.name,cur); + if(f_confirm && !confirm("delete",p)) { + free(p); + continue; + } + if(f_verbose) + fprintf(msg_file,"%s: deleting %s\n",tar,p); + if(recursively_delete(p)) { + msg("%s: Error while deleting %s\n",tar,p); + } + free(p); + } + + } + flush_buffer(the_buffer); + free(archive_dir); +} + +int +recursively_delete(path) +char *path; +{ + struct stat sbuf; + DIR *dirp; + struct direct *dp; + char *path_buf; + /* int path_len; */ + + + if(lstat(path,&sbuf)<0) + return 1; + if(S_ISDIR(sbuf.st_mode)) { + + /* path_len=strlen(path); */ + dirp=opendir(path); + if(dirp==0) + return 1; + while(dp=readdir(dirp)) { + if(is_dot_or_dotdot(dp->d_name)) + continue; + path_buf=new_name(path,dp->d_name); + if(recursively_delete(path_buf)) { + free(path_buf); + closedir(dirp); + return 1; + } + free(path_buf); + } + closedir(dirp); + + if(rmdir(path)<0) + return 1; + return 0; + } + if(unlink(path)<0) + return 1; + return 0; +} + -- 2.45.2