]> Dogcows Code - chaz/tar/blob - src/update.c
*** empty log message ***
[chaz/tar] / src / update.c
1 /* Update a tar archive.
2 Copyright (C) 1988, 1992 Free Software Foundation
3
4 This file is part of GNU Tar.
5
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 /* JF implement the 'r' 'u' and 'A' options for tar. */
21 /* The 'A' option is my own invention: It means that the file-names are
22 tar files, and they should simply be appended to the end of the archive.
23 No attempt is made to block the reads from the args; if they're on raw
24 tape or something like that, it'll probably lose. . . */
25
26 #include <sys/types.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #ifndef STDC_HEADERS
30 extern int errno;
31 #endif
32
33 #ifdef HAVE_SYS_MTIO_H
34 #include <sys/ioctl.h>
35 #include <sys/mtio.h>
36 #endif
37
38 #ifdef BSD42
39 #include <sys/file.h>
40 #else
41 #ifndef V7
42 #include <fcntl.h>
43 #endif
44 #endif
45
46 #ifndef __MSDOS__
47 #include <pwd.h>
48 #include <grp.h>
49 #endif
50
51 #define STDIN 0
52 #define STDOUT 1
53
54 #include "tar.h"
55 #include "port.h"
56 #include "rmt.h"
57
58 int time_to_start_writing = 0; /* We've hit the end of the old stuff,
59 and its time to start writing new stuff
60 to the tape. This involves seeking
61 back one block and re-writing the current
62 block (which has been changed). */
63
64 char *output_start; /* Pointer to where we started to write in
65 the first block we write out. This is used
66 if we can't backspace the output and have
67 to null out the first part of the block */
68
69 extern void skip_file ();
70 extern void skip_extended_headers ();
71
72 extern union record *head;
73 extern struct stat hstat;
74
75 void append_file ();
76 void close_archive ();
77 int confirm ();
78 void decode_header ();
79 void fl_read ();
80 void fl_write ();
81 void flush_archive ();
82 int move_arch ();
83 struct name *name_scan ();
84 char *name_from_list ();
85 void name_expand ();
86 void name_gather ();
87 void names_notfound ();
88 void open_archive ();
89 int read_header ();
90 void reset_eof ();
91 void write_block ();
92 void write_eot ();
93
94 /* Implement the 'r' (add files to end of archive), and 'u' (add files to
95 end of archive if they arent there, or are more up to date than the
96 version in the archive.) commands.*/
97 void
98 update_archive ()
99 {
100 int found_end = 0;
101 int status = 3;
102 int prev_status;
103 char *p;
104 struct name *name;
105 extern void dump_file ();
106
107 name_gather ();
108 if (cmd_mode == CMD_UPDATE)
109 name_expand ();
110 open_archive (2); /* Open for updating */
111
112 do
113 {
114 prev_status = status;
115 status = read_header ();
116 switch (status)
117 {
118 case EOF:
119 found_end = 1;
120 break;
121
122 case 0: /* A bad record */
123 userec (head);
124 switch (prev_status)
125 {
126 case 3:
127 msg ("This doesn't look like a tar archive.");
128 /* FALL THROUGH */
129 case 2:
130 case 1:
131 msg ("Skipping to next header");
132 case 0:
133 break;
134 }
135 break;
136
137 /* A good record */
138 case 1:
139 /* printf("File %s\n",head->header.name); */
140 /* head->header.name[NAMSIZ-1]='\0'; */
141 if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name)))
142 {
143
144 /* struct stat hstat; */
145 struct stat nstat;
146 int head_standard;
147
148 decode_header (head, &hstat, &head_standard, 0);
149 if (stat (current_file_name, &nstat) < 0)
150 {
151 msg_perror ("can't stat %s:", current_file_name);
152 }
153 else
154 {
155 if (hstat.st_mtime >= nstat.st_mtime)
156 name->found++;
157 }
158 }
159 userec (head);
160 if (head->header.isextended)
161 skip_extended_headers ();
162 skip_file ((long) hstat.st_size);
163 break;
164
165 case 2:
166 ar_record = head;
167 found_end = 1;
168 break;
169 }
170 }
171 while (!found_end);
172
173 reset_eof ();
174 time_to_start_writing = 1;
175 output_start = ar_record->charptr;
176
177 while (p = name_from_list ())
178 {
179 if (f_confirm && !confirm ("add", p))
180 continue;
181 if (cmd_mode == CMD_CAT)
182 append_file (p);
183 else
184 dump_file (p, -1, 1);
185 }
186
187 write_eot ();
188 close_archive ();
189 names_notfound ();
190 }
191
192 /* Catenate file p to the archive without creating a header for it. It had
193 better be a tar file or the archive is screwed */
194
195 void
196 append_file (p)
197 char *p;
198 {
199 int fd;
200 struct stat statbuf;
201 long bytes_left;
202 union record *start;
203 long bufsiz, count;
204
205 if (0 != stat (p, &statbuf) || (fd = open (p, O_RDONLY | O_BINARY)) < 0)
206 {
207 msg_perror ("can't open file %s", p);
208 errors++;
209 return;
210 }
211
212 bytes_left = statbuf.st_size;
213
214 while (bytes_left > 0)
215 {
216 start = findrec ();
217 bufsiz = endofrecs ()->charptr - start->charptr;
218 if (bytes_left < bufsiz)
219 {
220 bufsiz = bytes_left;
221 count = bufsiz % RECORDSIZE;
222 if (count)
223 bzero (start->charptr + bytes_left, (int) (RECORDSIZE - count));
224 }
225 count = read (fd, start->charptr, bufsiz);
226 if (count < 0)
227 {
228 msg_perror ("read error at byte %ld reading %d bytes in file %s", statbuf.st_size - bytes_left, bufsiz, p);
229 exit (EX_ARGSBAD); /* FOO */
230 }
231 bytes_left -= count;
232 userec (start + (count - 1) / RECORDSIZE);
233 if (count != bufsiz)
234 {
235 msg ("%s: file shrunk by %d bytes, yark!", p, bytes_left);
236 abort ();
237 }
238 }
239 (void) close (fd);
240 }
241
242 #ifdef DONTDEF
243 bprint (fp, buf, num)
244 FILE *fp;
245 char *buf;
246 {
247 int c;
248
249 if (num == 0 || num == -1)
250 return;
251 fputs (" '", fp);
252 while (num--)
253 {
254 c = *buf++;
255 if (c == '\\')
256 fputs ("\\\\", fp);
257 else if (c >= ' ' && c <= '~')
258 putc (c, fp);
259 else
260 switch (c)
261 {
262 case '\n':
263 fputs ("\\n", fp);
264 break;
265 case '\r':
266 fputs ("\\r", fp);
267 break;
268 case '\b':
269 fputs ("\\b", fp);
270 break;
271 case '\0':
272 /* fputs("\\-",fp); */
273 break;
274 default:
275 fprintf (fp, "\\%03o", c);
276 break;
277 }
278 }
279 fputs ("'\n", fp);
280 }
281
282 #endif
283
284 int number_of_blocks_read = 0;
285
286 int number_of_new_records = 0;
287 int number_of_records_needed = 0;
288
289 union record *new_block = 0;
290 union record *save_block = 0;
291
292 void
293 junk_archive ()
294 {
295 int found_stuff = 0;
296 int status = 3;
297 int prev_status;
298 struct name *name;
299
300 /* int dummy_head; */
301 int number_of_records_to_skip = 0;
302 int number_of_records_to_keep = 0;
303 int number_of_kept_records_in_block;
304 int sub_status;
305 extern int write_archive_to_stdout;
306
307 /* fprintf(stderr,"Junk files\n"); */
308 name_gather ();
309 open_archive (2);
310
311 while (!found_stuff)
312 {
313 prev_status = status;
314 status = read_header ();
315 switch (status)
316 {
317 case EOF:
318 found_stuff = 1;
319 break;
320
321 case 0:
322 userec (head);
323 switch (prev_status)
324 {
325 case 3:
326 msg ("This doesn't look like a tar archive.");
327 /* FALL THROUGH */
328 case 2:
329 case 1:
330 msg ("Skipping to next header");
331 /* FALL THROUGH */
332 case 0:
333 break;
334 }
335 break;
336
337 case 1:
338 /* head->header.name[NAMSIZ-1] = '\0'; */
339 /* fprintf(stderr,"file %s\n",head->header.name); */
340 if ((name = name_scan (current_file_name)) == (struct name *) 0)
341 {
342 userec (head);
343 /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */
344 if (head->header.isextended)
345 skip_extended_headers ();
346 skip_file ((long) (hstat.st_size));
347 break;
348 }
349 name->found = 1;
350 found_stuff = 2;
351 break;
352
353 case 2:
354 found_stuff = 1;
355 break;
356 }
357 }
358 /* fprintf(stderr,"Out of first loop\n"); */
359
360 if (found_stuff != 2)
361 {
362 write_eot ();
363 close_archive ();
364 names_notfound ();
365 return;
366 }
367
368 if (write_archive_to_stdout)
369 write_archive_to_stdout = 0;
370 new_block = (union record *) malloc (blocksize);
371 if (new_block == 0)
372 {
373 msg ("Can't allocate secondary block of %d bytes", blocksize);
374 exit (EX_SYSTEM);
375 }
376
377 /* Save away records before this one in this block */
378 number_of_new_records = ar_record - ar_block;
379 number_of_records_needed = blocking - number_of_new_records;
380 if (number_of_new_records)
381 bcopy ((void *) ar_block, (void *) new_block, (number_of_new_records) * RECORDSIZE);
382
383 /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */
384 userec (head);
385 if (head->header.isextended)
386 skip_extended_headers ();
387 skip_file ((long) (hstat.st_size));
388 found_stuff = 0;
389 /* goto flush_file; */
390
391 for (;;)
392 {
393 /* Fill in a block */
394 /* another_file: */
395 if (ar_record == ar_last)
396 {
397 /* fprintf(stderr,"New block\n"); */
398 flush_archive ();
399 number_of_blocks_read++;
400 }
401 sub_status = read_header ();
402 /* fprintf(stderr,"Header type %d\n",sub_status); */
403
404 if (sub_status == 2 && f_ignorez)
405 {
406 userec (head);
407 continue;
408 }
409 if (sub_status == EOF || sub_status == 2)
410 {
411 found_stuff = 1;
412 bzero (new_block[number_of_new_records].charptr, RECORDSIZE * number_of_records_needed);
413 number_of_new_records += number_of_records_needed;
414 number_of_records_needed = 0;
415 write_block (0);
416 break;
417 }
418
419 if (sub_status == 0)
420 {
421 msg ("Deleting non-header from archive.");
422 userec (head);
423 continue;
424 }
425
426 /* Found another header. Yipee! */
427 /* head->header.name[NAMSIZ-1] = '\0'; */
428 /* fprintf(stderr,"File %s ",head->header.name); */
429 if (name = name_scan (current_file_name))
430 {
431 name->found = 1;
432 /* fprintf(stderr,"Flush it\n"); */
433 /* flush_file: */
434 /* decode_header(head,&hstat,&dummy_head,0); */
435 userec (head);
436 number_of_records_to_skip = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
437 /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */
438
439 while (ar_last - ar_record <= number_of_records_to_skip)
440 {
441
442 /* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */
443 number_of_records_to_skip -= (ar_last - ar_record);
444 flush_archive ();
445 number_of_blocks_read++;
446 /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */
447 }
448 ar_record += number_of_records_to_skip;
449 /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */
450 number_of_records_to_skip = 0;
451 continue;
452 }
453
454 /* copy_header: */
455 new_block[number_of_new_records] = *head;
456 number_of_new_records++;
457 number_of_records_needed--;
458 number_of_records_to_keep = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
459 userec (head);
460 if (number_of_records_needed == 0)
461 write_block (1);
462 /* copy_data: */
463 number_of_kept_records_in_block = ar_last - ar_record;
464 if (number_of_kept_records_in_block > number_of_records_to_keep)
465 number_of_kept_records_in_block = number_of_records_to_keep;
466
467 /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */
468
469 while (number_of_records_to_keep)
470 {
471 int n;
472
473 if (ar_record == ar_last)
474 {
475 /* fprintf(stderr,"Flush. . .\n"); */
476 fl_read ();
477 number_of_blocks_read++;
478 ar_record = ar_block;
479 number_of_kept_records_in_block = blocking;
480 if (number_of_kept_records_in_block > number_of_records_to_keep)
481 number_of_kept_records_in_block = number_of_records_to_keep;
482 }
483 n = number_of_kept_records_in_block;
484 if (n > number_of_records_needed)
485 n = number_of_records_needed;
486
487 /* fprintf(stderr,"Copying %d\n",n); */
488 bcopy ((void *) ar_record, (void *) (new_block + number_of_new_records), n * RECORDSIZE);
489 number_of_new_records += n;
490 number_of_records_needed -= n;
491 ar_record += n;
492 number_of_records_to_keep -= n;
493 number_of_kept_records_in_block -= n;
494 /* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n",
495 number_of_new_records,number_of_records_needed,number_of_records_to_keep,
496 number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */
497
498 if (number_of_records_needed == 0)
499 {
500 write_block (1);
501 }
502 }
503 }
504
505 write_eot ();
506 close_archive ();
507 names_notfound ();
508 }
509
510 void
511 write_block (f)
512 int f;
513 {
514 /* fprintf(stderr,"Write block\n"); */
515 /* We've filled out a block. Write it out. */
516
517 /* Backspace back to where we started. . . */
518 if (archive != STDIN)
519 (void) move_arch (-(number_of_blocks_read + 1));
520
521 save_block = ar_block;
522 ar_block = new_block;
523
524 if (archive == STDIN)
525 archive = STDOUT;
526 fl_write ();
527
528 if (archive == STDOUT)
529 archive = STDIN;
530 ar_block = save_block;
531
532 if (f)
533 {
534 /* Move the tape head back to where we were */
535 if (archive != STDIN)
536 (void) move_arch (number_of_blocks_read);
537 number_of_blocks_read--;
538 }
539
540 number_of_records_needed = blocking;
541 number_of_new_records = 0;
542 }
543
544 /* Move archive descriptor by n blocks worth. If n is positive we move
545 forward, else we move negative. If its a tape, MTIOCTOP had better
546 work. If its something else, we try to seek on it. If we can't
547 seek, we lose! */
548 int
549 move_arch (n)
550 int n;
551 {
552 long cur;
553
554 #ifdef MTIOCTOP
555 struct mtop t;
556 int er;
557
558 if (n > 0)
559 {
560 t.mt_op = MTFSR;
561 t.mt_count = n;
562 }
563 else
564 {
565 t.mt_op = MTBSR;
566 t.mt_count = -n;
567 }
568 if ((er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
569 return 1;
570 if (errno == EIO && (er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
571 return 1;
572 #endif
573
574 cur = rmtlseek (archive, 0L, 1);
575 cur += blocksize * n;
576
577 /* fprintf(stderr,"Fore to %x\n",cur); */
578 if (rmtlseek (archive, cur, 0) != cur)
579 {
580 /* Lseek failed. Try a different method */
581 msg ("Couldn't re-position archive file.");
582 exit (EX_BADARCH);
583 }
584 return 3;
585 }
This page took 0.059191 seconds and 5 git commands to generate.