Merge branch 'jc/setup'
authorJunio C Hamano <gitster@pobox.com>
Thu, 21 Feb 2008 00:13:16 +0000 (16:13 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 21 Feb 2008 00:13:16 +0000 (16:13 -0800)
* jc/setup:
builtin-mv: minimum fix to avoid losing files
git-add: adjust to the get_pathspec() changes.
Make blame accept absolute paths
setup: sanitize absolute and funny paths in get_pathspec()

1  2 
builtin-blame.c
builtin-ls-files.c
setup.c
diff --combined builtin-blame.c
index 2d4a3e150081e350ebe28fd3e677708a94c1f548,dea640d17bc0ecd4378e51bc92a32cb8c8803735..59d7237f21f406b71aabc66ea7997faf98981869
@@@ -1894,9 -1894,7 +1894,7 @@@ static unsigned parse_score(const char 
  
  static const char *add_prefix(const char *prefix, const char *path)
  {
-       if (!prefix || !prefix[0])
-               return path;
-       return prefix_path(prefix, strlen(prefix), path);
+       return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
  }
  
  /*
@@@ -2073,7 -2071,7 +2071,7 @@@ static struct commit *fake_working_tree
                if (strbuf_read(&buf, 0, 0) < 0)
                        die("read error %s from stdin", strerror(errno));
        }
 -      convert_to_git(path, buf.buf, buf.len, &buf);
 +      convert_to_git(path, buf.buf, buf.len, &buf, 0);
        origin->file.ptr = buf.buf;
        origin->file.size = buf.len;
        pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
        if (!mode) {
                int pos = cache_name_pos(path, len);
                if (0 <= pos)
 -                      mode = ntohl(active_cache[pos]->ce_mode);
 +                      mode = active_cache[pos]->ce_mode;
                else
                        /* Let's not bother reading from HEAD tree */
                        mode = S_IFREG | 0644;
@@@ -2369,8 -2367,7 +2367,8 @@@ int cmd_blame(int argc, const char **ar
         * bottom commits we would reach while traversing as
         * uninteresting.
         */
 -      prepare_revision_walk(&revs);
 +      if (prepare_revision_walk(&revs))
 +              die("revision walk setup failed");
  
        if (is_null_sha1(sb.final->object.sha1)) {
                char *buf;
diff --combined builtin-ls-files.c
index dc7eab89b34fed32dbb198a9aa9a7503fc162216,3801cf4cec7665dd496f025320dcd9591f09e498..25dbfb44999566d0491b3f870a47f7df80aa7649
@@@ -189,7 -189,7 +189,7 @@@ static void show_ce_entry(const char *t
                return;
  
        if (tag && *tag && show_valid_bit &&
 -          (ce->ce_flags & htons(CE_VALID))) {
 +          (ce->ce_flags & CE_VALID)) {
                static char alttag[4];
                memcpy(alttag, tag, 3);
                if (isalpha(tag[0]))
        } else {
                printf("%s%06o %s %d\t",
                       tag,
 -                     ntohl(ce->ce_mode),
 +                     ce->ce_mode,
                       abbrev ? find_unique_abbrev(ce->sha1,abbrev)
                                : sha1_to_hex(ce->sha1),
                       ce_stage(ce));
@@@ -238,12 -238,11 +238,12 @@@ static void show_files(struct dir_struc
        if (show_cached | show_stage) {
                for (i = 0; i < active_nr; i++) {
                        struct cache_entry *ce = active_cache[i];
 -                      if (excluded(dir, ce->name) != dir->show_ignored)
 +                      int dtype = ce_to_dtype(ce);
 +                      if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
                                continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
 -                      if (ce->ce_flags & htons(CE_UPDATE))
 +                      if (ce->ce_flags & CE_UPDATE)
                                continue;
                        show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
                }
                        struct cache_entry *ce = active_cache[i];
                        struct stat st;
                        int err;
 -                      if (excluded(dir, ce->name) != dir->show_ignored)
 +                      int dtype = ce_to_dtype(ce);
 +                      if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
                                continue;
                        err = lstat(ce->name, &st);
                        if (show_deleted && err)
@@@ -352,7 -350,7 +352,7 @@@ void overlay_tree_on_cache(const char *
                struct cache_entry *ce = active_cache[i];
                if (!ce_stage(ce))
                        continue;
 -              ce->ce_flags |= htons(CE_STAGEMASK);
 +              ce->ce_flags |= CE_STAGEMASK;
        }
  
        if (prefix) {
                         */
                        if (last_stage0 &&
                            !strcmp(last_stage0->name, ce->name))
 -                              ce->ce_flags |= htons(CE_UPDATE);
 +                              ce->ce_flags |= CE_UPDATE;
                }
        }
  }
@@@ -574,8 -572,17 +574,17 @@@ int cmd_ls_files(int argc, const char *
        pathspec = get_pathspec(prefix, argv + i);
  
        /* Verify that the pathspec matches the prefix */
-       if (pathspec)
+       if (pathspec) {
+               if (argc != i) {
+                       int cnt;
+                       for (cnt = 0; pathspec[cnt]; cnt++)
+                               ;
+                       if (cnt != (argc - i))
+                               exit(1); /* error message already given */
+               }
                prefix = verify_pathspec(prefix);
+       } else if (argc != i)
+               exit(1); /* error message already given */
  
        /* Treat unmatching pathspec elements as errors */
        if (pathspec && error_unmatch) {
diff --combined setup.c
index 4509598d577baba8b1d7e8782d8e6ff8e74f9556,23c9a11be5630406e266d04f1ce229220f4c1b34..bc80301c4239f1f101670cc623badb8bb694bd3d
+++ b/setup.c
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
  
const char *prefix_path(const char *prefix, int len, const char *path)
static int sanitary_path_copy(char *dst, const char *src)
  {
-       const char *orig = path;
+       char *dst0 = dst;
+       if (*src == '/') {
+               *dst++ = '/';
+               while (*src == '/')
+                       src++;
+       }
        for (;;) {
-               char c;
-               if (*path != '.')
-                       break;
-               c = path[1];
-               /* "." */
-               if (!c) {
-                       path++;
-                       break;
+               char c = *src;
+               /*
+                * A path component that begins with . could be
+                * special:
+                * (1) "." and ends   -- ignore and terminate.
+                * (2) "./"           -- ignore them, eat slash and continue.
+                * (3) ".." and ends  -- strip one and terminate.
+                * (4) "../"          -- strip one, eat slash and continue.
+                */
+               if (c == '.') {
+                       switch (src[1]) {
+                       case '\0':
+                               /* (1) */
+                               src++;
+                               break;
+                       case '/':
+                               /* (2) */
+                               src += 2;
+                               while (*src == '/')
+                                       src++;
+                               continue;
+                       case '.':
+                               switch (src[2]) {
+                               case '\0':
+                                       /* (3) */
+                                       src += 2;
+                                       goto up_one;
+                               case '/':
+                                       /* (4) */
+                                       src += 3;
+                                       while (*src == '/')
+                                               src++;
+                                       goto up_one;
+                               }
+                       }
                }
-               /* "./" */
+               /* copy up to the next '/', and eat all '/' */
+               while ((c = *src++) != '\0' && c != '/')
+                       *dst++ = c;
                if (c == '/') {
-                       path += 2;
-                       continue;
-               }
-               if (c != '.')
-                       break;
-               c = path[2];
-               if (!c)
-                       path += 2;
-               else if (c == '/')
-                       path += 3;
-               else
+                       *dst++ = c;
+                       while (c == '/')
+                               c = *src++;
+                       src--;
+               } else if (!c)
                        break;
-               /* ".." and "../" */
-               /* Remove last component of the prefix */
-               do {
-                       if (!len)
-                               die("'%s' is outside repository", orig);
-                       len--;
-               } while (len && prefix[len-1] != '/');
                continue;
+       up_one:
+               /*
+                * dst0..dst is prefix portion, and dst[-1] is '/';
+                * go up one level.
+                */
+               dst -= 2; /* go past trailing '/' if any */
+               if (dst < dst0)
+                       return -1;
+               while (1) {
+                       if (dst <= dst0)
+                               break;
+                       c = *dst--;
+                       if (c == '/') {
+                               dst += 2;
+                               break;
+                       }
+               }
        }
-       if (len) {
-               int speclen = strlen(path);
-               char *n = xmalloc(speclen + len + 1);
+       *dst = '\0';
+       return 0;
+ }
  
-               memcpy(n, prefix, len);
-               memcpy(n + len, path, speclen+1);
-               path = n;
+ const char *prefix_path(const char *prefix, int len, const char *path)
+ {
+       const char *orig = path;
+       char *sanitized = xmalloc(len + strlen(path) + 1);
+       if (*orig == '/')
+               strcpy(sanitized, path);
+       else {
+               if (len)
+                       memcpy(sanitized, prefix, len);
+               strcpy(sanitized + len, path);
        }
-       return path;
+       if (sanitary_path_copy(sanitized, sanitized))
+               goto error_out;
+       if (*orig == '/') {
+               const char *work_tree = get_git_work_tree();
+               size_t len = strlen(work_tree);
+               size_t total = strlen(sanitized) + 1;
+               if (strncmp(sanitized, work_tree, len) ||
+                   (sanitized[len] != '\0' && sanitized[len] != '/')) {
+               error_out:
+                       error("'%s' is outside repository", orig);
+                       free(sanitized);
+                       return NULL;
+               }
+               if (sanitized[len] == '/')
+                       len++;
+               memmove(sanitized, sanitized + len, total - len);
+       }
+       return sanitized;
  }
  
  /*
@@@ -114,7 -181,7 +181,7 @@@ void verify_non_filename(const char *pr
  const char **get_pathspec(const char *prefix, const char **pathspec)
  {
        const char *entry = *pathspec;
-       const char **p;
+       const char **src, **dst;
        int prefixlen;
  
        if (!prefix && !entry)
        }
  
        /* Otherwise we have to re-write the entries.. */
-       p = pathspec;
+       src = pathspec;
+       dst = pathspec;
        prefixlen = prefix ? strlen(prefix) : 0;
-       do {
-               *p = prefix_path(prefix, prefixlen, entry);
-       } while ((entry = *++p) != NULL);
-       return (const char **) pathspec;
+       while (*src) {
+               const char *p = prefix_path(prefix, prefixlen, *src);
+               if (p)
+                       *(dst++) = p;
+               src++;
+       }
+       *dst = NULL;
+       if (!*pathspec)
+               return NULL;
+       return pathspec;
  }
  
  /*
@@@ -372,8 -446,6 +446,8 @@@ int check_repository_format_version(con
                if (is_bare_repository_cfg == 1)
                        inside_work_tree = -1;
        } else if (strcmp(var, "core.worktree") == 0) {
 +              if (!value)
 +                      return config_error_nonbool(var);
                if (git_work_tree_cfg)
                        free(git_work_tree_cfg);
                git_work_tree_cfg = xstrdup(value);