X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=update-cache.c;h=a6f9d6c178be67db9c681f536c650791479e6ef4;hb=dbbce55b3a1129fcc6c5141dd5b8053512286b83;hp=735d19920d998a3d53dbfd9a68336cc13780ef23;hpb=ee267527aa80807f37caf1d00bcf1b5263945adb;p=git.git diff --git a/update-cache.c b/update-cache.c index 735d1992..a6f9d6c1 100644 --- a/update-cache.c +++ b/update-cache.c @@ -13,7 +13,7 @@ * like "update-cache *" and suddenly having all the object * files be revision controlled. */ -static int allow_add = 0, allow_remove = 0, not_new = 0; +static int allow_add = 0, allow_remove = 0, allow_replace = 0, not_new = 0; /* Three functions to allow overloaded pointer return; see linux/err.h */ static inline void *ERR_PTR(long error) @@ -53,18 +53,27 @@ static void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) static int add_file_to_cache(char *path) { - int size, namelen; + int size, namelen, option, status; struct cache_entry *ce; struct stat st; int fd; char *target; - if (lstat(path, &st) < 0) { - if (errno == ENOENT || errno == ENOTDIR) { + status = lstat(path, &st); + if (status < 0 || S_ISDIR(st.st_mode)) { + /* When we used to have "path" and now we want to add + * "path/file", we need a way to remove "path" before + * being able to add "path/file". However, + * "git-update-cache --remove path" would not work. + * --force-remove can be used but this is more user + * friendly, especially since we can do the opposite + * case just fine without --force-remove. + */ + if (status == 0 || (errno == ENOENT || errno == ENOTDIR)) { if (allow_remove) return remove_file_from_cache(path); } - return -1; + return error("open(\"%s\"): %s", path, strerror(errno)); } namelen = strlen(path); size = cache_entry_size(namelen); @@ -95,7 +104,9 @@ static int add_file_to_cache(char *path) default: return -1; } - return add_cache_entry(ce, allow_add); + option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; + option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; + return add_cache_entry(ce, option); } static int match_data(int fd, void *buffer, unsigned long size) @@ -120,7 +131,7 @@ static int compare_data(struct cache_entry *ce, unsigned long expected_size) if (fd >= 0) { void *buffer; unsigned long size; - char type[10]; + char type[20]; buffer = read_sha1_file(ce->sha1, type, &size); if (buffer) { @@ -180,7 +191,7 @@ static struct cache_entry *refresh_entry(struct cache_entry *ce) if (lstat(ce->name, &st) < 0) return ERR_PTR(-errno); - changed = cache_match_stat(ce, &st); + changed = ce_match_stat(ce, &st); if (!changed) return ce; @@ -238,6 +249,9 @@ static int refresh_cache(void) continue; } active_cache_changed = 1; + /* You can NOT just free active_cache[i] here, since it + * might not be necessarily malloc()ed but can also come + * from mmap(). */ active_cache[i] = new; } return has_errors; @@ -273,7 +287,7 @@ inside: static int add_cacheinfo(char *arg1, char *arg2, char *arg3) { - int size, len; + int size, len, option; unsigned int mode; unsigned char sha1[20]; struct cache_entry *ce; @@ -294,7 +308,9 @@ static int add_cacheinfo(char *arg1, char *arg2, char *arg3) memcpy(ce->name, arg3, len); ce->ce_flags = htons(len); ce->ce_mode = create_ce_mode(mode); - return add_cache_entry(ce, allow_add); + option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; + option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; + return add_cache_entry(ce, option); } static const char *lockfile_name = NULL; @@ -343,6 +359,10 @@ int main(int argc, char **argv) allow_add = 1; continue; } + if (!strcmp(path, "--replace")) { + allow_replace = 1; + continue; + } if (!strcmp(path, "--remove")) { allow_remove = 1; continue; @@ -352,8 +372,10 @@ int main(int argc, char **argv) continue; } if (!strcmp(path, "--cacheinfo")) { - if (i+3 >= argc || add_cacheinfo(argv[i+1], argv[i+2], argv[i+3])) + if (i+3 >= argc) die("update-cache: --cacheinfo "); + if (add_cacheinfo(argv[i+1], argv[i+2], argv[i+3])) + die("update-cache: --cacheinfo cannot add %s", argv[i+3]); i += 3; continue; }