Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F146118188
D21535.id61697.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D21535.id61697.diff
View Options
Index: usr.bin/patch/patch.c
===================================================================
--- usr.bin/patch/patch.c
+++ usr.bin/patch/patch.c
@@ -103,6 +103,7 @@
static bool patch_match(LINENUM, LINENUM, LINENUM);
static bool similar(const char *, const char *, int);
static void usage(void);
+static bool handle_creation(bool, bool *);
/* true if -E was specified on command line. */
static bool remove_empty_files = false;
@@ -147,8 +148,10 @@
int
main(int argc, char *argv[])
{
+ struct stat statbuf;
int error = 0, hunk, failed, i, fd;
- bool patch_seen, reverse_seen;
+ bool out_creating, out_existed, patch_seen, remove_file;
+ bool reverse_seen;
LINENUM where = 0, newwhere, fuzz, mymaxfuzz;
const char *tmpdir;
char *v;
@@ -219,6 +222,12 @@
reinitialize_almost_everything()) {
/* for each patch in patch file */
+ if (source_file != NULL && (diff_type == CONTEXT_DIFF ||
+ diff_type == NEW_CONTEXT_DIFF ||
+ diff_type == UNI_DIFF))
+ out_creating = strcmp(source_file, _PATH_DEVNULL) == 0;
+ else
+ out_creating = false;
patch_seen = true;
warn_on_invalid_line = true;
@@ -226,6 +235,8 @@
if (outname == NULL)
outname = xstrdup(filearg[0]);
+ out_existed = stat(outname, &statbuf) == 0;
+
/* for ed script just up and do it and exit */
if (diff_type == ED_DIFF) {
do_ed_script();
@@ -252,9 +263,15 @@
failed = 0;
reverse_seen = false;
out_of_mem = false;
+ remove_file = false;
while (another_hunk()) {
hunk++;
fuzz = 0;
+
+ if (out_creating)
+ reverse_seen = handle_creation(out_existed,
+ &remove_file);
+
mymaxfuzz = pch_context();
if (maxfuzz < mymaxfuzz)
mymaxfuzz = maxfuzz;
@@ -372,7 +389,6 @@
/* and put the output where desired */
ignore_signals();
if (!skip_rest_of_patch) {
- struct stat statbuf;
char *realout = outname;
if (!check_only) {
@@ -383,7 +399,7 @@
} else
chmod(outname, filemode);
- if (remove_empty_files &&
+ if ((remove_empty_files || remove_file) &&
stat(realout, &statbuf) == 0 &&
statbuf.st_size == 0) {
if (verbose)
@@ -444,6 +460,9 @@
filearg[0] = NULL;
}
+ free(source_file);
+ source_file = NULL;
+
free(outname);
outname = NULL;
@@ -1084,3 +1103,58 @@
return true; /* actually, this is not reached */
/* since there is always a \n */
}
+
+static bool
+handle_creation(bool out_existed, bool *remove)
+{
+ bool reverse_seen;
+
+ reverse_seen = false;
+ if (reverse && out_existed) {
+ *remove = true;
+ } else if (!reverse && out_existed) {
+ if (force) {
+ skip_rest_of_patch = true;
+ return (false);
+ }
+ if (noreverse) {
+ say("Ignoring previously applied (or reversed) patch.\n");
+ skip_rest_of_patch = true;
+ return (false);
+ }
+
+ /* Unreversed... suspicious if the file existed. */
+ if (!pch_swap())
+ fatal("lost hunk on alloc error!\n");
+
+ reverse = !reverse;
+
+ if (batch) {
+ if (verbose)
+ say("Patch creates file that already exists, %s %seversed",
+ reverse ? "Assuming" : "Ignoring",
+ reverse ? "R" : "Unr");
+ } else {
+ ask("Patch creates file that already exists! %s -R? [y] ",
+ reverse ? "Assume" : "Ignore");
+
+ if (*buf == 'n') {
+ ask("Apply anyway? [n]");
+ if (*buf != 'y')
+ /* Don't apply; error out */
+ skip_rest_of_patch = true;
+ else
+ /* Attempt to apply */
+ reverse_seen = true;
+ reverse = !reverse;
+ if (!pch_swap())
+ fatal("lost hunk on alloc error!\n");
+ } else {
+ /* They've opted to assume -R */
+ *remove = true;
+ }
+ }
+ }
+
+ return (reverse_seen);
+}
Index: usr.bin/patch/pch.h
===================================================================
--- usr.bin/patch/pch.h
+++ usr.bin/patch/pch.h
@@ -37,6 +37,8 @@
bool exists;
};
+extern char *source_file;
+
void re_patch(void);
void open_patch_file(const char *);
void set_hunkmax(void);
Index: usr.bin/patch/pch.c
===================================================================
--- usr.bin/patch/pch.c
+++ usr.bin/patch/pch.c
@@ -70,6 +70,8 @@
static FILE *pfp = NULL; /* patch file pointer */
static char *bestguess = NULL; /* guess at correct filename */
+char *source_file;
+
static void grow_hunkmax(void);
static int intuit_diff_type(void);
static void next_intuit_at(off_t, LINENUM);
@@ -218,7 +220,12 @@
bestguess = xstrdup(buf);
filearg[0] = fetchname(buf, &exists, 0);
}
- if (!exists) {
+ /*
+ * fetchname can now return buf = NULL, exists = true, to
+ * indicate to the caller that /dev/null was specified. Retain
+ * previous behavior for now until this can be better evaluted.
+ */
+ if (filearg[0] == NULL || !exists) {
int def_skip = *bestguess == '\0';
ask("No file found--skip this patch? [%c] ",
def_skip ? 'y' : 'n');
@@ -403,6 +410,23 @@
names[OLD_FILE] = names[NEW_FILE];
names[NEW_FILE] = tmp;
}
+
+ /* Invalidated */
+ free(source_file);
+ source_file = NULL;
+
+ if (retval != 0) {
+ /*
+ * In the case of success, path == NULL means _PATH_DEVNULL if
+ * exists is set. Explicitly specify it here to make it easier
+ * to detect later on that we're actually creating a file and
+ * not that we've just goofed something up.
+ */
+ if (names[OLD_FILE].path != NULL)
+ source_file = xstrdup(names[OLD_FILE].path);
+ else if (names[OLD_FILE].exists)
+ source_file = xstrdup(_PATH_DEVNULL);
+ }
if (filearg[0] == NULL) {
if (posix)
filearg[0] = posix_name(names, ok_to_create_file);
Index: usr.bin/patch/tests/unified_patch_test.sh
===================================================================
--- usr.bin/patch/tests/unified_patch_test.sh
+++ usr.bin/patch/tests/unified_patch_test.sh
@@ -108,22 +108,17 @@
file_nodupe_body()
{
- # WIP
- atf_expect_fail "patch(1) erroneously duplicates created files"
echo "x" > foo
diff -u /dev/null foo > foo.diff
- atf_check -x "patch -s < foo.diff"
- atf_check -s not-exit:0 -x "patch -fs < foo.diff"
+ atf_check -s not-exit:0 -o ignore -x "patch -Ns < foo.diff"
+ atf_check -s not-exit:0 -o ignore -x "patch -fs < foo.diff"
}
atf_test_case file_removal
file_removal_body()
{
- # WIP
- atf_expect_fail "patch(1) does not yet recognize /dev/null as creation"
-
echo "x" > foo
diff -u /dev/null foo > foo.diff
Index: usr.bin/patch/util.c
===================================================================
--- usr.bin/patch/util.c
+++ usr.bin/patch/util.c
@@ -366,8 +366,10 @@
say("fetchname %s %d\n", at, strip_leading);
#endif
/* So files can be created by diffing against /dev/null. */
- if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
+ if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1)) {
+ *exists = true;
return NULL;
+ }
name = fullname = t = savestr(at);
tab = strchr(t, '\t') != NULL;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 28, 11:31 PM (5 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29086683
Default Alt Text
D21535.id61697.diff (6 KB)
Attached To
Mode
D21535: patch(1): give /dev/null patches special treatment
Attached
Detach File
Event Timeline
Log In to Comment