diff options
Diffstat (limited to 'entry.c')
| -rw-r--r-- | entry.c | 47 |
1 files changed, 36 insertions, 11 deletions
@@ -1,9 +1,14 @@ -#include "cache.h" -#include "blob.h" -#include "object-store.h" +#include "git-compat-util.h" +#include "object-store-ll.h" #include "dir.h" +#include "environment.h" +#include "gettext.h" +#include "hex.h" +#include "name-hash.h" +#include "sparse-index.h" #include "streaming.h" #include "submodule.h" +#include "symlinks.h" #include "progress.h" #include "fsmonitor.h" #include "entry.h" @@ -86,7 +91,8 @@ void *read_blob_entry(const struct cache_entry *ce, size_t *size) { enum object_type type; unsigned long ul; - void *blob_data = read_object_file(&ce->oid, &type, &ul); + void *blob_data = repo_read_object_file(the_repository, &ce->oid, + &type, &ul); *size = ul; if (blob_data) { @@ -383,7 +389,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca return error("cannot create submodule directory %s", path); sub = submodule_from_ce(ce); if (sub) - return submodule_move_head(ce->name, + return submodule_move_head(ce->name, state->super_prefix, NULL, oid_to_hex(&ce->oid), state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0); break; @@ -454,7 +460,7 @@ static void mark_colliding_entries(const struct checkout *state, continue; if ((trust_ino && !match_stat_data(&dup->ce_stat_data, st)) || - (!trust_ino && !fspathcmp(ce->name, dup->name))) { + paths_collide(ce->name, dup->name)) { dup->ce_flags |= CE_MATCHED; break; } @@ -476,7 +482,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, * no pathname to return. */ BUG("Can't remove entry to a path"); - unlink_entry(ce); + unlink_entry(ce, state->super_prefix); return 0; } @@ -510,10 +516,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, if (!(st.st_mode & S_IFDIR)) unlink_or_warn(ce->name); - return submodule_move_head(ce->name, + return submodule_move_head(ce->name, state->super_prefix, NULL, oid_to_hex(&ce->oid), 0); } else - return submodule_move_head(ce->name, + return submodule_move_head(ce->name, state->super_prefix, "HEAD", oid_to_hex(&ce->oid), state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0); } @@ -541,6 +547,20 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, /* If it is a gitlink, leave it alone! */ if (S_ISGITLINK(ce->ce_mode)) return 0; + /* + * We must avoid replacing submodules' leading + * directories with symbolic links, lest recursive + * clones can write into arbitrary locations. + * + * Technically, this logic is not limited + * to recursive clones, or for that matter to + * submodules' paths colliding with symbolic links' + * paths. Yet it strikes a balance in favor of + * simplicity, and if paths are colliding, we might + * just as well keep the directories during a clone. + */ + if (state->clone && S_ISLNK(ce->ce_mode)) + return 0; remove_subtree(&path); } else if (unlink(path.buf)) return error_errno("unable to unlink old '%s'", path.buf); @@ -560,12 +580,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca, return write_entry(ce, path.buf, ca, state, 0, nr_checkouts); } -void unlink_entry(const struct cache_entry *ce) +void unlink_entry(const struct cache_entry *ce, const char *super_prefix) { const struct submodule *sub = submodule_from_ce(ce); if (sub) { /* state.force is set at the caller. */ - submodule_move_head(ce->name, "HEAD", NULL, + submodule_move_head(ce->name, super_prefix, "HEAD", NULL, SUBMODULE_MOVE_HEAD_FORCE); } if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0) @@ -574,3 +594,8 @@ void unlink_entry(const struct cache_entry *ce) return; schedule_dir_for_removal(ce->name, ce_namelen(ce)); } + +int remove_or_warn(unsigned int mode, const char *file) +{ + return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file); +} |
