summaryrefslogtreecommitdiff
path: root/cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'cache.h')
-rw-r--r--cache.h574
1 files changed, 398 insertions, 176 deletions
diff --git a/cache.h b/cache.h
index 415d883..22b7b81 100644
--- a/cache.h
+++ b/cache.h
@@ -3,10 +3,12 @@
#include "git-compat-util.h"
#include "strbuf.h"
-#include "hash.h"
+#include "hashmap.h"
#include "advice.h"
#include "gettext.h"
#include "convert.h"
+#include "trace.h"
+#include "string-list.h"
#include SHA1_HEADER
#ifndef git_SHA_CTX
@@ -75,6 +77,21 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
/*
+ * Some mode bits are also used internally for computations.
+ *
+ * They *must* not overlap with any valid modes, and they *must* not be emitted
+ * to outside world - i.e. appear on disk or network. In other words, it's just
+ * temporary fields, which we internally use, but they have to stay in-house.
+ *
+ * ( such approach is valid, as standard S_IF* fits into 16 bits, and in Git
+ * codebase mode is `unsigned int` which is assumed to be at least 32 bits )
+ */
+
+/* used internally in tree-diff */
+#define S_DIFFTREE_IFXMIN_NEQ 0x80000000
+
+
+/*
* Intensive research over the course of many years has shown that
* port 9418 is totally unused by anything else. Or
*
@@ -101,9 +118,9 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
struct cache_header {
- unsigned int hdr_signature;
- unsigned int hdr_version;
- unsigned int hdr_entries;
+ uint32_t hdr_signature;
+ uint32_t hdr_version;
+ uint32_t hdr_entries;
};
#define INDEX_FORMAT_LB 2
@@ -115,8 +132,8 @@ struct cache_header {
* check it for equality in the 32 bits we save.
*/
struct cache_time {
- unsigned int sec;
- unsigned int nsec;
+ uint32_t sec;
+ uint32_t nsec;
};
struct stat_data {
@@ -130,12 +147,13 @@ struct stat_data {
};
struct cache_entry {
+ struct hashmap_entry ent;
struct stat_data ce_stat_data;
unsigned int ce_mode;
unsigned int ce_flags;
unsigned int ce_namelen;
+ unsigned int index; /* for link extension */
unsigned char sha1[20];
- struct cache_entry *next;
char name[FLEX_ARRAY]; /* more */
};
@@ -145,7 +163,7 @@ struct cache_entry {
#define CE_STAGESHIFT 12
/*
- * Range 0xFFFF0000 in ce_flags is divided into
+ * Range 0xFFFF0FFF 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
@@ -159,7 +177,6 @@ struct cache_entry {
#define CE_ADDED (1 << 19)
#define CE_HASHED (1 << 20)
-#define CE_UNHASHED (1 << 21)
#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
#define CE_CONFLICTED (1 << 23)
@@ -169,6 +186,9 @@ struct cache_entry {
/* used to temporarily mark paths matched by pathspecs */
#define CE_MATCHED (1 << 26)
+#define CE_UPDATE_IN_BASE (1 << 27)
+#define CE_STRIP_NAME (1 << 28)
+
/*
* Extended on-disk flags
*/
@@ -189,21 +209,24 @@ struct cache_entry {
#error "CE_EXTENDED_FLAGS out of range"
#endif
+struct pathspec;
+
/*
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
*/
-#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
static inline void copy_cache_entry(struct cache_entry *dst,
const struct cache_entry *src)
{
- unsigned int state = dst->ce_flags & CE_STATE_MASK;
+ unsigned int state = dst->ce_flags & CE_HASHED;
/* Don't copy hash chain and name */
- memcpy(dst, src, offsetof(struct cache_entry, next));
+ memcpy(&dst->ce_stat_data, &src->ce_stat_data,
+ offsetof(struct cache_entry, name) -
+ offsetof(struct cache_entry, ce_stat_data));
/* Restore the hash state */
- dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
+ dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}
static inline unsigned create_ce_flags(unsigned stage)
@@ -266,17 +289,28 @@ static inline unsigned int canon_mode(unsigned int mode)
#define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1)
+#define SOMETHING_CHANGED (1 << 0) /* unclassified changes go here */
+#define CE_ENTRY_CHANGED (1 << 1)
+#define CE_ENTRY_REMOVED (1 << 2)
+#define CE_ENTRY_ADDED (1 << 3)
+#define RESOLVE_UNDO_CHANGED (1 << 4)
+#define CACHE_TREE_CHANGED (1 << 5)
+#define SPLIT_INDEX_ORDERED (1 << 6)
+
+struct split_index;
struct index_state {
struct cache_entry **cache;
unsigned int version;
unsigned int cache_nr, cache_alloc, cache_changed;
struct string_list *resolve_undo;
struct cache_tree *cache_tree;
+ struct split_index *split_index;
struct cache_time timestamp;
unsigned name_hash_initialized : 1,
initialized : 1;
- struct hash_table name_hash;
- struct hash_table dir_hash;
+ struct hashmap name_hash;
+ struct hashmap dir_hash;
+ unsigned char sha1[20];
};
extern struct index_state the_index;
@@ -299,7 +333,6 @@ extern void free_name_hash(struct index_state *istate);
#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)
#define unmerged_cache() unmerged_index(&the_index)
#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
@@ -312,7 +345,8 @@ extern void free_name_hash(struct index_state *istate);
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
#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_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
+#define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
@@ -350,6 +384,7 @@ static inline enum object_type object_type(unsigned int mode)
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
+#define GIT_SHALLOW_FILE_ENVIRONMENT "GIT_SHALLOW_FILE"
#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
#define CONFIG_ENVIRONMENT "GIT_CONFIG"
#define CONFIG_DATA_ENVIRONMENT "GIT_CONFIG_PARAMETERS"
@@ -365,6 +400,9 @@ static inline enum object_type object_type(unsigned int mode)
#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
+#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
+#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
+#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
/*
* This environment variable is expected to contain a boolean indicating
@@ -391,7 +429,6 @@ 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 int is_git_directory(const char *path);
extern char *get_object_directory(void);
@@ -412,6 +449,7 @@ extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
extern char *prefix_path(const char *prefix, int len, const char *path);
+extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
extern const char *prefix_filename(const char *prefix, int len, const char *path);
extern int check_filename(const char *prefix, const char *name);
extern void verify_filename(const char *prefix,
@@ -426,6 +464,7 @@ 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);
extern void sanitize_stdfds(void);
+extern int daemonize(void);
#define alloc_nr(x) (((x)+16)*3/2)
@@ -443,27 +482,34 @@ extern void sanitize_stdfds(void);
alloc = (nr); \
else \
alloc = alloc_nr(alloc); \
- x = xrealloc((x), alloc * sizeof(*(x))); \
+ REALLOC_ARRAY(x, alloc); \
} \
} while (0)
/* Initialize and use the cache information */
+struct lock_file;
extern int read_index(struct index_state *);
-extern int read_index_preload(struct index_state *, const char **pathspec);
+extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
+extern int do_read_index(struct index_state *istate, const char *path,
+ int must_exist); /* for testting only! */
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(struct index_state *, int newfd);
+#define COMMIT_LOCK (1 << 0)
+#define CLOSE_LOCK (1 << 1)
+extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
extern int discard_index(struct index_state *);
extern int unmerged_index(const struct index_state *);
extern int verify_path(const char *path);
-extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
+extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
+extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
extern int index_name_pos(const struct index_state *, const char *name, int namelen);
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
#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 */
+#define ADD_CACHE_KEEP_CACHE_TREE 32 /* Do not invalidate cache-tree */
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
extern int remove_index_entry_at(struct index_state *, int pos);
@@ -474,11 +520,11 @@ extern int remove_file_from_index(struct index_state *, const char *path);
#define ADD_CACHE_IGNORE_ERRORS 4
#define ADD_CACHE_IGNORE_REMOVAL 8
#define ADD_CACHE_INTENT 16
-#define ADD_CACHE_IMPLICIT_DOT 32 /* internal to "git add -u/-A" */
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);
+extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
+extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
extern int index_name_is_other(const struct index_state *, const char *, int);
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
@@ -488,31 +534,13 @@ extern void *read_blob_data_from_index(struct index_state *, const char *, unsig
#define CE_MATCH_RACY_IS_DIRTY 02
/* do stat comparison even if CE_SKIP_WORKTREE is true */
#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
+/* ignore non-existent files during stat update */
+#define CE_MATCH_IGNORE_MISSING 0x08
+/* enable stat refresh */
+#define CE_MATCH_REFRESH 0x10
extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
-
-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;
- int nowildcard_len;
- int flags;
- } *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);
-
-extern int limit_pathspec_to_literal(void);
-
#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);
@@ -540,29 +568,13 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
#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, const char *header_msg);
-
-struct lock_file {
- struct lock_file *next;
- int fd;
- pid_t owner;
- char on_list;
- char filename[PATH_MAX];
-};
-#define LOCK_DIE_ON_ERROR 1
-#define LOCK_NODEREF 2
-extern int unable_to_lock_error(const char *path, int err);
-extern NORETURN void unable_to_lock_index_die(const char *path, int err);
-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 *);
+extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
+
extern void update_index_if_able(struct index_state *, struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
-extern int commit_locked_index(struct lock_file *);
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, int delopt);
/* Environment bits from configuration mechanism */
@@ -590,17 +602,30 @@ extern size_t packed_git_limit;
extern size_t delta_base_cache_limit;
extern unsigned long big_file_threshold;
extern unsigned long pack_size_limit_cfg;
-extern int read_replace_refs;
+
+/*
+ * Do replace refs need to be checked this run? This variable is
+ * initialized to true unless --no-replace-object is used or
+ * $GIT_NO_REPLACE_OBJECTS is set, but is set to false by some
+ * commands that do not want replace references to be active. As an
+ * optimization it is also set to false if replace references have
+ * been sought but there were none.
+ */
+extern int check_replace_refs;
+
extern int fsync_object_files;
extern int core_preload_index;
extern int core_apply_sparse_checkout;
extern int precomposed_unicode;
+extern int protect_hfs;
+extern int protect_ntfs;
/*
* The character that begins a commented line in user-editable file
* that is subject to stripspace.
*/
extern char comment_line_char;
+extern int auto_comment_line_char;
enum branch_track {
BRANCH_TRACK_UNSPECIFIED = -1,
@@ -669,9 +694,28 @@ extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)
extern char *git_path_submodule(const char *path, const char *fmt, ...)
__attribute__((format (printf, 2, 3)));
-extern char *sha1_file_name(const unsigned char *sha1);
+/*
+ * Return the name of the file in the local object database that would
+ * be used to store a loose object with the specified sha1. The
+ * return value is a pointer to a statically allocated buffer that is
+ * overwritten each time the function is called.
+ */
+extern const char *sha1_file_name(const unsigned char *sha1);
+
+/*
+ * Return the name of the (local) packfile with the specified sha1 in
+ * its name. The return value is a pointer to memory that is
+ * overwritten each time this function is called.
+ */
extern char *sha1_pack_name(const unsigned char *sha1);
+
+/*
+ * Return the name of the (local) pack index file with the specified
+ * sha1 in its name. The return value is a pointer to memory that is
+ * overwritten each time this function is called.
+ */
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];
@@ -747,8 +791,29 @@ enum sharedrepo {
};
int git_config_perm(const char *var, const char *value);
int adjust_shared_perm(const char *path);
-int safe_create_leading_directories(char *path);
-int safe_create_leading_directories_const(const char *path);
+
+/*
+ * Create the directory containing the named path, using care to be
+ * somewhat safe against races. Return one of the scld_error values
+ * to indicate success/failure.
+ *
+ * SCLD_VANISHED indicates that one of the ancestor directories of the
+ * path existed at one point during the function call and then
+ * suddenly vanished, probably because another process pruned the
+ * directory while we were working. To be robust against this kind of
+ * race, callers might want to try invoking the function again when it
+ * returns SCLD_VANISHED.
+ */
+enum scld_error {
+ SCLD_OK = 0,
+ SCLD_FAILED = -1,
+ SCLD_PERMS = -2,
+ SCLD_EXISTS = -3,
+ SCLD_VANISHED = -4
+};
+enum scld_error safe_create_leading_directories(char *path);
+enum scld_error safe_create_leading_directories_const(const char *path);
+
int mkdir_in_gitdir(const char *path);
extern void home_config_paths(char **global, char **xdg, char *file);
extern char *expand_user_path(const char *path);
@@ -761,34 +826,56 @@ int is_directory(const char *);
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
const char *absolute_path(const char *path);
+const char *remove_leading_path(const char *in, const char *prefix);
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
int daemon_avoid_alias(const char *path);
-int offset_1st_component(const char *path);
+extern int is_ntfs_dotgit(const char *name);
/* object replacement */
-#define READ_SHA1_FILE_REPLACE 1
+#define LOOKUP_REPLACE_OBJECT 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_extended(sha1, type, size, READ_SHA1_FILE_REPLACE);
+ return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
}
+
+/*
+ * This internal function is only declared here for the benefit of
+ * lookup_replace_object(). Please do not call it directly.
+ */
extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
+
+/*
+ * If object sha1 should be replaced, return the replacement object's
+ * name (replaced recursively, if necessary). The return value is
+ * either sha1 or a pointer to a permanently-allocated value. When
+ * object replacement is suppressed, always return sha1.
+ */
static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
{
- if (!read_replace_refs)
+ if (!check_replace_refs)
return sha1;
return do_lookup_replace_object(sha1);
}
+static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
+{
+ if (!(flag & LOOKUP_REPLACE_OBJECT))
+ return sha1;
+ return 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 *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
+extern int git_open_noatime(const char *name);
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
@@ -801,7 +888,19 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l
extern int move_temp_to_file(const char *tmpfile, const char *filename);
extern int has_sha1_pack(const unsigned char *sha1);
+
+/*
+ * Return true iff we have an object named sha1, whether local or in
+ * an alternate object database, and whether packed or loose. This
+ * function does not respect replace references.
+ */
extern int has_sha1_file(const unsigned char *sha1);
+
+/*
+ * Return true iff an alternate object database has a loose object
+ * with the specified name. This function does not respect replace
+ * references.
+ */
extern int has_loose_object_nonlocal(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1);
@@ -854,8 +953,8 @@ extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
-extern int read_ref_full(const char *refname, unsigned char *sha1,
- int reading, int *flags);
+extern int read_ref_full(const char *refname, int resolve_flags,
+ unsigned char *sha1, int *flags);
extern int read_ref(const char *refname, unsigned char *sha1);
/*
@@ -867,45 +966,68 @@ extern int read_ref(const char *refname, unsigned char *sha1);
* or the input ref.
*
* If the reference cannot be resolved to an object, the behavior
- * depends on the "reading" argument:
+ * depends on the RESOLVE_REF_READING flag:
*
- * - If reading is set, return NULL.
+ * - If RESOLVE_REF_READING is set, return NULL.
*
- * - If reading is not set, clear sha1 and return the name of the last
- * reference name in the chain, which will either be a non-symbolic
+ * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
+ * the last reference name in the chain, which will either be a non-symbolic
* reference or an undefined reference. If this is a prelude to
* "writing" to the ref, the return value is the name of the ref
* that will actually be created or changed.
*
- * If flag is non-NULL, set the value that it points to the
+ * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
+ * level of symbolic reference. The value stored in sha1 for a symbolic
+ * reference will always be null_sha1 in this case, and the return
+ * value is the reference that the symref refers to directly.
+ *
+ * If flags is non-NULL, set the value that it points to the
* combination of REF_ISPACKED (if the reference was found among the
- * packed references) and REF_ISSYMREF (if the initial reference was a
- * symbolic reference).
+ * packed references), REF_ISSYMREF (if the initial reference was a
+ * symbolic reference), REF_BAD_NAME (if the reference name is ill
+ * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
+ * (if the ref is malformed or has a bad name). See refs.h for more detail
+ * on each flag.
*
* If ref is not a properly-formatted, normalized reference, return
* NULL. If more than MAXDEPTH recursive symbolic lookups are needed,
* give up and return NULL.
*
- * errno is sometimes set on errors, but not always.
+ * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
+ * name is invalid according to git-check-ref-format(1). If the name
+ * is bad then the value stored in sha1 will be null_sha1 and the two
+ * flags REF_ISBROKEN and REF_BAD_NAME will be set.
+ *
+ * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
+ * directory and do not consist of all caps and underscores cannot be
+ * resolved. The function returns NULL for such ref names.
+ * Caps and underscores refers to the special refs, such as HEAD,
+ * FETCH_HEAD and friends, that all live outside of the refs/ directory.
*/
-extern const char *resolve_ref_unsafe(const char *ref, unsigned char *sha1, int reading, int *flag);
-extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
+#define RESOLVE_REF_READING 0x01
+#define RESOLVE_REF_NO_RECURSE 0x02
+#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
+extern const char *resolve_ref_unsafe(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
+extern char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
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_branch_name(const char *str, struct strbuf *);
+extern int interpret_branch_name(const char *str, int len, struct strbuf *);
extern int get_sha1_mb(const char *str, unsigned char *sha1);
-extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
-extern const char *ref_rev_parse_rules[];
-#define ref_fetch_rules ref_rev_parse_rules
+/*
+ * Return true iff abbrev_name is a possible abbreviation for
+ * full_name according to the rules defined by ref_rev_parse_rules in
+ * refs.c.
+ */
+extern int refname_match(const char *abbrev_name, const char *full_name);
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
extern int validate_headref(const char *ref);
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
-extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
+extern int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
extern void *read_object_with_reference(const unsigned char *sha1,
@@ -922,6 +1044,7 @@ enum date_mode {
DATE_SHORT,
DATE_LOCAL,
DATE_ISO8601,
+ DATE_ISO8601_STRICT,
DATE_RFC2822,
DATE_RAW
};
@@ -929,14 +1052,15 @@ enum date_mode {
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
void show_date_relative(unsigned long time, int tz, const struct timeval *now,
struct strbuf *timebuf);
-int parse_date(const char *date, char *buf, int bufsize);
+int parse_date(const char *date, struct strbuf *out);
int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
int parse_expiry_date(const char *date, unsigned long *timestamp);
-void datestamp(char *buf, int bufsize);
+void datestamp(struct strbuf *out);
#define approxidate(s) approxidate_careful((s), NULL)
unsigned long approxidate_careful(const char *, int *);
unsigned long approxidate_relative(const char *date, const struct timeval *now);
enum date_mode parse_date_format(const char *format);
+int date_overflows(unsigned long date);
#define IDENT_STRICT 1
#define IDENT_NO_DATE 2
@@ -945,6 +1069,7 @@ extern const char *git_author_info(int);
extern const char *git_committer_info(int);
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
extern const char *fmt_name(const char *name, const char *email);
+extern const char *ident_default_name(void);
extern const char *ident_default_email(void);
extern const char *git_editor(void);
extern const char *git_pager(int stdout_is_tty);
@@ -967,6 +1092,13 @@ struct ident_split {
extern int split_ident_line(struct ident_split *, const char *, int);
/*
+ * Like show_date, but pull the timestamp and tz parameters from
+ * the ident_split. It will also sanity-check the values and produce
+ * a well-known sentinel date if they appear bogus.
+ */
+const char *show_ident_date(const struct ident_split *id, enum date_mode mode);
+
+/*
* Compare split idents for equality or strict ordering. Note that we
* compare only the ident part of the line, ignoring any timestamp.
*
@@ -976,6 +1108,7 @@ extern int split_ident_line(struct ident_split *, const char *, int);
extern int ident_cmp(const struct ident_split *, const struct ident_split *);
struct checkout {
+ struct index_state *istate;
const char *base_dir;
int base_dir_len;
unsigned force:1,
@@ -984,15 +1117,20 @@ struct checkout {
refresh_cache:1;
};
+#define TEMPORARY_FILENAME_LENGTH 25
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
struct cache_def {
- char path[PATH_MAX + 1];
- int len;
+ struct strbuf path;
int flags;
int track_flags;
int prefix_len_stat_func;
};
+#define CACHE_DEF_INIT { STRBUF_INIT, 0, 0, 0 }
+static inline void cache_def_clear(struct cache_def *cache)
+{
+ strbuf_release(&cache->path);
+}
extern int has_symlink_leading_path(const char *name, int len);
extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
@@ -1010,7 +1148,7 @@ extern void prepare_alt_odb(void);
extern void read_info_alternates(const char * relative_base, int depth);
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*);
+extern int foreach_alt_odb(alt_odb_fn, void*);
struct pack_window {
struct pack_window *next;
@@ -1047,67 +1185,6 @@ struct pack_entry {
struct packed_git *p;
};
-struct ref {
- struct ref *next;
- unsigned char old_sha1[20];
- unsigned char new_sha1[20];
- char *symref;
- unsigned int
- force:1,
- forced_update:1,
- deletion:1,
- matched:1;
-
- /*
- * Order is important here, as we write to FETCH_HEAD
- * in numeric order. And the default NOT_FOR_MERGE
- * should be 0, so that xcalloc'd structures get it
- * by default.
- */
- enum {
- FETCH_HEAD_MERGE = -1,
- FETCH_HEAD_NOT_FOR_MERGE = 0,
- FETCH_HEAD_IGNORE = 1
- } fetch_head_status;
-
- enum {
- REF_STATUS_NONE = 0,
- REF_STATUS_OK,
- REF_STATUS_REJECT_NONFASTFORWARD,
- REF_STATUS_REJECT_ALREADY_EXISTS,
- REF_STATUS_REJECT_NODELETE,
- REF_STATUS_REJECT_FETCH_FIRST,
- REF_STATUS_REJECT_NEEDS_FORCE,
- REF_STATUS_UPTODATE,
- REF_STATUS_REMOTE_REJECT,
- REF_STATUS_EXPECTING_REPORT
- } status;
- char *remote_status;
- struct ref *peer_ref; /* when renaming */
- char name[FLEX_ARRAY]; /* more */
-};
-
-#define REF_NORMAL (1u << 0)
-#define REF_HEADS (1u << 1)
-#define REF_TAGS (1u << 2)
-
-extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
-
-#define CONNECT_VERBOSE (1u << 0)
-extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
-extern int finish_connect(struct child_process *conn);
-extern int git_connection_is_socket(struct child_process *conn);
-struct extra_have_objects {
- int nr, alloc;
- unsigned char (*array)[20];
-};
-extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
- struct ref **list, unsigned int flags,
- struct extra_have_objects *);
-extern int server_supports(const char *feature);
-extern int parse_feature_request(const char *features, const char *feature);
-extern const char *server_feature_value(const char *feature, int *len_ret);
-
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
/* A hook for count-objects to report invalid files in pack directory */
@@ -1121,28 +1198,102 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
struct packed_git *packs);
extern void pack_report(void);
+
+/*
+ * mmap the index file for the specified packfile (if it is not
+ * already mmapped). Return 0 on success.
+ */
extern int open_pack_index(struct packed_git *);
+
+/*
+ * munmap the index file for the specified packfile (if it is
+ * currently mmapped).
+ */
extern void close_pack_index(struct packed_git *);
+
extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
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 *);
+
+/*
+ * Return the SHA-1 of the nth object within the specified packfile.
+ * Open the index if it is not already open. The return value points
+ * at the SHA-1 within the mmapped index. Return NULL if there is an
+ * error.
+ */
+extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t n);
+
+/*
+ * Return the offset of the nth object within the specified packfile.
+ * The index must already be opened.
+ */
+extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
+
+/*
+ * If the object named sha1 is present in the specified packfile,
+ * return its offset within the packfile; otherwise, return 0.
+ */
+extern off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *);
+
extern int is_pack_valid(struct packed_git *);
extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
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 int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *);
+/*
+ * Iterate over the files in the loose-object parts of the object
+ * directory "path", triggering the following callbacks:
+ *
+ * - loose_object is called for each loose object we find.
+ *
+ * - loose_cruft is called for any files that do not appear to be
+ * loose objects. Note that we only look in the loose object
+ * directories "objects/[0-9a-f]{2}/", so we will not report
+ * "objects/foobar" as cruft.
+ *
+ * - loose_subdir is called for each top-level hashed subdirectory
+ * of the object directory (e.g., "$OBJDIR/f0"). It is called
+ * after the objects in the directory are processed.
+ *
+ * Any callback that is NULL will be ignored. Callbacks returning non-zero
+ * will end the iteration.
+ */
+typedef int each_loose_object_fn(const unsigned char *sha1,
+ const char *path,
+ void *data);
+typedef int each_loose_cruft_fn(const char *basename,
+ const char *path,
+ void *data);
+typedef int each_loose_subdir_fn(int nr,
+ const char *path,
+ void *data);
+int for_each_loose_file_in_objdir(const char *path,
+ each_loose_object_fn obj_cb,
+ each_loose_cruft_fn cruft_cb,
+ each_loose_subdir_fn subdir_cb,
+ void *data);
+
+/*
+ * Iterate over loose and packed objects in both the local
+ * repository and any alternates repositories.
+ */
+typedef int each_packed_object_fn(const unsigned char *sha1,
+ struct packed_git *pack,
+ uint32_t pos,
+ void *data);
+extern int for_each_loose_object(each_loose_object_fn, void *);
+extern int for_each_packed_object(each_packed_object_fn, void *);
+
struct object_info {
/* Request */
enum object_type *typep;
unsigned long *sizep;
unsigned long *disk_sizep;
+ unsigned char *delta_base_sha1;
/* Response */
enum {
@@ -1167,7 +1318,7 @@ struct object_info {
} packed;
} u;
};
-extern int sha1_object_info_extended(const unsigned char *, struct object_info *);
+extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
/* Dumb servers support */
extern int update_server_info(int);
@@ -1183,6 +1334,14 @@ extern int update_server_info(int);
#define CONFIG_INVALID_PATTERN 6
#define CONFIG_GENERIC_ERROR 7
+#define CONFIG_REGEX_NONE ((void *)1)
+
+struct git_config_source {
+ unsigned int use_stdin:1;
+ const char *file;
+ const char *blob;
+};
+
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 *);
@@ -1190,14 +1349,14 @@ extern int git_config_from_buf(config_fn_t fn, const char *name,
const char *buf, size_t len, void *data);
extern void git_config_push_parameter(const char *text);
extern int git_config_from_parameters(config_fn_t fn, void *data);
-extern int git_config(config_fn_t fn, void *);
+extern void git_config(config_fn_t fn, void *);
extern int git_config_with_options(config_fn_t fn, void *,
- const char *filename,
- const char *blob_ref,
+ struct git_config_source *config_source,
int respect_includes);
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
+extern int64_t git_config_int64(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
extern int git_config_bool_or_int(const char *, const char *, int *);
extern int git_config_bool(const char *, const char *);
@@ -1214,10 +1373,11 @@ extern int git_config_rename_section_in_file(const char *, const char *, const c
extern const char *git_etc_gitconfig(void);
extern int check_repository_format_version(const char *var, const char *value, void *cb);
extern int git_env_bool(const char *, int);
+extern unsigned long git_env_ulong(const char *, unsigned long);
extern int git_config_system(void);
extern int config_error_nonbool(const char *);
-#if defined(__GNUC__) && ! defined(__clang__)
-#define config_error_nonbool(s) (config_error_nonbool(s), -1)
+#if defined(__GNUC__)
+#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
#endif
extern const char *get_log_output_encoding(void);
extern const char *get_commit_output_encoding(void);
@@ -1247,6 +1407,69 @@ extern int parse_config_key(const char *var,
const char **subsection, int *subsection_len,
const char **key);
+struct config_set_element {
+ struct hashmap_entry ent;
+ char *key;
+ struct string_list value_list;
+};
+
+struct configset_list_item {
+ struct config_set_element *e;
+ int value_index;
+};
+
+/*
+ * the contents of the list are ordered according to their
+ * position in the config files and order of parsing the files.
+ * (i.e. key-value pair at the last position of .git/config will
+ * be at the last item of the list)
+ */
+struct configset_list {
+ struct configset_list_item *items;
+ unsigned int nr, alloc;
+};
+
+struct config_set {
+ struct hashmap config_hash;
+ int hash_initialized;
+ struct configset_list list;
+};
+
+extern void git_configset_init(struct config_set *cs);
+extern int git_configset_add_file(struct config_set *cs, const char *filename);
+extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
+extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
+extern void git_configset_clear(struct config_set *cs);
+extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
+extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
+extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
+extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
+extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
+extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
+extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
+extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
+
+extern int git_config_get_value(const char *key, const char **value);
+extern const struct string_list *git_config_get_value_multi(const char *key);
+extern void git_config_clear(void);
+extern void git_config_iter(config_fn_t fn, void *data);
+extern int git_config_get_string_const(const char *key, const char **dest);
+extern int git_config_get_string(const char *key, char **dest);
+extern int git_config_get_int(const char *key, int *dest);
+extern int git_config_get_ulong(const char *key, unsigned long *dest);
+extern int git_config_get_bool(const char *key, int *dest);
+extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+extern int git_config_get_maybe_bool(const char *key, int *dest);
+extern int git_config_get_pathname(const char *key, const char **dest);
+
+struct key_value_info {
+ const char *filename;
+ int linenr;
+};
+
+extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
+
extern int committer_ident_sufficiently_given(void);
extern int author_ident_sufficiently_given(void);
@@ -1257,6 +1480,8 @@ extern const char *git_mailmap_blob;
/* IO helper functions */
extern void maybe_flush_or_die(FILE *, const char *);
+__attribute__((format (printf, 2, 3)))
+extern void fprintf_or_die(FILE *, const char *fmt, ...);
extern int copy_fd(int ifd, int ofd);
extern int copy_file(const char *dst, const char *src, int mode);
extern int copy_file_with_time(const char *dst, const char *src, int mode);
@@ -1267,6 +1492,8 @@ extern void fsync_or_die(int fd, const char *);
extern ssize_t read_in_full(int fd, void *buf, size_t count);
extern ssize_t write_in_full(int fd, const void *buf, size_t count);
+extern ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
+
static inline ssize_t write_str_in_full(int fd, const char *str)
{
return write_in_full(fd, str, strlen(str));
@@ -1296,16 +1523,9 @@ extern void *alloc_commit_node(void);
extern void *alloc_tag_node(void);
extern void *alloc_object_node(void);
extern void alloc_report(void);
+extern unsigned int alloc_commit_index(void);
-/* trace.c */
-__attribute__((format (printf, 1, 2)))
-extern void trace_printf(const char *format, ...);
-__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);
-
+/* pkt-line.c */
void packet_trace_identity(const char *prog);
/* add */
@@ -1313,7 +1533,7 @@ void packet_trace_identity(const char *prog);
* return 0 if success, 1 - if addition of a file failed and
* ADD_FILES_IGNORE_ERRORS was specified in flags
*/
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags);
+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
/* diff.c */
extern int diff_auto_refresh_index;
@@ -1347,7 +1567,7 @@ extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
/* ls-files */
-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix);
+int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);
void overlay_tree_on_cache(const char *tree_name, const char *prefix);
char *alias_lookup(const char *alias);
@@ -1401,4 +1621,6 @@ int stat_validity_check(struct stat_validity *sv, const char *path);
*/
void stat_validity_update(struct stat_validity *sv, int fd);
+int versioncmp(const char *s1, const char *s2);
+
#endif /* CACHE_H */