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