/* Check if FILE_NAME already exists and make a backup of it right now. Return success (nonzero) only if the backup is either unneeded, or successful. For now, directories are considered to never need backup. If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and so, we do not have to backup block or character devices, nor remote entities. */ bool maybe_backup_file (const char *file_name, bool this_is_the_archive) { struct stat file_stat; assign_string (&before_backup_name, file_name); /* A run situation may exist between Emacs or other GNU programs trying to make a backup for the same file simultaneously. If theoretically possible, real problems are unlikely. Doing any better would require a convention, GNU-wide, for all programs doing backups. */ assign_string (&after_backup_name, 0); /* Check if we really need to backup the file. */ if (this_is_the_archive && _remdev (file_name)) return true; if (deref_stat (file_name, &file_stat) != 0) { if (errno == ENOENT) return true; stat_error (file_name); return false; } if (S_ISDIR (file_stat.st_mode)) return true; if (this_is_the_archive && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode))) return true; after_backup_name = find_backup_file_name (file_name, backup_type); if (! after_backup_name) xalloc_die (); if (renameat (chdir_fd, before_backup_name, chdir_fd, after_backup_name) == 0) { if (verbose_option) fprintf (stdlis, _("Renaming %s to %s\n"), quote_n (0, before_backup_name), quote_n (1, after_backup_name)); return true; } else { /* The backup operation failed. */ int e = errno; ERROR ((0, e, _("%s: Cannot rename to %s"), quotearg_colon (before_backup_name), quote_n (1, after_backup_name))); assign_string (&after_backup_name, 0); return false; } }
int maybe_backup_file (const char *path, int archive) { struct L_STAT file_stat; /* Check if we really need to backup the file. */ if (archive && _remdev (path)) return 1; if (L_STAT (path, &file_stat)) { if (errno == ENOENT) return 1; ERROR ((0, errno, "%s", path)); return 0; } if (S_ISDIR (file_stat.st_mode)) return 1; #ifdef S_ISBLK if (archive && S_ISBLK (file_stat.st_mode)) return 1; #endif #ifdef S_ISCHR if (archive && S_ISCHR (file_stat.st_mode)) return 1; #endif assign_string (&before_backup_name, path); /* A run situation may exist between Emacs or other GNU programs trying to make a backup for the same file simultaneously. If theoretically possible, real problems are unlikely. Doing any better would require a convention, GNU-wide, for all programs doing backups. */ assign_string (&after_backup_name, NULL); after_backup_name = find_backup_file_name (path); if (after_backup_name == NULL) FATAL_ERROR ((0, 0, "Virtual memory exhausted")); if (rename (before_backup_name, after_backup_name) == 0) { if (verbose_option) fprintf (stdlis, _("Renaming previous `%s' to `%s'\n"), before_backup_name, after_backup_name); return 1; } /* The backup operation failed. */ ERROR ((0, errno, _("%s: Cannot rename for backup"), before_backup_name)); assign_string (&after_backup_name, NULL); return 0; }
/* Set ARCHIVE for uncompressing, then reading an archive. */ pid_t sys_child_open_for_uncompress (void) { int parent_pipe[2]; int child_pipe[2]; pid_t grandchild_pid; pid_t child_pid; xpipe (parent_pipe); child_pid = xfork (); if (child_pid > 0) { /* The parent tar is still here! Just clean up. */ archive = parent_pipe[PREAD]; xclose (parent_pipe[PWRITE]); return child_pid; } /* The newborn child tar is here! */ set_program_name (_("tar (child)")); signal (SIGPIPE, SIG_DFL); xdup2 (parent_pipe[PWRITE], STDOUT_FILENO); xclose (parent_pipe[PREAD]); /* Check if we need a grandchild tar. This happens only if either: a) we're reading stdin: to force unblocking; b) the file is to be accessed by rmt: compressor doesn't know how; c) the file is not a plain file. */ if (strcmp (archive_name_array[0], "-") != 0 && !_remdev (archive_name_array[0]) && is_regular_file (archive_name_array[0])) { /* We don't need a grandchild tar. Open the archive and lauch the uncompressor. */ archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW); if (archive < 0) open_fatal (archive_name_array[0]); xdup2 (archive, STDIN_FILENO); execlp (use_compress_program_option, use_compress_program_option, "-d", (char *) 0); exec_fatal (use_compress_program_option); } /* We do need a grandchild tar. */ xpipe (child_pipe); grandchild_pid = xfork (); if (grandchild_pid == 0) { /* The newborn grandchild tar is here! Launch the uncompressor. */ set_program_name (_("tar (grandchild)")); xdup2 (child_pipe[PREAD], STDIN_FILENO); xclose (child_pipe[PWRITE]); execlp (use_compress_program_option, use_compress_program_option, "-d", (char *) 0); exec_fatal (use_compress_program_option); } /* The child tar is still here! */ /* Prepare for unblocking the data from the archive into the uncompressor. */ xdup2 (child_pipe[PWRITE], STDOUT_FILENO); xclose (child_pipe[PREAD]); if (strcmp (archive_name_array[0], "-") == 0) archive = STDIN_FILENO; else archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW, rsh_command_option); if (archive < 0) open_fatal (archive_name_array[0]); /* Let's read the archive and pipe it into stdout. */ while (1) { char *cursor; size_t maximum; size_t count; size_t status; clear_read_error_count (); error_loop: status = rmtread (archive, record_start->buffer, record_size); if (status == SAFE_READ_ERROR) { archive_read_error (); goto error_loop; } if (status == 0) break; cursor = record_start->buffer; maximum = status; while (maximum) { count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE; if (full_write (STDOUT_FILENO, cursor, count) != count) write_error (use_compress_program_option); cursor += count; maximum -= count; } } xclose (STDOUT_FILENO); wait_for_grandchild (grandchild_pid); }
/* Set ARCHIVE for writing, then compressing an archive. */ pid_t sys_child_open_for_compress (void) { int parent_pipe[2]; int child_pipe[2]; pid_t grandchild_pid; pid_t child_pid; xpipe (parent_pipe); child_pid = xfork (); if (child_pid > 0) { /* The parent tar is still here! Just clean up. */ archive = parent_pipe[PWRITE]; xclose (parent_pipe[PREAD]); return child_pid; } /* The new born child tar is here! */ set_program_name (_("tar (child)")); signal (SIGPIPE, SIG_DFL); xdup2 (parent_pipe[PREAD], STDIN_FILENO); xclose (parent_pipe[PWRITE]); /* Check if we need a grandchild tar. This happens only if either: a) the file is to be accessed by rmt: compressor doesn't know how; b) the file is not a plain file. */ if (!_remdev (archive_name_array[0]) && is_regular_file (archive_name_array[0])) { if (backup_option) maybe_backup_file (archive_name_array[0], 1); /* We don't need a grandchild tar. Open the archive and launch the compressor. */ if (strcmp (archive_name_array[0], "-")) { archive = creat (archive_name_array[0], MODE_RW); if (archive < 0) { int saved_errno = errno; if (backup_option) undo_last_backup (); errno = saved_errno; open_fatal (archive_name_array[0]); } xdup2 (archive, STDOUT_FILENO); } execlp (use_compress_program_option, use_compress_program_option, NULL); exec_fatal (use_compress_program_option); } /* We do need a grandchild tar. */ xpipe (child_pipe); grandchild_pid = xfork (); if (grandchild_pid == 0) { /* The newborn grandchild tar is here! Launch the compressor. */ set_program_name (_("tar (grandchild)")); xdup2 (child_pipe[PWRITE], STDOUT_FILENO); xclose (child_pipe[PREAD]); execlp (use_compress_program_option, use_compress_program_option, (char *) 0); exec_fatal (use_compress_program_option); } /* The child tar is still here! */ /* Prepare for reblocking the data from the compressor into the archive. */ xdup2 (child_pipe[PREAD], STDIN_FILENO); xclose (child_pipe[PWRITE]); if (strcmp (archive_name_array[0], "-") == 0) archive = STDOUT_FILENO; else { archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option); if (archive < 0) open_fatal (archive_name_array[0]); } /* Let's read out of the stdin pipe and write an archive. */ while (1) { size_t status = 0; char *cursor; size_t length; /* Assemble a record. */ for (length = 0, cursor = record_start->buffer; length < record_size; length += status, cursor += status) { size_t size = record_size - length; status = safe_read (STDIN_FILENO, cursor, size); if (status == SAFE_READ_ERROR) read_fatal (use_compress_program_option); if (status == 0) break; } /* Copy the record. */ if (status == 0) { /* We hit the end of the file. Write last record at full length, as the only role of the grandchild is doing proper reblocking. */ if (length > 0) { memset (record_start->buffer + length, 0, record_size - length); status = sys_write_archive_buffer (); if (status != record_size) archive_write_error (status); } /* There is nothing else to read, break out. */ break; } status = sys_write_archive_buffer (); if (status != record_size) archive_write_error (status); } wait_for_grandchild (grandchild_pid); }