@ -23,6 +23,10 @@ static int quiet; /* --refresh needing update is not error */
static int info_only;
static int info_only;
static int force_remove;
static int force_remove;
static int verbose;
static int verbose;
static int mark_valid_only = 0;
#define MARK_VALID 1
#define UNMARK_VALID 2
/* Three functions to allow overloaded pointer return; see linux/err.h */
/* Three functions to allow overloaded pointer return; see linux/err.h */
static inline void *ERR_PTR(long error)
static inline void *ERR_PTR(long error)
@ -53,6 +57,25 @@ static void report(const char *fmt, ...)
va_end(vp);
va_end(vp);
}
}
static int mark_valid(const char *path)
{
int namelen = strlen(path);
int pos = cache_name_pos(path, namelen);
if (0 <= pos) {
switch (mark_valid_only) {
case MARK_VALID:
active_cache[pos]->ce_flags |= htons(CE_VALID);
break;
case UNMARK_VALID:
active_cache[pos]->ce_flags &= ~htons(CE_VALID);
break;
}
active_cache_changed = 1;
return 0;
}
return -1;
}
static int add_file_to_cache(const char *path)
static int add_file_to_cache(const char *path)
{
{
int size, namelen, option, status;
int size, namelen, option, status;
@ -94,6 +117,7 @@ static int add_file_to_cache(const char *path)
ce = xmalloc(size);
ce = xmalloc(size);
memset(ce, 0, size);
memset(ce, 0, size);
memcpy(ce->name, path, namelen);
memcpy(ce->name, path, namelen);
ce->ce_flags = htons(namelen);
fill_stat_cache_info(ce, &st);
fill_stat_cache_info(ce, &st);
ce->ce_mode = create_ce_mode(st.st_mode);
ce->ce_mode = create_ce_mode(st.st_mode);
@ -105,7 +129,6 @@ static int add_file_to_cache(const char *path)
if (0 <= pos)
if (0 <= pos)
ce->ce_mode = active_cache[pos]->ce_mode;
ce->ce_mode = active_cache[pos]->ce_mode;
}
}
ce->ce_flags = htons(namelen);
if (index_path(ce->sha1, path, &st, !info_only))
if (index_path(ce->sha1, path, &st, !info_only))
return -1;
return -1;
@ -128,7 +151,7 @@ static int add_file_to_cache(const char *path)
* For example, you'd want to do this after doing a "git-read-tree",
* For example, you'd want to do this after doing a "git-read-tree",
* to link up the stat cache details with the proper files.
* to link up the stat cache details with the proper files.
*/
*/
static struct cache_entry *refresh_entry(struct cache_entry *ce)
static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)
{
{
struct stat st;
struct stat st;
struct cache_entry *updated;
struct cache_entry *updated;
@ -137,21 +160,31 @@ static struct cache_entry *refresh_entry(struct cache_entry *ce)
if (lstat(ce->name, &st) < 0)
if (lstat(ce->name, &st) < 0)
return ERR_PTR(-errno);
return ERR_PTR(-errno);
changed = ce_match_stat(ce, &st);
changed = ce_match_stat(ce, &st, really);
if (!changed)
if (!changed)
return NULL;
return NULL;
if (ce_modified(ce, &st))
if (ce_modified(ce, &st, really))
return ERR_PTR(-EINVAL);
return ERR_PTR(-EINVAL);
size = ce_size(ce);
size = ce_size(ce);
updated = xmalloc(size);
updated = xmalloc(size);
memcpy(updated, ce, size);
memcpy(updated, ce, size);
fill_stat_cache_info(updated, &st);
fill_stat_cache_info(updated, &st);
/* In this case, if really is not set, we should leave
* CE_VALID bit alone. Otherwise, paths marked with
* --no-assume-unchanged (i.e. things to be edited) will
* reacquire CE_VALID bit automatically, which is not
* really what we want.
*/
if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
updated->ce_flags &= ~htons(CE_VALID);
return updated;
return updated;
}
}
static int refresh_cache(void)
static int refresh_cache(int really)
{
{
int i;
int i;
int has_errors = 0;
int has_errors = 0;
@ -171,12 +204,19 @@ static int refresh_cache(void)
continue;
continue;
}
}
new = refresh_entry(ce);
new = refresh_entry(ce, really);
if (!new)
if (!new)
continue;
continue;
if (IS_ERR(new)) {
if (IS_ERR(new)) {
if (not_new && PTR_ERR(new) == -ENOENT)
if (not_new && PTR_ERR(new) == -ENOENT)
continue;
continue;
if (really && PTR_ERR(new) == -EINVAL) {
/* If we are doing --really-refresh that
* means the index is not valid anymore.
*/
ce->ce_flags &= ~htons(CE_VALID);
active_cache_changed = 1;
}
if (quiet)
if (quiet)
continue;
continue;
printf("%s: needs update\n", ce->name);
printf("%s: needs update\n", ce->name);
@ -274,6 +314,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
memcpy(ce->name, path, len);
memcpy(ce->name, path, len);
ce->ce_flags = create_ce_flags(len, stage);
ce->ce_flags = create_ce_flags(len, stage);
ce->ce_mode = create_ce_mode(mode);
ce->ce_mode = create_ce_mode(mode);
if (assume_unchanged)
ce->ce_flags |= htons(CE_VALID);
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
if (add_cache_entry(ce, option))
if (add_cache_entry(ce, option))
@ -317,6 +359,12 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
fprintf(stderr, "Ignoring path %s\n", path);
fprintf(stderr, "Ignoring path %s\n", path);
return;
return;
}
}
if (mark_valid_only) {
if (mark_valid(p))
die("Unable to mark file %s", path);
return;
}
if (force_remove) {
if (force_remove) {
if (remove_file_from_cache(p))
if (remove_file_from_cache(p))
die("git-update-index: unable to remove %s", path);
die("git-update-index: unable to remove %s", path);
@ -467,7 +515,11 @@ int main(int argc, const char **argv)
continue;
continue;
}
}
if (!strcmp(path, "--refresh")) {
if (!strcmp(path, "--refresh")) {
has_errors |= refresh_cache();
has_errors |= refresh_cache(0);
continue;
}
if (!strcmp(path, "--really-refresh")) {
has_errors |= refresh_cache(1);
continue;
continue;
}
}
if (!strcmp(path, "--cacheinfo")) {
if (!strcmp(path, "--cacheinfo")) {
@ -493,6 +545,14 @@ int main(int argc, const char **argv)
die("git-update-index: %s cannot chmod %s", path, argv[i]);
die("git-update-index: %s cannot chmod %s", path, argv[i]);
continue;
continue;
}
}
if (!strcmp(path, "--assume-unchanged")) {
mark_valid_only = MARK_VALID;
continue;
}
if (!strcmp(path, "--no-assume-unchanged")) {
mark_valid_only = UNMARK_VALID;
continue;
}
if (!strcmp(path, "--info-only")) {
if (!strcmp(path, "--info-only")) {
info_only = 1;
info_only = 1;
continue;
continue;