Merge branch 'maint' of git://linux-nfs.org/~bfields/git into maint
[gitweb.git] / entry.c
diff --git a/entry.c b/entry.c
index b51addbf8d0c766c1800dc5814ce50c35321143e..fc3a506ecef4ed654f26c11996df109dd135a4ed 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,24 +1,47 @@
 #include "cache.h"
 #include "blob.h"
 
-static void create_directories(const char *path, struct checkout *state)
+static void create_directories(const char *path, const struct checkout *state)
 {
        int len = strlen(path);
        char *buf = xmalloc(len + 1);
        const char *slash = path;
 
        while ((slash = strchr(slash+1, '/')) != NULL) {
+               struct stat st;
+               int stat_status;
+
                len = slash - path;
                memcpy(buf, path, len);
                buf[len] = 0;
+
+               if (len <= state->base_dir_len)
+                       /*
+                        * checkout-index --prefix=<dir>; <dir> is
+                        * allowed to be a symlink to an existing
+                        * directory.
+                        */
+                       stat_status = stat(buf, &st);
+               else
+                       /*
+                        * if there currently is a symlink, we would
+                        * want to replace it with a real directory.
+                        */
+                       stat_status = lstat(buf, &st);
+
+               if (!stat_status && S_ISDIR(st.st_mode))
+                       continue; /* ok, it is already a directory. */
+
+               /*
+                * We know stat_status == 0 means something exists
+                * there and this mkdir would fail, but that is an
+                * error codepath; we do not care, as we unlink and
+                * mkdir again in such a case.
+                */
                if (mkdir(buf, 0777)) {
-                       if (errno == EEXIST) {
-                               struct stat st;
-                               if (len > state->base_dir_len && state->force && !unlink(buf) && !mkdir(buf, 0777))
-                                       continue;
-                               if (!stat(buf, &st) && S_ISDIR(st.st_mode))
-                                       continue; /* ok */
-                       }
+                       if (errno == EEXIST && state->force &&
+                           !unlink(buf) && !mkdir(buf, 0777))
+                               continue;
                        die("cannot create directory at %s", buf);
                }
        }
@@ -31,7 +54,7 @@ static void remove_subtree(const char *path)
        struct dirent *de;
        char pathbuf[PATH_MAX];
        char *name;
-       
+
        if (!dir)
                die("cannot opendir %s (%s)", path, strerror(errno));
        strcpy(pathbuf, path);
@@ -75,7 +98,7 @@ static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned
        return NULL;
 }
 
-static int write_entry(struct cache_entry *ce, char *path, struct checkout *state, int to_tempfile)
+static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
 {
        int fd;
        long wrote;
@@ -89,6 +112,16 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
                if (!new)
                        return error("git-checkout-index: unable to read sha1 file of %s (%s)",
                                path, sha1_to_hex(ce->sha1));
+
+               /*
+                * Convert from git internal format to working tree format
+                */
+               buf = convert_to_working_tree(ce->name, new, &size);
+               if (buf) {
+                       free(new);
+                       new = buf;
+               }
+
                if (to_tempfile) {
                        strcpy(path, ".merge_file_XXXXXX");
                        fd = mkstemp(path);
@@ -100,15 +133,6 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
                                path, strerror(errno));
                }
 
-               /*
-                * Convert from git internal format to working tree format
-                */
-               buf = convert_to_working_tree(ce->name, new, &size);
-               if (buf) {
-                       free(new);
-                       new = buf;
-               }
-
                wrote = write_in_full(fd, new, size);
                close(fd);
                free(new);
@@ -145,7 +169,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
                                                 "symlink %s (%s)", path, strerror(errno));
                }
                break;
-       case S_IFDIRLNK:
+       case S_IFGITLINK:
                if (to_tempfile)
                        return error("git-checkout-index: cannot create temporary subproject %s", path);
                if (mkdir(path, 0777) < 0)
@@ -163,7 +187,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
        return 0;
 }
 
-int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
+int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
 {
        static char path[PATH_MAX + 1];
        struct stat st;
@@ -194,7 +218,7 @@ int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
                unlink(path);
                if (S_ISDIR(st.st_mode)) {
                        /* If it is a gitlink, leave it alone! */
-                       if (S_ISDIRLNK(ntohl(ce->ce_mode)))
+                       if (S_ISGITLINK(ntohl(ce->ce_mode)))
                                return 0;
                        if (!state->force)
                                return error("%s is a directory", path);