X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=entry.c;h=cfadc6a292033d349f6b1efff75d2c4f9f2525fe;hb=5410a02ab9e6a1987147724f8ea65e6a077b3832;hp=50ffae40c76478a10d1c3fc9623105e7f14f863e;hpb=f0807e62b42df51a079c730dcf4868de9ad44ea5;p=git.git diff --git a/entry.c b/entry.c index 50ffae40c..cfadc6a29 100644 --- 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=; 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,9 +54,9 @@ static void remove_subtree(const char *path) struct dirent *de; char pathbuf[PATH_MAX]; char *name; - + if (!dir) - die("cannot opendir %s", path); + die("cannot opendir %s (%s)", path, strerror(errno)); strcpy(pathbuf, path); name = pathbuf + strlen(path); *name++ = '/'; @@ -45,15 +68,15 @@ static void remove_subtree(const char *path) continue; strcpy(name, de->d_name); if (lstat(pathbuf, &st)) - die("cannot lstat %s", pathbuf); + die("cannot lstat %s (%s)", pathbuf, strerror(errno)); if (S_ISDIR(st.st_mode)) remove_subtree(pathbuf); else if (unlink(pathbuf)) - die("cannot unlink %s", pathbuf); + die("cannot unlink %s (%s)", pathbuf, strerror(errno)); } closedir(dir); if (rmdir(path)) - die("cannot rmdir %s", path); + die("cannot rmdir %s (%s)", path, strerror(errno)); } static int create_file(const char *path, unsigned int mode) @@ -75,20 +98,33 @@ 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; switch (ntohl(ce->ce_mode) & S_IFMT) { - char *buf, *new; - unsigned long size, nsize; + char *new; + struct strbuf buf; + unsigned long size; case S_IFREG: new = read_blob_entry(ce, path, &size); 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 + */ + strbuf_init(&buf, 0); + if (convert_to_working_tree(ce->name, new, size, &buf)) { + size_t newsize = 0; + free(new); + new = strbuf_detach(&buf, &newsize); + size = newsize; + } + if (to_tempfile) { strcpy(path, ".merge_file_XXXXXX"); fd = mkstemp(path); @@ -100,17 +136,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 = new; - nsize = size; - if (convert_to_working_tree(ce->name, &buf, &nsize)) { - free(new); - new = buf; - size = nsize; - } - wrote = write_in_full(fd, new, size); close(fd); free(new); @@ -147,7 +172,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) @@ -165,7 +190,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; @@ -196,7 +221,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);