Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}