summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c153
1 files changed, 106 insertions, 47 deletions
diff --git a/dir.c b/dir.c
index eb6f581..0943a81 100644
--- a/dir.c
+++ b/dir.c
@@ -377,6 +377,49 @@ int match_pathspec(const struct pathspec *ps,
return negative ? 0 : positive;
}
+int report_path_error(const char *ps_matched,
+ const struct pathspec *pathspec,
+ const char *prefix)
+{
+ /*
+ * Make sure all pathspec matched; otherwise it is an error.
+ */
+ struct strbuf sb = STRBUF_INIT;
+ int num, errors = 0;
+ for (num = 0; num < pathspec->nr; num++) {
+ int other, found_dup;
+
+ if (ps_matched[num])
+ continue;
+ /*
+ * The caller might have fed identical pathspec
+ * twice. Do not barf on such a mistake.
+ * FIXME: parse_pathspec should have eliminated
+ * duplicate pathspec.
+ */
+ for (found_dup = other = 0;
+ !found_dup && other < pathspec->nr;
+ other++) {
+ if (other == num || !ps_matched[other])
+ continue;
+ if (!strcmp(pathspec->items[other].original,
+ pathspec->items[num].original))
+ /*
+ * Ok, we have a match already.
+ */
+ found_dup = 1;
+ }
+ if (found_dup)
+ continue;
+
+ error("pathspec '%s' did not match any file(s) known to git.",
+ pathspec->items[num].original);
+ errors++;
+ }
+ strbuf_release(&sb);
+ return errors;
+}
+
/*
* Return the length of the "simple" part of a path match limiter.
*/
@@ -508,21 +551,25 @@ void clear_exclude_list(struct exclude_list *el)
static void trim_trailing_spaces(char *buf)
{
- int i, last_space = -1, nr_spaces, len = strlen(buf);
- for (i = 0; i < len; i++)
- if (buf[i] == '\\')
- i++;
- else if (buf[i] == ' ') {
- if (last_space == -1) {
- last_space = i;
- nr_spaces = 1;
- } else
- nr_spaces++;
- } else
- last_space = -1;
-
- if (last_space != -1 && last_space + nr_spaces == len)
- buf[last_space] = '\0';
+ char *p, *last_space = NULL;
+
+ for (p = buf; *p; p++)
+ switch (*p) {
+ case ' ':
+ if (!last_space)
+ last_space = p;
+ break;
+ case '\\':
+ p++;
+ if (!*p)
+ return;
+ /* fallthrough */
+ default:
+ last_space = NULL;
+ }
+
+ if (last_space)
+ *last_space = '\0';
}
int add_excludes_from_file_to_list(const char *fname,
@@ -553,8 +600,7 @@ int add_excludes_from_file_to_list(const char *fname,
buf = xrealloc(buf, size+1);
buf[size++] = '\n';
}
- }
- else {
+ } else {
size = xsize_t(st.st_size);
if (size == 0) {
close(fd);
@@ -789,17 +835,19 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
group = &dir->exclude_list_group[EXC_DIRS];
- /* Pop the exclude lists from the EXCL_DIRS exclude_list_group
+ /*
+ * Pop the exclude lists from the EXCL_DIRS exclude_list_group
* which originate from directories not in the prefix of the
- * path being checked. */
+ * path being checked.
+ */
while ((stk = dir->exclude_stack) != NULL) {
if (stk->baselen <= baselen &&
- !strncmp(dir->basebuf, base, stk->baselen))
+ !strncmp(dir->basebuf.buf, base, stk->baselen))
break;
el = &group->el[dir->exclude_stack->exclude_ix];
dir->exclude_stack = stk->prev;
dir->exclude = NULL;
- free((char *)el->src); /* see strdup() below */
+ free((char *)el->src); /* see strbuf_detach() below */
clear_exclude_list(el);
free(stk);
group->nr--;
@@ -809,17 +857,25 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
if (dir->exclude)
return;
+ /*
+ * Lazy initialization. All call sites currently just
+ * memset(dir, 0, sizeof(*dir)) before use. Changing all of
+ * them seems lots of work for little benefit.
+ */
+ if (!dir->basebuf.buf)
+ strbuf_init(&dir->basebuf, PATH_MAX);
+
/* Read from the parent directories and push them down. */
current = stk ? stk->baselen : -1;
+ strbuf_setlen(&dir->basebuf, current < 0 ? 0 : current);
while (current < baselen) {
- struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
const char *cp;
+ stk = xcalloc(1, sizeof(*stk));
if (current < 0) {
cp = base;
current = 0;
- }
- else {
+ } else {
cp = strchr(base + current + 1, '/');
if (!cp)
die("oops in prep_exclude");
@@ -829,48 +885,47 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
stk->baselen = cp - base;
stk->exclude_ix = group->nr;
el = add_exclude_list(dir, EXC_DIRS, NULL);
- memcpy(dir->basebuf + current, base + current,
- stk->baselen - current);
+ strbuf_add(&dir->basebuf, base + current, stk->baselen - current);
+ assert(stk->baselen == dir->basebuf.len);
/* Abort if the directory is excluded */
if (stk->baselen) {
int dt = DT_DIR;
- dir->basebuf[stk->baselen - 1] = 0;
+ dir->basebuf.buf[stk->baselen - 1] = 0;
dir->exclude = last_exclude_matching_from_lists(dir,
- dir->basebuf, stk->baselen - 1,
- dir->basebuf + current, &dt);
- dir->basebuf[stk->baselen - 1] = '/';
+ dir->basebuf.buf, stk->baselen - 1,
+ dir->basebuf.buf + current, &dt);
+ dir->basebuf.buf[stk->baselen - 1] = '/';
if (dir->exclude &&
dir->exclude->flags & EXC_FLAG_NEGATIVE)
dir->exclude = NULL;
if (dir->exclude) {
- dir->basebuf[stk->baselen] = 0;
dir->exclude_stack = stk;
return;
}
}
- /* Try to read per-directory file unless path is too long */
- if (dir->exclude_per_dir &&
- stk->baselen + strlen(dir->exclude_per_dir) < PATH_MAX) {
- strcpy(dir->basebuf + stk->baselen,
- dir->exclude_per_dir);
+ /* Try to read per-directory file */
+ if (dir->exclude_per_dir) {
/*
* dir->basebuf gets reused by the traversal, but we
* need fname to remain unchanged to ensure the src
* member of each struct exclude correctly
* back-references its source file. Other invocations
* of add_exclude_list provide stable strings, so we
- * strdup() and free() here in the caller.
+ * strbuf_detach() and free() here in the caller.
*/
- el->src = strdup(dir->basebuf);
- add_excludes_from_file_to_list(dir->basebuf,
- dir->basebuf, stk->baselen, el, 1);
+ struct strbuf sb = STRBUF_INIT;
+ strbuf_addbuf(&sb, &dir->basebuf);
+ strbuf_addstr(&sb, dir->exclude_per_dir);
+ el->src = strbuf_detach(&sb, NULL);
+ add_excludes_from_file_to_list(el->src, el->src,
+ stk->baselen, el, 1);
}
dir->exclude_stack = stk;
current = stk->baselen;
}
- dir->basebuf[baselen] = '\0';
+ strbuf_setlen(&dir->basebuf, baselen);
}
/*
@@ -1350,8 +1405,7 @@ static int cmp_name(const void *p1, const void *p2)
const struct dir_entry *e1 = *(const struct dir_entry **)p1;
const struct dir_entry *e2 = *(const struct dir_entry **)p2;
- return cache_name_compare(e1->name, e1->len,
- e2->name, e2->len);
+ return name_compare(e1->name, e1->len, e2->name, e2->len);
}
static struct path_simplify *create_simplify(const char **pathspec)
@@ -1496,12 +1550,16 @@ int dir_inside_of(const char *subdir, const char *dir)
int is_inside_dir(const char *dir)
{
- char cwd[PATH_MAX];
+ char *cwd;
+ int rc;
+
if (!dir)
return 0;
- if (!getcwd(cwd, sizeof(cwd)))
- die_errno("can't find the current directory");
- return dir_inside_of(cwd, dir) >= 0;
+
+ cwd = xgetcwd();
+ rc = (dir_inside_of(cwd, dir) >= 0);
+ free(cwd);
+ return rc;
}
int is_empty_dir(const char *path)
@@ -1668,4 +1726,5 @@ void clear_directory(struct dir_struct *dir)
free(stk);
stk = prev;
}
+ strbuf_release(&dir->basebuf);
}