aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-11-21 05:53:34 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-11-21 05:53:34 +0100
commitb82ae98ea4d5216d20a5deedab2aa6153562337b (patch)
tree20e89268f222d4e463f65706d2f9a2bce61b9d4c
parentf718e3a0dbe47ed7ed0398fe4461d33c8f69c669 (diff)
downloadbusybox-w32-b82ae98ea4d5216d20a5deedab2aa6153562337b.tar.gz
busybox-w32-b82ae98ea4d5216d20a5deedab2aa6153562337b.tar.bz2
busybox-w32-b82ae98ea4d5216d20a5deedab2aa6153562337b.zip
patch: busyboxify by migrating from toybox to busybox helpers
function old new delta get_line 90 128 +38 bbconfig_config_bz2 4959 4965 +6 makedevs_main 1038 1035 -3 fail_hunk 133 130 -3 finish_oldfile 174 124 -50 patch_main 2066 1987 -79 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/4 up/down: 44/-135) Total: -91 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/patch.c245
-rwxr-xr-xtestsuite/patch.tests4
2 files changed, 87 insertions, 162 deletions
diff --git a/editors/patch.c b/editors/patch.c
index 33ff8b569..4fadbb8fe 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -1,8 +1,7 @@
1/* Adapted from toybox's patch. */
2
3/* vi: set sw=4 ts=4: 1/* vi: set sw=4 ts=4:
4 * 2 *
5 * patch.c - Apply a "universal" diff. 3 * Apply a "universal" diff.
4 * Adapted from toybox's patch implementation.
6 * 5 *
7 * Copyright 2007 Rob Landley <rob@landley.net> 6 * Copyright 2007 Rob Landley <rob@landley.net>
8 * 7 *
@@ -20,29 +19,41 @@
20 * -f force (no questions asked) 19 * -f force (no questions asked)
21 * -F fuzz (number, default 2) 20 * -F fuzz (number, default 2)
22 * [file] which file to patch 21 * [file] which file to patch
22 */
23
24//applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP))
25
26//kbuild:lib-$(CONFIG_PATCH) += patch.o
27
28//config:config PATCH
29//config: bool "patch"
30//config: default y
31//config: help
32//config: Apply a unified diff formatted patch.
33
34//usage:#define patch_trivial_usage
35//usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]"
36//usage:#define patch_full_usage "\n\n"
37//usage: IF_LONG_OPTS(
38//usage: " -p,--strip N Strip N leading components from file names"
39//usage: "\n -i,--input DIFF Read DIFF instead of stdin"
40//usage: "\n -R,--reverse Reverse patch"
41//usage: "\n -N,--forward Ignore already applied patches"
42//usage: "\n --dry-run Don't actually change files"
43//usage: "\n -E,--remove-empty-files Remove output files if they become empty"
44//usage: )
45//usage: IF_NOT_LONG_OPTS(
46//usage: " -p N Strip N leading components from file names"
47//usage: "\n -i DIFF Read DIFF instead of stdin"
48//usage: "\n -R Reverse patch"
49//usage: "\n -N Ignore already applied patches"
50//usage: "\n -E Remove output files if they become empty"
51//usage: )
52//usage:
53//usage:#define patch_example_usage
54//usage: "$ patch -p1 < example.diff\n"
55//usage: "$ patch -p0 -i example.diff"
23 56
24USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN))
25
26config PATCH
27 bool "patch"
28 default y
29 help
30 usage: patch [-i file] [-p depth] [-Ru]
31
32 Apply a unified diff to one or more files.
33
34 -i Input file (defaults=stdin)
35 -p number of '/' to strip from start of file paths (default=all)
36 -R Reverse patch.
37 -u Ignored (only handles "unified" diffs)
38
39 This version of patch only handles unified diffs, and only modifies
40 a file when all all hunks to that file apply. Patch prints failed
41 hunks to stderr, and exits with nonzero status if any hunks fail.
42
43 A file compared against /dev/null (or with a date <= the epoch) is
44 created or deleted if -E or --remove-empty-files set.
45*/
46#include "libbb.h" 57#include "libbb.h"
47 58
48struct double_list { 59struct double_list {
@@ -101,125 +112,6 @@ struct double_list *dlist_add(struct double_list **list, char *data)
101 return line; 112 return line;
102} 113}
103 114
104// Ensure entire path exists.
105// If mode != -1 set permissions on newly created dirs.
106// Requires that path string be writable (for temporary null terminators).
107static
108void xmkpath(char *path, int mode)
109{
110 char *p, old;
111 mode_t mask;
112 int rc;
113 struct stat st;
114
115 for (p = path; ; p++) {
116 if (!*p || *p == '/') {
117 old = *p;
118 *p = rc = 0;
119 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
120 if (mode != -1) {
121 mask = umask(0);
122 rc = mkdir(path, mode);
123 umask(mask);
124 } else rc = mkdir(path, 0777);
125 }
126 *p = old;
127 if(rc) bb_perror_msg_and_die("mkpath '%s'", path);
128 }
129 if (!*p) break;
130 }
131}
132
133// Slow, but small.
134static
135char *get_rawline(int fd, long *plen, char end)
136{
137 char c, *buf = NULL;
138 long len = 0;
139
140 for (;;) {
141 if (1>read(fd, &c, 1)) break;
142 if (!(len & 63)) buf=xrealloc(buf, len+65);
143 if ((buf[len++]=c) == end) break;
144 }
145 if (buf) buf[len]=0;
146 if (plen) *plen = len;
147
148 return buf;
149}
150
151static
152char *get_line(int fd)
153{
154 long len;
155 char *buf = get_rawline(fd, &len, '\n');
156
157 if (buf && buf[--len]=='\n') buf[len]=0;
158
159 return buf;
160}
161
162// Copy the rest of in to out and close both files.
163static
164void xsendfile(int in, int out)
165{
166 long len;
167 char buf[4096];
168
169 if (in<0) return;
170 for (;;) {
171 len = safe_read(in, buf, 4096);
172 if (len<1) break;
173 xwrite(out, buf, len);
174 }
175}
176
177// Copy the rest of the data and replace the original with the copy.
178static
179void replace_tempfile(int fdin, int fdout, char **tempname)
180{
181 char *temp = xstrdup(*tempname);
182
183 temp[strlen(temp)-6]=0;
184 if (fdin != -1) {
185 xsendfile(fdin, fdout);
186 xclose(fdin);
187 }
188 xclose(fdout);
189 rename(*tempname, temp);
190 free(*tempname);
191 free(temp);
192 *tempname = NULL;
193}
194
195// Open a temporary file to copy an existing file into.
196static
197int copy_tempfile(int fdin, char *name, char **tempname)
198{
199 struct stat statbuf;
200 int fd;
201
202 *tempname = xasprintf("%sXXXXXX", name);
203 fd = xmkstemp(*tempname);
204
205 // Set permissions of output file
206 fstat(fdin, &statbuf);
207 fchmod(fd, statbuf.st_mode);
208
209 return fd;
210}
211
212// Abort the copy and delete the temporary file.
213static
214void delete_tempfile(int fdin, int fdout, char **tempname)
215{
216 close(fdin);
217 close(fdout);
218 unlink(*tempname);
219 free(*tempname);
220 *tempname = NULL;
221}
222
223 115
224 116
225struct globals { 117struct globals {
@@ -229,7 +121,7 @@ struct globals {
229 struct double_list *current_hunk; 121 struct double_list *current_hunk;
230 long oldline, oldlen, newline, newlen; 122 long oldline, oldlen, newline, newlen;
231 long linenum; 123 long linenum;
232 int context, state, filein, fileout, filepatch, hunknum; 124 int context, state, filein, fileout, hunknum;
233 char *tempname; 125 char *tempname;
234 126
235 // was toys.foo: 127 // was toys.foo:
@@ -263,7 +155,7 @@ struct globals {
263 155
264static void do_line(void *data) 156static void do_line(void *data)
265{ 157{
266 struct double_list *dlist = (struct double_list *)data; 158 struct double_list *dlist = data;
267 159
268 if (TT.state>1 && *dlist->data != TT.state) 160 if (TT.state>1 && *dlist->data != TT.state)
269 fdprintf(TT.state == 2 ? 2 : TT.fileout, 161 fdprintf(TT.state == 2 ? 2 : TT.fileout,
@@ -272,19 +164,36 @@ static void do_line(void *data)
272 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); 164 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data);
273 165
274 free(dlist->data); 166 free(dlist->data);
275 free(data); 167 free(dlist);
276} 168}
277 169
278static void finish_oldfile(void) 170static void finish_oldfile(void)
279{ 171{
280 if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); 172 if (TT.tempname) {
173 // Copy the rest of the data and replace the original with the copy.
174 char *temp;
175
176 if (TT.filein != -1) {
177 bb_copyfd_eof(TT.filein, TT.fileout);
178 xclose(TT.filein);
179 }
180 xclose(TT.fileout);
181
182 temp = xstrdup(TT.tempname);
183 temp[strlen(temp) - 6] = '\0';
184 rename(TT.tempname, temp);
185 free(temp);
186
187 free(TT.tempname);
188 TT.tempname = NULL;
189 }
281 TT.fileout = TT.filein = -1; 190 TT.fileout = TT.filein = -1;
282} 191}
283 192
284static void fail_hunk(void) 193static void fail_hunk(void)
285{ 194{
286 if (!TT.current_hunk) return; 195 if (!TT.current_hunk) return;
287 TT.current_hunk->prev->next = 0; 196 TT.current_hunk->prev->next = NULL;
288 197
289 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); 198 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline);
290 TT.exitval = 1; 199 TT.exitval = 1;
@@ -295,7 +204,14 @@ static void fail_hunk(void)
295 TT.state = 2; 204 TT.state = 2;
296 llist_free(TT.current_hunk, do_line); 205 llist_free(TT.current_hunk, do_line);
297 TT.current_hunk = NULL; 206 TT.current_hunk = NULL;
298 delete_tempfile(TT.filein, TT.fileout, &TT.tempname); 207
208 // Abort the copy and delete the temporary file.
209 close(TT.filein);
210 close(TT.fileout);
211 unlink(TT.tempname);
212 free(TT.tempname);
213 TT.tempname = NULL;
214
299 TT.state = 0; 215 TT.state = 0;
300} 216}
301 217
@@ -334,7 +250,7 @@ static int apply_one_hunk(void)
334 plist = TT.current_hunk; 250 plist = TT.current_hunk;
335 buf = NULL; 251 buf = NULL;
336 if (TT.context) for (;;) { 252 if (TT.context) for (;;) {
337 char *data = get_line(TT.filein); 253 char *data = xmalloc_reads(TT.filein, NULL, NULL);
338 254
339 TT.linenum++; 255 TT.linenum++;
340 256
@@ -368,7 +284,9 @@ static int apply_one_hunk(void)
368 // File ended before we found a place for this hunk. 284 // File ended before we found a place for this hunk.
369 fail_hunk(); 285 fail_hunk();
370 goto done; 286 goto done;
371 } else if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); 287 }
288
289 if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data);
372 check = dlist_add(&buf, data); 290 check = dlist_add(&buf, data);
373 291
374 // Compare this line with next expected line of hunk. 292 // Compare this line with next expected line of hunk.
@@ -398,8 +316,8 @@ static int apply_one_hunk(void)
398 316
399 // If we've reached the end of the buffer without confirming a 317 // If we've reached the end of the buffer without confirming a
400 // match, read more lines. 318 // match, read more lines.
401 if (check==buf) { 319 if (check == buf) {
402 buf = 0; 320 buf = NULL;
403 break; 321 break;
404 } 322 }
405 check = buf; 323 check = buf;
@@ -453,10 +371,10 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
453 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! 371 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative!
454 TT.filein = TT.fileout = -1; 372 TT.filein = TT.fileout = -1;
455 if (opts & FLAG_INPUT) { 373 if (opts & FLAG_INPUT) {
456 TT.filepatch = xopen_stdin(opt_i); 374 xmove_fd(xopen_stdin(opt_i), STDIN_FILENO);
457 } else { 375 } else {
458 if (argv[0] && argv[1]) { 376 if (argv[0] && argv[1]) {
459 TT.filepatch = xopen_stdin(argv[1]); 377 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
460 } 378 }
461 } 379 }
462 if (argv[0]) { 380 if (argv[0]) {
@@ -468,7 +386,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
468 for(;;) { 386 for(;;) {
469 char *patchline; 387 char *patchline;
470 388
471 patchline = get_line(TT.filepatch); 389 patchline = xmalloc_fgetline(stdin);
472 if (!patchline) break; 390 if (!patchline) break;
473 391
474 // Other versions of patch accept damaged patches, 392 // Other versions of patch accept damaged patches,
@@ -588,13 +506,15 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
588 } 506 }
589 // If we've got a file to open, do so. 507 // If we've got a file to open, do so.
590 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { 508 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) {
509 struct stat statbuf;
510
591 // If the old file was null, we're creating a new one. 511 // If the old file was null, we're creating a new one.
592 if (!strcmp(oldname, "/dev/null") || !oldsum) { 512 if (!strcmp(oldname, "/dev/null") || !oldsum) {
593 printf("creating %s\n", name); 513 printf("creating %s\n", name);
594 s = strrchr(name, '/'); 514 s = strrchr(name, '/');
595 if (s) { 515 if (s) {
596 *s = 0; 516 *s = 0;
597 xmkpath(name, -1); 517 bb_make_directory(name, -1, FILEUTILS_RECUR);
598 *s = '/'; 518 *s = '/';
599 } 519 }
600 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); 520 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
@@ -602,7 +522,13 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
602 printf("patching file %s\n", name); 522 printf("patching file %s\n", name);
603 TT.filein = xopen(name, O_RDONLY); 523 TT.filein = xopen(name, O_RDONLY);
604 } 524 }
605 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); 525
526 TT.tempname = xasprintf("%sXXXXXX", name);
527 TT.fileout = xmkstemp(TT.tempname);
528 // Set permissions of output file
529 fstat(TT.filein, &statbuf);
530 fchmod(TT.fileout, statbuf.st_mode);
531
606 TT.linenum = 0; 532 TT.linenum = 0;
607 TT.hunknum = 0; 533 TT.hunknum = 0;
608 } 534 }
@@ -620,7 +546,6 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
620 finish_oldfile(); 546 finish_oldfile();
621 547
622 if (ENABLE_FEATURE_CLEAN_UP) { 548 if (ENABLE_FEATURE_CLEAN_UP) {
623 close(TT.filepatch);
624 free(oldname); 549 free(oldname);
625 free(newname); 550 free(newname);
626 } 551 }
diff --git a/testsuite/patch.tests b/testsuite/patch.tests
index e482304f6..ba37e8218 100755
--- a/testsuite/patch.tests
+++ b/testsuite/patch.tests
@@ -75,7 +75,7 @@ zxc
75testing "patch detects already applied hunk" \ 75testing "patch detects already applied hunk" \
76 'patch 2>&1; echo $?; cat input' \ 76 'patch 2>&1; echo $?; cat input' \
77"\ 77"\
78Possibly reversed hunk 1 at 2 78Possibly reversed hunk 1 at 4
79Hunk 1 FAILED 1/1. 79Hunk 1 FAILED 1/1.
80 abc 80 abc
81+def 81+def
@@ -103,7 +103,7 @@ def
103testing "patch detects already applied hunk at the EOF" \ 103testing "patch detects already applied hunk at the EOF" \
104 'patch 2>&1; echo $?; cat input' \ 104 'patch 2>&1; echo $?; cat input' \
105"\ 105"\
106Possibly reversed hunk 1 at 3 106Possibly reversed hunk 1 at 4
107Hunk 1 FAILED 1/1. 107Hunk 1 FAILED 1/1.
108 abc 108 abc
109 123 109 123