summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/tar/update.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/tar/update.c')
-rw-r--r--gnu/usr.bin/tar/update.c585
1 files changed, 585 insertions, 0 deletions
diff --git a/gnu/usr.bin/tar/update.c b/gnu/usr.bin/tar/update.c
new file mode 100644
index 0000000..a64317c
--- /dev/null
+++ b/gnu/usr.bin/tar/update.c
@@ -0,0 +1,585 @@
+/* Update a tar archive.
+ Copyright (C) 1988, 1992 Free Software Foundation
+
+This file is part of GNU Tar.
+
+GNU Tar is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Tar is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Tar; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* JF implement the 'r' 'u' and 'A' options for tar. */
+/* The 'A' option is my own invention: It means that the file-names are
+ tar files, and they should simply be appended to the end of the archive.
+ No attempt is made to block the reads from the args; if they're on raw
+ tape or something like that, it'll probably lose. . . */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+#ifdef HAVE_SYS_MTIO_H
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#endif
+
+#ifdef BSD42
+#include <sys/file.h>
+#else
+#ifndef V7
+#include <fcntl.h>
+#endif
+#endif
+
+#ifndef __MSDOS__
+#include <pwd.h>
+#include <grp.h>
+#endif
+
+#define STDIN 0
+#define STDOUT 1
+
+#include "tar.h"
+#include "port.h"
+#include "rmt.h"
+
+int time_to_start_writing = 0; /* We've hit the end of the old stuff,
+ and its time to start writing new stuff
+ to the tape. This involves seeking
+ back one block and re-writing the current
+ block (which has been changed). */
+
+char *output_start; /* Pointer to where we started to write in
+ the first block we write out. This is used
+ if we can't backspace the output and have
+ to null out the first part of the block */
+
+extern void skip_file ();
+extern void skip_extended_headers ();
+
+extern union record *head;
+extern struct stat hstat;
+
+void append_file ();
+void close_archive ();
+int confirm ();
+void decode_header ();
+void fl_read ();
+void fl_write ();
+void flush_archive ();
+int move_arch ();
+struct name *name_scan ();
+char *name_from_list ();
+void name_expand ();
+void name_gather ();
+void names_notfound ();
+void open_archive ();
+int read_header ();
+void reset_eof ();
+void write_block ();
+void write_eot ();
+
+/* Implement the 'r' (add files to end of archive), and 'u' (add files to
+ end of archive if they arent there, or are more up to date than the
+ version in the archive.) commands.*/
+void
+update_archive ()
+{
+ int found_end = 0;
+ int status = 3;
+ int prev_status;
+ char *p;
+ struct name *name;
+ extern void dump_file ();
+
+ name_gather ();
+ if (cmd_mode == CMD_UPDATE)
+ name_expand ();
+ open_archive (2); /* Open for updating */
+
+ do
+ {
+ prev_status = status;
+ status = read_header ();
+ switch (status)
+ {
+ case EOF:
+ found_end = 1;
+ break;
+
+ case 0: /* A bad record */
+ userec (head);
+ switch (prev_status)
+ {
+ case 3:
+ msg ("This doesn't look like a tar archive.");
+ /* FALL THROUGH */
+ case 2:
+ case 1:
+ msg ("Skipping to next header");
+ case 0:
+ break;
+ }
+ break;
+
+ /* A good record */
+ case 1:
+ /* printf("File %s\n",head->header.name); */
+ /* head->header.name[NAMSIZ-1]='\0'; */
+ if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name)))
+ {
+
+ /* struct stat hstat; */
+ struct stat nstat;
+ int head_standard;
+
+ decode_header (head, &hstat, &head_standard, 0);
+ if (stat (current_file_name, &nstat) < 0)
+ {
+ msg_perror ("can't stat %s:", current_file_name);
+ }
+ else
+ {
+ if (hstat.st_mtime >= nstat.st_mtime)
+ name->found++;
+ }
+ }
+ userec (head);
+ if (head->header.isextended)
+ skip_extended_headers ();
+ skip_file ((long) hstat.st_size);
+ break;
+
+ case 2:
+ ar_record = head;
+ found_end = 1;
+ break;
+ }
+ }
+ while (!found_end);
+
+ reset_eof ();
+ time_to_start_writing = 1;
+ output_start = ar_record->charptr;
+
+ while (p = name_from_list ())
+ {
+ if (f_confirm && !confirm ("add", p))
+ continue;
+ if (cmd_mode == CMD_CAT)
+ append_file (p);
+ else
+ dump_file (p, -1, 1);
+ }
+
+ write_eot ();
+ close_archive ();
+ names_notfound ();
+}
+
+/* Catenate file p to the archive without creating a header for it. It had
+ better be a tar file or the archive is screwed */
+
+void
+append_file (p)
+ char *p;
+{
+ int fd;
+ struct stat statbuf;
+ long bytes_left;
+ union record *start;
+ long bufsiz, count;
+
+ if (0 != stat (p, &statbuf) || (fd = open (p, O_RDONLY | O_BINARY)) < 0)
+ {
+ msg_perror ("can't open file %s", p);
+ errors++;
+ return;
+ }
+
+ bytes_left = statbuf.st_size;
+
+ while (bytes_left > 0)
+ {
+ start = findrec ();
+ bufsiz = endofrecs ()->charptr - start->charptr;
+ if (bytes_left < bufsiz)
+ {
+ bufsiz = bytes_left;
+ count = bufsiz % RECORDSIZE;
+ if (count)
+ bzero (start->charptr + bytes_left, (int) (RECORDSIZE - count));
+ }
+ count = read (fd, start->charptr, bufsiz);
+ if (count < 0)
+ {
+ msg_perror ("read error at byte %ld reading %d bytes in file %s", statbuf.st_size - bytes_left, bufsiz, p);
+ exit (EX_ARGSBAD); /* FOO */
+ }
+ bytes_left -= count;
+ userec (start + (count - 1) / RECORDSIZE);
+ if (count != bufsiz)
+ {
+ msg ("%s: file shrunk by %d bytes, yark!", p, bytes_left);
+ abort ();
+ }
+ }
+ (void) close (fd);
+}
+
+#ifdef DONTDEF
+bprint (fp, buf, num)
+ FILE *fp;
+ char *buf;
+{
+ int c;
+
+ if (num == 0 || num == -1)
+ return;
+ fputs (" '", fp);
+ while (num--)
+ {
+ c = *buf++;
+ if (c == '\\')
+ fputs ("\\\\", fp);
+ else if (c >= ' ' && c <= '~')
+ putc (c, fp);
+ else
+ switch (c)
+ {
+ case '\n':
+ fputs ("\\n", fp);
+ break;
+ case '\r':
+ fputs ("\\r", fp);
+ break;
+ case '\b':
+ fputs ("\\b", fp);
+ break;
+ case '\0':
+ /* fputs("\\-",fp); */
+ break;
+ default:
+ fprintf (fp, "\\%03o", c);
+ break;
+ }
+ }
+ fputs ("'\n", fp);
+}
+
+#endif
+
+int number_of_blocks_read = 0;
+
+int number_of_new_records = 0;
+int number_of_records_needed = 0;
+
+union record *new_block = 0;
+union record *save_block = 0;
+
+void
+junk_archive ()
+{
+ int found_stuff = 0;
+ int status = 3;
+ int prev_status;
+ struct name *name;
+
+ /* int dummy_head; */
+ int number_of_records_to_skip = 0;
+ int number_of_records_to_keep = 0;
+ int number_of_kept_records_in_block;
+ int sub_status;
+ extern int write_archive_to_stdout;
+
+ /* fprintf(stderr,"Junk files\n"); */
+ name_gather ();
+ open_archive (2);
+
+ while (!found_stuff)
+ {
+ prev_status = status;
+ status = read_header ();
+ switch (status)
+ {
+ case EOF:
+ found_stuff = 1;
+ break;
+
+ case 0:
+ userec (head);
+ switch (prev_status)
+ {
+ case 3:
+ msg ("This doesn't look like a tar archive.");
+ /* FALL THROUGH */
+ case 2:
+ case 1:
+ msg ("Skipping to next header");
+ /* FALL THROUGH */
+ case 0:
+ break;
+ }
+ break;
+
+ case 1:
+ /* head->header.name[NAMSIZ-1] = '\0'; */
+ /* fprintf(stderr,"file %s\n",head->header.name); */
+ if ((name = name_scan (current_file_name)) == (struct name *) 0)
+ {
+ userec (head);
+ /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */
+ if (head->header.isextended)
+ skip_extended_headers ();
+ skip_file ((long) (hstat.st_size));
+ break;
+ }
+ name->found = 1;
+ found_stuff = 2;
+ break;
+
+ case 2:
+ found_stuff = 1;
+ break;
+ }
+ }
+ /* fprintf(stderr,"Out of first loop\n"); */
+
+ if (found_stuff != 2)
+ {
+ write_eot ();
+ close_archive ();
+ names_notfound ();
+ return;
+ }
+
+ if (write_archive_to_stdout)
+ write_archive_to_stdout = 0;
+ new_block = (union record *) malloc (blocksize);
+ if (new_block == 0)
+ {
+ msg ("Can't allocate secondary block of %d bytes", blocksize);
+ exit (EX_SYSTEM);
+ }
+
+ /* Save away records before this one in this block */
+ number_of_new_records = ar_record - ar_block;
+ number_of_records_needed = blocking - number_of_new_records;
+ if (number_of_new_records)
+ bcopy ((void *) ar_block, (void *) new_block, (number_of_new_records) * RECORDSIZE);
+
+ /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */
+ userec (head);
+ if (head->header.isextended)
+ skip_extended_headers ();
+ skip_file ((long) (hstat.st_size));
+ found_stuff = 0;
+ /* goto flush_file; */
+
+ for (;;)
+ {
+ /* Fill in a block */
+ /* another_file: */
+ if (ar_record == ar_last)
+ {
+ /* fprintf(stderr,"New block\n"); */
+ flush_archive ();
+ number_of_blocks_read++;
+ }
+ sub_status = read_header ();
+ /* fprintf(stderr,"Header type %d\n",sub_status); */
+
+ if (sub_status == 2 && f_ignorez)
+ {
+ userec (head);
+ continue;
+ }
+ if (sub_status == EOF || sub_status == 2)
+ {
+ found_stuff = 1;
+ bzero (new_block[number_of_new_records].charptr, RECORDSIZE * number_of_records_needed);
+ number_of_new_records += number_of_records_needed;
+ number_of_records_needed = 0;
+ write_block (0);
+ break;
+ }
+
+ if (sub_status == 0)
+ {
+ msg ("Deleting non-header from archive.");
+ userec (head);
+ continue;
+ }
+
+ /* Found another header. Yipee! */
+ /* head->header.name[NAMSIZ-1] = '\0'; */
+ /* fprintf(stderr,"File %s ",head->header.name); */
+ if (name = name_scan (current_file_name))
+ {
+ name->found = 1;
+ /* fprintf(stderr,"Flush it\n"); */
+ /* flush_file: */
+ /* decode_header(head,&hstat,&dummy_head,0); */
+ userec (head);
+ number_of_records_to_skip = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
+ /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */
+
+ while (ar_last - ar_record <= number_of_records_to_skip)
+ {
+
+ /* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */
+ number_of_records_to_skip -= (ar_last - ar_record);
+ flush_archive ();
+ number_of_blocks_read++;
+ /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */
+ }
+ ar_record += number_of_records_to_skip;
+ /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */
+ number_of_records_to_skip = 0;
+ continue;
+ }
+
+ /* copy_header: */
+ new_block[number_of_new_records] = *head;
+ number_of_new_records++;
+ number_of_records_needed--;
+ number_of_records_to_keep = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
+ userec (head);
+ if (number_of_records_needed == 0)
+ write_block (1);
+ /* copy_data: */
+ number_of_kept_records_in_block = ar_last - ar_record;
+ if (number_of_kept_records_in_block > number_of_records_to_keep)
+ number_of_kept_records_in_block = number_of_records_to_keep;
+
+ /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */
+
+ while (number_of_records_to_keep)
+ {
+ int n;
+
+ if (ar_record == ar_last)
+ {
+ /* fprintf(stderr,"Flush. . .\n"); */
+ fl_read ();
+ number_of_blocks_read++;
+ ar_record = ar_block;
+ number_of_kept_records_in_block = blocking;
+ if (number_of_kept_records_in_block > number_of_records_to_keep)
+ number_of_kept_records_in_block = number_of_records_to_keep;
+ }
+ n = number_of_kept_records_in_block;
+ if (n > number_of_records_needed)
+ n = number_of_records_needed;
+
+ /* fprintf(stderr,"Copying %d\n",n); */
+ bcopy ((void *) ar_record, (void *) (new_block + number_of_new_records), n * RECORDSIZE);
+ number_of_new_records += n;
+ number_of_records_needed -= n;
+ ar_record += n;
+ number_of_records_to_keep -= n;
+ number_of_kept_records_in_block -= n;
+ /* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n",
+ number_of_new_records,number_of_records_needed,number_of_records_to_keep,
+ number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */
+
+ if (number_of_records_needed == 0)
+ {
+ write_block (1);
+ }
+ }
+ }
+
+ write_eot ();
+ close_archive ();
+ names_notfound ();
+}
+
+void
+write_block (f)
+ int f;
+{
+ /* fprintf(stderr,"Write block\n"); */
+ /* We've filled out a block. Write it out. */
+
+ /* Backspace back to where we started. . . */
+ if (archive != STDIN)
+ (void) move_arch (-(number_of_blocks_read + 1));
+
+ save_block = ar_block;
+ ar_block = new_block;
+
+ if (archive == STDIN)
+ archive = STDOUT;
+ fl_write ();
+
+ if (archive == STDOUT)
+ archive = STDIN;
+ ar_block = save_block;
+
+ if (f)
+ {
+ /* Move the tape head back to where we were */
+ if (archive != STDIN)
+ (void) move_arch (number_of_blocks_read);
+ number_of_blocks_read--;
+ }
+
+ number_of_records_needed = blocking;
+ number_of_new_records = 0;
+}
+
+/* Move archive descriptor by n blocks worth. If n is positive we move
+ forward, else we move negative. If its a tape, MTIOCTOP had better
+ work. If its something else, we try to seek on it. If we can't
+ seek, we lose! */
+int
+move_arch (n)
+ int n;
+{
+ long cur;
+
+#ifdef MTIOCTOP
+ struct mtop t;
+ int er;
+
+ if (n > 0)
+ {
+ t.mt_op = MTFSR;
+ t.mt_count = n;
+ }
+ else
+ {
+ t.mt_op = MTBSR;
+ t.mt_count = -n;
+ }
+ if ((er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
+ return 1;
+ if (errno == EIO && (er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
+ return 1;
+#endif
+
+ cur = rmtlseek (archive, 0L, 1);
+ cur += blocksize * n;
+
+ /* fprintf(stderr,"Fore to %x\n",cur); */
+ if (rmtlseek (archive, cur, 0) != cur)
+ {
+ /* Lseek failed. Try a different method */
+ msg ("Couldn't re-position archive file.");
+ exit (EX_BADARCH);
+ }
+ return 3;
+}
OpenPOWER on IntegriCloud