From: Junio C Hamano Date: Sat, 29 Nov 2008 01:22:35 +0000 (-0800) Subject: Merge branch 'nd/narrow' (early part) into jc/add-i-t-a X-Git-Tag: v1.6.1-rc2~18^2~3 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/fe60dff744aa9fc7440de0a521e8be71ec35a059?ds=inline;hp=-c Merge branch 'nd/narrow' (early part) into jc/add-i-t-a * 'nd/narrow' (early part): Extend index to save more flags --- fe60dff744aa9fc7440de0a521e8be71ec35a059 diff --combined cache.h index 487e5e1b1b,964f7e31cb..ef2e7f93f7 --- a/cache.h +++ b/cache.h @@@ -115,6 -115,26 +115,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; @@@ -136,7 -156,15 +156,15 @@@ #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) @@@ -145,6 -173,24 +173,24 @@@ #define CE_HASHED (0x100000) #define CE_UNHASHED (0x200000) + /* + * Extended on-disk flags + */ + /* CE_EXTENDED2 is for future extension */ + #define CE_EXTENDED2 0x80000000 + + #define CE_EXTENDED_FLAGS (0) + + /* + * 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! @@@ -177,7 -223,9 +223,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) @@@ -220,8 -268,10 +268,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; @@@ -262,8 -312,6 +312,8 @@@ 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)) #define discard_cache() discard_index(&the_index) @@@ -279,7 -327,6 +329,7 @@@ #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options)) #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase)) +#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen)) #endif enum object_type { @@@ -369,9 -416,7 +419,9 @@@ 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 *); extern int write_index(const struct index_state *, int newfd); extern int discard_index(struct index_state *); @@@ -398,7 -443,6 +448,7 @@@ extern int add_to_index(struct index_st 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); extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); +extern int index_name_is_other(const struct index_state *, const char *, int); /* do stat comparison even if CE_VALID is true */ #define CE_MATCH_IGNORE_VALID 01 @@@ -427,8 -471,6 +477,8 @@@ struct lock_file char on_list; char filename[PATH_MAX]; }; +#define LOCK_DIE_ON_ERROR 1 +#define LOCK_NODEREF 2 extern int hold_lock_file_for_update(struct lock_file *, const char *path, int); extern int hold_lock_file_for_append(struct lock_file *, const char *path, int); extern int commit_lock_file(struct lock_file *); @@@ -438,7 -480,7 +488,7 @@@ extern int commit_locked_index(struct l extern void set_alternate_index_output(const char *); extern int close_lock_file(struct lock_file *); extern void rollback_lock_file(struct lock_file *); -extern int delete_ref(const char *, const unsigned char *sha1); +extern int delete_ref(const char *, const unsigned char *sha1, int delopt); /* Environment bits from configuration mechanism */ extern int trust_executable_bit; @@@ -460,7 -502,6 +510,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, @@@ -500,13 -541,6 +550,13 @@@ extern int check_repository_format(void #define DATA_CHANGED 0x0020 #define TYPE_CHANGED 0x0040 +extern char *mksnpath(char *buf, size_t n, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); +extern char *git_snpath(char *buf, size_t n, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); +extern char *git_pathdup(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); + /* Return a statically allocated filename matching the sha1 signature */ extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); @@@ -531,13 -565,6 +581,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); @@@ -583,16 -610,12 +633,16 @@@ extern int force_object_loose(const uns /* 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); extern int move_temp_to_file(const char *tmpfile, const char *filename); extern int has_sha1_pack(const unsigned char *sha1, const char **ignore); extern int has_sha1_file(const unsigned char *sha1); +extern int has_loose_object_nonlocal(const unsigned char *sha1); extern int has_pack_file(const unsigned char *sha1); extern int has_pack_index(const unsigned char *sha1); @@@ -701,8 -724,7 +751,8 @@@ extern struct packed_git int index_version; time_t mtime; int pack_fd; - int pack_local; + unsigned pack_local:1, + pack_keep:1; unsigned char sha1[20]; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ @@@ -774,7 -796,7 +824,7 @@@ extern const unsigned char *nth_packed_ 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); diff --combined read-cache.c index 22a814311d,ea262fc37e..abc627ba0b --- a/read-cache.c +++ b/read-cache.c @@@ -160,7 -160,7 +160,7 @@@ static int ce_modified_check_fs(struct return 0; } -static int is_empty_blob_sha1(const unsigned char *sha1) +int is_empty_blob_sha1(const unsigned char *sha1) { static const unsigned char empty_blob_sha1[20] = { 0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b, @@@ -1098,7 -1098,7 +1098,7 @@@ static int verify_hdr(struct cache_head if (hdr->hdr_signature != htonl(CACHE_SIGNATURE)) return error("bad signature"); - if (hdr->hdr_version != htonl(2)) + if (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3)) return error("bad index version"); git_SHA1_Init(&c); git_SHA1_Update(&c, hdr, size - 20); @@@ -1133,6 -1133,7 +1133,7 @@@ int read_index(struct index_state *ista static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce) { size_t len; + const char *name; ce->ce_ctime = ntohl(ondisk->ctime.sec); ce->ce_mtime = ntohl(ondisk->mtime.sec); @@@ -1145,19 -1146,31 +1146,31 @@@ /* On-disk flags are just 16 bits */ ce->ce_flags = ntohs(ondisk->flags); - /* For future extension: we do not understand this entry yet */ - if (ce->ce_flags & CE_EXTENDED) - die("Unknown index entry format"); hashcpy(ce->sha1, ondisk->sha1); len = ce->ce_flags & CE_NAMEMASK; + + if (ce->ce_flags & CE_EXTENDED) { + struct ondisk_cache_entry_extended *ondisk2; + int extended_flags; + ondisk2 = (struct ondisk_cache_entry_extended *)ondisk; + extended_flags = ntohs(ondisk2->flags2) << 16; + /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */ + if (extended_flags & ~CE_EXTENDED_FLAGS) + die("Unknown index entry format %08x", extended_flags); + ce->ce_flags |= extended_flags; + name = ondisk2->name; + } + else + name = ondisk->name; + if (len == CE_NAMEMASK) - len = strlen(ondisk->name); + len = strlen(name); /* * NEEDSWORK: If the original index is crafted, this copy could * go unchecked. */ - memcpy(ce->name, ondisk->name, len + 1); + memcpy(ce->name, name, len + 1); } static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries) @@@ -1269,11 -1282,6 +1282,11 @@@ unmap die("index file corrupt"); } +int is_index_unborn(struct index_state *istate) +{ + return (!istate->cache_nr && !istate->alloc && !istate->timestamp); +} + int discard_index(struct index_state *istate) { istate->cache_nr = 0; @@@ -1422,6 -1430,7 +1435,7 @@@ static int ce_write_entry(git_SHA_CTX * { int size = ondisk_ce_size(ce); struct ondisk_cache_entry *ondisk = xcalloc(1, size); + char *name; ondisk->ctime.sec = htonl(ce->ce_ctime); ondisk->ctime.nsec = 0; @@@ -1435,7 -1444,15 +1449,15 @@@ ondisk->size = htonl(ce->ce_size); hashcpy(ondisk->sha1, ce->sha1); ondisk->flags = htons(ce->ce_flags); - memcpy(ondisk->name, ce->name, ce_namelen(ce)); + if (ce->ce_flags & CE_EXTENDED) { + struct ondisk_cache_entry_extended *ondisk2; + ondisk2 = (struct ondisk_cache_entry_extended *)ondisk; + ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16); + name = ondisk2->name; + } + else + name = ondisk->name; + memcpy(name, ce->name, ce_namelen(ce)); return ce_write(c, fd, ondisk, size); } @@@ -1444,16 -1461,25 +1466,25 @@@ int write_index(const struct index_stat { git_SHA_CTX c; struct cache_header hdr; - int i, err, removed; + int i, err, removed, extended; struct cache_entry **cache = istate->cache; int entries = istate->cache_nr; - for (i = removed = 0; i < entries; i++) + for (i = removed = extended = 0; i < entries; i++) { if (cache[i]->ce_flags & CE_REMOVE) removed++; + /* reduce extended entries if possible */ + cache[i]->ce_flags &= ~CE_EXTENDED; + if (cache[i]->ce_flags & CE_EXTENDED_FLAGS) { + extended++; + cache[i]->ce_flags |= CE_EXTENDED; + } + } + hdr.hdr_signature = htonl(CACHE_SIGNATURE); - hdr.hdr_version = htonl(2); + /* for extended format, increase version so older git won't try to read it */ + hdr.hdr_version = htonl(extended ? 3 : 2); hdr.hdr_entries = htonl(entries - removed); git_SHA1_Init(&c); @@@ -1494,30 -1520,25 +1525,30 @@@ int read_index_unmerged(struct index_state *istate) { int i; - struct cache_entry **dst; - struct cache_entry *last = NULL; + int unmerged = 0; read_index(istate); - dst = istate->cache; for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i]; - if (ce_stage(ce)) { - remove_name_hash(ce); - if (last && !strcmp(ce->name, last->name)) - continue; - cache_tree_invalidate_path(istate->cache_tree, ce->name); - last = ce; + struct cache_entry *new_ce; + int size, len; + + if (!ce_stage(ce)) continue; - } - *dst++ = ce; + unmerged = 1; + len = strlen(ce->name); + size = cache_entry_size(len); + new_ce = xcalloc(1, size); + hashcpy(new_ce->sha1, ce->sha1); + memcpy(new_ce->name, ce->name, len); + new_ce->ce_flags = create_ce_flags(len, 0); + new_ce->ce_mode = ce->ce_mode; + if (add_index_entry(istate, new_ce, 0)) + return error("%s: cannot drop to stage #0", + ce->name); + i = index_name_pos(istate, new_ce->name, len); } - istate->cache_nr = dst - istate->cache; - return !!last; + return unmerged; } struct update_callback_data @@@ -1575,30 -1596,3 +1606,30 @@@ int add_files_to_cache(const char *pref return !!data.add_errors; } +/* + * Returns 1 if the path is an "other" path with respect to + * the index; that is, the path is not mentioned in the index at all, + * either as a file, a directory with some files in the index, + * or as an unmerged entry. + * + * We helpfully remove a trailing "/" from directories so that + * the output of read_directory can be used as-is. + */ +int index_name_is_other(const struct index_state *istate, const char *name, + int namelen) +{ + int pos; + if (namelen && name[namelen - 1] == '/') + namelen--; + pos = index_name_pos(istate, name, namelen); + if (0 <= pos) + return 0; /* exact match */ + pos = -pos - 1; + if (pos < istate->cache_nr) { + struct cache_entry *ce = istate->cache[pos]; + if (ce_namelen(ce) == namelen && + !memcmp(ce->name, name, namelen)) + return 0; /* Yup, this one exists unmerged */ + } + return 1; +}