git-tar-tree: Move code for git-archive --format=tar to archive-tar.c
[gitweb.git] / dir.c
diff --git a/dir.c b/dir.c
index d40b62e1c19c342dfddeb157b295d8188f9a1f20..e2f472ba7f5d3e5146f110dd3eaae9e5494854e2 100644 (file)
--- a/dir.c
+++ b/dir.c
 #include "cache.h"
 #include "dir.h"
 
+int common_prefix(const char **pathspec)
+{
+       const char *path, *slash, *next;
+       int prefix;
+
+       if (!pathspec)
+               return 0;
+
+       path = *pathspec;
+       slash = strrchr(path, '/');
+       if (!slash)
+               return 0;
+
+       prefix = slash - path + 1;
+       while ((next = *++pathspec) != NULL) {
+               int len = strlen(next);
+               if (len >= prefix && !memcmp(path, next, len))
+                       continue;
+               for (;;) {
+                       if (!len)
+                               return 0;
+                       if (next[--len] != '/')
+                               continue;
+                       if (memcmp(path, next, len+1))
+                               continue;
+                       prefix = len + 1;
+                       break;
+               }
+       }
+       return prefix;
+}
+
+static int match_one(const char *match, const char *name, int namelen)
+{
+       int matchlen;
+
+       /* If the match was just the prefix, we matched */
+       matchlen = strlen(match);
+       if (!matchlen)
+               return 1;
+
+       /*
+        * If we don't match the matchstring exactly,
+        * we need to match by fnmatch
+        */
+       if (strncmp(match, name, matchlen))
+               return !fnmatch(match, name, 0);
+
+       /*
+        * If we did match the string exactly, we still
+        * need to make sure that it happened on a path
+        * component boundary (ie either the last character
+        * of the match was '/', or the next character of
+        * the name was '/' or the terminating NUL.
+        */
+       return  match[matchlen-1] == '/' ||
+               name[matchlen] == '/' ||
+               !name[matchlen];
+}
+
+int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen)
+{
+       int retval;
+       const char *match;
+
+       name += prefix;
+       namelen -= prefix;
+
+       for (retval = 0; (match = *pathspec++) != NULL; seen++) {
+               if (retval & *seen)
+                       continue;
+               match += prefix;
+               if (match_one(match, name, namelen)) {
+                       retval = 1;
+                       *seen = 1;
+               }
+       }
+       return retval;
+}
+
 void add_exclude(const char *string, const char *base,
                 int baselen, struct exclude_list *which)
 {
@@ -21,8 +101,8 @@ void add_exclude(const char *string, const char *base,
        x->baselen = baselen;
        if (which->nr == which->alloc) {
                which->alloc = alloc_nr(which->alloc);
-               which->excludes = realloc(which->excludes,
-                                         which->alloc * sizeof(x));
+               which->excludes = xrealloc(which->excludes,
+                                          which->alloc * sizeof(x));
        }
        which->excludes[which->nr++] = x;
 }
@@ -32,17 +112,15 @@ static int add_excludes_from_file_1(const char *fname,
                                    int baselen,
                                    struct exclude_list *which)
 {
+       struct stat st;
        int fd, i;
        long size;
        char *buf, *entry;
 
        fd = open(fname, O_RDONLY);
-       if (fd < 0)
+       if (fd < 0 || fstat(fd, &st) < 0)
                goto err;
-       size = lseek(fd, 0, SEEK_END);
-       if (size < 0)
-               goto err;
-       lseek(fd, 0, SEEK_SET);
+       size = st.st_size;
        if (size == 0) {
                close(fd);
                return 0;
@@ -213,7 +291,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
        if (fdir) {
                int exclude_stk;
                struct dirent *de;
-               char fullname[MAXPATHLEN + 1];
+               char fullname[PATH_MAX + 1];
                memcpy(fullname, base, baselen);
 
                exclude_stk = push_exclude_per_directory(dir, base, baselen);
@@ -256,7 +334,7 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                                if (dir->show_other_directories &&
                                    (subdir || !dir->hide_empty_directories) &&
                                    !dir_exists(fullname, baselen + len)) {
-                                       // Rewind the read subdirectory
+                                       /* Rewind the read subdirectory */
                                        while (dir->nr > rewind_base)
                                                free(dir->entries[--dir->nr]);
                                        break;
@@ -319,3 +397,10 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
        qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
        return dir->nr;
 }
+
+int
+file_exists(const char *f)
+{
+  struct stat sb;
+  return stat(f, &sb) == 0;
+}