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