static void read_and_process (long size, int (*processor) (long, char *)) { union block *data_block; long data_size; if (multi_volume_option) save_sizeleft = size; while (size) { data_block = find_next_block (); if (data_block == NULL) { ERROR ((0, 0, _("Unexpected EOF on archive file"))); return; } data_size = available_space_after (data_block); if (data_size > size) data_size = size; if (!(*processor) (data_size, data_block->buffer)) processor = process_noop; set_next_block_after ((union block *) (data_block->buffer + data_size - 1)); size -= data_size; if (multi_volume_option) save_sizeleft -= data_size; } }
/* Catenate file FILE_NAME to the archive without creating a header for it. It had better be a tar file or the archive is screwed. */ static void append_file (char *file_name) { int handle = open (file_name, O_RDONLY | O_BINARY); struct stat stat_data; if (handle < 0) { open_error (file_name); return; } if (fstat (handle, &stat_data) != 0) stat_error (file_name); else { off_t bytes_left = stat_data.st_size; while (bytes_left > 0) { union block *start = find_next_block (); size_t buffer_size = available_space_after (start); size_t status; char buf[UINTMAX_STRSIZE_BOUND]; if (bytes_left < buffer_size) { buffer_size = bytes_left; status = buffer_size % BLOCKSIZE; if (status) memset (start->buffer + bytes_left, 0, BLOCKSIZE - status); } status = safe_read (handle, start->buffer, buffer_size); if (status == SAFE_READ_ERROR) read_fatal_details (file_name, stat_data.st_size - bytes_left, buffer_size); if (status == 0) FATAL_ERROR ((0, 0, ngettext ("%s: File shrank by %s byte", "%s: File shrank by %s bytes", bytes_left), quotearg_colon (file_name), STRINGIFY_BIGINT (bytes_left, buf))); bytes_left -= status; set_next_block_after (start + (status - 1) / BLOCKSIZE); } } if (close (handle) != 0) close_error (file_name); }
static void get_gnu_dumpdir (struct tar_stat_info *stat_info) { size_t size; size_t copied; union block *data_block; char *to; char *archive_dir; size = stat_info->stat.st_size; archive_dir = xmalloc (size); to = archive_dir; set_next_block_after (current_header); mv_begin (stat_info); for (; size > 0; size -= copied) { mv_size_left (size); data_block = find_next_block (); if (!data_block) ERROR ((1, 0, _("Unexpected EOF in archive"))); copied = available_space_after (data_block); if (copied > size) copied = size; memcpy (to, data_block->buffer, copied); to += copied; set_next_block_after ((union block *) (data_block->buffer + copied - 1)); } mv_end (); stat_info->dumpdir = archive_dir; stat_info->skipped = true; /* For skip_member() and friends to work correctly */ }
void incremental_restore (int skipcrud) { char *current_dir; char *archive_dir; struct accumulator *accumulator; char *p; DIR *dirp; struct dirent *d; char *cur, *arc; long size; size_t size_to_copy; union block *data_block; char *to; #define CURRENT_FILE_NAME (skipcrud + current.name) dirp = opendir (CURRENT_FILE_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 (current.stat.st_size); return; } accumulator = new_accumulator (); while (d = readdir (dirp), d) { if (is_dot_or_dotdot (d->d_name)) continue; add_to_accumulator (accumulator, d->d_name, NAMLEN (d) + 1); } closedir (dirp); add_to_accumulator (accumulator, "", (size_t) 1); current_dir = get_accumulator (accumulator); archive_dir = (char *) xmalloc ((size_t) current.stat.st_size); to = archive_dir; for (size = current.stat.st_size; size > 0; size -= size_to_copy) { data_block = find_next_block (); if (!data_block) { ERROR ((0, 0, _("Unexpected end of file in archive"))); break; /* FIXME: What happens then? */ } size_to_copy = available_space_after (data_block); if (size_to_copy > size) size_to_copy = size; memcpy (to, data_block->buffer, size_to_copy); to += size_to_copy; set_next_block_after ((union block *) (data_block->buffer + size_to_copy - 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 = concat_with_slash (CURRENT_FILE_NAME, cur); if (interactive_option && !confirm (_("delete %s?"), p)) { free (p); continue; } if (verbose_option) { if (checkpoint_option) flush_progress_dots (); fprintf (stdlis, _("%s: Deleting %s\n"), program_name, p); } if (!remove_any_file (p, true)) ERROR ((0, errno, _("Error while deleting %s"), p)); free (p); } } delete_accumulator (accumulator); free (archive_dir); #undef CURRENT_FILE_NAME }
enum read_header read_header (void) { int i; long unsigned_sum; /* the POSIX one :-) */ long signed_sum; /* the Sun one :-( */ long recorded_sum; char *p; union block *header; char **longp; char *bp; union block *data_block; long long size, written; static char *next_long_name, *next_long_link; while (1) { header = find_next_block (); current_header = header; if (!header) return HEADER_END_OF_FILE; recorded_sum = from_oct (sizeof header->header.chksum, header->header.chksum); unsigned_sum = 0; signed_sum = 0; p = header->buffer; for (i = sizeof (*header); --i >= 0;) { /* We can't use unsigned char here because of old compilers, e.g. V7. */ unsigned_sum += 0xFF & *p; signed_sum += *p++; } /* Adjust checksum to count the "chksum" field as blanks. */ for (i = sizeof (header->header.chksum); --i >= 0;) { unsigned_sum -= 0xFF & header->header.chksum[i]; signed_sum -= header->header.chksum[i]; } unsigned_sum += ' ' * sizeof header->header.chksum; signed_sum += ' ' * sizeof header->header.chksum; if (unsigned_sum == sizeof header->header.chksum * ' ') { /* This is a zeroed block...whole block is 0's except for the blanks we faked for the checksum field. */ return HEADER_ZERO_BLOCK; } if (unsigned_sum != recorded_sum && signed_sum != recorded_sum) return HEADER_FAILURE; /* Good block. Decode file size and return. */ if (header->header.typeflag == LNKTYPE) current_stat.st_size = 0; /* links 0 size on tape */ else current_stat.st_size = llfrom_str (sizeof header->header.size, header->header.size); header->header.name[NAME_FIELD_SIZE - 1] = '\0'; if (header->header.typeflag == GNUTYPE_LONGNAME || header->header.typeflag == GNUTYPE_LONGLINK) { longp = ((header->header.typeflag == GNUTYPE_LONGNAME) ? &next_long_name : &next_long_link); set_next_block_after (header); if (*longp) free (*longp); bp = *longp = (char *) xmalloc ((size_t) current_stat.st_size); for (size = current_stat.st_size; size > 0; size -= written) { data_block = find_next_block (); if (data_block == NULL) { ERROR ((0, 0, _("Unexpected EOF on archive file"))); break; } written = available_space_after (data_block); if (written > size) written = size; memcpy (bp, data_block->buffer, (size_t) written); bp += written; set_next_block_after ((union block *) (data_block->buffer + written - 1)); } /* Loop! */ } else { assign_string (¤t_file_name, (next_long_name ? next_long_name : current_header->header.name)); assign_string (¤t_link_name, (next_long_link ? next_long_link : current_header->header.linkname)); next_long_link = next_long_name = 0; return HEADER_SUCCESS; } } }
void list_archive (void) { int isextended = 0; /* to remember if current_header is extended */ /* Print the header block. */ if (verbose_option) { if (verbose_option > 1) decode_header (current_header, ¤t_stat, ¤t_format, 0); print_header (); } if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR) { size_t size, written, check; union block *data_block; set_next_block_after (current_header); if (multi_volume_option) { assign_string (&save_name, current_file_name); save_totsize = current_stat.st_size; } for (size = current_stat.st_size; size > 0; size -= written) { if (multi_volume_option) save_sizeleft = size; data_block = find_next_block (); if (!data_block) { ERROR ((0, 0, _("EOF in archive file"))); break; /* FIXME: What happens, then? */ } written = available_space_after (data_block); if (written > size) written = size; errno = 0; /* FIXME: errno should be read-only */ check = fwrite (data_block->buffer, sizeof (char), written, stdlis); set_next_block_after ((union block *) (data_block->buffer + written - 1)); if (check != written) { ERROR ((0, errno, _("Only wrote %lu of %lu bytes to file %s"), (unsigned long) check, (unsigned long) written, current_file_name)); skip_file ((long long) (size - written)); break; } } if (multi_volume_option) assign_string (&save_name, NULL); fputc ('\n', stdlis); fflush (stdlis); return; } /* Check to see if we have an extended header to skip over also. */ if (current_header->oldgnu_header.isextended) isextended = 1; /* Skip past the header in the archive. */ set_next_block_after (current_header); /* If we needed to skip any extended headers, do so now, by reading extended headers and skipping past them in the archive. */ if (isextended) { #if 0 union block *exhdr; while (1) { exhdr = find_next_block (); if (!exhdr->sparse_header.isextended) { set_next_block_after (exhdr); break; } set_next_block_after (exhdr); } #endif skip_extended_headers (); } if (multi_volume_option) assign_string (&save_name, current_file_name); /* Skip to the next header on the archive. */ skip_file ((long long) current_stat.st_size); if (multi_volume_option) assign_string (&save_name, NULL); }
void list_archive (void) { bool is_extended = false; /* to remember if current.header is extended */ /* Print the header block. */ if (verbose_option) { if (verbose_option_count > 1) decode_header (¤t, false); print_header (¤t); } if (incremental_option && current.block->header.typeflag == GNUTAR_DUMPDIR) { size_t size; size_t size_to_write; ssize_t size_written; union block *data_block; set_next_block_after (current.block); if (multi_volume_option) { assign_string (&save_name, current.name); save_totsize = current.stat.st_size; } for (size = current.stat.st_size; size > 0; size -= size_to_write) { if (multi_volume_option) save_sizeleft = size; data_block = find_next_block (); if (!data_block) { ERROR ((0, 0, _("Unexpected end of file in archive"))); break; /* FIXME: What happens, then? */ } size_to_write = available_space_after (data_block); if (size_to_write > size) size_to_write = size; errno = 0; /* FIXME: errno should be read-only */ size_written = fwrite (data_block->buffer, 1, size_to_write, stdlis); set_next_block_after ((union block *) (data_block->buffer + size_to_write - 1)); if (size_written != size_to_write) { /* FIXME: size_written may be negative, here! */ ERROR ((0, errno, _("Only wrote %lu of %lu bytes to file %s"), (unsigned long) size_written, (unsigned long) size_to_write, current.name)); skip_file ((off_t) (size - size_to_write)); break; } } if (multi_volume_option) assign_string (&save_name, NULL); fputc ('\n', stdlis); fflush (stdlis); return; } /* Check to see if we have an extended header to skip over also. */ if (current.block->gnutar_header.isextended) is_extended = true; /* Skip past the header in the archive. */ set_next_block_after (current.block); /* If we needed to skip any extended headers, do so now, by reading extended headers and skipping past them in the archive. */ if (is_extended) { #if 0 union block *exhdr; while (true) { exhdr = find_next_block (); if (!exhdr->sparse_header.isextended) { set_next_block_after (exhdr); break; } set_next_block_after (exhdr); } #endif skip_extended_headers (); } if (multi_volume_option) assign_string (&save_name, current.name); /* Skip to the next header on the archive. */ skip_file (current.stat.st_size); if (multi_volume_option) assign_string (&save_name, NULL); }
void extract_mangle (void) { int size = current.stat.st_size; char *buffer = xmalloc ((size_t) (size + 1)); char *copy = buffer; char *cursor = buffer; buffer[size] = '\0'; while (size > 0) { union block *block = find_next_block (); size_t size_to_copy; if (!block) { ERROR ((0, 0, _("Unexpected end of file in mangled file names"))); return; } size_to_copy = available_space_after (block); if (size_to_copy > size) size_to_copy = size; memcpy (copy, block->buffer, size_to_copy); copy += size_to_copy; size -= size_to_copy; set_next_block_after ((union block *) (block->buffer + size_to_copy - 1)); } while (*cursor) { char *next_cursor; char *name; char *name_end; next_cursor = strchr (cursor, '\n'); *next_cursor++ = '\0'; if (!strncmp (cursor, "Rename ", 7)) { name = cursor + 7; name_end = strchr (name, ' '); while (strncmp (name_end, " to ", 4)) { name_end++; name_end = strchr (name_end, ' '); } *name_end = '\0'; if (next_cursor[-2] == '/') next_cursor[-2] = '\0'; unquote_string (name_end + 4); if (rename (name, name_end + 4)) ERROR ((0, errno, _("Cannot rename %s to %s"), name, name_end + 4)); else if (verbose_option) WARN ((0, 0, _("Renamed %s to %s"), name, name_end + 4)); } #ifdef S_ISLNK else if (!strncmp (cursor, "Symlink ", 8)) { name = cursor + 8; name_end = strchr (name, ' '); while (strncmp (name_end, " to ", 4)) { name_end++; name_end = strchr (name_end, ' '); } *name_end = '\0'; unquote_string (name); unquote_string (name_end + 4); if (symlink (name, name_end + 4) && (unlink (name_end + 4) || symlink (name, name_end + 4))) ERROR ((0, errno, _("Cannot symlink %s to %s"), name, name_end + 4)); else if (verbose_option) WARN ((0, 0, _("Symlinked %s to %s"), name, name_end + 4)); } #endif else ERROR ((0, 0, _("Unknown demangling command %s"), cursor)); cursor = next_cursor; } }
int shfs_arch_write_flush(shfs_arch_t *arch, size_t buffer_level) { ssize_t status; union block *header; char *copy_ptr; size_t copy_size; size_t bufsize; struct bufmap *map; status = shfs_arch_buffer_write(arch->archive, record_start->buffer, arch->record_size); if (status != arch->record_size && !multi_volume_option) {} else { if (status) arch->records_written++; bytes_written += status; } if (status == arch->record_size) { return; } map = bufmap_locate (status); tar_stat_destroy (&dummy); //increase_volume_number (); prev_written += bytes_written; bytes_written = 0; copy_ptr = record_start->buffer + status; copy_size = buffer_level - status; /* Switch to the next buffer */ arch->arch_record_index = !arch->arch_record_index; shfs_arch_init_buffer(arch); inhibit_map = 1; tar_stat_destroy (&dummy); header = shfs_arch_buffer_next(arch); bufmap_reset (map, header - record_start); bufsize = available_space_after (header); inhibit_map = 0; while (bufsize < copy_size) { memcpy (header->buffer, copy_ptr, bufsize); copy_ptr += bufsize; copy_size -= bufsize; shfs_arch_set_next_block_after(arch, header + (bufsize - 1) / BLOCKSIZE); header = shfs_arch_buffer_next(arch); bufsize = available_space_after (header); } memcpy (header->buffer, copy_ptr, copy_size); memset (header->buffer + copy_size, 0, bufsize - copy_size); shfs_arch_set_next_block_after(arch, header + (copy_size - 1) / BLOCKSIZE); shfs_arch_buffer_next(arch); return (0); }