git/pathspec.c

102 lines
3 KiB
C
Raw Normal View History

#include "cache.h"
#include "dir.h"
#include "pathspec.h"
/*
* Finds which of the given pathspecs match items in the index.
*
* For each pathspec, sets the corresponding entry in the seen[] array
* (which should be specs items long, i.e. the same size as pathspec)
* to the nature of the "closest" (i.e. most specific) match found for
* that pathspec in the index, if it was a closer type of match than
* the existing entry. As an optimization, matching is skipped
* altogether if seen[] already only contains non-zero entries.
*
* If seen[] has not already been written to, it may make sense
* to use find_pathspecs_matching_against_index() instead.
*/
void add_pathspec_matches_against_index(const char **pathspec,
char *seen, int specs)
{
int num_unmatched = 0, i;
/*
* Since we are walking the index as if we were walking the directory,
* we have to mark the matched pathspec as seen; otherwise we will
* mistakenly think that the user gave a pathspec that did not match
* anything.
*/
for (i = 0; i < specs; i++)
if (!seen[i])
num_unmatched++;
if (!num_unmatched)
return;
for (i = 0; i < active_nr; i++) {
Convert "struct cache_entry *" to "const ..." wherever possible I attempted to make index_state->cache[] a "const struct cache_entry **" to find out how existing entries in index are modified and where. The question I have is what do we do if we really need to keep track of on-disk changes in the index. The result is - diff-lib.c: setting CE_UPTODATE - name-hash.c: setting CE_HASHED - preload-index.c, read-cache.c, unpack-trees.c and builtin/update-index: obvious - entry.c: write_entry() may refresh the checked out entry via fill_stat_cache_info(). This causes "non-const struct cache_entry *" in builtin/apply.c, builtin/checkout-index.c and builtin/checkout.c - builtin/ls-files.c: --with-tree changes stagemask and may set CE_UPDATE Of these, write_entry() and its call sites are probably most interesting because it modifies on-disk info. But this is stat info and can be retrieved via refresh, at least for porcelain commands. Other just uses ce_flags for local purposes. So, keeping track of "dirty" entries is just a matter of setting a flag in index modification functions exposed by read-cache.c. Except unpack-trees, the rest of the code base does not do anything funny behind read-cache's back. The actual patch is less valueable than the summary above. But if anyone wants to re-identify the above sites. Applying this patch, then this: diff --git a/cache.h b/cache.h index 430d021..1692891 100644 --- a/cache.h +++ b/cache.h @@ -267,7 +267,7 @@ static inline unsigned int canon_mode(unsigned int mode) #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1) struct index_state { - struct cache_entry **cache; + const struct cache_entry **cache; unsigned int version; unsigned int cache_nr, cache_alloc, cache_changed; struct string_list *resolve_undo; will help quickly identify them without bogus warnings. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-09 15:29:00 +00:00
const struct cache_entry *ce = active_cache[i];
match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
}
}
/*
* Finds which of the given pathspecs match items in the index.
*
* This is a one-shot wrapper around add_pathspec_matches_against_index()
* which allocates, populates, and returns a seen[] array indicating the
* nature of the "closest" (i.e. most specific) matches which each of the
* given pathspecs achieves against all items in the index.
*/
char *find_pathspecs_matching_against_index(const char **pathspec)
{
char *seen;
int i;
for (i = 0; pathspec[i]; i++)
; /* just counting */
seen = xcalloc(i, 1);
add_pathspec_matches_against_index(pathspec, seen, i);
return seen;
}
/*
* Check the index to see whether path refers to a submodule, or
* something inside a submodule. If the former, returns the path with
* any trailing slash stripped. If the latter, dies with an error
* message.
*/
const char *check_path_for_gitlink(const char *path)
{
int i, path_len = strlen(path);
for (i = 0; i < active_nr; i++) {
Convert "struct cache_entry *" to "const ..." wherever possible I attempted to make index_state->cache[] a "const struct cache_entry **" to find out how existing entries in index are modified and where. The question I have is what do we do if we really need to keep track of on-disk changes in the index. The result is - diff-lib.c: setting CE_UPTODATE - name-hash.c: setting CE_HASHED - preload-index.c, read-cache.c, unpack-trees.c and builtin/update-index: obvious - entry.c: write_entry() may refresh the checked out entry via fill_stat_cache_info(). This causes "non-const struct cache_entry *" in builtin/apply.c, builtin/checkout-index.c and builtin/checkout.c - builtin/ls-files.c: --with-tree changes stagemask and may set CE_UPDATE Of these, write_entry() and its call sites are probably most interesting because it modifies on-disk info. But this is stat info and can be retrieved via refresh, at least for porcelain commands. Other just uses ce_flags for local purposes. So, keeping track of "dirty" entries is just a matter of setting a flag in index modification functions exposed by read-cache.c. Except unpack-trees, the rest of the code base does not do anything funny behind read-cache's back. The actual patch is less valueable than the summary above. But if anyone wants to re-identify the above sites. Applying this patch, then this: diff --git a/cache.h b/cache.h index 430d021..1692891 100644 --- a/cache.h +++ b/cache.h @@ -267,7 +267,7 @@ static inline unsigned int canon_mode(unsigned int mode) #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1) struct index_state { - struct cache_entry **cache; + const struct cache_entry **cache; unsigned int version; unsigned int cache_nr, cache_alloc, cache_changed; struct string_list *resolve_undo; will help quickly identify them without bogus warnings. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-07-09 15:29:00 +00:00
const struct cache_entry *ce = active_cache[i];
if (S_ISGITLINK(ce->ce_mode)) {
int ce_len = ce_namelen(ce);
if (path_len <= ce_len || path[ce_len] != '/' ||
memcmp(ce->name, path, ce_len))
/* path does not refer to this
* submodule or anything inside it */
continue;
if (path_len == ce_len + 1) {
/* path refers to submodule;
* strip trailing slash */
return xstrndup(ce->name, ce_len);
} else {
die (_("Path '%s' is in submodule '%.*s'"),
path, ce_len, ce->name);
}
}
}
return path;
}
/*
* Dies if the given path refers to a file inside a symlinked
* directory in the index.
*/
void die_if_path_beyond_symlink(const char *path, const char *prefix)
{
if (has_symlink_leading_path(path, strlen(path))) {
int len = prefix ? strlen(prefix) : 0;
die(_("'%s' is beyond a symbolic link"), path + len);
}
}