diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2007-04-19 22:48:21 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2007-04-19 22:48:21 -0700 |
commit | 851c603e9ca9d0954d89be1532d924a28ccb79fa (patch) | |
tree | d038d97634b0705a1836095c0a53eb926a2f77ae /merge-recursive.c | |
parent | 2de00bf9e8815970c61cefaef35efeacd8a7d6de (diff) | |
download | git-851c603e9ca9d0954d89be1532d924a28ccb79fa.tar.gz git-851c603e9ca9d0954d89be1532d924a28ccb79fa.tar.xz |
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.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/merge-recursive.c b/merge-recursive.c index 595b0226a..cea6c8771 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 |