diff options
Diffstat (limited to 'dd.c')
-rw-r--r-- | dd.c | 425 |
1 files changed, 167 insertions, 258 deletions
@@ -6,302 +6,211 @@ | |||
6 | * The "dd" command, originally taken from sash. | 6 | * The "dd" command, originally taken from sash. |
7 | * | 7 | * |
8 | * Permission to distribute this code under the GPL has been granted. | 8 | * Permission to distribute this code under the GPL has been granted. |
9 | * Majorly modified, and bugs fixed for busybox by Erik Andersen <andersee@debian.org> <andersen@lineo.com> | 9 | * Mostly rewritten and bugs fixed for busybox by Erik Andersen <andersee@debian.org> |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "internal.h" | 12 | #include "internal.h" |
13 | #ifdef BB_DD | 13 | #include <stdio.h> |
14 | #include <fcntl.h> | ||
15 | #include <errno.h> | ||
14 | 16 | ||
15 | const char dd_usage[] = | 17 | const char dd_usage[] = |
16 | "Copy a file, converting and formatting according to options\n\ | 18 | "Copy a file, converting and formatting according to options\n\ |
17 | \n\ | 19 | \n\ |
18 | usage: [if=name] [of=name] [bs=n] [count=n]\n\ | 20 | usage: [if=name] [of=name] [bs=n] [count=n]\n\ |
19 | \tif=FILE\tread from FILE instead of stdin\n\ | 21 | \tif=FILE\tread from FILE instead of stdin\n\ |
20 | \tof=FILE\twrite to FILE instead of stout\n\ | 22 | \tof=FILE\twrite to FILE instead of stout\n\ |
21 | \tbs=n\tread and write N bytes at a time\n\ | 23 | \tbs=n\tread and write N bytes at a time\n\ |
22 | \tcount=n\tcopy only n input blocks\n\ | 24 | \tcount=n\tcopy only n input blocks\n\ |
25 | \tskip=n\tskip n input blocks\n\ | ||
23 | \n\ | 26 | \n\ |
24 | BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n"; | 27 | BYTES may be suffixed: by k for x1024, b for x512, and w for x2.\n"; |
25 | 28 | ||
26 | 29 | ||
27 | #include <stdio.h> | ||
28 | #include <dirent.h> | ||
29 | #include <errno.h> | ||
30 | #include <fcntl.h> | ||
31 | #include <signal.h> | ||
32 | #include <time.h> | ||
33 | |||
34 | |||
35 | #define PAR_NONE 0 | ||
36 | #define PAR_IF 1 | ||
37 | #define PAR_OF 2 | ||
38 | #define PAR_BS 3 | ||
39 | #define PAR_COUNT 4 | ||
40 | 30 | ||
41 | 31 | ||
42 | typedef struct | 32 | /* |
33 | * Read a number with a possible multiplier. | ||
34 | * Returns -1 if the number format is illegal. | ||
35 | */ | ||
36 | static long getNum (const char *cp) | ||
43 | { | 37 | { |
44 | const char * name; | 38 | long value; |
45 | int value; | ||
46 | } PARAM; | ||
47 | 39 | ||
40 | if (!isDecimal (*cp)) | ||
41 | return -1; | ||
48 | 42 | ||
49 | static const PARAM params[] = | 43 | value = 0; |
50 | { | ||
51 | {"if", PAR_IF}, | ||
52 | {"of", PAR_OF}, | ||
53 | {"bs", PAR_BS}, | ||
54 | {"count", PAR_COUNT}, | ||
55 | {NULL, PAR_NONE} | ||
56 | }; | ||
57 | |||
58 | 44 | ||
59 | static long getNum(const char * cp); | 45 | while (isDecimal (*cp)) |
46 | value = value * 10 + *cp++ - '0'; | ||
60 | 47 | ||
61 | extern int | 48 | switch (*cp++) { |
62 | dd_main (int argc, char **argv) | 49 | case 'k': |
63 | { | 50 | value *= 1024; |
64 | const char * str; | 51 | break; |
65 | const PARAM * par; | ||
66 | const char * inFile; | ||
67 | const char * outFile; | ||
68 | char * cp; | ||
69 | int inFd; | ||
70 | int outFd; | ||
71 | int inCc=0; | ||
72 | int outCc; | ||
73 | int blockSize; | ||
74 | long count; | ||
75 | long intotal; | ||
76 | long outTotal; | ||
77 | unsigned char* buf; | ||
78 | unsigned char localBuf[BUF_SIZE]; | ||
79 | |||
80 | inFile = NULL; | ||
81 | outFile = NULL; | ||
82 | blockSize = 512; | ||
83 | count = 1; | ||
84 | |||
85 | |||
86 | while (--argc > 0) | ||
87 | { | ||
88 | str = *++argv; | ||
89 | cp = strchr(str, '='); | ||
90 | |||
91 | if (cp == NULL) | ||
92 | { | ||
93 | fprintf(stderr, "Bad dd argument\n"); | ||
94 | goto usage; | ||
95 | } | ||
96 | |||
97 | *cp++ = '\0'; | ||
98 | |||
99 | for (par = params; par->name; par++) | ||
100 | { | ||
101 | if (strcmp(str, par->name) == 0) | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | switch (par->value) | ||
106 | { | ||
107 | case PAR_IF: | ||
108 | if (inFile) | ||
109 | { | ||
110 | fprintf(stderr, "Multiple input files illegal\n"); | ||
111 | goto usage; | ||
112 | } | ||
113 | |||
114 | //fprintf(stderr, "if=%s\n", cp); | ||
115 | inFile = cp; | ||
116 | break; | ||
117 | |||
118 | case PAR_OF: | ||
119 | if (outFile) | ||
120 | { | ||
121 | fprintf(stderr, "Multiple output files illegal\n"); | ||
122 | goto usage; | ||
123 | } | ||
124 | |||
125 | //fprintf(stderr, "of=%s\n", cp); | ||
126 | outFile = cp; | ||
127 | break; | ||
128 | |||
129 | case PAR_BS: | ||
130 | blockSize = getNum(cp); | ||
131 | //fprintf(stderr, "bs=%d\n", blockSize); | ||
132 | |||
133 | if (blockSize <= 0) | ||
134 | { | ||
135 | fprintf(stderr, "Bad block size value\n"); | ||
136 | goto usage; | ||
137 | } | ||
138 | |||
139 | break; | ||
140 | |||
141 | case PAR_COUNT: | ||
142 | count = getNum(cp); | ||
143 | //fprintf(stderr, "count=%ld\n", count); | ||
144 | |||
145 | if (count < 0) | ||
146 | { | ||
147 | fprintf(stderr, "Bad count value\n"); | ||
148 | goto usage; | ||
149 | } | ||
150 | |||
151 | break; | ||
152 | |||
153 | default: | ||
154 | goto usage; | ||
155 | } | ||
156 | } | ||
157 | 52 | ||
158 | buf = localBuf; | 53 | case 'b': |
54 | value *= 512; | ||
55 | break; | ||
159 | 56 | ||
160 | if (blockSize > sizeof(localBuf)) | 57 | case 'w': |
161 | { | 58 | value *= 2; |
162 | buf = malloc(blockSize); | 59 | break; |
163 | 60 | ||
164 | if (buf == NULL) | 61 | case '\0': |
165 | { | 62 | return value; |
166 | fprintf(stderr, "Cannot allocate buffer\n"); | ||
167 | return 1; | ||
168 | } | ||
169 | } | ||
170 | 63 | ||
171 | intotal = 0; | 64 | default: |
172 | outTotal = 0; | 65 | return -1; |
66 | } | ||
173 | 67 | ||
174 | if (inFile == NULL) | 68 | if (*cp) |
175 | inFd = STDIN; | 69 | return -1; |
176 | else | ||
177 | inFd = open(inFile, 0); | ||
178 | 70 | ||
179 | if (inFd < 0) | 71 | return value; |
180 | { | 72 | } |
181 | perror(inFile); | ||
182 | 73 | ||
183 | if (buf != localBuf) | ||
184 | free(buf); | ||
185 | 74 | ||
186 | return 1; | 75 | extern int dd_main (int argc, char **argv) |
76 | { | ||
77 | const char *inFile; | ||
78 | const char *outFile; | ||
79 | char *cp; | ||
80 | int inFd; | ||
81 | int outFd; | ||
82 | int inCc = 0; | ||
83 | int outCc; | ||
84 | int skipBlocks; | ||
85 | int blockSize; | ||
86 | long count; | ||
87 | long intotal; | ||
88 | long outTotal; | ||
89 | unsigned char *buf; | ||
90 | |||
91 | inFile = NULL; | ||
92 | outFile = NULL; | ||
93 | blockSize = 512; | ||
94 | skipBlocks = 0; | ||
95 | count = 1; | ||
96 | |||
97 | |||
98 | argc--; | ||
99 | argv++; | ||
100 | |||
101 | /* Parse any options */ | ||
102 | while (argc) { | ||
103 | if (inFile == NULL && (strncmp("if", *argv, 2) == 0)) | ||
104 | inFile=*argv; | ||
105 | else if (outFile == NULL && (strncmp("of", *argv, 2) == 0)) | ||
106 | outFile=*argv; | ||
107 | else if (strncmp("count", *argv, 5) == 0) { | ||
108 | count = getNum (*argv); | ||
109 | if (count <= 0) { | ||
110 | fprintf (stderr, "Bad count value %ld\n", count); | ||
111 | goto usage; | ||
112 | } | ||
187 | } | 113 | } |
188 | 114 | else if (strncmp("bs", *argv, 2) == 0) { | |
189 | if (outFile == NULL) | 115 | blockSize = getNum(*argv); |
190 | outFd = STDOUT; | 116 | if (blockSize <= 0) { |
191 | else | 117 | fprintf (stderr, "Bad block size value %d\n", blockSize); |
192 | outFd = creat(outFile, 0666); | 118 | goto usage; |
193 | 119 | } | |
194 | if (outFd < 0) | ||
195 | { | ||
196 | perror(outFile); | ||
197 | close(inFd); | ||
198 | |||
199 | if (buf != localBuf) | ||
200 | free(buf); | ||
201 | |||
202 | return 1; | ||
203 | } | 120 | } |
121 | else if (strncmp("skip", *argv, 4) == 0) { | ||
122 | skipBlocks = atoi( *argv); | ||
123 | if (skipBlocks <= 0) { | ||
124 | fprintf (stderr, "Bad skip value %d\n", skipBlocks); | ||
125 | goto usage; | ||
126 | } | ||
204 | 127 | ||
205 | while ( outTotal < count*blockSize ) | ||
206 | { | ||
207 | inCc = read(inFd, buf, blockSize); | ||
208 | if (inCc < 0) { | ||
209 | perror(inFile); | ||
210 | goto cleanup; | ||
211 | } | ||
212 | //fprintf(stderr, "read in =%d\n", inCc); | ||
213 | intotal += inCc; | ||
214 | cp = buf; | ||
215 | |||
216 | |||
217 | while ( intotal > outTotal ) | ||
218 | { | ||
219 | if (outTotal+inCc > count*blockSize) | ||
220 | inCc=count*blockSize-outTotal; | ||
221 | outCc = write(outFd, cp, inCc); | ||
222 | if (outCc < 0) | ||
223 | { | ||
224 | perror(outFile); | ||
225 | goto cleanup; | ||
226 | } | ||
227 | //fprintf(stderr, "wrote out =%d\n", outCc); | ||
228 | |||
229 | inCc -= outCc; | ||
230 | cp += outCc; | ||
231 | outTotal += outCc; | ||
232 | //fprintf(stderr, "outTotal=%ld\n", outTotal); | ||
233 | } | ||
234 | } | 128 | } |
129 | else { | ||
130 | fprintf (stderr, "Got here. argv=%s\n", *argv); | ||
131 | goto usage; | ||
235 | 132 | ||
236 | if (inCc < 0) | 133 | argc--; |
237 | perror(inFile); | 134 | argv++; |
238 | 135 | } | |
239 | cleanup: | 136 | } |
240 | close(inFd); | 137 | if ( inFile == NULL || outFile == NULL) |
241 | 138 | goto usage; | |
242 | if (close(outFd) < 0) | 139 | |
243 | perror(outFile); | 140 | buf = malloc (blockSize); |
244 | 141 | if (buf == NULL) { | |
245 | if (buf != localBuf) | 142 | fprintf (stderr, "Cannot allocate buffer\n"); |
246 | free(buf); | 143 | return( FALSE); |
247 | 144 | } | |
248 | printf("%ld+%d records in\n", intotal / blockSize, | 145 | |
249 | (intotal % blockSize) != 0); | 146 | intotal = 0; |
250 | 147 | outTotal = 0; | |
251 | printf("%ld+%d records out\n", outTotal / blockSize, | 148 | |
252 | (outTotal % blockSize) != 0); | 149 | if (!inFile) |
253 | return 0; | 150 | inFd = STDIN; |
254 | usage: | 151 | else |
255 | 152 | inFd = open (inFile, 0); | |
256 | fprintf(stderr, "%s", dd_usage); | 153 | |
257 | return 1; | 154 | if (inFd < 0) { |
258 | } | 155 | perror (inFile); |
259 | 156 | free (buf); | |
260 | 157 | return( FALSE); | |
261 | /* | 158 | } |
262 | * Read a number with a possible multiplier. | 159 | |
263 | * Returns -1 if the number format is illegal. | 160 | if (!outFile) |
264 | */ | 161 | outFd = STDOUT; |
265 | static long | 162 | else |
266 | getNum(const char * cp) | 163 | outFd = creat (outFile, 0666); |
267 | { | 164 | |
268 | long value; | 165 | if (outFd < 0) { |
269 | 166 | perror (outFile); | |
270 | if (!isDecimal(*cp)) | 167 | close (inFd); |
271 | return -1; | 168 | free (buf); |
272 | 169 | return( FALSE); | |
273 | value = 0; | 170 | } |
274 | 171 | ||
275 | while (isDecimal(*cp)) | 172 | lseek(inFd, skipBlocks*blockSize, SEEK_SET); |
276 | value = value * 10 + *cp++ - '0'; | 173 | while (outTotal < count * blockSize) { |
277 | 174 | inCc = read (inFd, buf, blockSize); | |
278 | switch (*cp++) | 175 | if (inCc < 0) { |
279 | { | 176 | perror (inFile); |
280 | case 'k': | 177 | goto cleanup; |
281 | value *= 1024; | 178 | } |
282 | break; | 179 | intotal += inCc; |
283 | 180 | cp = buf; | |
284 | case 'b': | 181 | |
285 | value *= 512; | 182 | while (intotal > outTotal) { |
286 | break; | 183 | if (outTotal + inCc > count * blockSize) |
287 | 184 | inCc = count * blockSize - outTotal; | |
288 | case 'w': | 185 | outCc = write (outFd, cp, inCc); |
289 | value *= 2; | 186 | if (outCc < 0) { |
290 | break; | 187 | perror (outFile); |
188 | goto cleanup; | ||
189 | } | ||
190 | |||
191 | inCc -= outCc; | ||
192 | cp += outCc; | ||
193 | outTotal += outCc; | ||
194 | } | ||
195 | } | ||
291 | 196 | ||
292 | case '\0': | 197 | if (inCc < 0) |
293 | return value; | 198 | perror (inFile); |
294 | 199 | ||
295 | default: | 200 | cleanup: |
296 | return -1; | 201 | close (inFd); |
297 | } | 202 | close (outFd); |
203 | free (buf); | ||
298 | 204 | ||
299 | if (*cp) | 205 | printf ("%ld+%d records in\n", intotal / blockSize, |
300 | return -1; | 206 | (intotal % blockSize) != 0); |
207 | printf ("%ld+%d records out\n", outTotal / blockSize, | ||
208 | (outTotal % blockSize) != 0); | ||
209 | exit( TRUE); | ||
210 | usage: | ||
301 | 211 | ||
302 | return value; | 212 | fprintf (stderr, "%s", dd_usage); |
213 | exit( FALSE); | ||
303 | } | 214 | } |
304 | 215 | ||
305 | #endif | ||
306 | /* END CODE */ | ||
307 | 216 | ||