xref: /plan9/sys/src/cmd/bsplit.c (revision 4d2c0504d2bd576e9eb786d7a9d27f921b5ebd5e)
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
bufreset(Buffer * bp)50 bufreset(Buffer *bp)
51 {
52 	bp->rp = bp->wp = bp->base;
53 }
54 
55 static void
bufinit(Buffer * bp,uchar * block,unsigned size)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
eopen(char * file,int mode)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
ecreate(char * file,int mode)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 *
filename(Copy * cp)84 filename(Copy *cp)
85 {
86 	return cp->filenm;
87 }
88 
89 static int
opennext(Copy * cp)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
closeout(Copy * cp)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
process(int in,char * inname)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
usage(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
main(int argc,char ** argv)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