Code

combined diff: correctly handle truncated file
[git.git] / dir.c
diff --git a/dir.c b/dir.c
index 1538ad5da30e08c03e4297ceb369b7a09a301af4..cb83332a261f97026f9c6273afb162245944dec7 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -242,6 +242,14 @@ int add_excludes_from_file_to_list(const char *fname,
                if (!check_index ||
                    (buf = read_skip_worktree_file_from_index(fname, &size)) == NULL)
                        return -1;
+               if (size == 0) {
+                       free(buf);
+                       return 0;
+               }
+               if (buf[size-1] != '\n') {
+                       buf = xrealloc(buf, size+1);
+                       buf[size++] = '\n';
+               }
        }
        else {
                size = xsize_t(st.st_size);
@@ -249,19 +257,21 @@ int add_excludes_from_file_to_list(const char *fname,
                        close(fd);
                        return 0;
                }
-               buf = xmalloc(size);
+               buf = xmalloc(size+1);
                if (read_in_full(fd, buf, size) != size) {
+                       free(buf);
                        close(fd);
                        return -1;
                }
+               buf[size++] = '\n';
                close(fd);
        }
 
        if (buf_p)
                *buf_p = buf;
        entry = buf;
-       for (i = 0; i <= size; i++) {
-               if (i == size || buf[i] == '\n') {
+       for (i = 0; i < size; i++) {
+               if (buf[i] == '\n') {
                        if (entry != buf + i && entry[0] != '#') {
                                buf[i - (i && buf[i-1] == '\r')] = 0;
                                add_exclude(entry, base, baselen, which);
@@ -584,13 +594,29 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
        return 0;
 }
 
-static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)
+/*
+ * This function tells us whether an excluded path matches a
+ * list of "interesting" pathspecs. That is, whether a path matched
+ * by any of the pathspecs could possibly be ignored by excluding
+ * the specified path. This can happen if:
+ *
+ *   1. the path is mentioned explicitly in the pathspec
+ *
+ *   2. the path is a directory prefix of some element in the
+ *      pathspec
+ */
+static int exclude_matches_pathspec(const char *path, int len,
+               const struct path_simplify *simplify)
 {
        if (simplify) {
                for (; simplify->path; simplify++) {
                        if (len == simplify->len
                            && !memcmp(path, simplify->path, len))
                                return 1;
+                       if (len < simplify->len
+                           && simplify->path[len] == '/'
+                           && !memcmp(path, simplify->path, len))
+                               return 1;
                }
        }
        return 0;
@@ -668,7 +694,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
 {
        int exclude = excluded(dir, path, &dtype);
        if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
-           && in_pathspec(path, *len, simplify))
+           && exclude_matches_pathspec(path, *len, simplify))
                dir_add_ignored(dir, path, *len);
 
        /*
@@ -1034,7 +1060,7 @@ int remove_path(const char *name)
                slash = dirs + (slash - name);
                do {
                        *slash = '\0';
-               } while (rmdir(dirs) && (slash = strrchr(dirs, '/')));
+               } while (rmdir(dirs) == 0 && (slash = strrchr(dirs, '/')));
                free(dirs);
        }
        return 0;