Research V7 development
[unix-history] / usr / src / cmd / tar / tar.c
CommitLineData
c8761a23
KT
1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <sys/dir.h>
5#include <signal.h>
6
7char *sprintf();
8char *strcat();
9daddr_t bsrch();
10#define TBLOCK 512
11#define NBLOCK 20
12#define NAMSIZ 100
13union hblock {
14 char dummy[TBLOCK];
15 struct header {
16 char name[NAMSIZ];
17 char mode[8];
18 char uid[8];
19 char gid[8];
20 char size[12];
21 char mtime[12];
22 char chksum[8];
23 char linkflag;
24 char linkname[NAMSIZ];
25 } dbuf;
26} dblock, tbuf[NBLOCK];
27
28struct linkbuf {
29 ino_t inum;
30 dev_t devnum;
31 int count;
32 char pathname[NAMSIZ];
33 struct linkbuf *nextp;
34} *ihead;
35
36struct stat stbuf;
37
38int rflag, xflag, vflag, tflag, mt, cflag, mflag;
39int term, chksum, wflag, recno, first, linkerrok;
40int freemem = 1;
41int nblock = 1;
42
43daddr_t low;
44daddr_t high;
45
46FILE *tfile;
47char tname[] = "/tmp/tarXXXXXX";
48
49
50char *usefile;
51char magtape[] = "/dev/mt1";
52
53char *malloc();
54
55main(argc, argv)
56int argc;
57char *argv[];
58{
59 char *cp;
60 int onintr(), onquit(), onhup(), onterm();
61
62 if (argc < 2)
63 usage();
64
65 tfile = NULL;
66 usefile = magtape;
67 argv[argc] = 0;
68 argv++;
69 for (cp = *argv++; *cp; cp++)
70 switch(*cp) {
71 case 'f':
72 usefile = *argv++;
73 if (nblock == 1)
74 nblock = 0;
75 break;
76 case 'c':
77 cflag++;
78 rflag++;
79 break;
80 case 'u':
81 mktemp(tname);
82 if ((tfile = fopen(tname, "w")) == NULL) {
83 fprintf(stderr, "Tar: cannot create temporary file (%s)\n", tname);
84 done(1);
85 }
86 fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n");
87 /* FALL THROUGH */
88 case 'r':
89 rflag++;
90 if (nblock != 1 && cflag == 0) {
91noupdate:
92 fprintf(stderr, "Tar: Blocked tapes cannot be updated (yet)\n");
93 done(1);
94 }
95 break;
96 case 'v':
97 vflag++;
98 break;
99 case 'w':
100 wflag++;
101 break;
102 case 'x':
103 xflag++;
104 break;
105 case 't':
106 tflag++;
107 break;
108 case 'm':
109 mflag++;
110 break;
111 case '-':
112 break;
113 case '0':
114 case '1':
115 magtape[7] = *cp;
116 usefile = magtape;
117 break;
118 case 'b':
119 nblock = atoi(*argv++);
120 if (nblock > NBLOCK || nblock <= 0) {
121 fprintf(stderr, "Invalid blocksize. (Max %d)\n", NBLOCK);
122 done(1);
123 }
124 if (rflag && !cflag)
125 goto noupdate;
126 break;
127 case 'l':
128 linkerrok++;
129 break;
130 default:
131 fprintf(stderr, "tar: %c: unknown option\n", *cp);
132 usage();
133 }
134
135 if (rflag) {
136 if (cflag && tfile != NULL) {
137 usage();
138 done(1);
139 }
140 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
141 signal(SIGINT, onintr);
142 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
143 signal(SIGHUP, onhup);
144 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
145 signal(SIGQUIT, onquit);
146/*
147 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
148 signal(SIGTERM, onterm);
149*/
150 if (strcmp(usefile, "-") == 0) {
151 if (cflag == 0) {
152 fprintf(stderr, "Can only create standard output archives\n");
153 done(1);
154 }
155 mt = dup(1);
156 nblock = 1;
157 }
158 else if ((mt = open(usefile, 2)) < 0) {
159 if (cflag == 0 || (mt = creat(usefile, 0666)) < 0) {
160 fprintf(stderr, "tar: cannot open %s\n", usefile);
161 done(1);
162 }
163 }
164 if (cflag == 0 && nblock == 0)
165 nblock = 1;
166 dorep(argv);
167 }
168 else if (xflag) {
169 if (strcmp(usefile, "-") == 0) {
170 mt = dup(0);
171 nblock = 1;
172 }
173 else if ((mt = open(usefile, 0)) < 0) {
174 fprintf(stderr, "tar: cannot open %s\n", usefile);
175 done(1);
176 }
177 doxtract(argv);
178 }
179 else if (tflag) {
180 if (strcmp(usefile, "-") == 0) {
181 mt = dup(0);
182 nblock = 1;
183 }
184 else if ((mt = open(usefile, 0)) < 0) {
185 fprintf(stderr, "tar: cannot open %s\n", usefile);
186 done(1);
187 }
188 dotable();
189 }
190 else
191 usage();
192 done(0);
193}
194
195usage()
196{
197 fprintf(stderr, "tar: usage tar -{txru}[cvfblm] [tapefile] [blocksize] file1 file2...\n");
198 done(1);
199}
200
201dorep(argv)
202char *argv[];
203{
204 register char *cp, *cp2;
205 char wdir[60];
206
207 if (!cflag) {
208 getdir();
209 do {
210 passtape();
211 if (term)
212 done(0);
213 getdir();
214 } while (!endtape());
215 if (tfile != NULL) {
216 char buf[200];
217
218 strcat(buf, "sort +0 -1 +1nr ");
219 strcat(buf, tname);
220 strcat(buf, " -o ");
221 strcat(buf, tname);
222 sprintf(buf, "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX;mv %sX %s",
223 tname, tname, tname, tname, tname, tname);
224 fflush(tfile);
225 system(buf);
226 freopen(tname, "r", tfile);
227 fstat(fileno(tfile), &stbuf);
228 high = stbuf.st_size;
229 }
230 }
231
232 getwdir(wdir);
233 while (*argv && ! term) {
234 cp2 = *argv;
235 for (cp = *argv; *cp; cp++)
236 if (*cp == '/')
237 cp2 = cp;
238 if (cp2 != *argv) {
239 *cp2 = '\0';
240 chdir(*argv);
241 *cp2 = '/';
242 cp2++;
243 }
244 putfile(*argv++, cp2);
245 chdir(wdir);
246 }
247 putempty();
248 putempty();
249 flushtape();
250 if (linkerrok == 1)
251 for (; ihead != NULL; ihead = ihead->nextp)
252 if (ihead->count != 0)
253 fprintf(stderr, "Missing links to %s\n", ihead->pathname);
254}
255
256endtape()
257{
258 if (dblock.dbuf.name[0] == '\0') {
259 backtape();
260 return(1);
261 }
262 else
263 return(0);
264}
265
266getdir()
267{
268 register struct stat *sp;
269 int i;
270
271 readtape( (char *) &dblock);
272 if (dblock.dbuf.name[0] == '\0')
273 return;
274 sp = &stbuf;
275 sscanf(dblock.dbuf.mode, "%o", &i);
276 sp->st_mode = i;
277 sscanf(dblock.dbuf.uid, "%o", &i);
278 sp->st_uid = i;
279 sscanf(dblock.dbuf.gid, "%o", &i);
280 sp->st_gid = i;
281 sscanf(dblock.dbuf.size, "%lo", &sp->st_size);
282 sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime);
283 sscanf(dblock.dbuf.chksum, "%o", &chksum);
284 if (chksum != checksum()) {
285 fprintf(stderr, "directory checksum error\n");
286 done(2);
287 }
288 if (tfile != NULL)
289 fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime);
290}
291
292passtape()
293{
294 long blocks;
295 char buf[TBLOCK];
296
297 if (dblock.dbuf.linkflag == '1')
298 return;
299 blocks = stbuf.st_size;
300 blocks += TBLOCK-1;
301 blocks /= TBLOCK;
302
303 while (blocks-- > 0)
304 readtape(buf);
305}
306
307putfile(longname, shortname)
308char *longname;
309char *shortname;
310{
311 int infile;
312 long blocks;
313 char buf[TBLOCK];
314 register char *cp, *cp2;
315 struct direct dbuf;
316 int i, j;
317
318 infile = open(shortname, 0);
319 if (infile < 0) {
320 fprintf(stderr, "tar: %s: cannot open file\n", longname);
321 return;
322 }
323
324 fstat(infile, &stbuf);
325
326 if (tfile != NULL && checkupdate(longname) == 0) {
327 close(infile);
328 return;
329 }
330 if (checkw('r', longname) == 0) {
331 close(infile);
332 return;
333 }
334
335 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
336 for (i = 0, cp = buf; *cp++ = longname[i++];);
337 *--cp = '/';
338 cp++;
339 i = 0;
340 chdir(shortname);
341 while (read(infile, (char *)&dbuf, sizeof(dbuf)) > 0 && !term) {
342 if (dbuf.d_ino == 0) {
343 i++;
344 continue;
345 }
346 if (strcmp(".", dbuf.d_name) == 0 || strcmp("..", dbuf.d_name) == 0) {
347 i++;
348 continue;
349 }
350 cp2 = cp;
351 for (j=0; j < DIRSIZ; j++)
352 *cp2++ = dbuf.d_name[j];
353 *cp2 = '\0';
354 close(infile);
355 putfile(buf, cp);
356 infile = open(".", 0);
357 i++;
358 lseek(infile, (long) (sizeof(dbuf) * i), 0);
359 }
360 close(infile);
361 chdir("..");
362 return;
363 }
364 if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
365 fprintf(stderr, "tar: %s is not a file. Not dumped\n", longname);
366 return;
367 }
368
369 tomodes(&stbuf);
370
371 cp2 = longname;
372 for (cp = dblock.dbuf.name, i=0; (*cp++ = *cp2++) && i < NAMSIZ; i++);
373 if (i >= NAMSIZ) {
374 fprintf(stderr, "%s: file name too long\n", longname);
375 close(infile);
376 return;
377 }
378
379 if (stbuf.st_nlink > 1) {
380 struct linkbuf *lp;
381 int found = 0;
382
383 for (lp = ihead; lp != NULL; lp = lp->nextp) {
384 if (lp->inum == stbuf.st_ino && lp->devnum == stbuf.st_dev) {
385 found++;
386 break;
387 }
388 }
389 if (found) {
390 strcpy(dblock.dbuf.linkname, lp->pathname);
391 dblock.dbuf.linkflag = '1';
392 sprintf(dblock.dbuf.chksum, "%6o", checksum());
393 writetape( (char *) &dblock);
394 if (vflag) {
395 fprintf(stderr, "a %s ", longname);
396 fprintf(stderr, "link to %s\n", lp->pathname);
397 }
398 lp->count--;
399 close(infile);
400 return;
401 }
402 else {
403 lp = (struct linkbuf *) malloc(sizeof(*lp));
404 if (lp == NULL) {
405 if (freemem) {
406 fprintf(stderr, "Out of memory. Link information lost\n");
407 freemem = 0;
408 }
409 }
410 else {
411 lp->nextp = ihead;
412 ihead = lp;
413 lp->inum = stbuf.st_ino;
414 lp->devnum = stbuf.st_dev;
415 lp->count = stbuf.st_nlink - 1;
416 strcpy(lp->pathname, longname);
417 }
418 }
419 }
420
421 blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK;
422 if (vflag) {
423 fprintf(stderr, "a %s ", longname);
424 fprintf(stderr, "%ld blocks\n", blocks);
425 }
426 sprintf(dblock.dbuf.chksum, "%6o", checksum());
427 writetape( (char *) &dblock);
428
429 while ((i = read(infile, buf, TBLOCK)) > 0 && blocks > 0) {
430 writetape(buf);
431 blocks--;
432 }
433 close(infile);
434 if (blocks != 0 || i != 0)
435 fprintf(stderr, "%s: file changed size\n", longname);
436 while (blocks-- > 0)
437 putempty();
438}
439
440
441
442doxtract(argv)
443char *argv[];
444{
445 long blocks, bytes;
446 char buf[TBLOCK];
447 char **cp;
448 int ofile;
449
450 for (;;) {
451 getdir();
452 if (endtape())
453 break;
454
455 if (*argv == 0)
456 goto gotit;
457
458 for (cp = argv; *cp; cp++)
459 if (prefix(*cp, dblock.dbuf.name))
460 goto gotit;
461 passtape();
462 continue;
463
464gotit:
465 if (checkw('x', dblock.dbuf.name) == 0) {
466 passtape();
467 continue;
468 }
469
470 checkdir(dblock.dbuf.name);
471
472 if (dblock.dbuf.linkflag == '1') {
473 unlink(dblock.dbuf.name);
474 if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) {
475 fprintf(stderr, "%s: cannot link\n", dblock.dbuf.name);
476 continue;
477 }
478 if (vflag)
479 fprintf(stderr, "%s linked to %s\n", dblock.dbuf.name, dblock.dbuf.linkname);
480 continue;
481 }
482 if ((ofile = creat(dblock.dbuf.name, stbuf.st_mode & 07777)) < 0) {
483 fprintf(stderr, "tar: %s - cannot create\n", dblock.dbuf.name);
484 passtape();
485 continue;
486 }
487
488 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid);
489
490 blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK;
491 if (vflag)
492 fprintf(stderr, "x %s, %ld bytes, %ld tape blocks\n", dblock.dbuf.name, bytes, blocks);
493 while (blocks-- > 0) {
494 readtape(buf);
495 if (bytes > TBLOCK) {
496 if (write(ofile, buf, TBLOCK) < 0) {
497 fprintf(stderr, "tar: %s: HELP - extract write error\n", dblock.dbuf.name);
498 done(2);
499 }
500 } else
501 if (write(ofile, buf, (int) bytes) < 0) {
502 fprintf(stderr, "tar: %s: HELP - extract write error\n", dblock.dbuf.name);
503 done(2);
504 }
505 bytes -= TBLOCK;
506 }
507 close(ofile);
508 if (mflag == 0) {
509 time_t timep[2];
510
511 timep[0] = time(NULL);
512 timep[1] = stbuf.st_mtime;
513 utime(dblock.dbuf.name, timep);
514 }
515 }
516}
517
518dotable()
519{
520 for (;;) {
521 getdir();
522 if (endtape())
523 break;
524 if (vflag)
525 longt(&stbuf);
526 printf("%s", dblock.dbuf.name);
527 if (dblock.dbuf.linkflag == '1')
528 printf(" linked to %s", dblock.dbuf.linkname);
529 printf("\n");
530 passtape();
531 }
532}
533
534putempty()
535{
536 char buf[TBLOCK];
537 char *cp;
538
539 for (cp = buf; cp < &buf[TBLOCK]; )
540 *cp++ = '\0';
541 writetape(buf);
542}
543
544longt(st)
545register struct stat *st;
546{
547 register char *cp;
548 char *ctime();
549
550 pmode(st);
551 printf("%3d/%1d", st->st_uid, st->st_gid);
552 printf("%7D", st->st_size);
553 cp = ctime(&st->st_mtime);
554 printf(" %-12.12s %-4.4s ", cp+4, cp+20);
555}
556
557#define SUID 04000
558#define SGID 02000
559#define ROWN 0400
560#define WOWN 0200
561#define XOWN 0100
562#define RGRP 040
563#define WGRP 020
564#define XGRP 010
565#define ROTH 04
566#define WOTH 02
567#define XOTH 01
568#define STXT 01000
569int m1[] = { 1, ROWN, 'r', '-' };
570int m2[] = { 1, WOWN, 'w', '-' };
571int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
572int m4[] = { 1, RGRP, 'r', '-' };
573int m5[] = { 1, WGRP, 'w', '-' };
574int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
575int m7[] = { 1, ROTH, 'r', '-' };
576int m8[] = { 1, WOTH, 'w', '-' };
577int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
578
579int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
580
581pmode(st)
582register struct stat *st;
583{
584 register int **mp;
585
586 for (mp = &m[0]; mp < &m[9];)
587 select(*mp++, st);
588}
589
590select(pairp, st)
591int *pairp;
592struct stat *st;
593{
594 register int n, *ap;
595
596 ap = pairp;
597 n = *ap++;
598 while (--n>=0 && (st->st_mode&*ap++)==0)
599 ap++;
600 printf("%c", *ap);
601}
602
603checkdir(name)
604register char *name;
605{
606 register char *cp;
607 int i;
608 for (cp = name; *cp; cp++) {
609 if (*cp == '/') {
610 *cp = '\0';
611 if (access(name, 01) < 0) {
612 if (fork() == 0) {
613 execl("/bin/mkdir", "mkdir", name, 0);
614 execl("/usr/bin/mkdir", "mkdir", name, 0);
615 fprintf(stderr, "tar: cannot find mkdir!\n");
616 done(0);
617 }
618 while (wait(&i) >= 0);
619 chown(name, stbuf.st_uid, stbuf.st_gid);
620 }
621 *cp = '/';
622 }
623 }
624}
625
626onintr()
627{
628 signal(SIGINT, SIG_IGN);
629 term++;
630}
631
632onquit()
633{
634 signal(SIGQUIT, SIG_IGN);
635 term++;
636}
637
638onhup()
639{
640 signal(SIGHUP, SIG_IGN);
641 term++;
642}
643
644onterm()
645{
646 signal(SIGTERM, SIG_IGN);
647 term++;
648}
649
650tomodes(sp)
651register struct stat *sp;
652{
653 register char *cp;
654
655 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
656 *cp = '\0';
657 sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777);
658 sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid);
659 sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid);
660 sprintf(dblock.dbuf.size, "%11lo ", sp->st_size);
661 sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime);
662}
663
664checksum()
665{
666 register i;
667 register char *cp;
668
669 for (cp = dblock.dbuf.chksum; cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++)
670 *cp = ' ';
671 i = 0;
672 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++)
673 i += *cp;
674 return(i);
675}
676
677checkw(c, name)
678char *name;
679{
680 if (wflag) {
681 printf("%c ", c);
682 if (vflag)
683 longt(&stbuf);
684 printf("%s: ", name);
685 if (response() == 'y'){
686 return(1);
687 }
688 return(0);
689 }
690 return(1);
691}
692
693response()
694{
695 char c;
696
697 c = getchar();
698 if (c != '\n')
699 while (getchar() != '\n');
700 else c = 'n';
701 return(c);
702}
703
704checkupdate(arg)
705char *arg;
706{
707 char name[100];
708 long mtime;
709 daddr_t seekp;
710 daddr_t lookup();
711
712 rewind(tfile);
713 for (;;) {
714 if ((seekp = lookup(arg)) < 0)
715 return(1);
716 fseek(tfile, seekp, 0);
717 fscanf(tfile, "%s %lo", name, &mtime);
718 if (stbuf.st_mtime > mtime)
719 return(1);
720 else
721 return(0);
722 }
723}
724
725done(n)
726{
727 unlink(tname);
728 exit(n);
729}
730
731prefix(s1, s2)
732register char *s1, *s2;
733{
734 while (*s1)
735 if (*s1++ != *s2++)
736 return(0);
737 if (*s2)
738 return(*s2 == '/');
739 return(1);
740}
741
742getwdir(s)
743char *s;
744{
745 int i;
746 int pipdes[2];
747
748 pipe(pipdes);
749 if ((i = fork()) == 0) {
750 close(1);
751 dup(pipdes[1]);
752 execl("/bin/pwd", "pwd", 0);
753 execl("/usr/bin/pwd", "pwd", 0);
754 fprintf(stderr, "pwd failed!\n");
755 printf("/\n");
756 exit(1);
757 }
758 while (wait((int *)NULL) != -1)
759 ;
760 read(pipdes[0], s, 50);
761 while(*s != '\n')
762 s++;
763 *s = '\0';
764 close(pipdes[0]);
765 close(pipdes[1]);
766}
767
768#define N 200
769int njab;
770daddr_t
771lookup(s)
772char *s;
773{
774 register i;
775 daddr_t a;
776
777 for(i=0; s[i]; i++)
778 if(s[i] == ' ')
779 break;
780 a = bsrch(s, i, low, high);
781 return(a);
782}
783
784daddr_t
785bsrch(s, n, l, h)
786daddr_t l, h;
787char *s;
788{
789 register i, j;
790 char b[N];
791 daddr_t m, m1;
792
793 njab = 0;
794
795loop:
796 if(l >= h)
797 return(-1L);
798 m = l + (h-l)/2 - N/2;
799 if(m < l)
800 m = l;
801 fseek(tfile, m, 0);
802 fread(b, 1, N, tfile);
803 njab++;
804 for(i=0; i<N; i++) {
805 if(b[i] == '\n')
806 break;
807 m++;
808 }
809 if(m >= h)
810 return(-1L);
811 m1 = m;
812 j = i;
813 for(i++; i<N; i++) {
814 m1++;
815 if(b[i] == '\n')
816 break;
817 }
818 i = cmp(b+j, s, n);
819 if(i < 0) {
820 h = m;
821 goto loop;
822 }
823 if(i > 0) {
824 l = m1;
825 goto loop;
826 }
827 return(m);
828}
829
830cmp(b, s, n)
831char *b, *s;
832{
833 register i;
834
835 if(b[0] != '\n')
836 exit(2);
837 for(i=0; i<n; i++) {
838 if(b[i+1] > s[i])
839 return(-1);
840 if(b[i+1] < s[i])
841 return(1);
842 }
843 return(b[i+1] == ' '? 0 : -1);
844}
845
846readtape(buffer)
847char *buffer;
848{
849 int i, j;
850
851 if (recno >= nblock || first == 0) {
852 if (first == 0 && nblock == 0)
853 j = NBLOCK;
854 else
855 j = nblock;
856 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
857 fprintf(stderr, "Tar: tape read error\n");
858 done(3);
859 }
860 if (first == 0) {
861 if ((i % TBLOCK) != 0) {
862 fprintf(stderr, "Tar: tape blocksize error\n");
863 done(3);
864 }
865 i /= TBLOCK;
866 if (rflag && i != 1) {
867 fprintf(stderr, "Tar: Cannot update blocked tapes (yet)\n");
868 done(4);
869 }
870 if (i != nblock && i != 1) {
871 fprintf(stderr, "Tar: blocksize = %d\n", i);
872 nblock = i;
873 }
874 }
875 recno = 0;
876 }
877 first = 1;
878 copy(buffer, &tbuf[recno++]);
879 return(TBLOCK);
880}
881
882writetape(buffer)
883char *buffer;
884{
885 first = 1;
886 if (nblock == 0)
887 nblock = 1;
888 if (recno >= nblock) {
889 if (write(mt, tbuf, TBLOCK*nblock) < 0) {
890 fprintf(stderr, "Tar: tape write error\n");
891 done(2);
892 }
893 recno = 0;
894 }
895 copy(&tbuf[recno++], buffer);
896 if (recno >= nblock) {
897 if (write(mt, tbuf, TBLOCK*nblock) < 0) {
898 fprintf(stderr, "Tar: tape write error\n");
899 done(2);
900 }
901 recno = 0;
902 }
903 return(TBLOCK);
904}
905
906backtape()
907{
908 lseek(mt, (long) -TBLOCK, 1);
909 if (recno >= nblock) {
910 recno = nblock - 1;
911 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
912 fprintf(stderr, "Tar: tape read error after seek\n");
913 done(4);
914 }
915 lseek(mt, (long) -TBLOCK, 1);
916 }
917}
918
919flushtape()
920{
921 write(mt, tbuf, TBLOCK*nblock);
922}
923
924copy(to, from)
925register char *to, *from;
926{
927 register i;
928
929 i = TBLOCK;
930 do {
931 *to++ = *from++;
932 } while (--i);
933}