From: François Pinard Date: Wed, 16 Nov 1994 02:45:55 +0000 (+0000) Subject: *** empty log message *** X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;h=5b394b2c7eb52752e8ccb0ba36f580c46c6c8baa;p=chaz%2Ftar *** empty log message *** --- diff --git a/src/extract.c b/src/extract.c index 4a989a3..ff86642 100644 --- a/src/extract.c +++ b/src/extract.c @@ -145,6 +145,9 @@ extract_archive() union record *exhdr; struct saved_dir_info *tmp; /* int end_nulls; */ + char **longp; + static char *longname; + static char *longlink; saverec(&head); /* Make sure it sticks around */ userec(head); /* And go past it in the archive */ @@ -177,298 +180,298 @@ extract_archive() skipcrud++; /* Force relative path */ if (!warned_once++) { msg("Removing leading / from absolute path names in the archive."); - } - } - - switch (head->header.linkflag) { - - default: - msg("Unknown file type '%c' for %s, extracted as normal file", - head->header.linkflag, skipcrud+head->header.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 - * at which to write and 2) how many bytes to write into numbers, - * which we store into the scratch array, "sparsearray". This - * array makes our life easier the same way it did in creating - * 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., - * 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 - as before */ - - /* static */ int ind = SPARSE_IN_HDR; - - for (;;) { - - exhdr = findrec(); - for (i = 0; i < SPARSE_EXT_HDR; i++) { - - 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: - /* - * Appears to be a file. - * See if it's really a directory. - */ - namelen = strlen(skipcrud+head->header.name)-1; - if (head->header.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 - * with O_APPEND, it writes to the last place - * that something was written, thereby ignoring - * any lseeks that we have done. We add this - * extra condition to make it able to lseek when - * a file is sparse, i.e., we don't open the new - * file with this flag. (Grump -- this bug caused - * me to waste a good deal of time, I might add) - */ - - 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(skipcrud+head->header.name, 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(skipcrud+head->header.name, - hstat.st_mode); -#else - /* - * With 3-arg open(), we can do this up right. - */ - fd = open(skipcrud+head->header.name, openflag, - hstat.st_mode); -#endif - } - - if (fd < 0) { - if (make_dirs(skipcrud+head->header.name)) - goto again_file; - msg_perror("Could not create file %s",skipcrud+head->header.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 - * the name will get munged, so any error messages - * that happen to contain the filename will look - * REAL interesting unless we do this. - */ - namelen = strlen(skipcrud+head->header.name); - name = (char *) malloc((sizeof(char)) * namelen); - bcopy(skipcrud+head->header.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=head->header.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; - } - /* - * 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) { - 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); - /* - * 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; - /* - * 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+head->header.name); - else - msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.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 (head->header.isextended) { - register union record *exhdr; - register int i; - - for (i = 0; i < 21; i++) { - long offset; - - if (!exhdr->ext_hdr.sp[i].numbytes) - break; - offset = from_oct(1+12, - exhdr->ext_hdr.sp[i].offset); - written = from_oct(1+12, - exhdr->ext_hdr.sp[i].numbytes); - lseek(fd, offset, 0); - check = write(fd, data, written); - if (check == written) continue; - - } - - - }*/ - check = close(fd); - if (check < 0) { - msg_perror("Error while closing %s",skipcrud+head->header.name); - } - - - 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+head->header.name, hstat.st_uid, - hstat.st_gid) < 0) { - msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.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? */ + } + } + + switch (head->header.linkflag) { + + default: + msg("Unknown file type '%c' for %s, extracted as normal file", + head->header.linkflag, skipcrud+head->header.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 + * at which to write and 2) how many bytes to write into numbers, + * which we store into the scratch array, "sparsearray". This + * array makes our life easier the same way it did in creating + * 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., + * 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 + as before */ + + /* static */ int ind = SPARSE_IN_HDR; + + for (;;) { + + exhdr = findrec(); + for (i = 0; i < SPARSE_EXT_HDR; i++) { + + 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: + /* + * Appears to be a file. + * See if it's really a directory. + */ + namelen = strlen(skipcrud+head->header.name)-1; + if (head->header.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 + * with O_APPEND, it writes to the last place + * that something was written, thereby ignoring + * any lseeks that we have done. We add this + * extra condition to make it able to lseek when + * a file is sparse, i.e., we don't open the new + * file with this flag. (Grump -- this bug caused + * me to waste a good deal of time, I might add) + */ + + 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(skipcrud+head->header.name, 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(skipcrud+head->header.name, + hstat.st_mode); + #else + /* + * With 3-arg open(), we can do this up right. + */ + fd = open(skipcrud+head->header.name, openflag, + hstat.st_mode); + #endif + } + + if (fd < 0) { + if (make_dirs(skipcrud+head->header.name)) + goto again_file; + msg_perror("Could not create file %s",skipcrud+head->header.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 + * the name will get munged, so any error messages + * that happen to contain the filename will look + * REAL interesting unless we do this. + */ + namelen = strlen(skipcrud+head->header.name); + name = (char *) malloc((sizeof(char)) * namelen); + bcopy(skipcrud+head->header.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=head->header.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; + } + /* + * 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) { + 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); + /* + * 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; + /* + * 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+head->header.name); + else + msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.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 (head->header.isextended) { + register union record *exhdr; + register int i; + + for (i = 0; i < 21; i++) { + long offset; + + if (!exhdr->ext_hdr.sp[i].numbytes) + break; + offset = from_oct(1+12, + exhdr->ext_hdr.sp[i].offset); + written = from_oct(1+12, + exhdr->ext_hdr.sp[i].numbytes); + lseek(fd, offset, 0); + check = write(fd, data, written); + if (check == written) continue; + + } + + + }*/ + check = close(fd); + if (check < 0) { + msg_perror("Error while closing %s",skipcrud+head->header.name); + } + + + 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+head->header.name, hstat.st_uid, + hstat.st_gid) < 0) { + msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.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[0]=hstat.st_atime; else acc_upd_times[0] = now; /* Accessed now */ @@ -649,6 +652,28 @@ extract_archive() skip_file((long)hstat.st_size); break; + case LF_LONGNAME: + longp = &longname; + goto extract_long; + + case LF_LONGLINK + longp = &longlink; + extract_long: + + if (*longp) + free (*longp); + *longp = ck_malloc (hstat.st_size); + + /* This loop is copied from the extract_file label above; + as a result, some of the variable names (like `written') + might be confusing. */ + for (size = hstat.st_size; + size > 0; + size -= written) + { + + + } /* We don't need to save it any longer. */