Merge branch 'ef/maint-win-verify-path'
authorJunio C Hamano <gitster@pobox.com>
Thu, 30 Jun 2011 00:09:17 +0000 (17:09 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 30 Jun 2011 00:09:17 +0000 (17:09 -0700)
* ef/maint-win-verify-path:
verify_dotfile(): do not assume '/' is the path seperator
verify_path(): simplify check at the directory boundary
verify_path: consider dos drive prefix
real_path: do not assume '/' is the path seperator
A Windows path starting with a backslash is absolute

1  2 
abspath.c
cache.h
compat/mingw.h
git-compat-util.h
read-cache.c
diff --combined abspath.c
index 3005aedde68b48297aacd2082797b2e2f249b094,54899008f828963cdefa7523d82a44588841e82c..01858eb7bca277a125c414ef4bf1904fd0ea9059
+++ b/abspath.c
@@@ -14,14 -14,7 +14,14 @@@ int is_directory(const char *path
  /* We allow "recursive" symbolic links. Only within reason, though. */
  #define MAXDEPTH 5
  
 -const char *make_absolute_path(const char *path)
 +/*
 + * Use this to get the real path, i.e. resolve links. If you want an
 + * absolute path but don't mind links, use absolute_path.
 + *
 + * If path is our buffer, then return path, as it's already what the
 + * user wants.
 + */
 +const char *real_path(const char *path)
  {
        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
        char cwd[1024] = "";
@@@ -40,7 -33,7 +40,7 @@@
  
        while (depth--) {
                if (!is_directory(buf)) {
-                       char *last_slash = strrchr(buf, '/');
+                       char *last_slash = find_last_dir_sep(buf);
                        if (last_slash) {
                                *last_slash = '\0';
                                last_elem = xstrdup(last_slash + 1);
@@@ -65,7 -58,7 +65,7 @@@
                        if (len + strlen(last_elem) + 2 > PATH_MAX)
                                die ("Too long path name: '%s/%s'",
                                                buf, last_elem);
-                       if (len && buf[len-1] != '/')
+                       if (len && !is_dir_sep(buf[len-1]))
                                buf[len++] = '/';
                        strcpy(buf + len, last_elem);
                        free(last_elem);
@@@ -111,14 -104,7 +111,14 @@@ static const char *get_pwd_cwd(void
        return cwd;
  }
  
 -const char *make_nonrelative_path(const char *path)
 +/*
 + * Use this to get an absolute path from a relative one. If you want
 + * to resolve links, you should use real_path.
 + *
 + * If the path is already absolute, then return path. As the user is
 + * never meant to free the return value, we're safe.
 + */
 +const char *absolute_path(const char *path)
  {
        static char buf[PATH_MAX + 1];
  
diff --combined cache.h
index e11cf6ab1c73ac97c94e76e8c8699d55af95b978,9d3d92cf9e1c7989fd46b77c61fceb0375dbcc4c..f4bb43ec6aa3e910e8a7d2ba2d9f06440e400fc2
+++ b/cache.h
@@@ -5,7 -5,6 +5,7 @@@
  #include "strbuf.h"
  #include "hash.h"
  #include "advice.h"
 +#include "gettext.h"
  
  #include SHA1_HEADER
  #ifndef git_SHA_CTX
@@@ -437,7 -436,6 +437,7 @@@ extern void verify_non_filename(const c
  
  #define INIT_DB_QUIET 0x0001
  
 +extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int);
  extern int init_db(const char *template_dir, unsigned int flags);
  
  #define alloc_nr(x) (((x)+16)*3/2)
@@@ -502,27 -500,9 +502,27 @@@ extern int index_name_is_other(const st
  extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  
 -extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 -extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
 +struct pathspec {
 +      const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
 +      int nr;
 +      unsigned int has_wildcard:1;
 +      unsigned int recursive:1;
 +      int max_depth;
 +      struct pathspec_item {
 +              const char *match;
 +              int len;
 +              unsigned int use_wildcard:1;
 +      } *items;
 +};
 +
 +extern int init_pathspec(struct pathspec *, const char **);
 +extern void free_pathspec(struct pathspec *);
 +extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
 +
 +#define HASH_WRITE_OBJECT 1
 +#define HASH_FORMAT_CHECK 2
 +extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
 +extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
  #define REFRESH_REALLY                0x0001  /* ignore_valid */
  #define REFRESH_IGNORE_MISSING        0x0008  /* ignore non-existent */
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
  #define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
 -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
 +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);
  
  struct lock_file {
        struct lock_file *next;
@@@ -576,7 -556,6 +576,7 @@@ extern int core_compression_seen
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
 +extern unsigned long big_file_threshold;
  extern int read_replace_refs;
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -609,7 -588,7 +609,7 @@@ enum eol 
  #endif
  };
  
 -extern enum eol eol;
 +extern enum eol core_eol;
  
  enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
@@@ -679,24 -658,14 +679,24 @@@ extern char *sha1_pack_name(const unsig
  extern char *sha1_pack_index_name(const unsigned char *sha1);
  extern const char *find_unique_abbrev(const unsigned char *sha1, int);
  extern const unsigned char null_sha1[20];
 -static inline int is_null_sha1(const unsigned char *sha1)
 +
 +static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
 -      return !memcmp(sha1, null_sha1, 20);
 +      int i;
 +
 +      for (i = 0; i < 20; i++, sha1++, sha2++) {
 +              if (*sha1 != *sha2)
 +                      return *sha1 - *sha2;
 +      }
 +
 +      return 0;
  }
 -static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
 +
 +static inline int is_null_sha1(const unsigned char *sha1)
  {
 -      return memcmp(sha1, sha2, 20);
 +      return !hashcmp(sha1, null_sha1);
  }
 +
  static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
  {
        memcpy(sha_dst, sha_src, 20);
@@@ -742,40 -711,29 +742,40 @@@ int set_shared_perm(const char *path, i
  #define adjust_shared_perm(path) set_shared_perm((path), 0)
  int safe_create_leading_directories(char *path);
  int safe_create_leading_directories_const(const char *path);
 +int mkdir_in_gitdir(const char *path);
  extern char *expand_user_path(const char *path);
  char *enter_repo(char *path, int strict);
  static inline int is_absolute_path(const char *path)
  {
-       return path[0] == '/' || has_dos_drive_prefix(path);
+       return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
  }
  int is_directory(const char *);
 -const char *make_absolute_path(const char *path);
 -const char *make_nonrelative_path(const char *path);
 -const char *make_relative_path(const char *abs, const char *base);
 +const char *real_path(const char *path);
 +const char *absolute_path(const char *path);
 +const char *relative_path(const char *abs, const char *base);
  int normalize_path_copy(char *dst, const char *src);
  int longest_ancestor_length(const char *path, const char *prefix_list);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
  int offset_1st_component(const char *path);
  
 -/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 -extern int sha1_object_info(const unsigned char *, unsigned long *);
 -extern void *read_sha1_file_repl(const unsigned char *sha1, enum object_type *type, unsigned long *size, const unsigned char **replacement);
 +/* object replacement */
 +#define READ_SHA1_FILE_REPLACE 1
 +extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
 -      return read_sha1_file_repl(sha1, type, size, NULL);
 +      return read_sha1_file_extended(sha1, type, size, READ_SHA1_FILE_REPLACE);
 +}
 +extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
 +static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
 +{
 +      if (!read_replace_refs)
 +              return sha1;
 +      return do_lookup_replace_object(sha1);
  }
 +
 +/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 +extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
@@@ -813,15 -771,15 +813,15 @@@ struct object_context 
  };
  
  extern int get_sha1(const char *str, unsigned char *sha1);
 -extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
 +extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int only_to_die, const char *prefix);
  static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
  {
 -      return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
 +      return get_sha1_with_mode_1(str, sha1, mode, 0, NULL);
  }
 -extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int gently, const char *prefix);
 +extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int only_to_die, const char *prefix);
  static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
  {
 -      return get_sha1_with_context_1(str, sha1, orc, 1, NULL);
 +      return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
  }
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
@@@ -1026,20 -984,12 +1026,20 @@@ extern const char *packed_object_info_d
  /* Dumb servers support */
  extern int update_server_info(int);
  
 +/* git_config_parse_key() returns these negated: */
 +#define CONFIG_INVALID_KEY 1
 +#define CONFIG_NO_SECTION_OR_NAME 2
 +/* git_config_set(), git_config_set_multivar() return the above or these: */
 +#define CONFIG_NO_LOCK -1
 +#define CONFIG_INVALID_FILE 3
 +#define CONFIG_NO_WRITE 4
 +#define CONFIG_NOTHING_SET 5
 +#define CONFIG_INVALID_PATTERN 6
 +
  typedef int (*config_fn_t)(const char *, const char *, void *);
  extern int git_default_config(const char *, const char *, void *);
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
  extern void git_config_push_parameter(const char *text);
 -extern int git_config_parse_parameter(const char *text);
 -extern int git_config_parse_environment(void);
  extern int git_config_from_parameters(config_fn_t fn, void *data);
  extern int git_config(config_fn_t fn, void *);
  extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
@@@ -1059,6 -1009,7 +1059,6 @@@ extern const char *git_etc_gitconfig(vo
  extern int check_repository_format_version(const char *var, const char *value, void *cb);
  extern int git_env_bool(const char *, int);
  extern int git_config_system(void);
 -extern int git_config_global(void);
  extern int config_error_nonbool(const char *);
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
@@@ -1120,14 -1071,9 +1120,14 @@@ extern void alloc_report(void)
  /* trace.c */
  __attribute__((format (printf, 1, 2)))
  extern void trace_printf(const char *format, ...);
 +extern void trace_vprintf(const char *key, const char *format, va_list ap);
  __attribute__((format (printf, 2, 3)))
  extern void trace_argv_printf(const char **argv, const char *format, ...);
  extern void trace_repo_setup(const char *prefix);
 +extern int trace_want(const char *key);
 +extern void trace_strbuf(const char *key, const struct strbuf *buf);
 +
 +void packet_trace_identity(const char *prog);
  
  /* convert.c */
  /* returns 1 if *dst was used */
diff --combined compat/mingw.h
index 547568b9181d61d50f06cf5b4b0ab43af78e5aa2,bea909d76f2c7ab94fd51091258eb91404013df8..ce9dd980eb211c0301c4008249c61fb0b09f1280
@@@ -119,6 -119,14 +119,6 @@@ static inline int mingw_mkdir(const cha
  }
  #define mkdir mingw_mkdir
  
 -static inline int mingw_unlink(const char *pathname)
 -{
 -      /* read-only files cannot be removed */
 -      chmod(pathname, 0666);
 -      return unlink(pathname);
 -}
 -#define unlink mingw_unlink
 -
  #define WNOHANG 1
  pid_t waitpid(pid_t pid, int *status, unsigned options);
  
@@@ -166,12 -174,6 +166,12 @@@ int link(const char *oldpath, const cha
   * replacements of existing functions
   */
  
 +int mingw_unlink(const char *pathname);
 +#define unlink mingw_unlink
 +
 +int mingw_rmdir(const char *path);
 +#define rmdir mingw_rmdir
 +
  int mingw_open (const char *filename, int oflags, ...);
  #define open mingw_open
  
@@@ -217,9 -219,6 +217,9 @@@ int mingw_bind(int sockfd, struct socka
  int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
  #define setsockopt mingw_setsockopt
  
 +int mingw_shutdown(int sockfd, int how);
 +#define shutdown mingw_shutdown
 +
  int mingw_listen(int sockfd, int backlog);
  #define listen mingw_listen
  
@@@ -300,6 -299,15 +300,15 @@@ int winansi_fprintf(FILE *stream, cons
  
  #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
  #define is_dir_sep(c) ((c) == '/' || (c) == '\\')
+ static inline char *mingw_find_last_dir_sep(const char *path)
+ {
+       char *ret = NULL;
+       for (; *path; ++path)
+               if (is_dir_sep(*path))
+                       ret = (char *)path;
+       return ret;
+ }
+ #define find_last_dir_sep mingw_find_last_dir_sep
  #define PATH_SEP ';'
  #define PRIuMAX "I64u"
  
diff --combined git-compat-util.h
index e0bb81ed8d0bd89f18b31b1c03d3e23744aea5a1,15bf3ef81010a90498e4773f54e39a9286a9f0c5..a75530df7b7865059a51f84eb6257962c4f863cd
@@@ -215,6 -215,10 +215,10 @@@ extern char *gitbasename(char *)
  #define is_dir_sep(c) ((c) == '/')
  #endif
  
+ #ifndef find_last_dir_sep
+ #define find_last_dir_sep(path) strrchr(path, '/')
+ #endif
  #if __HP_cc >= 61000
  #define NORETURN __attribute__((noreturn))
  #define NORETURN_PTR
@@@ -463,7 -467,6 +467,7 @@@ extern unsigned char sane_ctype[256]
  #define GIT_ALPHA 0x04
  #define GIT_GLOB_SPECIAL 0x08
  #define GIT_REGEX_SPECIAL 0x10
 +#define GIT_PATHSPEC_MAGIC 0x20
  #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
  #define isascii(x) (((x) & ~0x7f) == 0)
  #define isspace(x) sane_istest(x,GIT_SPACE)
  #define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
  #define tolower(x) sane_case((unsigned char)(x), 0x20)
  #define toupper(x) sane_case((unsigned char)(x), 0)
 +#define is_pathspec_magic(x) sane_istest(x,GIT_PATHSPEC_MAGIC)
  
  static inline int sane_case(int x, int high)
  {
@@@ -541,19 -543,6 +545,19 @@@ void git_qsort(void *base, size_t nmemb
  #define fstat_is_reliable() 1
  #endif
  
 +#ifndef va_copy
 +/*
 + * Since an obvious implementation of va_list would be to make it a
 + * pointer into the stack frame, a simple assignment will work on
 + * many systems.  But let's try to be more portable.
 + */
 +#ifdef __va_copy
 +#define va_copy(dst, src) __va_copy(dst, src)
 +#else
 +#define va_copy(dst, src) ((dst) = (src))
 +#endif
 +#endif
 +
  /*
   * Preserves errno, prints a message, but gives no warning for ENOENT.
   * Always returns the return value of unlink(2).
diff --combined read-cache.c
index 4ac9a037f478e769a69072c324a47876e298cae4,e7c9684218d04830ceda15035d3d8701140f575b..46a9e60708ad98db5299f9242db05de5915a0ebb
@@@ -92,7 -92,7 +92,7 @@@ static int ce_compare_data(struct cache
  
        if (fd >= 0) {
                unsigned char sha1[20];
 -              if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name))
 +              if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))
                        match = hashcmp(sha1, ce->sha1);
                /* index_fd() closed the file descriptor already */
        }
@@@ -641,7 -641,7 +641,7 @@@ int add_to_index(struct index_state *is
                return 0;
        }
        if (!intent_only) {
 -              if (index_path(ce->sha1, path, st, 1))
 +              if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
                        return error("unable to index file %s", path);
        } else
                record_intent_to_add(ce);
@@@ -706,9 -706,30 +706,9 @@@ int ce_same_name(struct cache_entry *a
        return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
  }
  
 -int ce_path_match(const struct cache_entry *ce, const char **pathspec)
 +int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)
  {
 -      const char *match, *name;
 -      int len;
 -
 -      if (!pathspec)
 -              return 1;
 -
 -      len = ce_namelen(ce);
 -      name = ce->name;
 -      while ((match = *pathspec++) != NULL) {
 -              int matchlen = strlen(match);
 -              if (matchlen > len)
 -                      continue;
 -              if (memcmp(name, match, matchlen))
 -                      continue;
 -              if (matchlen && name[matchlen-1] == '/')
 -                      return 1;
 -              if (name[matchlen] == '/' || !name[matchlen])
 -                      return 1;
 -              if (!matchlen)
 -                      return 1;
 -      }
 -      return 0;
 +      return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);
  }
  
  /*
@@@ -726,11 -747,12 +726,12 @@@ static int verify_dotfile(const char *r
         * has already been discarded, we now test
         * the rest.
         */
-       switch (*rest) {
        /* "." is not allowed */
-       case '\0': case '/':
+       if (*rest == '\0' || is_dir_sep(*rest))
                return 0;
  
+       switch (*rest) {
        /*
         * ".git" followed by  NUL or slash is bad. This
         * shares the path end test with the ".." case.
                rest += 2;
        /* fallthrough */
        case '.':
-               if (rest[1] == '\0' || rest[1] == '/')
+               if (rest[1] == '\0' || is_dir_sep(rest[1]))
                        return 0;
        }
        return 1;
@@@ -753,23 -775,19 +754,19 @@@ int verify_path(const char *path
  {
        char c;
  
+       if (has_dos_drive_prefix(path))
+               return 0;
        goto inside;
        for (;;) {
                if (!c)
                        return 1;
-               if (c == '/') {
+               if (is_dir_sep(c)) {
  inside:
                        c = *path++;
-                       switch (c) {
-                       default:
-                               continue;
-                       case '/': case '\0':
-                               break;
-                       case '.':
-                               if (verify_dotfile(path))
-                                       continue;
-                       }
-                       return 0;
+                       if ((c == '.' && !verify_dotfile(path)) ||
+                           is_dir_sep(c) || c == '\0')
+                               return 0;
                }
                c = *path++;
        }
@@@ -1083,7 -1101,7 +1080,7 @@@ static struct cache_entry *refresh_cach
  }
  
  static void show_file(const char * fmt, const char * name, int in_porcelain,
 -                    int * first, char *header_msg)
 +                    int * first, const char *header_msg)
  {
        if (in_porcelain && *first && header_msg) {
                printf("%s\n", header_msg);
  }
  
  int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
 -                char *seen, char *header_msg)
 +                char *seen, const char *header_msg)
  {
        int i;
        int has_errors = 0;