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