static void copy_to_fd (const char *from, int tofd) { int fromfd; ssize_t i; if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0) pfatal ("Can't reopen file %s", quotearg (from)); while ((i = read (fromfd, buf, bufsize)) != 0) { if (i == (ssize_t) -1) read_fatal (); if (full_write (tofd, buf, i) != i) write_fatal (); } if (close (fromfd) != 0) read_fatal (); }
void copy_file (char const *from, char const *to, int to_flags, mode_t mode) { int tofd; int fromfd; size_t i; if ((fromfd = open (from, O_RDONLY | O_BINARY, 0)) < 0) pfatal ("Can't reopen file %s", quotearg (from)); tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode); while ((i = read (fromfd, buf, bufsize)) != 0) { if (i == (size_t) -1) read_fatal (); if (write (tofd, buf, i) != i) write_fatal (); } if (close (fromfd) != 0) read_fatal (); if (close (tofd) != 0) write_fatal (); }
char const * ifetch (LINENUM line, bool whichbuf, size_t *psize) { register char const *q; register char const *p; if (line < 1 || line > input_lines) { *psize = 0; return ""; } if (using_plan_a) { p = i_ptr[line]; *psize = i_ptr[line + 1] - p; return p; } else { LINENUM offline = line % lines_per_buf; LINENUM baseline = line - offline; if (tiline[0] == baseline) whichbuf = false; else if (tiline[1] == baseline) whichbuf = true; else { tiline[whichbuf] = baseline; if (lseek (tifd, (off_t) (baseline/lines_per_buf * tibufsize), SEEK_SET) == -1 || read (tifd, tibuf[whichbuf], tibufsize) < 0) read_fatal (); } p = tibuf[whichbuf] + (tireclen*offline); if (line == input_lines) *psize = last_line_size; else { for (q = p; *q++ != '\n'; ) continue; *psize = q - p; } return p; } }
void move_file (char const *from, bool *from_needs_removal, struct stat const *fromst, char const *to, mode_t mode, bool backup) { struct stat to_st; int to_errno; to_errno = stat_file (to, &to_st); if (backup) create_backup (to, to_errno ? NULL : &to_st, false); if (! to_errno) insert_file_id (&to_st, OVERWRITTEN); if (from) { if (S_ISLNK (mode)) { bool to_dir_known_to_exist = false; /* FROM contains the contents of the symlink we have patched; need to convert that back into a symlink. */ char *buffer = xmalloc (PATH_MAX); int fd, size = 0, i; if ((fd = open (from, O_RDONLY | O_BINARY)) < 0) pfatal ("Can't reopen file %s", quotearg (from)); while ((i = read (fd, buffer + size, PATH_MAX - size)) > 0) size += i; if (i != 0 || close (fd) != 0) read_fatal (); buffer[size] = 0; if (! backup) { if (unlink (to) == 0) to_dir_known_to_exist = true; } if (symlink (buffer, to) != 0) { if (errno == ENOENT && ! to_dir_known_to_exist) makedirs (to); if (symlink (buffer, to) != 0) pfatal ("Can't create %s %s", "symbolic link", to); } free (buffer); if (lstat (to, &to_st) != 0) pfatal ("Can't get file attributes of %s %s", "symbolic link", to); insert_file_id (&to_st, CREATED); } else { if (debug & 4) say ("Renaming file %s to %s\n", quotearg_n (0, from), quotearg_n (1, to)); if (rename (from, to) != 0) { bool to_dir_known_to_exist = false; if (errno == ENOENT && (to_errno == -1 || to_errno == ENOENT)) { makedirs (to); to_dir_known_to_exist = true; if (rename (from, to) == 0) goto rename_succeeded; } if (errno == EXDEV) { struct stat tost; if (! backup) { if (unlink (to) == 0) to_dir_known_to_exist = true; else if (errno != ENOENT) pfatal ("Can't remove file %s", quotearg (to)); } copy_file (from, to, &tost, 0, mode, to_dir_known_to_exist); insert_file_id (&tost, CREATED); return; } pfatal ("Can't rename file %s to %s", quotearg_n (0, from), quotearg_n (1, to)); } rename_succeeded: insert_file_id (fromst, CREATED); /* Do not clear *FROM_NEEDS_REMOVAL if it's possible that the rename returned zero because FROM and TO are hard links to the same file. */ if ((0 < to_errno || (to_errno == 0 && to_st.st_nlink <= 1)) && from_needs_removal) *from_needs_removal = false; } } else if (! backup) { if (debug & 4) say ("Removing file %s\n", quotearg (to)); if (unlink (to) != 0 && errno != ENOENT) pfatal ("Can't remove file %s", quotearg (to)); } }
/* 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); }
static void plan_b (char const *filename) { register FILE *ifp; register int c; register size_t len; register size_t maxlen; register bool found_revision; register size_t i; register char const *rev; register size_t revlen; register LINENUM line = 1; int exclusive; if (instat.st_size == 0) filename = NULL_DEVICE; if (! (ifp = fopen (filename, binary_transput ? "rb" : "rt"))) pfatal ("Can't open file %s", quotearg (filename)); exclusive = TMPINNAME_needs_removal ? 0 : O_EXCL; TMPINNAME_needs_removal = 1; tifd = create_file (TMPINNAME, O_RDWR | O_BINARY | exclusive, (mode_t) 0); i = 0; len = 0; maxlen = 1; rev = revision; found_revision = !rev; revlen = rev ? strlen (rev) : 0; while ((c = getc (ifp)) != EOF) { len++; if (c == '\n') { if (++line < 0) too_many_lines (filename); if (maxlen < len) maxlen = len; len = 0; } if (!found_revision) { if (i == revlen) { found_revision = ISSPACE ((unsigned char) c); i = (size_t) -1; } else if (i != (size_t) -1) i = rev[i]==c ? i + 1 : (size_t) -1; if (i == (size_t) -1 && ISSPACE ((unsigned char) c)) i = 0; } } if (revision) report_revision (found_revision); Fseek (ifp, (off_t) 0, SEEK_SET); /* rewind file */ for (tibufsize = TIBUFSIZE_MINIMUM; tibufsize < maxlen; tibufsize <<= 1) continue; lines_per_buf = tibufsize / maxlen; tireclen = maxlen; tibuf[0] = (char *)malloc (2 * tibufsize); tibuf[1] = tibuf[0] + tibufsize; for (line = 1; ; line++) { char *p = tibuf[0] + maxlen * (line % lines_per_buf); char const *p0 = p; if (! (line % lines_per_buf)) /* new block */ if (write (tifd, tibuf[0], tibufsize) != tibufsize) write_fatal (); if ((c = getc (ifp)) == EOF) break; for (;;) { *p++ = c; if (c == '\n') { last_line_size = p - p0; break; } if ((c = getc (ifp)) == EOF) { last_line_size = p - p0; line++; goto EOF_reached; } } } EOF_reached: if (ferror (ifp) || fclose (ifp) != 0) read_fatal (); if (line % lines_per_buf != 0) if (write (tifd, tibuf[0], tibufsize) != tibufsize) write_fatal (); input_lines = line - 1; }
static bool plan_a (char const *filename) { register char const *s; register char const *lim; register char const **ptr; register char *buffer; register LINENUM iline; size_t size = (size_t)instat.st_size; /* Fail if the file size doesn't fit in a size_t, or if storage isn't available. */ if (! (size == instat.st_size && (buffer = (char *)malloc (size ? size : (size_t) 1)))) return false; /* Read the input file, but don't bother reading it if it's empty. When creating files, the files do not actually exist. */ if (size) { int ifd = open (filename, O_RDONLY|binary_transput); size_t buffered = 0, n; if (ifd < 0) pfatal ("can't open file %s", quotearg (filename)); while (size - buffered != 0) { n = read (ifd, buffer + buffered, size - buffered); if (n == 0) { /* Some non-POSIX hosts exaggerate st_size in text mode; or the file may have shrunk! */ size = buffered; break; } if (n == (size_t) -1) { /* Perhaps size is too large for this host. */ close (ifd); free (buffer); return false; } buffered += n; } if (close (ifd) != 0) read_fatal (); } /* Scan the buffer and build array of pointers to lines. */ lim = buffer + size; iline = 3; /* 1 unused, 1 for SOF, 1 for EOF if last line is incomplete */ for (s = buffer; (s = (char *) memchr (s, '\n', lim - s)); s++) if (++iline < 0) too_many_lines (filename); if (! (iline == (size_t) iline && (size_t) iline * sizeof *ptr / sizeof *ptr == (size_t) iline && (ptr = (char const **) malloc ((size_t) iline * sizeof *ptr)))) { free (buffer); return false; } iline = 0; for (s = buffer; ; s++) { ptr[++iline] = s; if (! (s = (char *) memchr (s, '\n', lim - s))) break; } if (size && lim[-1] != '\n') ptr[++iline] = lim; input_lines = iline - 1; if (revision) { char const *rev = revision; int rev0 = rev[0]; bool found_revision = false; size_t revlen = strlen (rev); if (revlen <= size) { char const *limrev = lim - revlen; for (s = buffer; (s = (char *) memchr (s, rev0, limrev - s)); s++) if (memcmp (s, rev, revlen) == 0 && (s == buffer || ISSPACE ((unsigned char) s[-1])) && (s + 1 == limrev || ISSPACE ((unsigned char) s[revlen]))) { found_revision = true; break; } } report_revision (found_revision); } /* Plan A will work. */ i_buffer = buffer; i_ptr = ptr; return true; }
static bool read_num (FILE *fp, char const *fieldname, intmax_t min_val, uintmax_t max_val, intmax_t *pval) { int i; char buf[INT_BUFSIZE_BOUND (intmax_t)]; char offbuf[INT_BUFSIZE_BOUND (off_t)]; char minbuf[INT_BUFSIZE_BOUND (intmax_t)]; char maxbuf[INT_BUFSIZE_BOUND (intmax_t)]; int conversion_errno; int c = getc (fp); bool negative = c == '-'; for (i = 0; (i == 0 && negative) || ISDIGIT (c); i++) { buf[i] = c; if (i == sizeof buf - 1) FATAL_ERROR ((0, 0, _("%s: byte %s: %s %.*s... too long"), quotearg_colon (listed_incremental_option), offtostr (ftello (fp), offbuf), fieldname, i + 1, buf)); c = getc (fp); } buf[i] = 0; if (c < 0) { if (ferror (fp)) read_fatal (listed_incremental_option); if (i != 0) FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (listed_incremental_option), _("Unexpected EOF in snapshot file"))); return false; } if (c) { unsigned uc = c; FATAL_ERROR ((0, 0, _("%s: byte %s: %s %s followed by invalid byte 0x%02x"), quotearg_colon (listed_incremental_option), offtostr (ftello (fp), offbuf), fieldname, buf, uc)); } *pval = strtosysint (buf, NULL, min_val, max_val); conversion_errno = errno; switch (conversion_errno) { case ERANGE: FATAL_ERROR ((0, conversion_errno, _("%s: byte %s: (valid range %s..%s)\n\t%s %s"), quotearg_colon (listed_incremental_option), offtostr (ftello (fp), offbuf), imaxtostr (min_val, minbuf), umaxtostr (max_val, maxbuf), fieldname, buf)); default: FATAL_ERROR ((0, conversion_errno, _("%s: byte %s: %s %s"), quotearg_colon (listed_incremental_option), offtostr (ftello (fp), offbuf), fieldname, buf)); case 0: break; } return true; }