]> 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 #ifndef NO_MTIO
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 prev_status=status;
114 status=read_header();
115 switch(status) {
116 case EOF:
117 found_end=1;
118 break;
119
120 case 0: /* A bad record */
121 userec(head);
122 switch(prev_status) {
123 case 3:
124 msg("This doesn't look like a tar archive.");
125 /* FALL THROUGH */
126 case 2:
127 case 1:
128 msg("Skipping to next header");
129 case 0:
130 break;
131 }
132 break;
133
134 /* A good record */
135 case 1:
136 /* printf("File %s\n",head->header.name); */
137 /* head->header.name[NAMSIZ-1]='\0'; */
138 if(cmd_mode==CMD_UPDATE && (name=name_scan(head->header.name))) {
139 /* struct stat hstat; */
140 struct stat nstat;
141 int head_standard;
142
143 decode_header(head,&hstat,&head_standard,0);
144 if(stat(head->header.name,&nstat)<0) {
145 msg_perror("can't stat %s:",head->header.name);
146 } else {
147 if(hstat.st_mtime>=nstat.st_mtime)
148 name->found++;
149 }
150 }
151 userec(head);
152 if (head->header.isextended)
153 skip_extended_headers();
154 skip_file((long)hstat.st_size);
155 break;
156
157 case 2:
158 ar_record=head;
159 found_end = 1;
160 break;
161 }
162 } while(!found_end);
163
164 reset_eof();
165 time_to_start_writing = 1;
166 output_start=ar_record->charptr;
167
168 while(p=name_from_list()) {
169 if(f_confirm && !confirm("add", p))
170 continue;
171 if(cmd_mode==CMD_CAT)
172 append_file(p);
173 else
174 dump_file(p,-1, 1);
175 }
176
177 write_eot();
178 close_archive();
179 names_notfound();
180 }
181
182 /* Catenate file p to the archive without creating a header for it. It had
183 better be a tar file or the archive is screwed */
184
185 void
186 append_file(p)
187 char *p;
188 {
189 int fd;
190 struct stat statbuf;
191 long bytes_left;
192 union record *start;
193 long bufsiz,count;
194
195 if(0 != stat(p,&statbuf) || (fd=open(p,O_RDONLY|O_BINARY))<0) {
196 msg_perror("can't open file %s",p);
197 errors++;
198 return;
199 }
200
201 bytes_left = statbuf.st_size;
202
203 while(bytes_left>0) {
204 start=findrec();
205 bufsiz=endofrecs()->charptr - start->charptr;
206 if(bytes_left < bufsiz) {
207 bufsiz = bytes_left;
208 count = bufsiz % RECORDSIZE;
209 if(count)
210 bzero(start->charptr + bytes_left,(int)(RECORDSIZE-count));
211 }
212 count=read(fd,start->charptr,bufsiz);
213 if(count<0) {
214 msg_perror("read error at byte %ld reading %d bytes in file %s",statbuf.st_size-bytes_left,bufsiz,p);
215 exit(EX_ARGSBAD); /* FOO */
216 }
217 bytes_left-=count;
218 userec(start+(count-1)/RECORDSIZE);
219 if(count!=bufsiz) {
220 msg("%s: file shrunk by %d bytes, yark!",p,bytes_left);
221 abort();
222 }
223 }
224 (void)close(fd);
225 }
226
227 #ifdef DONTDEF
228 bprint(fp,buf,num)
229 FILE *fp;
230 char *buf;
231 {
232 int c;
233
234 if(num==0 || num==-1)
235 return;
236 fputs(" '",fp);
237 while(num--) {
238 c= *buf++;
239 if(c=='\\') fputs("\\\\",fp);
240 else if(c>=' ' && c<='~')
241 putc(c,fp);
242 else switch(c) {
243 case '\n':
244 fputs("\\n",fp);
245 break;
246 case '\r':
247 fputs("\\r",fp);
248 break;
249 case '\b':
250 fputs("\\b",fp);
251 break;
252 case '\0':
253 /* fputs("\\-",fp); */
254 break;
255 default:
256 fprintf(fp,"\\%03o",c);
257 break;
258 }
259 }
260 fputs("'\n",fp);
261 }
262 #endif
263
264 int number_of_blocks_read = 0;
265
266 int number_of_new_records = 0;
267 int number_of_records_needed = 0;
268
269 union record *new_block = 0;
270 union record *save_block = 0;
271
272 void
273 junk_archive()
274 {
275 int found_stuff = 0;
276 int status = 3;
277 int prev_status;
278 struct name *name;
279
280 /* int dummy_head; */
281 int number_of_records_to_skip = 0;
282 int number_of_records_to_keep = 0;
283 int number_of_kept_records_in_block;
284 int sub_status;
285 extern int write_archive_to_stdout;
286
287 /* fprintf(stderr,"Junk files\n"); */
288 name_gather();
289 open_archive(2);
290
291 while(!found_stuff) {
292 prev_status=status;
293 status=read_header();
294 switch(status) {
295 case EOF:
296 found_stuff = 1;
297 break;
298
299 case 0:
300 userec(head);
301 switch(prev_status) {
302 case 3:
303 msg("This doesn't look like a tar archive.");
304 /* FALL THROUGH */
305 case 2:
306 case 1:
307 msg("Skipping to next header");
308 /* FALL THROUGH */
309 case 0:
310 break;
311 }
312 break;
313
314 case 1:
315 /* head->header.name[NAMSIZ-1] = '\0'; */
316 /* fprintf(stderr,"file %s\n",head->header.name); */
317 if((name=name_scan(head->header.name))==(struct name *)0) {
318 userec(head);
319 /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */
320 if (head->header.isextended)
321 skip_extended_headers();
322 skip_file((long)(hstat.st_size));
323 break;
324 }
325 name->found = 1;
326 found_stuff = 2;
327 break;
328
329 case 2:
330 found_stuff = 1;
331 break;
332 }
333 }
334 /* fprintf(stderr,"Out of first loop\n"); */
335
336 if(found_stuff!=2) {
337 write_eot();
338 close_archive();
339 names_notfound();
340 return;
341 }
342
343 if(write_archive_to_stdout)
344 write_archive_to_stdout = 0;
345 new_block = (union record *)malloc(blocksize);
346 if(new_block==0) {
347 msg("Can't allocate secondary block of %d bytes",blocksize);
348 exit(EX_SYSTEM);
349 }
350
351 /* Save away records before this one in this block */
352 number_of_new_records=ar_record-ar_block;
353 number_of_records_needed = blocking - number_of_new_records;
354 if(number_of_new_records)
355 bcopy((void *)ar_block,(void *)new_block,(number_of_new_records)*RECORDSIZE);
356
357 /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */
358 userec(head);
359 if (head->header.isextended)
360 skip_extended_headers();
361 skip_file((long)(hstat.st_size));
362 found_stuff=0;
363 /* goto flush_file; */
364
365 for(;;) {
366 /* Fill in a block */
367 /* another_file: */
368 if(ar_record==ar_last) {
369 /* fprintf(stderr,"New block\n"); */
370 flush_archive();
371 number_of_blocks_read++;
372 }
373 sub_status = read_header();
374 /* fprintf(stderr,"Header type %d\n",sub_status); */
375
376 if(sub_status==2 && f_ignorez) {
377 userec(head);
378 continue;
379 }
380 if(sub_status==EOF || sub_status==2) {
381 found_stuff = 1;
382 bzero(new_block[number_of_new_records].charptr,RECORDSIZE*number_of_records_needed);
383 number_of_new_records+=number_of_records_needed;
384 number_of_records_needed = 0;
385 write_block(0);
386 break;
387 }
388
389 if(sub_status==0) {
390 msg("Deleting non-header from archive.");
391 userec(head);
392 continue;
393 }
394
395 /* Found another header. Yipee! */
396 /* head->header.name[NAMSIZ-1] = '\0'; */
397 /* fprintf(stderr,"File %s ",head->header.name); */
398 if(name=name_scan(head->header.name)) {
399 name->found = 1;
400 /* fprintf(stderr,"Flush it\n"); */
401 /* flush_file: */
402 /* decode_header(head,&hstat,&dummy_head,0); */
403 userec(head);
404 number_of_records_to_skip=(hstat.st_size+RECORDSIZE-1)/RECORDSIZE;
405 /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */
406
407 while(ar_last-ar_record<=number_of_records_to_skip) {
408
409 /* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */
410 number_of_records_to_skip -= (ar_last - ar_record);
411 flush_archive();
412 number_of_blocks_read++;
413 /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */
414 }
415 ar_record+=number_of_records_to_skip;
416 /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */
417 number_of_records_to_skip = 0;
418 continue;
419 }
420
421 /* copy_header: */
422 new_block[number_of_new_records]= *head;
423 number_of_new_records++;
424 number_of_records_needed--;
425 number_of_records_to_keep=(hstat.st_size+RECORDSIZE-1)/RECORDSIZE;
426 userec(head);
427 if(number_of_records_needed==0)
428 write_block(1);
429 /* copy_data: */
430 number_of_kept_records_in_block = ar_last - ar_record;
431 if(number_of_kept_records_in_block > number_of_records_to_keep)
432 number_of_kept_records_in_block = number_of_records_to_keep;
433
434 /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */
435
436 while(number_of_records_to_keep) {
437 int n;
438
439 if(ar_record==ar_last) {
440 /* fprintf(stderr,"Flush. . .\n"); */
441 fl_read();
442 number_of_blocks_read++;
443 ar_record=ar_block;
444 number_of_kept_records_in_block = blocking;
445 if(number_of_kept_records_in_block > number_of_records_to_keep)
446 number_of_kept_records_in_block = number_of_records_to_keep;
447 }
448 n = number_of_kept_records_in_block;
449 if(n>number_of_records_needed)
450 n = number_of_records_needed;
451
452 /* fprintf(stderr,"Copying %d\n",n); */
453 bcopy((void *)ar_record, (void *)(new_block+number_of_new_records), n*RECORDSIZE);
454 number_of_new_records += n;
455 number_of_records_needed -= n;
456 ar_record += n;
457 number_of_records_to_keep -= n;
458 number_of_kept_records_in_block -= n;
459 /* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n",
460 number_of_new_records,number_of_records_needed,number_of_records_to_keep,
461 number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */
462
463 if(number_of_records_needed == 0) {
464 write_block(1);
465 }
466 }
467 }
468
469 write_eot();
470 close_archive();
471 names_notfound();
472 }
473
474 void
475 write_block(f)
476 int f;
477 {
478 /* fprintf(stderr,"Write block\n"); */
479 /* We've filled out a block. Write it out. */
480
481 /* Backspace back to where we started. . . */
482 if(archive!=STDIN)
483 (void)move_arch(-(number_of_blocks_read+1));
484
485 save_block = ar_block;
486 ar_block = new_block;
487
488 if(archive==STDIN)
489 archive=STDOUT;
490 fl_write();
491
492 if(archive==STDOUT)
493 archive=STDIN;
494 ar_block = save_block;
495
496 if(f) {
497 /* Move the tape head back to where we were */
498 if(archive!=STDIN)
499 (void)move_arch(number_of_blocks_read);
500 number_of_blocks_read--;
501 }
502
503 number_of_records_needed = blocking;
504 number_of_new_records = 0;
505 }
506
507 /* Move archive descriptor by n blocks worth. If n is positive we move
508 forward, else we move negative. If its a tape, MTIOCTOP had better
509 work. If its something else, we try to seek on it. If we can't
510 seek, we lose! */
511 int
512 move_arch(n)
513 int n;
514 {
515 long cur;
516
517 #ifdef MTIOCTOP
518 struct mtop t;
519 int er;
520
521 if(n>0) {
522 t.mt_op = MTFSR;
523 t.mt_count = n;
524 } else {
525 t.mt_op = MTBSR;
526 t.mt_count = -n;
527 }
528 if((er=rmtioctl(archive,MTIOCTOP,&t))>=0)
529 return 1;
530 if(errno==EIO && (er=rmtioctl(archive,MTIOCTOP,&t))>=0)
531 return 1;
532 #endif
533
534 cur=rmtlseek(archive,0L,1);
535 cur+=blocksize*n;
536
537 /* fprintf(stderr,"Fore to %x\n",cur); */
538 if(rmtlseek(archive,cur,0)!=cur) {
539 /* Lseek failed. Try a different method */
540 msg("Couldn't re-position archive file.");
541 exit(EX_BADARCH);
542 }
543 return 3;
544 }
545
This page took 0.066051 seconds and 5 git commands to generate.