📄 buffer.c
字号:
archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY, MODE_RW, rsh_command_option); if (check_compressed_archive (NULL) != ct_none) FATAL_ERROR ((0, 0, _("Cannot update compressed archives"))); break; } if (archive < 0 || (! _isrmt (archive) && !sys_get_archive_stat ())) { int saved_errno = errno; if (backed_up_flag) undo_last_backup (); errno = saved_errno; open_fatal (archive_name_array[0]); } sys_detect_dev_null_output (); sys_save_archive_dev_ino (); SET_BINARY_MODE (archive); switch (wanted_access) { case ACCESS_READ: find_next_block (); /* read it in, check for EOF */ break; case ACCESS_UPDATE: case ACCESS_WRITE: records_written = 0; break; }}/* Perform a write to flush the buffer. */ssize_t_flush_write (void){ ssize_t status; checkpoint_run (true); if (tape_length_option && tape_length_option <= bytes_written) { errno = ENOSPC; status = 0; } else if (dev_null_output) status = record_size; else status = sys_write_archive_buffer (); return status;}/* Handle write errors on the archive. Write errors are always fatal. Hitting the end of a volume does not cause a write error unless the write was the first record of the volume. */voidarchive_write_error (ssize_t status){ /* It might be useful to know how much was written before the error occurred. */ if (totals_option) { int e = errno; print_total_stats (); errno = e; } write_fatal_details (*archive_name_cursor, status, record_size);}/* Handle read errors on the archive. If the read should be retried, return to the caller. */voidarchive_read_error (void){ read_error (*archive_name_cursor); if (record_start_block == 0) FATAL_ERROR ((0, 0, _("At beginning of tape, quitting now"))); /* Read error in mid archive. We retry up to READ_ERROR_MAX times and then give up on reading the archive. */ if (read_error_count++ > READ_ERROR_MAX) FATAL_ERROR ((0, 0, _("Too many errors, quitting"))); return;}static voidshort_read (size_t status){ size_t left; /* bytes left */ char *more; /* pointer to next byte to read */ more = record_start->buffer + status; left = record_size - status; while (left % BLOCKSIZE != 0 || (left && status && read_full_records)) { if (status) while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR) archive_read_error (); if (status == 0) break; if (! read_full_records) { unsigned long rest = record_size - left; FATAL_ERROR ((0, 0, ngettext ("Unaligned block (%lu byte) in archive", "Unaligned block (%lu bytes) in archive", rest), rest)); } /* User warned us about this. Fix up. */ left -= status; more += status; } /* FIXME: for size=0, multi-volume support. On the first record, warn about the problem. */ if (!read_full_records && verbose_option > 1 && record_start_block == 0 && status != 0) { unsigned long rsize = (record_size - left) / BLOCKSIZE; WARN ((0, 0, ngettext ("Record size = %lu block", "Record size = %lu blocks", rsize), rsize)); } record_end = record_start + (record_size - left) / BLOCKSIZE; records_read++;}/* Flush the current buffer to/from the archive. */voidflush_archive (void){ size_t buffer_level = current_block->buffer - record_start->buffer; record_start_block += record_end - record_start; current_block = record_start; record_end = record_start + blocking_factor; if (access_mode == ACCESS_READ && time_to_start_writing) { access_mode = ACCESS_WRITE; time_to_start_writing = false; backspace_output (); } switch (access_mode) { case ACCESS_READ: flush_read (); break; case ACCESS_WRITE: flush_write_ptr (buffer_level); break; case ACCESS_UPDATE: abort (); }}/* Backspace the archive descriptor by one record worth. If it's a tape, MTIOCTOP will work. If it's something else, try to seek on it. If we can't seek, we lose! */static voidbackspace_output (void){#ifdef MTIOCTOP { struct mtop operation; operation.mt_op = MTBSR; operation.mt_count = 1; if (rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0) return; if (errno == EIO && rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0) return; }#endif { off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR); /* Seek back to the beginning of this record and start writing there. */ position -= record_size; if (position < 0) position = 0; if (rmtlseek (archive, position, SEEK_SET) != position) { /* Lseek failed. Try a different method. */ WARN ((0, 0, _("Cannot backspace archive file; it may be unreadable without -i"))); /* Replace the first part of the record with NULs. */ if (record_start->buffer != output_start) memset (record_start->buffer, 0, output_start - record_start->buffer); } }}off_tseek_archive (off_t size){ off_t start = current_block_ordinal (); off_t offset; off_t nrec, nblk; off_t skipped = (blocking_factor - (current_block - record_start)); size -= skipped * BLOCKSIZE; if (size < record_size) return 0; /* FIXME: flush? */ /* Compute number of records to skip */ nrec = size / record_size; offset = rmtlseek (archive, nrec * record_size, SEEK_CUR); if (offset < 0) return offset; if (offset % record_size) FATAL_ERROR ((0, 0, _("rmtlseek not stopped at a record boundary"))); /* Convert to number of records */ offset /= BLOCKSIZE; /* Compute number of skipped blocks */ nblk = offset - start; /* Update buffering info */ records_read += nblk / blocking_factor; record_start_block = offset - blocking_factor; current_block = record_end; return nblk;}/* Close the archive file. */voidclose_archive (void){ if (time_to_start_writing || access_mode == ACCESS_WRITE) { flush_archive (); if (current_block > record_start) flush_archive (); } sys_drain_input_pipe (); compute_duration (); if (verify_option) verify_volume (); if (rmtclose (archive) != 0) close_error (*archive_name_cursor); sys_wait_for_child (child_pid); tar_stat_destroy (¤t_stat_info); if (save_name) free (save_name); if (real_s_name) free (real_s_name); free (record_buffer[0]); free (record_buffer[1]);}/* Called to initialize the global volume number. */voidinit_volume_number (void){ FILE *file = fopen (volno_file_option, "r"); if (file) { if (fscanf (file, "%d", &global_volno) != 1 || global_volno < 0) FATAL_ERROR ((0, 0, _("%s: contains invalid volume number"), quotearg_colon (volno_file_option))); if (ferror (file)) read_error (volno_file_option); if (fclose (file) != 0) close_error (volno_file_option); } else if (errno != ENOENT) open_error (volno_file_option);}/* Called to write out the closing global volume number. */voidcloseout_volume_number (void){ FILE *file = fopen (volno_file_option, "w"); if (file) { fprintf (file, "%d\n", global_volno); if (ferror (file)) write_error (volno_file_option); if (fclose (file) != 0) close_error (volno_file_option); } else open_error (volno_file_option);}static voidincrease_volume_number (){ global_volno++; if (global_volno < 0) FATAL_ERROR ((0, 0, _("Volume number overflow"))); volno++;}voidchange_tape_menu (FILE *read_file){ char *input_buffer = NULL; size_t size = 0; bool stop = false; while (!stop) { fputc ('\007', stderr); fprintf (stderr, _("Prepare volume #%d for %s and hit return: "), global_volno + 1, quote (*archive_name_cursor)); fflush (stderr); if (getline (&input_buffer, &size, read_file) <= 0) { WARN ((0, 0, _("EOF where user reply was expected"))); if (subcommand_option != EXTRACT_SUBCOMMAND && subcommand_option != LIST_SUBCOMMAND && subcommand_option != DIFF_SUBCOMMAND) WARN ((0, 0, _("WARNING: Archive is incomplete"))); fatal_exit (); } if (input_buffer[0] == '\n' || input_buffer[0] == 'y' || input_buffer[0] == 'Y') break; switch (input_buffer[0]) { case '?': { fprintf (stderr, _("\ n name Give a new file name for the next (and subsequent) volume(s)\n\ q Abort tar\n\ y or newline Continue operation\n")); if (!restrict_option) fprintf (stderr, _(" ! Spawn a subshell\n")); fprintf (stderr, _(" ? Print this list\n")); } break; case 'q': /* Quit. */ WARN ((0, 0, _("No new volume; exiting.\n"))); if (subcommand_option != EXTRACT_SUBCOMMAND && subcommand_option != LIST_SUBCOMMAND && subcommand_option != DIFF_SUBCOMMAND) WARN ((0, 0, _("WARNING: Archive is incomplete"))); fatal_exit (); case 'n': /* Get new file name. */ { char *name; char *cursor; for (name = input_buffer + 1; *name == ' ' || *name == '\t'; name++) ; for (cursor = name; *cursor && *cursor != '\n'; cursor++) ; *cursor = '\0'; if (name[0]) { /* FIXME: the following allocation is never reclaimed. */ *archive_name_cursor = xstrdup (name); stop = true; } else fprintf (stderr, "%s", _("File name not specified. Try again.\n")); } break; case '!': if (!restrict_option) { sys_spawn_shell (); break; } /* FALL THROUGH */ default: fprintf (stderr, _("Invalid input. Type ? for help.\n")); } } free (input_buffer);}/* We've hit the end of the old volume. Close it and open the next one. Return nonzero on success.*/static boolnew_volume (enum access_mode mode){ static FILE *read_file; static int looped; int prompt; if (!read_file && !info_script_option) /* FIXME: if fopen is used, it will never be closed. */ read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin; if (now_verifying) return false; if (verify_option) verify_volume (); assign_string (&volume_label, NULL); assign_string (&continued_file_name, NULL); continued_file_size = continued_file_offset = 0; current_block = record_start; if (rmtclose (archive) != 0) close_error (*archive_name_cursor); archive_name_cursor++; if (archive_name_cursor == archive_name_array + archive_names) { archive_name_cursor = archive_name_array; looped = 1; } prompt = looped; tryagain: if (prompt) { /* We have to prompt from now on. */ if (info_script_option) { if (volno_file_option) closeout_volume_number (); if (sys_exec_info_script (archive_name_cursor, global_volno+1)) FATAL_ERROR ((0, 0, _("%s command failed"), quote (info_script_option))); } else change_tape_menu (read_file); } if (strcmp (archive_name_cursor[0], "-") == 0) { read_full_records = true; archive = STDIN_FILENO; } else if (verify_option) archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW, rsh_command_option); else switch (mode) { case ACCESS_READ: archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW, rsh_command_option); break; case ACCESS_WRITE: if (backup_option) maybe_backup_file (*archive_name_cursor, 1); archive = rmtcreat (*archive_name_cursor, MODE_RW, rsh_command_option); break; case ACCESS_UPDATE: archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW, rsh_command_option); break; } if (archive < 0) { open_warn (*archive_name_cursor); if (!verify_option && mode == ACCESS_WRITE && backup_option) undo_last_backup (); prompt = 1; goto tryagain; } SET_BINARY_MODE (archive); return true;}static boolread_header0 (struct tar_stat_info *info){ enum read_header rc; tar_stat_init (info); rc = read_header_primitive (false, info); if (rc == HEADER_SUCCESS) { set_next_block_after (current_header); return true; } ERROR ((0, 0, _("This does not look like a tar archive"))); return false;}booltry_new_volume (){ size_t status; union block *header; enum access_mode acc; switch (subcommand_option) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -