From: François Pinard Date: Wed, 16 Nov 1994 02:46:11 +0000 (+0000) Subject: *** empty log message *** X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=2017294abd655916338c95ddaa721c9f92a007bb;p=chaz%2Ftar *** empty log message *** --- diff --git a/src/extract.c b/src/extract.c index 8aa5ba0..8e6e277 100644 --- a/src/extract.c +++ b/src/extract.c @@ -30,7 +30,7 @@ extern int errno; #endif #include #include -time_t time(); +time_t time (); #ifdef BSD42 #include @@ -61,35 +61,36 @@ struct utimbuf long actime; long modtime; }; + #endif extern FILE *msg_file; -extern union record *head; /* Points to current tape header */ -extern struct stat hstat; /* Stat struct corresponding */ -extern int head_standard; /* Tape header is in ANSI format */ +extern union record *head; /* Points to current tape header */ +extern struct stat hstat; /* Stat struct corresponding */ +extern int head_standard; /* Tape header is in ANSI format */ extern char *save_name; extern long save_totsize; extern long save_sizeleft; -int confirm(); -void decode_header(); -void extract_mangle(); -void extract_sparse_file(); -long from_oct(); -void gnu_restore(); -extern void print_header(); -extern void skip_file(); -extern void skip_extended_headers(); -extern void pr_mkdir(); -void saverec(); +int confirm (); +void decode_header (); +void extract_mangle (); +void extract_sparse_file (); +long from_oct (); +void gnu_restore (); +extern void print_header (); +extern void skip_file (); +extern void skip_extended_headers (); +extern void pr_mkdir (); +void saverec (); -int make_dirs(); /* Makes required directories */ +int make_dirs (); /* Makes required directories */ -static time_t now = 0; /* Current time */ -static we_are_root = 0; /* True if our effective uid == 0 */ -static int notumask = ~0; /* Masks out bits user doesn't want */ +static time_t now = 0; /* Current time */ +static we_are_root = 0; /* True if our effective uid == 0 */ +static int notumask = ~0; /* Masks out bits user doesn't want */ /* * "Scratch" space to store the information about a sparse file before @@ -108,30 +109,31 @@ struct saved_dir_info int mtime; struct saved_dir_info *next; }; - + struct saved_dir_info *saved_dir_info_head; /* * Set up to extract files. */ void -extr_init() +extr_init () { - int ourmask; + int ourmask; - now = time((time_t *)0); - if (geteuid() == 0) - we_are_root = 1; + now = time ((time_t *) 0); + if (geteuid () == 0) + we_are_root = 1; - /* + /* * We need to know our umask. But if f_use_protection is set, * leave our kernel umask at 0, and our "notumask" at ~0. */ - ourmask = umask(0); /* Read it */ - if (!f_use_protection) { - (void) umask (ourmask); /* Set it back how it was */ - notumask = ~ourmask; /* Make umask override permissions */ - } + ourmask = umask (0); /* Read it */ + if (!f_use_protection) + { + (void) umask (ourmask); /* Set it back how it was */ + notumask = ~ourmask; /* Make umask override permissions */ + } } @@ -139,38 +141,39 @@ extr_init() * Extract a file from the archive. */ void -extract_archive() +extract_archive () { - register char *data; - int fd, check, namelen, written, openflag; - long size; - struct utimbuf acc_upd_times; - register int skipcrud; - register int i; -/* int sparse_ind = 0;*/ - union record *exhdr; - struct saved_dir_info *tmp; -/* int end_nulls; */ - char **longp; - char *bp; - - saverec(&head); /* Make sure it sticks around */ - userec(head); /* And go past it in the archive */ - decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */ - - if(f_confirm && !confirm("extract",current_file_name)) { - if (head->header.isextended) - skip_extended_headers(); - skip_file((long)hstat.st_size); - saverec((union record **)0); - return; - } + register char *data; + int fd, check, namelen, written, openflag; + long size; + struct utimbuf acc_upd_times; + register int skipcrud; + register int i; + /* int sparse_ind = 0;*/ + union record *exhdr; + struct saved_dir_info *tmp; + /* int end_nulls; */ + char **longp; + char *bp; + + saverec (&head); /* Make sure it sticks around */ + userec (head); /* And go past it in the archive */ + decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */ - /* Print the record from 'head' and 'hstat' */ - if (f_verbose) - print_header(); + if (f_confirm && !confirm ("extract", current_file_name)) + { + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + saverec ((union record **) 0); + return; + } - /* + /* Print the record from 'head' and 'hstat' */ + if (f_verbose) + print_header (); + + /* * Check for fully specified pathnames and other atrocities. * * Note, we can't just make a pointer to the new file name, @@ -178,25 +181,28 @@ extract_archive() * We have to start from "head" every time we want to touch * the header record. */ - skipcrud = 0; - while (!f_absolute_paths - && '/' == current_file_name[skipcrud]) { - static int warned_once = 0; + skipcrud = 0; + while (!f_absolute_paths + && '/' == current_file_name[skipcrud]) + { + static int warned_once = 0; - skipcrud++; /* Force relative path */ - if (!warned_once++) { - msg("Removing leading / from absolute path names in the archive."); - } - } + skipcrud++; /* Force relative path */ + if (!warned_once++) + { + msg ("Removing leading / from absolute path names in the archive."); + } + } - switch (head->header.linkflag) { + switch (head->header.linkflag) + { - default: - msg("Unknown file type '%c' for %s, extracted as normal file", - head->header.linkflag, skipcrud+current_file_name); - /* FALL THRU */ + default: + msg ("Unknown file type '%c' for %s, extracted as normal file", + head->header.linkflag, skipcrud + current_file_name); + /* FALL THRU */ - /* + /* * JK - What we want to do if the file is sparse is loop through * the array of sparse structures in the header and read in * and translate the character strings representing 1) the offset @@ -206,83 +212,89 @@ extract_archive() * the tar file that had to deal with a sparse file. * * After we read in the first five (at most) sparse structures, - * we check to see if the file has an extended header, i.e., + * we check to see if the file has an extended header, i.e., * if more sparse structures are needed to describe the contents * of the new file. If so, we read in the extended headers * and continue to store their contents into the sparsearray. */ - case LF_SPARSE: - sp_array_size = 10; - sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array)); - for (i = 0; i < SPARSE_IN_HDR; i++) { - sparsearray[i].offset = - from_oct(1+12, head->header.sp[i].offset); - sparsearray[i].numbytes = - from_oct(1+12, head->header.sp[i].numbytes); - if (!sparsearray[i].numbytes) - break; - } - - /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/ - - if (head->header.isextended) { - /* read in the list of extended headers - and translate them into the sparsearray + case LF_SPARSE: + sp_array_size = 10; + sparsearray = (struct sp_array *) malloc (sp_array_size * sizeof (struct sp_array)); + for (i = 0; i < SPARSE_IN_HDR; i++) + { + sparsearray[i].offset = + from_oct (1 + 12, head->header.sp[i].offset); + sparsearray[i].numbytes = + from_oct (1 + 12, head->header.sp[i].numbytes); + if (!sparsearray[i].numbytes) + break; + } + + /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/ + + if (head->header.isextended) + { + /* read in the list of extended headers + and translate them into the sparsearray as before */ - /* static */ int ind = SPARSE_IN_HDR; + /* static */ int ind = SPARSE_IN_HDR; - for (;;) { + for (;;) + { - exhdr = findrec(); - for (i = 0; i < SPARSE_EXT_HDR; i++) { + exhdr = findrec (); + for (i = 0; i < SPARSE_EXT_HDR; i++) + { - if (i+ind > sp_array_size-1) { - /* + if (i + ind > sp_array_size - 1) + { + /* * realloc the scratch area * since we've run out of room -- */ - sparsearray = (struct sp_array *) - realloc(sparsearray, - 2 * sp_array_size * (sizeof(struct sp_array))); - sp_array_size *= 2; - } - if (!exhdr->ext_hdr.sp[i].numbytes) - break; - sparsearray[i+ind].offset = - from_oct(1+12, exhdr->ext_hdr.sp[i].offset); - sparsearray[i+ind].numbytes = - from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes); - } - if (!exhdr->ext_hdr.isextended) - break; - else { - ind += SPARSE_EXT_HDR; - userec(exhdr); - } - } - userec(exhdr); - } - - /* FALL THRU */ - case LF_OLDNORMAL: - case LF_NORMAL: - case LF_CONTIG: - /* + sparsearray = (struct sp_array *) + realloc (sparsearray, + 2 * sp_array_size * (sizeof (struct sp_array))); + sp_array_size *= 2; + } + if (!exhdr->ext_hdr.sp[i].numbytes) + break; + sparsearray[i + ind].offset = + from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset); + sparsearray[i + ind].numbytes = + from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes); + } + if (!exhdr->ext_hdr.isextended) + break; + else + { + ind += SPARSE_EXT_HDR; + userec (exhdr); + } + } + userec (exhdr); + } + + /* FALL THRU */ + case LF_OLDNORMAL: + case LF_NORMAL: + case LF_CONTIG: + /* * Appears to be a file. * See if it's really a directory. */ - namelen = strlen(skipcrud+current_file_name)-1; - if (current_file_name[skipcrud+namelen] == '/') - goto really_dir; - - /* FIXME, deal with protection issues */ - again_file: - openflag = (f_keep? - O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL: - O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC) - | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND); - /* + namelen = strlen (skipcrud + current_file_name) - 1; + if (current_file_name[skipcrud + namelen] == '/') + goto really_dir; + + /* FIXME, deal with protection issues */ + again_file: + openflag = (f_keep ? + O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL : + O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC) + | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND); + /* * JK - The last | is a kludge to solve the problem * the O_APPEND flag causes with files we are * trying to make sparse: when a file is opened @@ -295,58 +307,61 @@ extract_archive() * me to waste a good deal of time, I might add) */ - if(f_exstdout) { - fd = 1; - goto extract_file; - } + if (f_exstdout) + { + fd = 1; + goto extract_file; + } #ifdef O_CTG - /* + /* * Contiguous files (on the Masscomp) have to specify * the size in the open call that creates them. */ - if (head->header.linkflag == LF_CONTIG) - fd = open((longname ? longname : head->header.name) - + skipcrud, - openflag | O_CTG, - hstat.st_mode, hstat.st_size); - else + if (head->header.linkflag == LF_CONTIG) + fd = open ((longname ? longname : head->header.name) + + skipcrud, + openflag | O_CTG, + hstat.st_mode, hstat.st_size); + else #endif - { + { #ifdef NO_OPEN3 - /* + /* * On raw V7 we won't let them specify -k (f_keep), but * we just bull ahead and create the files. */ - fd = creat((longname - ? longname - : head->header.name) + skipcrud, - hstat.st_mode); + fd = creat ((longname + ? longname + : head->header.name) + skipcrud, + hstat.st_mode); #else - /* + /* * With 3-arg open(), we can do this up right. */ - fd = open(skipcrud + current_file_name, - openflag, hstat.st_mode); + fd = open (skipcrud + current_file_name, + openflag, hstat.st_mode); #endif - } - - if (fd < 0) { - if (make_dirs(skipcrud + current_file_name)) - goto again_file; - msg_perror("Could not create file %s", - skipcrud + current_file_name); - if (head->header.isextended) - skip_extended_headers(); - skip_file((long)hstat.st_size); - goto quit; - } - - extract_file: - if (head->header.linkflag == LF_SPARSE) { - char *name; - int namelen; - - /* + } + + if (fd < 0) + { + if (make_dirs (skipcrud + current_file_name)) + goto again_file; + msg_perror ("Could not create file %s", + skipcrud + current_file_name); + if (head->header.isextended) + skip_extended_headers (); + skip_file ((long) hstat.st_size); + goto quit; + } + + extract_file: + if (head->header.linkflag == LF_SPARSE) + { + char *name; + int namelen; + + /* * Kludge alert. NAME is assigned to header.name * because during the extraction, the space that * contains the header will get scribbled on, and @@ -354,86 +369,90 @@ extract_archive() * that happen to contain the filename will look * REAL interesting unless we do this. */ - namelen = strlen(skipcrud + current_file_name); - name = (char *) malloc((sizeof(char)) * namelen); - bcopy(skipcrud+current_file_name, name, namelen); - size = hstat.st_size; - extract_sparse_file(fd, &size, hstat.st_size, name); - } - else - for (size = hstat.st_size; - size > 0; - size -= written) { - - /* long offset, + namelen = strlen (skipcrud + current_file_name); + name = (char *) malloc ((sizeof (char)) * namelen); + bcopy (skipcrud + current_file_name, name, namelen); + size = hstat.st_size; + extract_sparse_file (fd, &size, hstat.st_size, name); + } + else + for (size = hstat.st_size; + size > 0; + size -= written) + { + + /* long offset, numbytes;*/ - if(f_multivol) { - save_name=current_file_name; - save_totsize=hstat.st_size; - save_sizeleft=size; - } + if (f_multivol) + { + save_name = current_file_name; + save_totsize = hstat.st_size; + save_sizeleft = size; + } - /* + /* * Locate data, determine max length * writeable, write it, record that * we have used the data, then check * if the write worked. */ - data = findrec()->charptr; - if (data == NULL) { /* Check it... */ - msg("Unexpected EOF on archive file"); - break; - } - /* + data = findrec ()->charptr; + if (data == NULL) + { /* Check it... */ + msg ("Unexpected EOF on archive file"); + break; + } + /* * JK - If the file is sparse, use the sparsearray * that we created before to lseek into the new * file the proper amount, and to see how many * bytes we want to write at that position. */ - /* if (head->header.linkflag == LF_SPARSE) { + /* if (head->header.linkflag == LF_SPARSE) { off_t pos; pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0); printf("%d at %d\n", (int) pos, sparse_ind); written = sparsearray[sparse_ind++].numbytes; } else*/ - written = endofrecs()->charptr - data; - if (written > size) - written = size; - errno = 0; - check = write(fd, data, written); - /* + written = endofrecs ()->charptr - data; + if (written > size) + written = size; + errno = 0; + check = write (fd, data, written); + /* * The following is in violation of strict * typing, since the arg to userec * should be a struct rec *. FIXME. */ - userec((union record *)(data + written - 1)); - if (check == written) continue; - /* + userec ((union record *) (data + written - 1)); + if (check == written) + continue; + /* * Error in writing to file. * Print it, skip to next file in archive. */ - if(check<0) - msg_perror("couldn't write to file %s", - skipcrud + current_file_name); - else - msg("could only write %d of %d bytes to file %s", - written,check,skipcrud + current_file_name); - skip_file((long)(size - written)); - break; /* Still do the close, mod time, chmod, etc */ - } - - if(f_multivol) - save_name = 0; - - /* If writing to stdout, don't try to do anything + if (check < 0) + msg_perror ("couldn't write to file %s", + skipcrud + current_file_name); + else + msg ("could only write %d of %d bytes to file %s", + written, check, skipcrud + current_file_name); + skip_file ((long) (size - written)); + break; /* Still do the close, mod time, chmod, etc */ + } + + if (f_multivol) + save_name = 0; + + /* If writing to stdout, don't try to do anything to the filename; it doesn't exist, or we don't want to touch it anyway */ - if(f_exstdout) - break; + if (f_exstdout) + break; - /* if (head->header.isextended) { + /* if (head->header.isextended) { register union record *exhdr; register int i; @@ -454,54 +473,59 @@ extract_archive() }*/ - check = close(fd); - if (check < 0) { - msg_perror("Error while closing %s", - skipcrud + current_file_name); - } + check = close (fd); + if (check < 0) + { + msg_perror ("Error while closing %s", + skipcrud + current_file_name); + } - set_filestat: + set_filestat: - /* + /* * If we are root, set the owner and group of the extracted * file. This does what is wanted both on real Unix and on * System V. If we are running as a user, we extract as that * user; if running as root, we extract as the original owner. */ - if (we_are_root || f_do_chown) { - if (chown(skipcrud + current_file_name, - hstat.st_uid, hstat.st_gid) < 0) { - msg_perror("cannot chown file %s to uid %d gid %d", - skipcrud + current_file_name, - hstat.st_uid,hstat.st_gid); - } - } + if (we_are_root || f_do_chown) + { + if (chown (skipcrud + current_file_name, + hstat.st_uid, hstat.st_gid) < 0) + { + msg_perror ("cannot chown file %s to uid %d gid %d", + skipcrud + current_file_name, + hstat.st_uid, hstat.st_gid); + } + } - /* + /* * Set the modified time of the file. - * + * * Note that we set the accessed time to "now", which * is really "the time we started extracting files". * unless f_gnudump is used, in which case .st_atime is used */ - if (!f_modified) { - /* fixme if f_gnudump should set ctime too, but how? */ - if(f_gnudump) - acc_upd_times.actime=hstat.st_atime; - else - acc_upd_times.actime = now; /* Accessed now */ - acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */ - if (utime(skipcrud + current_file_name, - &acc_upd_times) < 0) { - msg_perror("couldn't change access and modification times of %s",skipcrud + current_file_name); - } - } - /* We do the utime before the chmod because some versions of + if (!f_modified) + { + /* fixme if f_gnudump should set ctime too, but how? */ + if (f_gnudump) + acc_upd_times.actime = hstat.st_atime; + else + acc_upd_times.actime = now; /* Accessed now */ + acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */ + if (utime (skipcrud + current_file_name, + &acc_upd_times) < 0) + { + msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name); + } + } + /* We do the utime before the chmod because some versions of utime are broken and trash the modes of the file. Since we then change the mode anyway, we don't care. . . */ - /* + /* * If '-k' is not set, open() or creat() could have saved * the permission bits from a previously created file, * ignoring the ones we specified. @@ -514,176 +538,185 @@ extract_archive() * skip the chmod. This works because we did umask(0) if -p * is set, so umask will have left the specified mode alone. */ - if ((!f_keep) - || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) { - if (chmod(skipcrud + current_file_name, - notumask & (int)hstat.st_mode) < 0) { - msg_perror("cannot change mode of file %s to %ld", - skipcrud + current_file_name, - notumask & (int)hstat.st_mode); - } - } - - quit: - break; - - case LF_LINK: - again_link: + if ((!f_keep) + || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))) { - struct stat st1,st2; - - check = link (current_link_name, skipcrud + current_file_name); - - if (check == 0) - break; - if (make_dirs(skipcrud + current_file_name)) - goto again_link; - if(f_gnudump && errno==EEXIST) - break; - if(stat(current_link_name, &st1) == 0 - && stat(current_file_name + skipcrud, &st2)==0 - && st1.st_dev==st2.st_dev - && st1.st_ino==st2.st_ino) - break; - msg_perror("Could not link %s to %s", - skipcrud + current_file_name, - current_link_name); + if (chmod (skipcrud + current_file_name, + notumask & (int) hstat.st_mode) < 0) + { + msg_perror ("cannot change mode of file %s to %ld", + skipcrud + current_file_name, + notumask & (int) hstat.st_mode); + } } - break; + + quit: + break; + + case LF_LINK: + again_link: + { + struct stat st1, st2; + + check = link (current_link_name, skipcrud + current_file_name); + + if (check == 0) + break; + if (make_dirs (skipcrud + current_file_name)) + goto again_link; + if (f_gnudump && errno == EEXIST) + break; + if (stat (current_link_name, &st1) == 0 + && stat (current_file_name + skipcrud, &st2) == 0 + && st1.st_dev == st2.st_dev + && st1.st_ino == st2.st_ino) + break; + msg_perror ("Could not link %s to %s", + skipcrud + current_file_name, + current_link_name); + } + break; #ifdef S_ISLNK - case LF_SYMLINK: - again_symlink: - check = symlink(current_link_name, - skipcrud + current_file_name); - /* FIXME, don't worry uid, gid, etc... */ - if (check == 0) - break; - if (make_dirs(current_file_name + skipcrud)) - goto again_symlink; - msg_perror("Could not create symlink to %s", - current_link_name); - break; + case LF_SYMLINK: + again_symlink: + check = symlink (current_link_name, + skipcrud + current_file_name); + /* FIXME, don't worry uid, gid, etc... */ + if (check == 0) + break; + if (make_dirs (current_file_name + skipcrud)) + goto again_symlink; + msg_perror ("Could not create symlink to %s", + current_link_name); + break; #endif #ifdef S_IFCHR - case LF_CHR: - hstat.st_mode |= S_IFCHR; - goto make_node; + case LF_CHR: + hstat.st_mode |= S_IFCHR; + goto make_node; #endif #ifdef S_IFBLK - case LF_BLK: - hstat.st_mode |= S_IFBLK; + case LF_BLK: + hstat.st_mode |= S_IFBLK; #endif #if defined(S_IFCHR) || defined(S_IFBLK) - make_node: - check = mknod(current_file_name + skipcrud, - (int) hstat.st_mode, (int) hstat.st_rdev); - if (check != 0) { - if (make_dirs(skipcrud + current_file_name)) - goto make_node; - msg_perror("Could not make %s", - current_file_name + skipcrud); - break; - }; - goto set_filestat; + make_node: + check = mknod (current_file_name + skipcrud, + (int) hstat.st_mode, (int) hstat.st_rdev); + if (check != 0) + { + if (make_dirs (skipcrud + current_file_name)) + goto make_node; + msg_perror ("Could not make %s", + current_file_name + skipcrud); + break; + }; + goto set_filestat; #endif #ifdef S_ISFIFO - /* If local system doesn't support FIFOs, use default case */ - case LF_FIFO: - make_fifo: - check = mkfifo(current_file_name + skipcrud, - (int) hstat.st_mode); - if (check != 0) { - if (make_dirs(current_file_name + skipcrud)) - goto make_fifo; - msg_perror("Could not make %s", - skipcrud + current_file_name); - break; - }; - goto set_filestat; + /* If local system doesn't support FIFOs, use default case */ + case LF_FIFO: + make_fifo: + check = mkfifo (current_file_name + skipcrud, + (int) hstat.st_mode); + if (check != 0) + { + if (make_dirs (current_file_name + skipcrud)) + goto make_fifo; + msg_perror ("Could not make %s", + skipcrud + current_file_name); + break; + }; + goto set_filestat; #endif - case LF_DIR: - case LF_DUMPDIR: - namelen = strlen(current_file_name) + skipcrud - 1; - really_dir: - /* Check for trailing /, and zap as many as we find. */ - while (namelen - && current_file_name[skipcrud+namelen] == '/') - current_file_name[skipcrud+namelen--] = '\0'; - if(f_gnudump) { /* Read the entry and delete files + case LF_DIR: + case LF_DUMPDIR: + namelen = strlen (current_file_name) + skipcrud - 1; + really_dir: + /* Check for trailing /, and zap as many as we find. */ + while (namelen + && current_file_name[skipcrud + namelen] == '/') + current_file_name[skipcrud + namelen--] = '\0'; + if (f_gnudump) + { /* Read the entry and delete files that aren't listed in the archive */ - gnu_restore(skipcrud); - - } else if(head->header.linkflag==LF_DUMPDIR) - skip_file((long)(hstat.st_size)); - - - again_dir: - check = mkdir(skipcrud+current_file_name, - (we_are_root ? 0 : 0300) | (int)hstat.st_mode); - if (check != 0) { - struct stat st1; - - if (make_dirs(skipcrud+current_file_name)) - goto again_dir; - /* If we're trying to create '.', let it be. */ - if (current_file_name[skipcrud+namelen] == '.' && - (namelen==0 || - current_file_name[skipcrud+namelen-1]=='/')) - goto check_perms; - if( errno==EEXIST - && stat(skipcrud+current_file_name,&st1)==0 - && (S_ISDIR(st1.st_mode))) - break; - msg_perror("Could not create directory %s",skipcrud+current_file_name); - break; - } - - check_perms: - if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) { - hstat.st_mode |= 0300; - msg("Added write and execute permission to directory %s", - skipcrud+current_file_name); - } + gnu_restore (skipcrud); - if (f_modified) - goto set_filestat; - tmp = (struct saved_dir_info *) malloc (sizeof (struct saved_dir_info)); - tmp->path = malloc (strlen (skipcrud + current_file_name) + 1); - strcpy (tmp->path, skipcrud + current_file_name); - tmp->mode = hstat.st_mode; - tmp->atime = hstat.st_atime; - tmp->mtime = hstat.st_mtime; - tmp->next = saved_dir_info_head; - saved_dir_info_head = tmp; - case LF_VOLHDR: - if(f_verbose) { - printf("Reading %s\n", current_file_name); - } - break; + } + else if (head->header.linkflag == LF_DUMPDIR) + skip_file ((long) (hstat.st_size)); - case LF_NAMES: - extract_mangle(head); - break; - case LF_MULTIVOL: - msg("Can't extract '%s'--file is continued from another volume\n",current_file_name); - skip_file((long)hstat.st_size); - break; + again_dir: + check = mkdir (skipcrud + current_file_name, + (we_are_root ? 0 : 0300) | (int) hstat.st_mode); + if (check != 0) + { + struct stat st1; + + if (make_dirs (skipcrud + current_file_name)) + goto again_dir; + /* If we're trying to create '.', let it be. */ + if (current_file_name[skipcrud + namelen] == '.' && + (namelen == 0 || + current_file_name[skipcrud + namelen - 1] == '/')) + goto check_perms; + if (errno == EEXIST + && stat (skipcrud + current_file_name, &st1) == 0 + && (S_ISDIR (st1.st_mode))) + break; + msg_perror ("Could not create directory %s", skipcrud + current_file_name); + break; + } + + check_perms: + if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) + { + hstat.st_mode |= 0300; + msg ("Added write and execute permission to directory %s", + skipcrud + current_file_name); + } - case LF_LONGNAME: - case LF_LONGLINK: - msg ("Visible long name error\n"); - skip_file ((long)hstat.st_size); - break; - } - - /* We don't need to save it any longer. */ - saverec((union record **) 0); /* Unsave it */ + if (f_modified) + goto set_filestat; + tmp = (struct saved_dir_info *) malloc (sizeof (struct saved_dir_info)); + tmp->path = malloc (strlen (skipcrud + current_file_name) + 1); + strcpy (tmp->path, skipcrud + current_file_name); + tmp->mode = hstat.st_mode; + tmp->atime = hstat.st_atime; + tmp->mtime = hstat.st_mtime; + tmp->next = saved_dir_info_head; + saved_dir_info_head = tmp; + case LF_VOLHDR: + if (f_verbose) + { + printf ("Reading %s\n", current_file_name); + } + break; + + case LF_NAMES: + extract_mangle (head); + break; + + case LF_MULTIVOL: + msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name); + skip_file ((long) hstat.st_size); + break; + + case LF_LONGNAME: + case LF_LONGLINK: + msg ("Visible long name error\n"); + skip_file ((long) hstat.st_size); + break; + } + + /* We don't need to save it any longer. */ + saverec ((union record **) 0);/* Unsave it */ } /* @@ -692,112 +725,121 @@ extract_archive() * so, create all required dirs. */ int -make_dirs(pathname) - char *pathname; +make_dirs (pathname) + char *pathname; { - char *p; /* Points into path */ - int madeone = 0; /* Did we do anything yet? */ - int save_errno = errno; /* Remember caller's errno */ - int check; - - if (errno != ENOENT) - return 0; /* Not our problem */ - - for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) { - /* Avoid mkdir of empty string, if leading or double '/' */ - if (p == pathname || p[-1] == '/') - continue; - /* Avoid mkdir where last part of path is '.' */ - if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/')) - continue; - *p = 0; /* Truncate the path there */ - check = mkdir (pathname, 0777); /* Try to create it as a dir */ - if (check == 0) { - /* Fix ownership */ - if (we_are_root) { - if (chown(pathname, hstat.st_uid, - hstat.st_gid) < 0) { - msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid); - } - } - pr_mkdir(pathname, p-pathname, notumask&0777); - madeone++; /* Remember if we made one */ - *p = '/'; - continue; + char *p; /* Points into path */ + int madeone = 0; /* Did we do anything yet? */ + int save_errno = errno; /* Remember caller's errno */ + int check; + + if (errno != ENOENT) + return 0; /* Not our problem */ + + for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/')) + { + /* Avoid mkdir of empty string, if leading or double '/' */ + if (p == pathname || p[-1] == '/') + continue; + /* Avoid mkdir where last part of path is '.' */ + if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/')) + continue; + *p = 0; /* Truncate the path there */ + check = mkdir (pathname, 0777); /* Try to create it as a dir */ + if (check == 0) + { + /* Fix ownership */ + if (we_are_root) + { + if (chown (pathname, hstat.st_uid, + hstat.st_gid) < 0) + { + msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid); } - *p = '/'; - if (errno == EEXIST) /* Directory already exists */ - continue; - /* + } + pr_mkdir (pathname, p - pathname, notumask & 0777); + madeone++; /* Remember if we made one */ + *p = '/'; + continue; + } + *p = '/'; + if (errno == EEXIST) /* Directory already exists */ + continue; + /* * Some other error in the mkdir. We return to the caller. */ - break; - } + break; + } - errno = save_errno; /* Restore caller's errno */ - return madeone; /* Tell them to retry if we made one */ + errno = save_errno; /* Restore caller's errno */ + return madeone; /* Tell them to retry if we made one */ } void -extract_sparse_file(fd, sizeleft, totalsize, name) - int fd; - long *sizeleft, - totalsize; - char *name; -{ -/* register char *data;*/ - union record *datarec; - int sparse_ind = 0; - int written, - count; - - /* assuming sizeleft is initially totalsize */ - - - while (*sizeleft > 0) { - datarec = findrec(); - if (datarec == NULL) { - msg("Unexpected EOF on archive file"); - return; - } - lseek(fd, sparsearray[sparse_ind].offset, 0); - written = sparsearray[sparse_ind++].numbytes; - while (written > RECORDSIZE) { - count = write(fd, datarec->charptr, RECORDSIZE); - if (count < 0) - msg_perror("couldn't write to file %s", name); - written -= count; - *sizeleft -= count; - userec(datarec); - datarec = findrec(); - } +extract_sparse_file (fd, sizeleft, totalsize, name) + int fd; + long *sizeleft, totalsize; + char *name; +{ + /* register char *data;*/ + union record *datarec; + int sparse_ind = 0; + int written, count; + + /* assuming sizeleft is initially totalsize */ - count = write(fd, datarec->charptr, written); - - if (count < 0) { - msg_perror("couldn't write to file %s", name); - } else if (count != written) { - msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name); - skip_file((long) (*sizeleft)); - } - written -= count; - *sizeleft -= count; - userec(datarec); + while (*sizeleft > 0) + { + datarec = findrec (); + if (datarec == NULL) + { + msg ("Unexpected EOF on archive file"); + return; } - free(sparsearray); -/* if (end_nulls) { + lseek (fd, sparsearray[sparse_ind].offset, 0); + written = sparsearray[sparse_ind++].numbytes; + while (written > RECORDSIZE) + { + count = write (fd, datarec->charptr, RECORDSIZE); + if (count < 0) + msg_perror ("couldn't write to file %s", name); + written -= count; + *sizeleft -= count; + userec (datarec); + datarec = findrec (); + } + + count = write (fd, datarec->charptr, written); + + if (count < 0) + { + msg_perror ("couldn't write to file %s", name); + } + else if (count != written) + { + msg ("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name); + skip_file ((long) (*sizeleft)); + } + + written -= count; + *sizeleft -= count; + userec (datarec); + } + free (sparsearray); + /* if (end_nulls) { register int i; printf("%d\n", (int) end_nulls); for (i = 0; i < end_nulls; i++) write(fd, "\000", 1); }*/ - userec(datarec); + userec (datarec); } /* Set back the utime and mode for all the extracted directories. */ -void restore_saved_dir_info () +void +restore_saved_dir_info () { struct utimbuf acc_upd_times; struct saved_dir_info *tmp; @@ -805,24 +847,26 @@ void restore_saved_dir_info () while (saved_dir_info_head != NULL) { /* fixme if f_gnudump should set ctime too, but how? */ - if(f_gnudump) - acc_upd_times.actime=saved_dir_info_head -> atime; - else - acc_upd_times.actime = now; /* Accessed now */ - acc_upd_times.modtime = saved_dir_info_head -> mtime; /* Mod'd */ - if (utime(saved_dir_info_head -> path, &acc_upd_times) < 0) { - msg_perror("couldn't change access and modification times of %s", - saved_dir_info_head -> path); - } - if ((!f_keep) || (saved_dir_info_head -> mode & (S_ISUID|S_ISGID|S_ISVTX))) + if (f_gnudump) + acc_upd_times.actime = saved_dir_info_head->atime; + else + acc_upd_times.actime = now; /* Accessed now */ + acc_upd_times.modtime = saved_dir_info_head->mtime; /* Mod'd */ + if (utime (saved_dir_info_head->path, &acc_upd_times) < 0) { - if (chmod(saved_dir_info_head -> path, - notumask & saved_dir_info_head -> mode) < 0) { - msg_perror("cannot change mode of file %s to %ld", - saved_dir_info_head -> path, - notumask & saved_dir_info_head -> mode); - } + msg_perror ("couldn't change access and modification times of %s", + saved_dir_info_head->path); + } + if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX))) + { + if (chmod (saved_dir_info_head->path, + notumask & saved_dir_info_head->mode) < 0) + { + msg_perror ("cannot change mode of file %s to %ld", + saved_dir_info_head->path, + notumask & saved_dir_info_head->mode); + } } - saved_dir_info_head = saved_dir_info_head -> next; + saved_dir_info_head = saved_dir_info_head->next; } }