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