buffer.c 17 KB

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