/* * Return the location of the next available input or output record. */ union record *findrec( void ) { if (ar_record == ar_last) { flush_archive(); if (ar_record == ar_last) return (union record *) NULL; /* EOF */ } return ar_record; }
/* * Return the location of the next available input or output record. * Return NULL for EOF. Once we have returned NULL, we just keep returning * it, to avoid accidentally going on to the next file on the "tape". */ union record * findrec() { if (ar_record == ar_last) { if (hit_eof) return (union record *)NULL; /* EOF */ flush_archive(); if (ar_record == ar_last) { hit_eof++; return (union record *)NULL; /* EOF */ } } return ar_record; }
/* * Close the archive file. */ void close_archive(void) { #ifndef MSDOS int child; int status; #endif if (!ar_reading) flush_archive(); (void) close(archive); #ifndef MSDOS if (f_compress) { /* * Loop waiting for the right child to die, or for no more kids. */ while (((child = wait(&status)) != compress_pid) && child != -1) ; if (child != -1) { switch (TERM_SIGNAL(status)) { case 0: /* Terminated by itself */ if (TERM_VALUE(status) == MAGIC_STAT) { exit(EX_SYSTEM); /* Child had trouble */ } if (TERM_VALUE(status)) fprintf(stderr, "tar: compress child returned status %d\n", TERM_VALUE(status)); #ifdef SIGPIPE case SIGPIPE: break; /* This is OK. */ #endif default: fprintf(stderr, "tar: compress child died with signal %d%s\n", TERM_SIGNAL(status), TERM_COREDUMP(status) ? " (core dumped)" : ""); } } } #endif /* MSDOS */ }
void delete_archive_members (void) { enum read_header logical_status = HEADER_STILL_UNREAD; enum read_header previous_status = HEADER_STILL_UNREAD; /* FIXME: Should clean the routine before cleaning these variables :-( */ struct name *name; off_t blocks_to_skip = 0; off_t blocks_to_keep = 0; int kept_blocks_in_record; name_gather (); open_archive (ACCESS_UPDATE); acting_as_filter = strcmp (archive_name_array[0], "-") == 0; do { enum read_header status = read_header (true); switch (status) { case HEADER_STILL_UNREAD: abort (); case HEADER_SUCCESS: if ((name = name_scan (current_stat_info.file_name)) == NULL) { skip_member (); break; } name->found_count++; if (!ISFOUND(name)) { skip_member (); break; } /* Fall through. */ case HEADER_SUCCESS_EXTENDED: logical_status = status; break; case HEADER_ZERO_BLOCK: if (ignore_zeros_option) { set_next_block_after (current_header); break; } /* Fall through. */ case HEADER_END_OF_FILE: logical_status = HEADER_END_OF_FILE; break; case HEADER_FAILURE: set_next_block_after (current_header); switch (previous_status) { case HEADER_STILL_UNREAD: WARN ((0, 0, _("This does not look like a tar archive"))); /* Fall through. */ case HEADER_SUCCESS: case HEADER_SUCCESS_EXTENDED: case HEADER_ZERO_BLOCK: ERROR ((0, 0, _("Skipping to next header"))); /* Fall through. */ case HEADER_FAILURE: break; case HEADER_END_OF_FILE: abort (); } break; } previous_status = status; } while (logical_status == HEADER_STILL_UNREAD); records_skipped = records_read - 1; new_record = xmalloc (record_size); if (logical_status == HEADER_SUCCESS || logical_status == HEADER_SUCCESS_EXTENDED) { write_archive_to_stdout = false; /* Save away blocks before this one in this record. */ new_blocks = current_block - record_start; if (new_blocks) memcpy (new_record, record_start, new_blocks * BLOCKSIZE); if (logical_status == HEADER_SUCCESS) { /* FIXME: Pheew! This is crufty code! */ logical_status = HEADER_STILL_UNREAD; goto flush_file; } /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says: "delete.c", line 223: warning: loop not entered at top Reported by Bruno Haible. */ while (1) { enum read_header status; /* Fill in a record. */ if (current_block == record_end) flush_archive (); status = read_header (false); xheader_decode (¤t_stat_info); if (status == HEADER_ZERO_BLOCK && ignore_zeros_option) { set_next_block_after (current_header); continue; } if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK) { logical_status = HEADER_END_OF_FILE; break; } if (status == HEADER_FAILURE) { ERROR ((0, 0, _("Deleting non-header from archive"))); set_next_block_after (current_header); continue; } /* Found another header. */ if ((name = name_scan (current_stat_info.file_name)) != NULL) { name->found_count++; if (ISFOUND(name)) { flush_file: set_next_block_after (current_header); blocks_to_skip = (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE; while (record_end - current_block <= blocks_to_skip) { blocks_to_skip -= (record_end - current_block); flush_archive (); } current_block += blocks_to_skip; blocks_to_skip = 0; continue; } } /* Copy header. */ if (extended_header.size) { write_recent_bytes (extended_header.buffer, extended_header.size); } else { write_recent_blocks (recent_long_name, recent_long_name_blocks); write_recent_blocks (recent_long_link, recent_long_link_blocks); } new_record[new_blocks] = *current_header; new_blocks++; blocks_to_keep = (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE; set_next_block_after (current_header); if (new_blocks == blocking_factor) write_record (1); /* Copy data. */ kept_blocks_in_record = record_end - current_block; if (kept_blocks_in_record > blocks_to_keep) kept_blocks_in_record = blocks_to_keep; while (blocks_to_keep) { int count; if (current_block == record_end) { flush_read (); current_block = record_start; kept_blocks_in_record = blocking_factor; if (kept_blocks_in_record > blocks_to_keep) kept_blocks_in_record = blocks_to_keep; } count = kept_blocks_in_record; if (blocking_factor - new_blocks < count) count = blocking_factor - new_blocks; if (! count) abort (); memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE); new_blocks += count; current_block += count; blocks_to_keep -= count; kept_blocks_in_record -= count; if (new_blocks == blocking_factor) write_record (1); } } if (logical_status == HEADER_END_OF_FILE) { /* Write the end of tape. FIXME: we can't use write_eot here, as it gets confused when the input is at end of file. */ int total_zero_blocks = 0; do { int zero_blocks = blocking_factor - new_blocks; memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks); total_zero_blocks += zero_blocks; write_record (total_zero_blocks < 2); } while (total_zero_blocks < 2); } if (! acting_as_filter && ! _isrmt (archive)) { if (sys_truncate (archive)) truncate_warn (archive_name_array[0]); } } free (new_record); close_archive (); names_notfound (); }
void delete_archive_members (void) { enum read_header logical_status = HEADER_STILL_UNREAD; enum read_header previous_status = HEADER_STILL_UNREAD; /* FIXME: Should clean the routine before cleaning these variables :-( */ struct name *name; int blocks_to_skip = 0; int blocks_to_keep = 0; int kept_blocks_in_record; name_gather (); open_archive (ACCESS_UPDATE); while (logical_status == HEADER_STILL_UNREAD) { enum read_header status = read_header (); switch (status) { case HEADER_STILL_UNREAD: abort (); case HEADER_SUCCESS: if (name = name_scan (current_file_name), !name) { set_next_block_after (current_header); if (current_header->oldgnu_header.isextended) skip_extended_headers (); skip_file ((long) (current_stat.st_size)); break; } name->found = 1; logical_status = HEADER_SUCCESS; break; case HEADER_ZERO_BLOCK: case HEADER_END_OF_FILE: logical_status = HEADER_END_OF_FILE; break; case HEADER_FAILURE: set_next_block_after (current_header); switch (previous_status) { case HEADER_STILL_UNREAD: WARN ((0, 0, _("This does not look like a tar archive"))); /* Fall through. */ case HEADER_SUCCESS: case HEADER_ZERO_BLOCK: ERROR ((0, 0, _("Skipping to next header"))); /* Fall through. */ case HEADER_FAILURE: break; case HEADER_END_OF_FILE: abort (); } break; } previous_status = status; } if (logical_status != HEADER_SUCCESS) { write_eot (); close_archive (); names_notfound (); return; } write_archive_to_stdout = 0; new_record = (union block *) xmalloc ((size_t) record_size); /* Save away blocks before this one in this record. */ new_blocks = current_block - record_start; blocks_needed = blocking_factor - new_blocks; if (new_blocks) memcpy ((void *) new_record, (void *) record_start, (size_t) (new_blocks * BLOCKSIZE)); #if 0 /* FIXME: Old code, before the goto was inserted. To be redesigned. */ set_next_block_after (current_header); if (current_header->oldgnu_header.isextended) skip_extended_headers (); skip_file ((long) (current_stat.st_size)); #endif logical_status = HEADER_STILL_UNREAD; goto flush_file; /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says: "delete.c", line 223: warning: loop not entered at top Reported by Bruno Haible. */ while (1) { enum read_header status; /* Fill in a record. */ if (current_block == record_end) { flush_archive (); records_read++; } status = read_header (); if (status == HEADER_ZERO_BLOCK && ignore_zeros_option) { set_next_block_after (current_header); continue; } if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK) { logical_status = HEADER_END_OF_FILE; memset (new_record[new_blocks].buffer, 0, (size_t) (BLOCKSIZE * blocks_needed)); new_blocks += blocks_needed; blocks_needed = 0; write_record (0); break; } if (status == HEADER_FAILURE) { ERROR ((0, 0, _("Deleting non-header from archive"))); set_next_block_after (current_header); continue; } /* Found another header. */ if (name = name_scan (current_file_name), name) { name->found = 1; flush_file: set_next_block_after (current_header); blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE; while (record_end - current_block <= blocks_to_skip) { blocks_to_skip -= (record_end - current_block); flush_archive (); records_read++; } current_block += blocks_to_skip; blocks_to_skip = 0; continue; } /* Copy header. */ new_record[new_blocks] = *current_header; new_blocks++; blocks_needed--; blocks_to_keep = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE; set_next_block_after (current_header); if (blocks_needed == 0) write_record (1); /* Copy data. */ kept_blocks_in_record = record_end - current_block; if (kept_blocks_in_record > blocks_to_keep) kept_blocks_in_record = blocks_to_keep; while (blocks_to_keep) { int count; if (current_block == record_end) { flush_read (); records_read++; current_block = record_start; kept_blocks_in_record = blocking_factor; if (kept_blocks_in_record > blocks_to_keep) kept_blocks_in_record = blocks_to_keep; } count = kept_blocks_in_record; if (count > blocks_needed) count = blocks_needed; memcpy ((void *) (new_record + new_blocks), (void *) current_block, (size_t) (count * BLOCKSIZE)); new_blocks += count; blocks_needed -= count; current_block += count; blocks_to_keep -= count; kept_blocks_in_record -= count; if (blocks_needed == 0) write_record (1); } } write_eot (); close_archive (); names_notfound (); }
/* * Open an archive file. The argument specifies whether we are * reading or writing. * * With DOS, we ALWAYS open the archive in binary mode: whether or not * to do CRLF translations depends on whether we open the input files * as binary or ASCII, but we always write the archive without making * any translations from what this program saw when it did the write. */ void open_archive( int read ) { if (ar_file[0] == '-' && ar_file[1] == '\0') { if (read) archive = STDIN; else archive = STDOUT; } else if (read) { #if defined(MSDOS) && !defined(__NO_PHYS__) archive = 9999; /* for debugging - invalid fd to cause err */ if (!f_phys) /* don't open if we're doing direct drive I/O */ #endif archive = open(ar_file, O_RDONLY #ifdef MSDOS | O_BINARY #endif ); } else { #if defined(MSDOS) && !defined(__NO_PHYS__) archive = 9999; if (!f_phys) #endif #ifdef V7 archive = creat(ar_file, 0666); #else archive = open(ar_file, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666); #endif } if (archive < 0) { perror(ar_file); exit(EX_BADARCH); } /* NOSTRICT */ ar_block = (union record *) valloc((unsigned) blocksize); if (!ar_block) { fprintf(stderr, "tar: could not allocate memory for blocking factor %d\n", blocking); exit(EX_ARGSBAD); } ar_record = ar_block; ar_last = ar_block + blocking; /* * Handle compressed archives. * * FIXME, currently supported for reading only. FIXME, writing involves * forking again for a small process that will reblock the output of * compress to the user's specs. */ #ifndef MSDOS if (f_compress) { int pipes[2]; int err; if (!read) { fprintf(stderr, "tar: cannot write compressed archives yet.\n"); exit(EX_ARGSBAD); } /* Create a pipe to get compress's output to us */ err = pipe(pipes); if (err < 0) { perror("tar: cannot create pipe to compress"); exit(EX_SYSTEM); } /* Fork compress process */ compress_pid = fork(); if (compress_pid < 0) { perror("tar: cannot fork compress"); exit(EX_SYSTEM); } /* * Child process. * * Move input to stdin, write side of pipe to stdout, then exec * compress. */ if (compress_pid == 0) { (void) close(pipes[PREAD]); /* We won't use it */ if (archive != STDIN) { (void) close(STDIN); err = dup(archive); if (err != 0) { perror( "tar: cannot dup input to stdin"); exit(EX_SYSTEM); } (void) close(archive); } if (pipes[PWRITE] != STDOUT) { (void) close(STDOUT); err = dup(pipes[PWRITE]); if (err != STDOUT) { perror( "tar: cannot dup pipe output"); exit(MAGIC_STAT); } (void) close(pipes[PWRITE]); } #ifdef V7 execl("/usr/bin/compress", "compress", "-d", (char *)0); #else execlp("compress", "compress", "-d", (char *) 0); #endif perror("tar: cannot exec compress"); exit(MAGIC_STAT); } /* * Parent process. Clean up. FIXME, note that this may leave * standard input closed, if the compressed archive was on standard * input. */ (void) close(archive); /* Close compressed archive */ (void) close(pipes[PWRITE]); /* Close write side of pipe */ archive = pipes[PREAD]; /* Read side is our archive */ #ifdef BSD42 f_reblock++; /* Pipe will give random # of bytes */ #endif /* BSD42 */ } #endif /* MSDOS */ ar_reading = read; if (read) { ar_last = ar_block; /* Set up for 1st block = # 0 */ flush_archive(); } }
void delete_archive_members (void) { enum read_header logical_status = HEADER_STILL_UNREAD; enum read_header previous_status = HEADER_STILL_UNREAD; /* FIXME: Should clean the routine before cleaning these variables :-( */ struct name *name; off_t blocks_to_skip = 0; off_t blocks_to_keep = 0; int kept_blocks_in_record; name_gather (); open_archive (ACCESS_UPDATE); acting_as_filter = strcmp (archive_name_array[0], "-") == 0; do { enum read_header status = read_header (); switch (status) { case HEADER_STILL_UNREAD: abort (); case HEADER_SUCCESS: if (name = name_scan (current_file_name), !name) { skip_member (); break; } name->found = 1; logical_status = HEADER_SUCCESS; break; case HEADER_ZERO_BLOCK: if (ignore_zeros_option) { set_next_block_after (current_header); break; } /* Fall through. */ case HEADER_END_OF_FILE: logical_status = HEADER_END_OF_FILE; break; case HEADER_FAILURE: set_next_block_after (current_header); switch (previous_status) { case HEADER_STILL_UNREAD: WARN ((0, 0, _("This does not look like a tar archive"))); /* Fall through. */ case HEADER_SUCCESS: case HEADER_ZERO_BLOCK: ERROR ((0, 0, _("Skipping to next header"))); /* Fall through. */ case HEADER_FAILURE: break; case HEADER_END_OF_FILE: abort (); } break; } previous_status = status; } while (logical_status == HEADER_STILL_UNREAD); new_record = xmalloc (record_size); if (logical_status == HEADER_SUCCESS) { write_archive_to_stdout = 0; /* Save away blocks before this one in this record. */ new_blocks = current_block - record_start; if (new_blocks) memcpy (new_record, record_start, new_blocks * BLOCKSIZE); #if 0 /* FIXME: Old code, before the goto was inserted. To be redesigned. */ skip_member (); #endif logical_status = HEADER_STILL_UNREAD; goto flush_file; /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says: "delete.c", line 223: warning: loop not entered at top Reported by Bruno Haible. */ while (1) { enum read_header status; /* Fill in a record. */ if (current_block == record_end) { flush_archive (); records_read++; } status = read_header (); if (status == HEADER_ZERO_BLOCK && ignore_zeros_option) { set_next_block_after (current_header); continue; } if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK) { logical_status = HEADER_END_OF_FILE; break; } if (status == HEADER_FAILURE) { ERROR ((0, 0, _("Deleting non-header from archive"))); set_next_block_after (current_header); continue; } /* Found another header. */ if (name = name_scan (current_file_name), name) { name->found = 1; flush_file: set_next_block_after (current_header); blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE; while (record_end - current_block <= blocks_to_skip) { blocks_to_skip -= (record_end - current_block); flush_archive (); records_read++; } current_block += blocks_to_skip; blocks_to_skip = 0; continue; } /* Copy header. */ new_record[new_blocks] = *current_header; new_blocks++; blocks_to_keep = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE; set_next_block_after (current_header); if (new_blocks == blocking_factor) write_record (1); /* Copy data. */ kept_blocks_in_record = record_end - current_block; if (kept_blocks_in_record > blocks_to_keep) kept_blocks_in_record = blocks_to_keep; while (blocks_to_keep) { int count; if (current_block == record_end) { flush_read (); records_read++; current_block = record_start; kept_blocks_in_record = blocking_factor; if (kept_blocks_in_record > blocks_to_keep) kept_blocks_in_record = blocks_to_keep; } count = kept_blocks_in_record; if (blocking_factor - new_blocks < count) count = blocking_factor - new_blocks; if (! count) abort (); memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE); new_blocks += count; current_block += count; blocks_to_keep -= count; kept_blocks_in_record -= count; if (new_blocks == blocking_factor) write_record (1); } } } if (logical_status == HEADER_END_OF_FILE) { /* Write the end of tape. FIXME: we can't use write_eot here, as it gets confused when the input is at end of file. */ int total_zero_blocks = 0; do { int zero_blocks = blocking_factor - new_blocks; memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks); total_zero_blocks += zero_blocks; write_record (total_zero_blocks < 2); } while (total_zero_blocks < 2); } free (new_record); if (! acting_as_filter && ! _isrmt (archive)) { #if MSDOS int status = write (archive, "", 0); #else off_t pos = lseek (archive, (off_t) 0, SEEK_CUR); int status = pos < 0 ? -1 : ftruncate (archive, pos); #endif if (status != 0) truncate_warn (archive_name_array[0]); } close_archive (); names_notfound (); }