bsplit.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * bsplit - split big binaries (copy-less plan 9 version)
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <authsrv.h> /* for ANAMELEN */
  15. enum {
  16. Stdin,
  17. Sectsiz = 512,
  18. Bufsiz = 256*Sectsiz,
  19. };
  20. /* disk address (in bytes or sectors), also type of 2nd arg. to seek */
  21. typedef uint64_t Daddr;
  22. #define BLEN(s) ((s)->wp - (s)->rp)
  23. #define BALLOC(s) ((s)->lim - (s)->base)
  24. typedef struct {
  25. uint8_t* rp; /* first unconsumed byte */
  26. uint8_t* wp; /* first empty byte */
  27. uint8_t* lim; /* 1 past the end of the buffer */
  28. uint8_t* base; /* start of the buffer */
  29. } Buffer;
  30. typedef struct {
  31. /* parameters */
  32. Daddr maxoutsz; /* maximum size of output file(s) */
  33. Daddr fileout; /* bytes written to the current output file */
  34. char *filenm;
  35. int filesz; /* size of filenm */
  36. char *prefix;
  37. int32_t filenum;
  38. int outf; /* open output file */
  39. Buffer buff;
  40. } Copy;
  41. /* global data */
  42. char *argv0;
  43. /* private data */
  44. static Copy cp = { 512*1024*1024 }; /* default maximum size */
  45. static int debug;
  46. static void
  47. bufreset(Buffer *bp)
  48. {
  49. bp->rp = bp->wp = bp->base;
  50. }
  51. static void
  52. bufinit(Buffer *bp, uint8_t *block, unsigned size)
  53. {
  54. bp->base = block;
  55. bp->lim = bp->base + size;
  56. bufreset(bp);
  57. }
  58. static int
  59. eopen(char *file, int mode)
  60. {
  61. int fd = open(file, mode);
  62. if (fd < 0)
  63. sysfatal("can't open %s: %r", file);
  64. return fd;
  65. }
  66. static int
  67. ecreate(char *file, int mode)
  68. {
  69. int fd = create(file, mode, 0666);
  70. if (fd < 0)
  71. sysfatal("can't create %s: %r", file);
  72. return fd;
  73. }
  74. static char *
  75. filename(Copy *cp)
  76. {
  77. return cp->filenm;
  78. }
  79. static int
  80. opennext(Copy *cp)
  81. {
  82. if (cp->outf >= 0)
  83. sysfatal("opennext called with file open");
  84. snprint(cp->filenm, cp->filesz, "%s%5.5ld", cp->prefix, cp->filenum++);
  85. cp->outf = ecreate(cp->filenm, OWRITE);
  86. cp->fileout = 0;
  87. return cp->outf;
  88. }
  89. static int
  90. closeout(Copy *cp)
  91. {
  92. if (cp->outf >= 0) {
  93. if (close(cp->outf) < 0)
  94. sysfatal("error writing %s: %r", filename(cp));
  95. cp->outf = -1;
  96. cp->fileout = 0;
  97. }
  98. return cp->outf;
  99. }
  100. /*
  101. * process - process input file
  102. */
  103. static void
  104. process(int in, char *inname)
  105. {
  106. int n = 1;
  107. unsigned avail, tolim, wsz;
  108. Buffer *bp = &cp.buff;
  109. USED(inname);
  110. do {
  111. if (BLEN(bp) == 0) {
  112. if (bp->lim == bp->wp)
  113. bufreset(bp);
  114. n = read(in, bp->wp, bp->lim - bp->wp);
  115. if (n <= 0)
  116. break;
  117. bp->wp += n;
  118. }
  119. if (cp.outf < 0)
  120. opennext(&cp);
  121. /*
  122. * write from buffer's current point to end or enough bytes to
  123. * reach file-size limit.
  124. */
  125. avail = BLEN(bp);
  126. tolim = cp.maxoutsz - cp.fileout;
  127. wsz = (tolim < avail? tolim: avail);
  128. /* try to write full sectors */
  129. if (tolim >= avail && n > 0 && wsz >= Sectsiz)
  130. wsz = (wsz / Sectsiz) * Sectsiz;
  131. if (write(cp.outf, bp->rp, wsz) != wsz)
  132. sysfatal("error writing %s: %r", filename(&cp));
  133. bp->rp += wsz;
  134. cp.fileout += wsz;
  135. if (cp.fileout >= cp.maxoutsz)
  136. closeout(&cp);
  137. } while (n > 0 || BLEN(bp) != 0);
  138. }
  139. static void
  140. usage(void)
  141. {
  142. fprint(2, "usage: %s [-d][-p pfx][-s size] [file...]\n", argv0);
  143. exits("usage");
  144. }
  145. void
  146. main(int argc, char **argv)
  147. {
  148. int i, errflg = 0;
  149. unsigned char block[Bufsiz];
  150. cp.prefix = "bs.";
  151. ARGBEGIN {
  152. case 'd':
  153. debug++;
  154. break;
  155. case 'p':
  156. cp.prefix = EARGF(usage());
  157. break;
  158. case 's':
  159. cp.maxoutsz = atoll(EARGF(usage()));
  160. if (cp.maxoutsz < 1)
  161. errflg++;
  162. break;
  163. default:
  164. errflg++;
  165. break;
  166. } ARGEND
  167. if (errflg || argc < 0)
  168. usage();
  169. bufinit(&cp.buff, block, sizeof block);
  170. cp.outf = -1;
  171. cp.filesz = strlen(cp.prefix) + 2*ANAMELEN; /* 2* is slop */
  172. cp.filenm = malloc(cp.filesz + 1);
  173. if (cp.filenm == nil)
  174. sysfatal("no memory: %r");
  175. if (argc == 0)
  176. process(Stdin, "/fd/0");
  177. else
  178. for (i = 0; i < argc; i++) {
  179. int in = eopen(argv[i], OREAD);
  180. process(in, argv[i]);
  181. close(in);
  182. }
  183. closeout(&cp);
  184. exits(0);
  185. }