summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2009-04-05 17:33:47 +0200
committerAndreas Gruenbacher <agruen@suse.de>2009-04-05 17:42:20 +0200
commit1d204bbab2b2b6a718604fad117170342657be80 (patch)
tree8a8419409a81327dea179600c42a7f2a08b717cc
parentb3fbd9a585502767572115ab15ac9326ebe630cc (diff)
downloadpatch-1d204bbab2b2b6a718604fad117170342657be80.tar.gz
Don't assume the target directory exists when making a backup copy
-rw-r--r--ChangeLog12
-rw-r--r--src/inp.c3
-rw-r--r--src/patch.c4
-rw-r--r--src/pch.c4
-rw-r--r--src/util.c44
-rw-r--r--src/util.h4
-rw-r--r--tests/unmodified-files4
7 files changed, 51 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index ce22397..b5f3a95 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -48,6 +48,18 @@
* src/util.h: Replace memory_fatal() with xalloc_die().
* src/pch.c: Don't leak memory with strlen (base_name (...)).
+ * src/util.c (create_file): Add to_dir_known_to_exist argument and
+ try to create parent directories when set and the create failed with
+ ENOENT.
+ (copy_file, create_backup_copy): Pass the new to_dir_known_to_exist
+ argument through.
+ (create_backup): Don't assume the target directory exists when making
+ a backup copy.
+ * src/util.h (create_file, copy_file): Change the declarations.
+ * src/patch.c, src/pch.c, src/inp.c: In the calls to create_file() and
+ copy_file(), assume the parent directory exists.
+ * tests/unmodified-files: Test the create_backup() fix.
+
2009-04-04 Andreas Gruenbacher <agruen@suse.de>
* pch.c (another_hunk): Add (back) the line number ranges to the
diff --git a/src/inp.c b/src/inp.c
index 3f6febf..5ecf84a 100644
--- a/src/inp.c
+++ b/src/inp.c
@@ -340,7 +340,8 @@ plan_b (char const *filename)
pfatal ("Can't open file %s", quotearg (filename));
exclusive = TMPINNAME_needs_removal ? 0 : O_EXCL;
TMPINNAME_needs_removal = 1;
- tifd = create_file (TMPINNAME, O_RDWR | O_BINARY | exclusive, (mode_t) 0);
+ tifd = create_file (TMPINNAME, O_RDWR | O_BINARY | exclusive, (mode_t) 0,
+ true);
i = 0;
len = 0;
maxlen = 1;
diff --git a/src/patch.c b/src/patch.c
index 241e8fa..d8c7390 100644
--- a/src/patch.c
+++ b/src/patch.c
@@ -443,7 +443,7 @@ main (int argc, char **argv)
{
if (! written_to_rejname)
{
- copy_file (TMPREJNAME, rejname, 0, 0, 0666);
+ copy_file (TMPREJNAME, rejname, 0, 0, 0666, true);
written_to_rejname = true;
}
else
@@ -1323,7 +1323,7 @@ static FILE *
create_output_file (char const *name, int open_flags)
{
int fd = create_file (name, O_WRONLY | binary_transput | open_flags,
- instat.st_mode);
+ instat.st_mode, true);
FILE *f = fdopen (fd, binary_transput ? "wb" : "w");
if (! f)
pfatal ("Can't create file %s", quotearg (name));
diff --git a/src/pch.c b/src/pch.c
index ca403cb..4626910 100644
--- a/src/pch.c
+++ b/src/pch.c
@@ -129,7 +129,7 @@ open_patch_file (char const *filename)
TMPPATNAME_needs_removal = 1;
pfp = fdopen (create_file (TMPPATNAME,
O_RDWR | O_BINARY | exclusive,
- (mode_t) 0),
+ (mode_t) 0, true),
"w+b");
if (!pfp)
pfatal ("Can't open stream for file %s", quotearg (TMPPATNAME));
@@ -2033,7 +2033,7 @@ do_ed_script (FILE *ofp)
int exclusive = TMPOUTNAME_needs_removal ? 0 : O_EXCL;
assert (! inerrno);
TMPOUTNAME_needs_removal = 1;
- copy_file (inname, TMPOUTNAME, 0, exclusive, instat.st_mode);
+ copy_file (inname, TMPOUTNAME, 0, exclusive, instat.st_mode, true);
sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ",
TMPOUTNAME);
fflush (stdout);
diff --git a/src/util.c b/src/util.c
index e1e69f7..0320484 100644
--- a/src/util.c
+++ b/src/util.c
@@ -127,11 +127,12 @@ contains_slash (const char *s)
}
static void
-create_backup_copy (char const *from, char const *to, struct stat *st)
+create_backup_copy (char const *from, char const *to, struct stat *st,
+ bool to_dir_known_to_exist)
{
struct utimbuf utimbuf;
- copy_file (from, to, 0, 0, st->st_mode);
+ copy_file (from, to, 0, 0, st->st_mode, to_dir_known_to_exist);
utimbuf.actime = st->st_atime;
utimbuf.modtime = st->st_mtime;
if (utime (to, &utimbuf) != 0)
@@ -223,7 +224,7 @@ create_backup (char *to, struct stat *to_st, int *to_errno,
pfatal ("Can't close file %s", quotearg (bakname));
}
else if (leave_original)
- create_backup_copy (to, bakname, to_st);
+ create_backup_copy (to, bakname, to_st, try_makedirs_errno == 0);
else
{
if (debug & 4)
@@ -238,7 +239,8 @@ create_backup (char *to, struct stat *to_st, int *to_errno,
}
else if (errno == EXDEV)
{
- create_backup_copy (to, bakname, to_st);
+ create_backup_copy (to, bakname, to_st,
+ try_makedirs_errno == 0);
unlink (to);
break;
}
@@ -301,9 +303,7 @@ move_file (char const *from, int volatile *from_needs_removal,
else if (errno != ENOENT)
pfatal ("Can't remove file %s", quotearg (to));
}
- if (! to_dir_known_to_exist)
- makedirs (to);
- copy_file (from, to, &tost, 0, mode);
+ copy_file (from, to, &tost, 0, mode, to_dir_known_to_exist);
insert_file (&tost);
return;
}
@@ -335,16 +335,29 @@ move_file (char const *from, int volatile *from_needs_removal,
we can read and write the file and that the file is not executable.
Return the file descriptor. */
int
-create_file (char const *file, int open_flags, mode_t mode)
+create_file (char const *file, int open_flags, mode_t mode,
+ bool to_dir_known_to_exist)
{
+ int try_makedirs_errno = to_dir_known_to_exist ? 0 : ENOENT;
int fd;
mode |= S_IRUSR | S_IWUSR;
mode &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
- if (! (O_CREAT && O_TRUNC))
- close (creat (file, mode));
- fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
- if (fd < 0)
- pfatal ("Can't create file %s", quotearg (file));
+ do
+ {
+ if (! (O_CREAT && O_TRUNC))
+ close (creat (file, mode));
+ fd = open (file, O_CREAT | O_TRUNC | open_flags, mode);
+ if (fd < 0)
+ {
+ char *f;
+ if (errno != try_makedirs_errno)
+ pfatal ("Can't create file %s", quotearg (file));
+ f = xstrdup (file);
+ makedirs (f);
+ free (f);
+ try_makedirs_errno = 0;
+ }
+ } while (fd < 0);
return fd;
}
@@ -371,14 +384,15 @@ copy_to_fd (const char *from, int tofd)
void
copy_file (char const *from, char const *to, struct stat *tost,
- int to_flags, mode_t mode)
+ int to_flags, mode_t mode, bool to_dir_known_to_exist)
{
int tofd;
if (debug & 4)
say ("Copying file %s to %s\n",
quotearg_n (0, from), quotearg_n (1, to));
- tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode);
+ tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode,
+ to_dir_known_to_exist);
copy_to_fd (from, tofd);
if ((tost && fstat (tofd, tost) != 0)
|| close (tofd) != 0)
diff --git a/src/util.h b/src/util.h
index acc413b..1f6bd88 100644
--- a/src/util.h
+++ b/src/util.h
@@ -52,11 +52,11 @@ char *savebuf (char const *, size_t);
char *savestr (char const *);
char const *version_controller (char const *, bool, struct stat const *, char **, char **);
bool version_get (char const *, char const *, bool, bool, char const *, struct stat *);
-int create_file (char const *, int, mode_t);
+int create_file (char const *, int, mode_t, bool);
int systemic (char const *);
char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], LINENUM);
void Fseek (FILE *, file_offset, int);
-void copy_file (char const *, char const *, struct stat *, int, mode_t);
+void copy_file (char const *, char const *, struct stat *, int, mode_t, bool);
void append_to_file (char const *, char const *);
void exit_with_signal (int) __attribute__ ((noreturn));
void ignore_signals (void);
diff --git a/tests/unmodified-files b/tests/unmodified-files
index 8d5bd5c..c970c3d 100644
--- a/tests/unmodified-files
+++ b/tests/unmodified-files
@@ -29,7 +29,7 @@ EOF
echo three > a
ln a a.first
-check 'patch -b a < a.diff || echo "Status: $?"' <<EOF
+check 'patch -b -B backup/ a < a.diff || echo "Status: $?"' <<EOF
patching file a
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file a.rej
@@ -38,7 +38,7 @@ EOF
ncheck 'test a -ef a.first'
-check 'cat a.orig' <<EOF
+check 'cat backup/a' <<EOF
three
EOF