static int process_path(const char *path) { int pos, len; struct stat st; const struct cache_entry *ce; len = strlen(path); if (has_symlink_leading_path(path, len)) return error("'%s' is beyond a symbolic link", path); pos = cache_name_pos(path, len); ce = pos < 0 ? NULL : active_cache[pos]; if (ce && ce_skip_worktree(ce)) { /* * working directory version is assumed "good" * so updating it does not make sense. * On the other hand, removing it from index should work */ if (allow_remove && remove_file_from_cache(path)) return error("%s: cannot remove from the index", path); return 0; } /* * First things first: get the stat information, to decide * what to do about the pathname! */ if (lstat(path, &st) < 0) return process_lstat_error(path, errno); if (S_ISDIR(st.st_mode)) return process_directory(path, len, &st); return add_one_path(ce, path, len, &st); }
/* * Handle a path that was a directory. Four cases: * * - it's already a gitlink in the index, and we keep it that * way, and update it if we can (if we cannot find the HEAD, * we're going to keep it unchanged in the index!) * * - it's a *file* in the index, in which case it should be * removed as a file if removal is allowed, since it doesn't * exist as such any more. If removal isn't allowed, it's * an error. * * (NOTE! This is old and arguably fairly strange behaviour. * We might want to make this an error unconditionally, and * use "--force-remove" if you actually want to force removal). * * - it used to exist as a subdirectory (ie multiple files with * this particular prefix) in the index, in which case it's wrong * to try to update it as a directory. * * - it doesn't exist at all in the index, but it is a valid * git directory, and it should be *added* as a gitlink. */ static int process_directory(const char *path, int len, struct stat *st) { unsigned char sha1[20]; int pos = cache_name_pos(path, len); /* Exact match: file or existing gitlink */ if (pos >= 0) { const struct cache_entry *ce = active_cache[pos]; if (S_ISGITLINK(ce->ce_mode)) { /* Do nothing to the index if there is no HEAD! */ if (resolve_gitlink_ref(path, "HEAD", sha1) < 0) return 0; return add_one_path(ce, path, len, st); } /* Should this be an unconditional error? */ return remove_one_path(path); } /* Inexact match: is there perhaps a subdirectory match? */ pos = -pos-1; while (pos < active_nr) { const struct cache_entry *ce = active_cache[pos++]; if (strncmp(ce->name, path, len)) break; if (ce->name[len] > '/') break; if (ce->name[len] < '/') continue; /* Subdirectory match - error out */ return error("%s: is a directory - add individual files instead", path); } /* No match - should we add it as a gitlink? */ if (!resolve_gitlink_ref(path, "HEAD", sha1)) return add_one_path(NULL, path, len, st); /* Error out. */ return error("%s: is a directory - add files inside instead", path); }
/* * Process a regular file */ static int process_file(const char *path, int len, struct stat *st) { int pos = cache_name_pos(path, len); struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos]; if (ce && S_ISGITLINK(ce->ce_mode)) return error("%s is already a gitlink, not replacing", path); return add_one_path(ce, path, len, st); }