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