xref: /plan9/sys/src/ape/cmd/pax/buffer.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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