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 } 857