1 /* $Source: /u/mark/src/pax/RCS/buffer.c,v $
2 *
3 * $Revision: 1.2 $
4 *
5 * buffer.c - Buffer management functions
6 *
7 * DESCRIPTION
8 *
9 * These functions handle buffer manipulations for the archiving
10 * formats. Functions are provided to get memory for buffers,
11 * flush buffers, read and write buffers and de-allocate buffers.
12 * Several housekeeping functions are provided as well to get some
13 * information about how full buffers are, etc.
14 *
15 * AUTHOR
16 *
17 * Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
18 *
19 * Sponsored by The USENIX Association for public distribution.
20 *
21 * Copyright (c) 1989 Mark H. Colburn.
22 * All rights reserved.
23 *
24 * Redistribution and use in source and binary forms are permitted
25 * provided that the above copyright notice is duplicated in all such
26 * forms and that any documentation, advertising materials, and other
27 * materials related to such distribution and use acknowledge that the
28 * software was developed * by Mark H. Colburn and sponsored by The
29 * USENIX Association.
30 *
31 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
33 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34 *
35 * $Log: buffer.c,v $
36 * Revision 1.2 89/02/12 10:04:02 mark
37 * 1.2 release fixes
38 *
39 * Revision 1.1 88/12/23 18:02:01 mark
40 * Initial revision
41 *
42 */
43
44 #ifndef lint
45 static char *ident = "$Id: buffer.c,v 1.2 89/02/12 10:04:02 mark Exp $";
46 static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
47 #endif /* ! lint */
48
49
50 /* Headers */
51
52 #include "pax.h"
53
54
55 /* Function Prototypes */
56
57 #ifdef __STDC__
58
59 static int ar_write(int, char *, uint);
60 static void buf_pad(OFFSET);
61 static int indata(int, OFFSET, char *);
62 static void outflush(void);
63 static void buf_use(uint);
64 static int buf_in_avail(char **, uint *);
65 static uint buf_out_avail(char **);
66
67 #else /* !__STDC__ */
68
69 static int ar_write();
70 static void buf_pad();
71 static int indata();
72 static void outflush();
73 static void buf_use();
74 static int buf_in_avail();
75 static uint buf_out_avail();
76
77 #endif /* __STDC__ */
78
79
80 /* inentry - install a single archive entry
81 *
82 * DESCRIPTION
83 *
84 * Inentry reads an archive entry from the archive file and writes it
85 * out the the named file. If we are in PASS mode during archive
86 * processing, the pass() function is called, otherwise we will
87 * extract from the archive file.
88 *
89 * Inentry actaully calls indata to process the actual data to the
90 * file.
91 *
92 * PARAMETERS
93 *
94 * char *name - name of the file to extract from the archive
95 * Stat *asb - stat block of the file to be extracted from the
96 * archive.
97 *
98 * RETURNS
99 *
100 * Returns zero if successful, -1 otherwise.
101 */
102
103 #ifdef __STDC__
104
inentry(char * name,Stat * asb)105 int inentry(char *name, Stat *asb)
106
107 #else
108
109 int inentry(name, asb)
110 char *name;
111 Stat *asb;
112
113 #endif
114 {
115 Link *linkp;
116 int ifd;
117 int ofd;
118 time_t tstamp[2];
119
120 if ((ofd = openout(name, asb, linkp = linkfrom(name, asb), 0)) > 0) {
121 if (asb->sb_size || linkp == (Link *)NULL || linkp->l_size == 0) {
122 close(indata(ofd, asb->sb_size, name));
123 } else if ((ifd = open(linkp->l_path->p_name, O_RDONLY)) < 0) {
124 warn(linkp->l_path->p_name, strerror());
125 } else {
126 passdata(linkp->l_path->p_name, ifd, name, ofd);
127 close(ifd);
128 close(ofd);
129 }
130 } else {
131 return(buf_skip((OFFSET) asb->sb_size) >= 0);
132 }
133 tstamp[0] = (!f_pass && f_access_time) ? asb->sb_atime : time((time_t *) 0);
134 tstamp[1] = f_mtime ? asb->sb_mtime : time((time_t *) 0);
135 utime(name, tstamp);
136 return (0);
137 }
138
139
140 /* outdata - write archive data
141 *
142 * DESCRIPTION
143 *
144 * Outdata transfers data from the named file to the archive buffer.
145 * It knows about the file padding which is required by tar, but no
146 * by cpio. Outdata continues after file read errors, padding with
147 * null characters if neccessary. Closes the input file descriptor
148 * when finished.
149 *
150 * PARAMETERS
151 *
152 * int fd - file descriptor of file to read data from
153 * char *name - name of file
154 * OFFSET size - size of the file
155 *
156 */
157
158 #ifdef __STDC__
159
outdata(int fd,char * name,OFFSET size)160 void outdata(int fd, char *name, OFFSET size)
161
162 #else
163
164 void outdata(fd, name, size)
165 int fd;
166 char *name;
167 OFFSET size;
168
169 #endif
170 {
171 uint chunk;
172 int got;
173 int oops;
174 uint avail;
175 int pad;
176 char *buf;
177
178 oops = got = 0;
179 if (pad = (size % BLOCKSIZE)) {
180 pad = (BLOCKSIZE - pad);
181 }
182 while (size) {
183 avail = buf_out_avail(&buf);
184 size -= (chunk = size < avail ? (uint) size : avail);
185 if (oops == 0 && (got = read(fd, buf, (unsigned int) chunk)) < 0) {
186 oops = -1;
187 warn(name, strerror());
188 got = 0;
189 }
190 if (got < chunk) {
191 if (oops == 0) {
192 oops = -1;
193 }
194 warn(name, "Early EOF");
195 while (got < chunk) {
196 buf[got++] = '\0';
197 }
198 }
199 buf_use(chunk);
200 }
201 close(fd);
202 if (ar_format == TAR) {
203 buf_pad((OFFSET) pad);
204 }
205 }
206
207
208 /* write_eot - write the end of archive record(s)
209 *
210 * DESCRIPTION
211 *
212 * Write out an End-Of-Tape record. We actually zero at least one
213 * record, through the end of the block. Old tar writes garbage after
214 * two zeroed records -- and PDtar used to.
215 */
216
217 #ifdef __STDC__
218
write_eot(void)219 void write_eot(void)
220
221 #else
222
223 void write_eot()
224
225 #endif
226 {
227 OFFSET pad;
228 char header[M_STRLEN + H_STRLEN + 1];
229
230 if (ar_format == TAR) {
231 /* write out two zero blocks for trailer */
232 pad = 2 * BLOCKSIZE;
233 } else {
234 if (pad = (total + M_STRLEN + H_STRLEN + TRAILZ) % BLOCKSIZE) {
235 pad = BLOCKSIZE - pad;
236 }
237 strcpy(header, M_ASCII);
238 sprintf(header + M_STRLEN, H_PRINT, 0, 0,
239 0, 0, 0, 1, 0, (time_t) 0, TRAILZ, pad);
240 outwrite(header, M_STRLEN + H_STRLEN);
241 outwrite(TRAILER, TRAILZ);
242 }
243 buf_pad((OFFSET) pad);
244 outflush();
245 }
246
247
248 /* outwrite - write archive data
249 *
250 * DESCRIPTION
251 *
252 * Writes out data in the archive buffer to the archive file. The
253 * buffer index and the total byte count are incremented by the number
254 * of data bytes written.
255 *
256 * PARAMETERS
257 *
258 * char *idx - pointer to data to write
259 * uint len - length of the data to write
260 */
261
262 #ifdef __STDC__
263
outwrite(char * idx,uint len)264 void outwrite(char *idx, uint len)
265
266 #else
267
268 void outwrite(idx, len)
269 char *idx; /* pointer to data to write */
270 uint len; /* length of data to write */
271
272 #endif
273 {
274 uint have;
275 uint want;
276 char *endx;
277
278 endx = idx + len;
279 while (want = endx - idx) {
280 if (bufend - bufidx < 0) {
281 fatal("Buffer overlow in out_write\n");
282 }
283 if ((have = bufend - bufidx) == 0) {
284 outflush();
285 }
286 if (have > want) {
287 have = want;
288 }
289 memcpy(bufidx, idx, (int) have);
290 bufidx += have;
291 idx += have;
292 total += have;
293 }
294 }
295
296
297 /* passdata - copy data to one file
298 *
299 * DESCRIPTION
300 *
301 * Copies a file from one place to another. Doesn't believe in input
302 * file descriptor zero (see description of kludge in openin() comments).
303 * Closes the provided output file descriptor.
304 *
305 * PARAMETERS
306 *
307 * char *from - input file name (old file)
308 * int ifd - input file descriptor
309 * char *to - output file name (new file)
310 * int ofd - output file descriptor
311 */
312
313 #ifdef __STDC__
314
passdata(char * from,int ifd,char * to,int ofd)315 void passdata(char *from, int ifd, char *to, int ofd)
316
317 #else
318
319 void passdata(from, ifd, to, ofd)
320 char *from;
321 int ifd;
322 char *to;
323 int ofd;
324
325 #endif
326 {
327 int got;
328 int sparse;
329 char block[BUFSIZ];
330
331 if (ifd) {
332 lseek(ifd, (OFFSET) 0, 0);
333 sparse = 0;
334 while ((got = read(ifd, block, sizeof(block))) > 0
335 && (sparse = ar_write(ofd, block, (uint) got)) >= 0) {
336 total += got;
337 }
338 if (got) {
339 warn(got < 0 ? from : to, strerror());
340 } else if (sparse > 0
341 && (lseek(ofd, (OFFSET)(-sparse), 1) < 0
342 || write(ofd, block, (uint) sparse) != sparse)) {
343 warn(to, strerror());
344 }
345 }
346 close(ofd);
347 }
348
349
350 /* buf_allocate - get space for the I/O buffer
351 *
352 * DESCRIPTION
353 *
354 * buf_allocate allocates an I/O buffer using malloc. The resulting
355 * buffer is used for all data buffering throughout the program.
356 * Buf_allocate must be called prior to any use of the buffer or any
357 * of the buffering calls.
358 *
359 * PARAMETERS
360 *
361 * int size - size of the I/O buffer to request
362 *
363 * ERRORS
364 *
365 * If an invalid size is given for a buffer or if a buffer of the
366 * required size cannot be allocated, then the function prints out an
367 * error message and returns a non-zero exit status to the calling
368 * process, terminating the program.
369 *
370 */
371
372 #ifdef __STDC__
373
buf_allocate(OFFSET size)374 void buf_allocate(OFFSET size)
375
376 #else
377
378 void buf_allocate(size)
379 OFFSET size;
380
381 #endif
382 {
383 if (size <= 0) {
384 fatal("invalid value for blocksize");
385 }
386 if ((bufstart = malloc((unsigned) size)) == (char *)NULL) {
387 fatal("Cannot allocate I/O buffer");
388 }
389 bufend = bufidx = bufstart;
390 bufend += size;
391 }
392
393
394 /* buf_skip - skip input archive data
395 *
396 * DESCRIPTION
397 *
398 * Buf_skip skips past archive data. It is used when the length of
399 * the archive data is known, and we do not wish to process the data.
400 *
401 * PARAMETERS
402 *
403 * OFFSET len - number of bytes to skip
404 *
405 * RETURNS
406 *
407 * Returns zero under normal circumstances, -1 if unreadable data is
408 * encountered.
409 */
410
411 #ifdef __STDC__
412
buf_skip(OFFSET len)413 int buf_skip(OFFSET len)
414
415 #else
416
417 int buf_skip(len)
418 OFFSET len;
419
420 #endif
421 {
422 uint chunk;
423 int corrupt = 0;
424
425 while (len) {
426 if (bufend - bufidx < 0) {
427 fatal("Buffer overlow in buf_skip\n");
428 }
429 while ((chunk = bufend - bufidx) == 0) {
430 corrupt |= ar_read();
431 }
432 if (chunk > len) {
433 chunk = len;
434 }
435 bufidx += chunk;
436 len -= chunk;
437 total += chunk;
438 }
439 return (corrupt);
440 }
441
442
443 /* buf_read - read a given number of characters from the input archive
444 *
445 * DESCRIPTION
446 *
447 * Reads len number of characters from the input archive and
448 * stores them in the buffer pointed at by dst.
449 *
450 * PARAMETERS
451 *
452 * char *dst - pointer to buffer to store data into
453 * uint len - length of data to read
454 *
455 * RETURNS
456 *
457 * Returns zero with valid data, -1 if unreadable portions were
458 * replaced by null characters.
459 */
460
461 #ifdef __STDC__
462
buf_read(char * dst,uint len)463 int buf_read(char *dst, uint len)
464
465 #else
466
467 int buf_read(dst, len)
468 char *dst;
469 uint len;
470
471 #endif
472 {
473 int have;
474 int want;
475 int corrupt = 0;
476 char *endx = dst + len;
477
478 while (want = endx - dst) {
479 if (bufend - bufidx < 0) {
480 fatal("Buffer overlow in buf_read\n");
481 }
482 while ((have = bufend - bufidx) == 0) {
483 have = 0;
484 corrupt |= ar_read();
485 }
486 if (have > want) {
487 have = want;
488 }
489 memcpy(dst, bufidx, have);
490 bufidx += have;
491 dst += have;
492 total += have;
493 }
494 return (corrupt);
495 }
496
497
498 /* indata - install data from an archive
499 *
500 * DESCRIPTION
501 *
502 * Indata writes size bytes of data from the archive buffer to the output
503 * file specified by fd. The filename which is being written, pointed
504 * to by name is provided only for diagnostics.
505 *
506 * PARAMETERS
507 *
508 * int fd - output file descriptor
509 * OFFSET size - number of bytes to write to output file
510 * char *name - name of file which corresponds to fd
511 *
512 * RETURNS
513 *
514 * Returns given file descriptor.
515 */
516
517 #ifdef __STDC__
518
indata(int fd,OFFSET size,char * name)519 static int indata(int fd, OFFSET size, char *name)
520
521 #else
522
523 static int indata(fd, size, name)
524 int fd;
525 OFFSET size;
526 char *name;
527
528 #endif
529 {
530 uint chunk;
531 char *oops;
532 int sparse;
533 int corrupt;
534 char *buf;
535 uint avail;
536
537 corrupt = sparse = 0;
538 oops = (char *)NULL;
539 while (size) {
540 corrupt |= buf_in_avail(&buf, &avail);
541 size -= (chunk = size < avail ? (uint) size : avail);
542 if (oops == (char *)NULL && (sparse = ar_write(fd, buf, chunk)) < 0) {
543 oops = strerror();
544 }
545 buf_use(chunk);
546 }
547 if (corrupt) {
548 warn(name, "Corrupt archive data");
549 }
550 if (oops) {
551 warn(name, oops);
552 } else if (sparse > 0 && (lseek(fd, (OFFSET) - 1, 1) < 0
553 || write(fd, "", 1) != 1)) {
554 warn(name, strerror());
555 }
556 return (fd);
557 }
558
559
560 /* outflush - flush the output buffer
561 *
562 * DESCRIPTION
563 *
564 * The output buffer is written, if there is anything in it, to the
565 * archive file.
566 */
567
568 #ifdef __STDC__
569
outflush(void)570 static void outflush(void)
571
572 #else
573
574 static void outflush()
575
576 #endif
577 {
578 char *buf;
579 int got;
580 uint len;
581
582 /* if (bufidx - buf > 0) */
583 for (buf = bufstart; len = bufidx - buf;) {
584 if ((got = write(archivefd, buf, MIN(len, blocksize))) > 0) {
585 buf += got;
586 } else if (got < 0) {
587 next(AR_WRITE);
588 }
589 }
590 bufend = (bufidx = bufstart) + blocksize;
591 }
592
593
594 /* ar_read - fill the archive buffer
595 *
596 * DESCRIPTION
597 *
598 * Remembers mid-buffer read failures and reports them the next time
599 * through. Replaces unreadable data with null characters. Resets
600 * the buffer pointers as appropriate.
601 *
602 * RETURNS
603 *
604 * Returns zero with valid data, -1 otherwise.
605 */
606
607 #ifdef __STDC__
608
ar_read(void)609 int ar_read(void)
610
611 #else
612
613 int ar_read()
614
615 #endif
616 {
617 int got;
618 static int failed;
619
620 bufend = bufidx = bufstart;
621 if (!failed) {
622 if (areof) {
623 if (total == 0) {
624 fatal("No input");
625 } else {
626 next(AR_READ);
627 }
628 }
629 while (!failed && !areof && bufstart + blocksize - bufend >= blocksize) {
630 if ((got = read(archivefd, bufend, (unsigned int) blocksize)) > 0) {
631 bufend += got;
632 } else if (got < 0) {
633 failed = -1;
634 warnarch(strerror(), (OFFSET) 0 - (bufend - bufidx));
635 } else {
636 ++areof;
637 }
638 }
639 }
640 if (failed && bufend == bufstart) {
641 failed = 0;
642 for (got = 0; got < blocksize; ++got) {
643 *bufend++ = '\0';
644 }
645 return (-1);
646 }
647 return (0);
648 }
649
650
651 /* ar_write - write a filesystem block
652 *
653 * DESCRIPTION
654 *
655 * Writes len bytes of data data from the specified buffer to the
656 * specified file. Seeks past sparse blocks.
657 *
658 * PARAMETERS
659 *
660 * int fd - file to write to
661 * char *buf - buffer to get data from
662 * uint len - number of bytes to transfer
663 *
664 * RETURNS
665 *
666 * Returns 0 if the block was written, the given length for a sparse
667 * block or -1 if unsuccessful.
668 */
669
670 #ifdef __STDC__
671
ar_write(int fd,char * buf,uint len)672 static int ar_write(int fd, char *buf, uint len)
673
674 #else
675
676 static int ar_write(fd, buf, len)
677 int fd;
678 char *buf;
679 uint len;
680
681 #endif
682 {
683 char *bidx;
684 char *bend;
685
686 bend = (bidx = buf) + len;
687 while (bidx < bend) {
688 if (*bidx++) {
689 return (write(fd, buf, len) == len ? 0 : -1);
690 }
691 }
692 return (lseek(fd, (OFFSET) len, 1) < 0 ? -1 : len);
693 }
694
695
696 /* buf_pad - pad the archive buffer
697 *
698 * DESCRIPTION
699 *
700 * Buf_pad writes len zero bytes to the archive buffer in order to
701 * pad it.
702 *
703 * PARAMETERS
704 *
705 * OFFSET pad - number of zero bytes to pad
706 *
707 */
708
709 #ifdef __STDC__
710
buf_pad(OFFSET pad)711 static void buf_pad(OFFSET pad)
712
713 #else
714
715 static void buf_pad(pad)
716 OFFSET pad;
717
718 #endif
719 {
720 int idx;
721 int have;
722
723 while (pad) {
724 if ((have = bufend - bufidx) > pad) {
725 have = pad;
726 }
727 for (idx = 0; idx < have; ++idx) {
728 *bufidx++ = '\0';
729 }
730 total += have;
731 pad -= have;
732 if (bufend - bufidx == 0) {
733 outflush();
734 }
735 }
736 }
737
738
739 /* buf_use - allocate buffer space
740 *
741 * DESCRIPTION
742 *
743 * Buf_use marks space in the buffer as being used; advancing both the
744 * buffer index (bufidx) and the total byte count (total).
745 *
746 * PARAMETERS
747 *
748 * uint len - Amount of space to allocate in the buffer
749 */
750
751 #ifdef __STDC__
752
buf_use(uint len)753 static void buf_use(uint len)
754
755 #else
756
757 static void buf_use(len)
758 uint len;
759
760 #endif
761 {
762 bufidx += len;
763 total += len;
764 }
765
766
767 /* buf_in_avail - index available input data within the buffer
768 *
769 * DESCRIPTION
770 *
771 * Buf_in_avail fills the archive buffer, and points the bufp
772 * parameter at the start of the data. The lenp parameter is
773 * modified to contain the number of bytes which were read.
774 *
775 * PARAMETERS
776 *
777 * char **bufp - pointer to the buffer to read data into
778 * uint *lenp - pointer to the number of bytes which were read
779 * (returned to the caller)
780 *
781 * RETURNS
782 *
783 * Stores a pointer to the data and its length in given locations.
784 * Returns zero with valid data, -1 if unreadable portions were
785 * replaced with nulls.
786 *
787 * ERRORS
788 *
789 * If an error occurs in ar_read, the error code is returned to the
790 * calling function.
791 *
792 */
793
794 #ifdef __STDC__
795
buf_in_avail(char ** bufp,uint * lenp)796 static int buf_in_avail(char **bufp, uint *lenp)
797
798 #else
799
800 static int buf_in_avail(bufp, lenp)
801 char **bufp;
802 uint *lenp;
803
804 #endif
805 {
806 uint have;
807 int corrupt = 0;
808
809 while ((have = bufend - bufidx) == 0) {
810 corrupt |= ar_read();
811 }
812 *bufp = bufidx;
813 *lenp = have;
814 return (corrupt);
815 }
816
817
818 /* buf_out_avail - index buffer space for archive output
819 *
820 * DESCRIPTION
821 *
822 * Stores a buffer pointer at a given location. Returns the number
823 * of bytes available.
824 *
825 * PARAMETERS
826 *
827 * char **bufp - pointer to the buffer which is to be stored
828 *
829 * RETURNS
830 *
831 * The number of bytes which are available in the buffer.
832 *
833 */
834
835 #ifdef __STDC__
836
buf_out_avail(char ** bufp)837 static uint buf_out_avail(char **bufp)
838
839 #else
840
841 static uint buf_out_avail(bufp)
842 char **bufp;
843
844 #endif
845 {
846 int have;
847
848 if (bufend - bufidx < 0) {
849 fatal("Buffer overlow in buf_out_avail\n");
850 }
851 if ((have = bufend - bufidx) == 0) {
852 outflush();
853 }
854 *bufp = bufidx;
855 return (have);
856 }
857