From: Junio C Hamano Date: Wed, 11 Feb 2009 05:30:52 +0000 (-0800) Subject: Merge branch 'js/maint-1.6.0-path-normalize' X-Git-Tag: v1.6.2-rc1~43 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/6e5d7ddc490fc7fdf46a5d0af35aa6fd64ae4a96?ds=sidebyside;hp=-c Merge branch 'js/maint-1.6.0-path-normalize' * js/maint-1.6.0-path-normalize: Remove unused normalize_absolute_path() Test and fix normalize_path_copy() Fix GIT_CEILING_DIRECTORIES on Windows Move sanitary_path_copy() to path.c and rename it to normalize_path_copy() Make test-path-utils more robust against incorrect use --- 6e5d7ddc490fc7fdf46a5d0af35aa6fd64ae4a96 diff --combined cache.h index d8ba693146,39f0d6fea4..7f1a6e8bd0 --- a/cache.h +++ b/cache.h @@@ -6,22 -6,12 +6,22 @@@ #include "hash.h" #include SHA1_HEADER -#include +#ifndef git_SHA_CTX +#define git_SHA_CTX SHA_CTX +#define git_SHA1_Init SHA1_Init +#define git_SHA1_Update SHA1_Update +#define git_SHA1_Final SHA1_Final +#endif +#include #if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200 #define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11) #endif +void git_inflate_init(z_streamp strm); +void git_inflate_end(z_streamp strm); +int git_inflate(z_streamp strm, int flush); + #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT) #define DTYPE(de) ((de)->d_type) #else @@@ -119,26 -109,6 +119,26 @@@ struct ondisk_cache_entry char name[FLEX_ARRAY]; /* more */ }; +/* + * This struct is used when CE_EXTENDED bit is 1 + * The struct must match ondisk_cache_entry exactly from + * ctime till flags + */ +struct ondisk_cache_entry_extended { + struct cache_time ctime; + struct cache_time mtime; + unsigned int dev; + unsigned int ino; + unsigned int mode; + unsigned int uid; + unsigned int gid; + unsigned int size; + unsigned char sha1[20]; + unsigned short flags; + unsigned short flags2; + char name[FLEX_ARRAY]; /* more */ +}; + struct cache_entry { unsigned int ce_ctime; unsigned int ce_mtime; @@@ -156,19 -126,10 +156,19 @@@ #define CE_NAMEMASK (0x0fff) #define CE_STAGEMASK (0x3000) +#define CE_EXTENDED (0x4000) #define CE_VALID (0x8000) #define CE_STAGESHIFT 12 -/* In-memory only */ +/* + * Range 0xFFFF0000 in ce_flags is divided into + * two parts: in-memory flags and on-disk ones. + * Flags in CE_EXTENDED_FLAGS will get saved on-disk + * if you want to save a new flag, add it in + * CE_EXTENDED_FLAGS + * + * In-memory only flags + */ #define CE_UPDATE (0x10000) #define CE_REMOVE (0x20000) #define CE_UPTODATE (0x40000) @@@ -177,25 -138,6 +177,25 @@@ #define CE_HASHED (0x100000) #define CE_UNHASHED (0x200000) +/* + * Extended on-disk flags + */ +#define CE_INTENT_TO_ADD 0x20000000 +/* CE_EXTENDED2 is for future extension */ +#define CE_EXTENDED2 0x80000000 + +#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD) + +/* + * Safeguard to avoid saving wrong flags: + * - CE_EXTENDED2 won't get saved until its semantic is known + * - Bits in 0x0000FFFF have been saved in ce_flags already + * - Bits in 0x003F0000 are currently in-memory flags + */ +#if CE_EXTENDED_FLAGS & 0x803FFFFF +#error "CE_EXTENDED_FLAGS out of range" +#endif + /* * Copy the sha1 and stat state of a cache entry from one to * another. But we never change the name, or the hash state! @@@ -228,9 -170,7 +228,9 @@@ static inline size_t ce_namelen(const s } #define ce_size(ce) cache_entry_size(ce_namelen(ce)) -#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce)) +#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \ + ondisk_cache_entry_extended_size(ce_namelen(ce)) : \ + ondisk_cache_entry_size(ce_namelen(ce))) #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT) #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) @@@ -273,10 -213,8 +273,10 @@@ static inline int ce_to_dtype(const str (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \ S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK) -#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7) -#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7) +#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7) +#define cache_entry_size(len) flexible_size(cache_entry,len) +#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len) +#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len) struct index_state { struct cache_entry **cache; @@@ -317,7 -255,6 +317,7 @@@ static inline void remove_name_hash(str #define read_cache() read_index(&the_index) #define read_cache_from(path) read_index_from(&the_index, (path)) +#define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec)) #define is_cache_unborn() is_index_unborn(&the_index) #define read_cache_unmerged() read_index_unmerged(&the_index) #define write_cache(newfd, cache, entries) write_index(&the_index, (newfd)) @@@ -371,15 -308,12 +371,15 @@@ static inline enum object_type object_t #define GITATTRIBUTES_FILE ".gitattributes" #define INFOATTRIBUTES_FILE "info/attributes" #define ATTRIBUTE_MACRO_PREFIX "[attr]" +#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF" +#define GIT_NOTES_DEFAULT_REF "refs/notes/commits" extern int is_bare_repository_cfg; extern int is_bare_repository(void); extern int is_inside_git_dir(void); extern char *git_work_tree_cfg; extern int is_inside_work_tree(void); +extern int have_git_dir(void); extern const char *get_git_dir(void); extern char *get_object_directory(void); extern char *get_index_file(void); @@@ -426,7 -360,6 +426,7 @@@ extern int init_db(const char *template /* Initialize and use the cache information */ extern int read_index(struct index_state *); +extern int read_index_preload(struct index_state *, const char **pathspec); extern int read_index_from(struct index_state *, const char *path); extern int is_index_unborn(struct index_state *); extern int read_index_unmerged(struct index_state *); @@@ -440,7 -373,6 +440,7 @@@ extern int index_name_pos(const struct #define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */ #define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */ #define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */ +#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option); extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name); @@@ -449,8 -381,6 +449,8 @@@ extern int remove_file_from_index(struc #define ADD_CACHE_VERBOSE 1 #define ADD_CACHE_PRETEND 2 #define ADD_CACHE_IGNORE_ERRORS 4 +#define ADD_CACHE_IGNORE_REMOVAL 8 +#define ADD_CACHE_INTENT 16 extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags); extern int add_file_to_index(struct index_state *, const char *path, int flags); extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh); @@@ -466,6 -396,7 +466,6 @@@ extern int ie_modified(const struct ind 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_pipe(unsigned char *sha1, int fd, const char *type, int write_object); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); @@@ -517,7 -448,6 +517,7 @@@ extern size_t packed_git_limit extern size_t delta_base_cache_limit; extern int auto_crlf; extern int fsync_object_files; +extern int core_preload_index; enum safe_crlf { SAFE_CRLF_FALSE = 0, @@@ -528,7 -458,6 +528,7 @@@ extern enum safe_crlf safe_crlf; enum branch_track { + BRANCH_TRACK_UNSPECIFIED = -1, BRANCH_TRACK_NEVER = 0, BRANCH_TRACK_REMOTE, BRANCH_TRACK_ALWAYS, @@@ -544,7 -473,6 +544,7 @@@ enum rebase_setup_type extern enum branch_track git_branch_track; extern enum rebase_setup_type autorebase; +extern char *notes_ref_name; #define GIT_REPO_VERSION 0 extern int repository_format_version; @@@ -589,13 -517,6 +589,13 @@@ static inline void hashclr(unsigned cha { memset(hash, 0, 20); } +extern int is_empty_blob_sha1(const unsigned char *sha1); + +#define EMPTY_TREE_SHA1_HEX \ + "4b825dc642cb6eb9a060e54bf8d69288fbee4904" +#define EMPTY_TREE_SHA1_BIN \ + "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \ + "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04" int git_mkstemp(char *path, size_t n, const char *template); @@@ -623,11 -544,10 +623,11 @@@ static inline int is_absolute_path(cons { return 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); - int normalize_absolute_path(char *buf, const char *path); + int normalize_path_copy(char *dst, const char *src); int longest_ancestor_length(const char *path, const char *prefix_list); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ @@@ -638,8 -558,8 +638,8 @@@ extern int write_sha1_file(void *buf, u extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *); extern int force_object_loose(const unsigned char *sha1, time_t mtime); -/* just like read_sha1_file(), but non fatal in presence of bad objects */ -extern void *read_object(const unsigned char *sha1, enum object_type *type, unsigned long *size); +/* global flag to enable extra checks when accessing packed objects */ +extern int do_check_packed_object_crc; extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type); @@@ -670,7 -590,6 +670,7 @@@ extern int read_ref(const char *filenam extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *); extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref); extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref); +extern int interpret_nth_last_branch(const char *str, struct strbuf *); extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules); extern const char *ref_rev_parse_rules[]; @@@ -725,10 -644,6 +725,10 @@@ struct checkout extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath); extern int has_symlink_leading_path(int len, const char *name); +extern int has_symlink_or_noent_leading_path(int len, const char *name); +extern int has_dirs_only_path(int len, const char *name, int prefix_len); +extern void invalidate_lstat_cache(int len, const char *name); +extern void clear_lstat_cache(void); extern struct alternate_object_database { struct alternate_object_database *next; @@@ -737,8 -652,6 +737,8 @@@ } *alt_odb_list; extern void prepare_alt_odb(void); extern void add_to_alternates_file(const char *reference); +typedef int alt_odb_fn(struct alternate_object_database *, void *); +extern void foreach_alt_odb(alt_odb_fn, void*); struct pack_window { struct pack_window *next; @@@ -808,11 -721,7 +808,11 @@@ extern struct child_process *git_connec extern int finish_connect(struct child_process *conn); extern int path_match(const char *path, int nr, char **match); extern int get_ack(int fd, unsigned char *result_sha1); -extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags); +struct extra_have_objects { + int nr, alloc; + unsigned char (*array)[20]; +}; +extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *); extern int server_supports(const char *feature); extern struct packed_git *parse_pack_index(unsigned char *sha1); @@@ -830,13 -739,12 +830,13 @@@ extern unsigned char* use_pack(struct p extern void close_pack_windows(struct packed_git *); extern void unuse_pack(struct pack_window **); extern void free_pack_by_name(const char *); +extern void clear_delta_base_cache(void); extern struct packed_git *add_packed_git(const char *, int, int); extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t); extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t); extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *); extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *); -extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); +extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t); extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *); extern int matches_pack_name(struct packed_git *p, const char *name); @@@ -848,6 -756,7 +848,6 @@@ typedef int (*config_fn_t)(const char * extern int git_default_config(const char *, const char *, void *); extern int git_config_from_file(config_fn_t fn, const char *, void *); extern int git_config(config_fn_t fn, void *); -extern int git_parse_long(const char *, long *); extern int git_parse_ulong(const char *, unsigned long *); extern int git_config_int(const char *, const char *); extern unsigned long git_config_ulong(const char *, const char *); @@@ -946,6 -855,7 +946,6 @@@ extern int ws_fix_copy(char *, const ch extern int ws_blank_line(const char *line, int len, unsigned ws_rule); /* ls-files */ -int pathspec_match(const char **spec, char *matched, const char *filename, int skiplen); int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset); void overlay_tree_on_cache(const char *tree_name, const char *prefix); diff --combined path.c index 108d9e9599,4b9107fed1..dd22370e8e --- a/path.c +++ b/path.c @@@ -154,7 -154,7 +154,7 @@@ int validate_headref(const char *path /* Make sure it is a "refs/.." symlink */ if (S_ISLNK(st.st_mode)) { len = readlink(path, buffer, sizeof(buffer)-1); - if (len >= 5 && !memcmp("refs/", buffer, 5)) + if (len >= 11 && !memcmp("refs/heads/", buffer, 11)) return 0; return -1; } @@@ -178,7 -178,7 +178,7 @@@ len -= 4; while (len && isspace(*buf)) buf++, len--; - if (len >= 5 && !memcmp("refs/", buf, 5)) + if (len >= 11 && !memcmp("refs/heads/", buf, 11)) return 0; } @@@ -363,56 -363,97 +363,97 @@@ const char *make_relative_path(const ch } /* - * path = absolute path - * buf = buffer of at least max(2, strlen(path)+1) bytes - * It is okay if buf == path, but they should not overlap otherwise. + * It is okay if dst == src, but they should not overlap otherwise. * - * Performs the following normalizations on path, storing the result in buf: - * - Removes trailing slashes. - * - Removes empty components. + * Performs the following normalizations on src, storing the result in dst: + * - Ensures that components are separated by '/' (Windows only) + * - Squashes sequences of '/'. * - Removes "." components. * - Removes ".." components, and the components the precede them. - * "" and paths that contain only slashes are normalized to "/". - * Returns the length of the output. + * Returns failure (non-zero) if a ".." component appears as first path + * component anytime during the normalization. Otherwise, returns success (0). * * Note that this function is purely textual. It does not follow symlinks, * verify the existence of the path, or make any system calls. */ - int normalize_absolute_path(char *buf, const char *path) + int normalize_path_copy(char *dst, const char *src) { - const char *comp_start = path, *comp_end = path; - char *dst = buf; - int comp_len; - assert(buf); - assert(path); - - while (*comp_start) { - assert(*comp_start == '/'); - while (*++comp_end && *comp_end != '/') - ; /* nothing */ - comp_len = comp_end - comp_start; - - if (!strncmp("/", comp_start, comp_len) || - !strncmp("/.", comp_start, comp_len)) - goto next; - - if (!strncmp("/..", comp_start, comp_len)) { - while (dst > buf && *--dst != '/') - ; /* nothing */ - goto next; - } + char *dst0; - memmove(dst, comp_start, comp_len); - dst += comp_len; - next: - comp_start = comp_end; + if (has_dos_drive_prefix(src)) { + *dst++ = *src++; + *dst++ = *src++; } + dst0 = dst; - if (dst == buf) + if (is_dir_sep(*src)) { *dst++ = '/'; + while (is_dir_sep(*src)) + src++; + } + + for (;;) { + 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 == '.') { + if (!src[1]) { + /* (1) */ + src++; + } else if (is_dir_sep(src[1])) { + /* (2) */ + src += 2; + while (is_dir_sep(*src)) + src++; + continue; + } else if (src[1] == '.') { + if (!src[2]) { + /* (3) */ + src += 2; + goto up_one; + } else if (is_dir_sep(src[2])) { + /* (4) */ + src += 3; + while (is_dir_sep(*src)) + src++; + goto up_one; + } + } + } + /* copy up to the next '/', and eat all '/' */ + while ((c = *src++) != '\0' && !is_dir_sep(c)) + *dst++ = c; + if (is_dir_sep(c)) { + *dst++ = '/'; + while (is_dir_sep(c)) + c = *src++; + src--; + } else if (!c) + break; + continue; + + up_one: + /* + * dst0..dst is prefix portion, and dst[-1] is '/'; + * go up one level. + */ + dst--; /* go to trailing '/' */ + if (dst <= dst0) + return -1; + /* Windows: dst[-1] cannot be backslash anymore */ + while (dst0 < dst && dst[-1] != '/') + dst--; + } *dst = '\0'; - return dst - buf; + return 0; } /* @@@ -438,15 -479,16 +479,16 @@@ int longest_ancestor_length(const char return -1; for (colon = ceil = prefix_list; *colon; ceil = colon+1) { - for (colon = ceil; *colon && *colon != ':'; colon++); + for (colon = ceil; *colon && *colon != PATH_SEP; colon++); len = colon - ceil; if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil)) continue; strlcpy(buf, ceil, len+1); - len = normalize_absolute_path(buf, buf); - /* Strip "trailing slashes" from "/". */ - if (len == 1) - len = 0; + if (normalize_path_copy(buf, buf) < 0) + continue; + len = strlen(buf); + if (len > 0 && buf[len-1] == '/') + buf[--len] = '\0'; if (!strncmp(path, buf, len) && path[len] == '/' && diff --combined setup.c index dfda532adc,59735c1450..6c2deda184 --- a/setup.c +++ b/setup.c @@@ -4,92 -4,6 +4,6 @@@ static int inside_git_dir = -1; static int inside_work_tree = -1; - static int sanitary_path_copy(char *dst, const char *src) - { - char *dst0; - - if (has_dos_drive_prefix(src)) { - *dst++ = *src++; - *dst++ = *src++; - } - dst0 = dst; - - if (is_dir_sep(*src)) { - *dst++ = '/'; - while (is_dir_sep(*src)) - src++; - } - - for (;;) { - 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 == '.') { - if (!src[1]) { - /* (1) */ - src++; - } else if (is_dir_sep(src[1])) { - /* (2) */ - src += 2; - while (is_dir_sep(*src)) - src++; - continue; - } else if (src[1] == '.') { - if (!src[2]) { - /* (3) */ - src += 2; - goto up_one; - } else if (is_dir_sep(src[2])) { - /* (4) */ - src += 3; - while (is_dir_sep(*src)) - src++; - goto up_one; - } - } - } - - /* copy up to the next '/', and eat all '/' */ - while ((c = *src++) != '\0' && !is_dir_sep(c)) - *dst++ = c; - if (is_dir_sep(c)) { - *dst++ = '/'; - while (is_dir_sep(c)) - c = *src++; - src--; - } else if (!c) - break; - 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 == '/') { /* MinGW: cannot be '\\' anymore */ - dst += 2; - break; - } - } - } - *dst = '\0'; - return 0; - } - const char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; @@@ -101,7 -15,7 +15,7 @@@ memcpy(sanitized, prefix, len); strcpy(sanitized + len, path); } - if (sanitary_path_copy(sanitized, sanitized)) + if (normalize_path_copy(sanitized, sanitized)) goto error_out; if (is_absolute_path(orig)) { const char *work_tree = get_git_work_tree(); @@@ -456,11 -370,7 +370,11 @@@ const char *setup_git_directory_gently( inside_git_dir = 1; if (!work_tree_env) inside_work_tree = 0; - setenv(GIT_DIR_ENVIRONMENT, ".", 1); + if (offset != len) { + cwd[offset] = '\0'; + setenv(GIT_DIR_ENVIRONMENT, cwd, 1); + } else + setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format_gently(nongit_ok); return NULL; } @@@ -472,10 -382,9 +386,10 @@@ *nongit_ok = 1; return NULL; } - die("Not a git repository"); + die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); } - chdir(".."); + if (chdir("..")) + die("Cannot change to %s/..: %s", cwd, strerror(errno)); } inside_git_dir = 0;