bsplit.c 3.7 KB

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