summaryrefslogtreecommitdiff
path: root/merge-recursive.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2007-04-20 05:48:21 (GMT)
committerJunio C Hamano <junkio@cox.net>2007-04-20 05:48:21 (GMT)
commit851c603e9ca9d0954d89be1532d924a28ccb79fa (patch)
treed038d97634b0705a1836095c0a53eb926a2f77ae /merge-recursive.c
parent2de00bf9e8815970c61cefaef35efeacd8a7d6de (diff)
downloadgit-851c603e9ca9d0954d89be1532d924a28ccb79fa.zip
git-851c603e9ca9d0954d89be1532d924a28ccb79fa.tar.gz
git-851c603e9ca9d0954d89be1532d924a28ccb79fa.tar.bz2
Fix working directory errno handling when unlinking a directory
Alex Riesen noticed that the case where a file replaced a directory entry in the working tree was broken on cygwin. It turns out that the code made some Linux-specific assumptions, and also ignored errors entirely for the case where the entry was a symlink rather than a file. This cleans it up by separating out the common case into a function of its own, so that both regular files and symlinks can share it, and by making the error handling more obvious (and not depend on any Linux-specific behaviour). Acked-by: Alex Riesen <raa.lkml@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'merge-recursive.c')
-rw-r--r--merge-recursive.c54
1 files changed, 29 insertions, 25 deletions
diff --git a/merge-recursive.c b/merge-recursive.c
index 595b022..cea6c87 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -574,6 +574,31 @@ static void flush_buffer(int fd, const char *buf, unsigned long size)
}
}
+static int make_room_for_path(const char *path)
+{
+ int status;
+ const char *msg = "failed to create path '%s'%s";
+
+ status = mkdir_p(path, 0777);
+ if (status) {
+ if (status == -3) {
+ /* something else exists */
+ error(msg, path, ": perhaps a D/F conflict?");
+ return -1;
+ }
+ die(msg, path, "");
+ }
+
+ /* Successful unlink is good.. */
+ if (!unlink(path))
+ return 0;
+ /* .. and so is no existing file */
+ if (errno == ENOENT)
+ return 0;
+ /* .. but not some other error (who really cares what?) */
+ return error(msg, path, ": perhaps a D/F conflict?");
+}
+
static void update_file_flags(const unsigned char *sha,
unsigned mode,
const char *path,
@@ -594,33 +619,12 @@ static void update_file_flags(const unsigned char *sha,
if (type != OBJ_BLOB)
die("blob expected for %s '%s'", sha1_to_hex(sha), path);
+ if (make_room_for_path(path) < 0) {
+ update_wd = 0;
+ goto update_index;
+ }
if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
int fd;
- int status;
- const char *msg = "failed to create path '%s'%s";
-
- status = mkdir_p(path, 0777);
- if (status) {
- if (status == -3) {
- /* something else exists */
- error(msg, path, ": perhaps a D/F conflict?");
- update_wd = 0;
- goto update_index;
- }
- die(msg, path, "");
- }
- if (unlink(path)) {
- if (errno == EISDIR) {
- /* something else exists */
- error(msg, path, ": perhaps a D/F conflict?");
- update_wd = 0;
- goto update_index;
- }
- if (errno != ENOENT)
- die("failed to unlink %s "
- "in preparation to update: %s",
- path, strerror(errno));
- }
if (mode & 0100)
mode = 0777;
else