]> git.lizzy.rs Git - plan9front.git/blob - sys/src/ape/cmd/pax/buffer.c
ape: bring strtod() in line with plan9's libc version
[plan9front.git] / sys / src / ape / cmd / pax / buffer.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }