Merge branch 'ap/path-max'
authorJunio C Hamano <gitster@pobox.com>
Fri, 10 Jan 2014 18:32:18 +0000 (10:32 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 10 Jan 2014 18:32:18 +0000 (10:32 -0800)
* ap/path-max:
Prevent buffer overflows when path is too long

abspath.c
diffcore-order.c
unpack-trees.c
index 8b3385a77749108b29d0a25042a13a174ddbc2e4..ca33558a91c5259a793fc56b571fa683e16b134f 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -215,23 +215,25 @@ const char *absolute_path(const char *path)
  */
 const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
 {
-       static char path[PATH_MAX];
+       static struct strbuf path = STRBUF_INIT;
 #ifndef GIT_WINDOWS_NATIVE
        if (!pfx_len || is_absolute_path(arg))
                return arg;
-       memcpy(path, pfx, pfx_len);
-       strcpy(path + pfx_len, arg);
+       strbuf_reset(&path);
+       strbuf_add(&path, pfx, pfx_len);
+       strbuf_addstr(&path, arg);
 #else
        char *p;
        /* don't add prefix to absolute paths, but still replace '\' by '/' */
+       strbuf_reset(&path);
        if (is_absolute_path(arg))
                pfx_len = 0;
        else if (pfx_len)
-               memcpy(path, pfx, pfx_len);
-       strcpy(path + pfx_len, arg);
-       for (p = path + pfx_len; *p; p++)
+               strbuf_add(&path, pfx, pfx_len);
+       strbuf_addstr(&path, arg);
+       for (p = path.buf + pfx_len; *p; p++)
                if (*p == '\\')
                        *p = '/';
 #endif
-       return path;
+       return path.buf;
 }
index 23e93852d8c701760d56e7e728dba7c08367fbe8..50c089bb2b3343458fb3929d4c9eac37966063cf 100644 (file)
@@ -73,15 +73,16 @@ struct pair_order {
 static int match_order(const char *path)
 {
        int i;
-       char p[PATH_MAX];
+       static struct strbuf p = STRBUF_INIT;
 
        for (i = 0; i < order_cnt; i++) {
-               strcpy(p, path);
-               while (p[0]) {
+               strbuf_reset(&p);
+               strbuf_addstr(&p, path);
+               while (p.buf[0]) {
                        char *cp;
-                       if (!fnmatch(order[i], p, 0))
+                       if (!fnmatch(order[i], p.buf, 0))
                                return i;
-                       cp = strrchr(p, '/');
+                       cp = strrchr(p.buf, '/');
                        if (!cp)
                                break;
                        *cp = 0;
index ad3e9a04fe8ccb9286b94480f4484b0569f70a57..164354dad7cbbaa7100f73256807680a75188021 100644 (file)
@@ -830,23 +830,24 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
 }
 
 static int clear_ce_flags_1(struct cache_entry **cache, int nr,
-                           char *prefix, int prefix_len,
+                           struct strbuf *prefix,
                            int select_mask, int clear_mask,
                            struct exclude_list *el, int defval);
 
 /* Whole directory matching */
 static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
-                             char *prefix, int prefix_len,
+                             struct strbuf *prefix,
                              char *basename,
                              int select_mask, int clear_mask,
                              struct exclude_list *el, int defval)
 {
        struct cache_entry **cache_end;
        int dtype = DT_DIR;
-       int ret = is_excluded_from_list(prefix, prefix_len,
+       int ret = is_excluded_from_list(prefix->buf, prefix->len,
                                        basename, &dtype, el);
+       int rc;
 
-       prefix[prefix_len++] = '/';
+       strbuf_addch(prefix, '/');
 
        /* If undecided, use matching result of parent dir in defval */
        if (ret < 0)
@@ -854,7 +855,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
 
        for (cache_end = cache; cache_end != cache + nr; cache_end++) {
                struct cache_entry *ce = *cache_end;
-               if (strncmp(ce->name, prefix, prefix_len))
+               if (strncmp(ce->name, prefix->buf, prefix->len))
                        break;
        }
 
@@ -865,10 +866,12 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
         * calling clear_ce_flags_1(). That function will call
         * the expensive is_excluded_from_list() on every entry.
         */
-       return clear_ce_flags_1(cache, cache_end - cache,
-                               prefix, prefix_len,
-                               select_mask, clear_mask,
-                               el, ret);
+       rc = clear_ce_flags_1(cache, cache_end - cache,
+                             prefix,
+                             select_mask, clear_mask,
+                             el, ret);
+       strbuf_setlen(prefix, prefix->len - 1);
+       return rc;
 }
 
 /*
@@ -887,7 +890,7 @@ static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
  * Top level path has prefix_len zero.
  */
 static int clear_ce_flags_1(struct cache_entry **cache, int nr,
-                           char *prefix, int prefix_len,
+                           struct strbuf *prefix,
                            int select_mask, int clear_mask,
                            struct exclude_list *el, int defval)
 {
@@ -907,10 +910,10 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
                        continue;
                }
 
-               if (prefix_len && strncmp(ce->name, prefix, prefix_len))
+               if (prefix->len && strncmp(ce->name, prefix->buf, prefix->len))
                        break;
 
-               name = ce->name + prefix_len;
+               name = ce->name + prefix->len;
                slash = strchr(name, '/');
 
                /* If it's a directory, try whole directory match first */
@@ -918,29 +921,26 @@ static int clear_ce_flags_1(struct cache_entry **cache, int nr,
                        int processed;
 
                        len = slash - name;
-                       memcpy(prefix + prefix_len, name, len);
+                       strbuf_add(prefix, name, len);
 
-                       /*
-                        * terminate the string (no trailing slash),
-                        * clear_c_f_dir needs it
-                        */
-                       prefix[prefix_len + len] = '\0';
                        processed = clear_ce_flags_dir(cache, cache_end - cache,
-                                                      prefix, prefix_len + len,
-                                                      prefix + prefix_len,
+                                                      prefix,
+                                                      prefix->buf + prefix->len - len,
                                                       select_mask, clear_mask,
                                                       el, defval);
 
                        /* clear_c_f_dir eats a whole dir already? */
                        if (processed) {
                                cache += processed;
+                               strbuf_setlen(prefix, prefix->len - len);
                                continue;
                        }
 
-                       prefix[prefix_len + len++] = '/';
+                       strbuf_addch(prefix, '/');
                        cache += clear_ce_flags_1(cache, cache_end - cache,
-                                                 prefix, prefix_len + len,
+                                                 prefix,
                                                  select_mask, clear_mask, el, defval);
+                       strbuf_setlen(prefix, prefix->len - len - 1);
                        continue;
                }
 
@@ -961,9 +961,12 @@ static int clear_ce_flags(struct cache_entry **cache, int nr,
                            int select_mask, int clear_mask,
                            struct exclude_list *el)
 {
-       char prefix[PATH_MAX];
+       static struct strbuf prefix = STRBUF_INIT;
+
+       strbuf_reset(&prefix);
+
        return clear_ce_flags_1(cache, nr,
-                               prefix, 0,
+                               &prefix,
                                select_mask, clear_mask,
                                el, 0);
 }