From 487884a9306e744eaebe659a7d0edb1c0c6c7ba7 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 13 May 2013 16:07:29 -0700 Subject: [PATCH 1/4] Improve docs for git_index_entry flag masks The constants for extracting data from git_index_entry flags and flags_extended are not named in a way that makes it easy to know where to use each one. This improves the docs for the flags (and slightly reorganizes them), so it should be more obvious. --- include/git2/index.h | 58 ++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/include/git2/index.h b/include/git2/index.h index bde38a9dd..42cc4d640 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -21,18 +21,44 @@ */ GIT_BEGIN_DECL +/** + * Bitmasks for on-disk fields of `git_index_entry` `flags` + * + * These bitmasks match the four fields in the `git_index_entry` `flags` + * value both in memory and on disk. You can use them to interpret the + * data in the `flags`. + */ #define GIT_IDXENTRY_NAMEMASK (0x0fff) #define GIT_IDXENTRY_STAGEMASK (0x3000) #define GIT_IDXENTRY_EXTENDED (0x4000) #define GIT_IDXENTRY_VALID (0x8000) #define GIT_IDXENTRY_STAGESHIFT 12 -/* - * Flags are divided into two parts: in-memory flags and - * on-disk ones. Flags in GIT_IDXENTRY_EXTENDED_FLAGS - * will get saved on-disk. +/** + * Bitmasks for on-disk fields of `git_index_entry` `flags_extended` * - * In-memory only flags: + * In memory, the `flags_extended` fields are divided into two parts: the + * fields that are read from and written to disk, and other fields that + * in-memory only and used by libgit2. Only the flags in + * `GIT_IDXENTRY_EXTENDED_FLAGS` will get saved on-disk. + * + * These bitmasks match the three fields in the `git_index_entry` + * `flags_extended` value that belong on disk. You can use them to + * interpret the data in the `flags_extended`. + */ +#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13) +#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14) +/* GIT_IDXENTRY_EXTENDED2 is reserved for future extension */ +#define GIT_IDXENTRY_EXTENDED2 (1 << 15) + +#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) + +/** + * Bitmasks for in-memory only fields of `git_index_entry` `flags_extended` + * + * These bitmasks match the other fields in the `git_index_entry` + * `flags_extended` value that are only used in-memory by libgit2. You + * can use them to interpret the data in the `flags_extended`. */ #define GIT_IDXENTRY_UPDATE (1 << 0) #define GIT_IDXENTRY_REMOVE (1 << 1) @@ -47,15 +73,6 @@ GIT_BEGIN_DECL #define GIT_IDXENTRY_UNPACKED (1 << 8) #define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) -/* - * Extended on-disk flags: - */ -#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13) -#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14) -/* GIT_IDXENTRY_EXTENDED2 is for future extension */ -#define GIT_IDXENTRY_EXTENDED2 (1 << 15) - -#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) #define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) @@ -87,12 +104,12 @@ typedef struct git_index_entry { } git_index_entry; /** Capabilities of system that affect index actions. */ -enum { +typedef enum { GIT_INDEXCAP_IGNORE_CASE = 1, GIT_INDEXCAP_NO_FILEMODE = 2, GIT_INDEXCAP_NO_SYMLINKS = 4, GIT_INDEXCAP_FROM_OWNER = ~0u -}; +} git_indexcap_t; /** @name Index File Functions * @@ -429,7 +446,7 @@ GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *pat * @return 0 or an error code */ GIT_EXTERN(int) git_index_conflict_add( - git_index *index, + git_index *index, const git_index_entry *ancestor_entry, const git_index_entry *our_entry, const git_index_entry *their_entry); @@ -447,7 +464,12 @@ GIT_EXTERN(int) git_index_conflict_add( * @param index an existing index object * @param path path to search */ -GIT_EXTERN(int) git_index_conflict_get(git_index_entry **ancestor_out, git_index_entry **our_out, git_index_entry **their_out, git_index *index, const char *path); +GIT_EXTERN(int) git_index_conflict_get( + git_index_entry **ancestor_out, + git_index_entry **our_out, + git_index_entry **their_out, + git_index *index, + const char *path); /** * Removes the index entries that represent a conflict of a single file. From 797dfb28fea6a3db542dc32d11a530570e147b73 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 13 May 2013 16:09:33 -0700 Subject: [PATCH 2/4] Add APIs to dup and free git_index_entrys This adds git_index_entry_dup to make a copy of an existing entry and git_index_entry_free to release the memory of the copy. It also updates the documentation for git_index_get_bypath and git_index_get_byindex to make it clear that the returned structure should *not* be modified. --- include/git2/index.h | 48 ++++++++++++++++++++++++++++++---------- src/index.c | 45 +++++++++++++++++++++++++++++++++++++ tests-clar/index/tests.c | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 12 deletions(-) diff --git a/include/git2/index.h b/include/git2/index.h index 42cc4d640..cfb55ae5b 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -73,6 +73,8 @@ GIT_BEGIN_DECL #define GIT_IDXENTRY_UNPACKED (1 << 8) #define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) +#define GIT_IDXENTRY_ALLOCATED (1 << 10) +#define GIT_IDXENTRY_ALLOCATED_PATH (1 << 11) #define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) @@ -284,11 +286,9 @@ GIT_EXTERN(void) git_index_clear(git_index *index); /** * Get a pointer to one of the entries in the index * - * The values of this entry can be modified (except the path) - * and the changes will be written back to disk on the next - * write() call. - * - * The entry should not be freed by the caller. + * The entry is not modifiable and should not be freed. If you need a + * permanent copy of the entry, use `git_index_entry_dup()` (after which + * you will be responsible for calling `git_index_entry_free()`) * * @param index an existing index object * @param n the position of the entry @@ -300,11 +300,9 @@ GIT_EXTERN(const git_index_entry *) git_index_get_byindex( /** * Get a pointer to one of the entries in the index * - * The values of this entry can be modified (except the path) - * and the changes will be written back to disk on the next - * write() call. - * - * The entry should not be freed by the caller. + * The entry is not modifiable and should not be freed. If you need a + * permanent copy of the entry, use `git_index_entry_dup()` (after which + * you will be responsible for calling `git_index_entry_free()`). * * @param index an existing index object * @param path path to search @@ -354,8 +352,7 @@ GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_en /** * Return the stage number from a git index entry * - * This entry is calculated from the entry's flag - * attribute like this: + * This entry is calculated from the entry's flag attribute like this: * * (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT * @@ -364,6 +361,33 @@ GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_en */ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry); +/** + * Make a copy of an entry that you can keep + * + * The `git_index_entry` pointers that are returned by the accessor + * functions are `const git_index_entry *` so they can't be modified + * and their lifetime as objects matches that of the `git_index`. + * + * This function allows you to make a copy of those entries that can + * be modified and which you are responsible for freeing. + * + * @param entry The entry to be copied + * @returns Newly allocated entry (or NULL if allocation failure) + */ +GIT_EXTERN(git_index_entry *) git_index_entry_dup(const git_index_entry *entry); + +/** + * Release the memory for a git_index_entry + * + * You should only call this on `git_index_entry` objects that you have + * obtained through `git_index_entry_dup()`. It is an error to call this + * on the values returned by `git_index_get_byindex()` or + * `git_index_get_bypath()`. + * + * @param entry The entry to be freed + */ +GIT_EXTERN(void) git_index_entry_free(git_index_entry *entry); + /**@}*/ /** @name Workdir Index Entry Functions diff --git a/src/index.c b/src/index.c index f767dfab7..f68c81769 100644 --- a/src/index.c +++ b/src/index.c @@ -550,6 +550,51 @@ const git_index_entry *git_index_get_bypath( return git_index_get_byindex(index, pos); } +typedef struct { + git_index_entry entry; + char pathdata[GIT_FLEX_ARRAY]; +} git_index_entry_with_path; + +git_index_entry *git_index_entry_dup(const git_index_entry *src) +{ + git_index_entry_with_path *tgt; + size_t pathlen; + + if (!src) + return NULL; + + pathlen = strlen(src->path); + + tgt = git__calloc(sizeof(git_index_entry_with_path) + pathlen + 1, 1); + if (!tgt) + return NULL; + + memcpy(&tgt->entry, src, sizeof(tgt->entry)); + tgt->entry.flags_extended |= GIT_IDXENTRY_ALLOCATED; + + memcpy(tgt->pathdata, src->path, pathlen + 1); + tgt->entry.path = tgt->pathdata; + + return (git_index_entry *)tgt; +} + +void git_index_entry_free(git_index_entry *entry) +{ + assert(entry); + + if (!(entry->flags_extended & GIT_IDXENTRY_ALLOCATED)) + return; + + if ((entry->flags_extended & GIT_IDXENTRY_ALLOCATED_PATH) != 0 && + entry->path != ((git_index_entry_with_path *)entry)->pathdata) + git__free(entry->path); + + /* ward off accidental double free */ + entry->flags_extended = (entry->flags_extended & ~GIT_IDXENTRY_ALLOCATED); + + git__free(entry); +} + void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st) { entry->ctime.seconds = (git_time_t)st->st_ctime; diff --git a/tests-clar/index/tests.c b/tests-clar/index/tests.c index 88e374e6e..565f11073 100644 --- a/tests-clar/index/tests.c +++ b/tests-clar/index/tests.c @@ -416,3 +416,51 @@ void test_index_tests__remove_directory(void) git_repository_free(repo); cl_fixture_cleanup("index_test"); } + +void test_index_tests__dup_and_free_entries(void) +{ + git_repository *repo; + git_index *index; + const git_index_entry *entry; + git_index_entry *dup1, *dup2; + + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(entry = git_index_get_bypath(index, "COPYING", 0)); + cl_assert((entry->flags_extended & GIT_IDXENTRY_ALLOCATED) == 0); + + cl_assert(dup1 = git_index_entry_dup(entry)); + cl_assert((dup1->flags_extended & GIT_IDXENTRY_ALLOCATED) != 0); + + cl_assert_equal_s(entry->path, dup1->path); + cl_assert(git_oid_equal(&entry->oid, &dup1->oid)); + + cl_assert(entry = git_index_get_byindex(index, 0)); + cl_assert((entry->flags_extended & GIT_IDXENTRY_ALLOCATED) == 0); + + cl_assert(dup2 = git_index_entry_dup(entry)); + cl_assert((dup2->flags_extended & GIT_IDXENTRY_ALLOCATED) != 0); + + cl_assert_equal_s(entry->path, dup2->path); + cl_assert(git_oid_equal(&entry->oid, &dup2->oid)); + + git_index_free(index); + git_repository_free(repo); + + /* entry is no longer pointing to valid memory, but dup1 and dup2 are */ + + cl_assert_equal_s("COPYING", dup1->path); + git_index_entry_free(dup1); + + cl_assert_equal_s(".HEADER", dup2->path); + + /* what would a binding that wanted to set the path do? */ + dup2->path = git__strdup("newpath"); + dup2->flags_extended |= GIT_IDXENTRY_ALLOCATED_PATH; + git_index_entry_free(dup2); + + /* at this point there should be no memory leaks nor double-frees in + * this function; that will have to be checked by an external tool. + */ +} From 96c01991c166a25d8906c031422f4215edeb8ba0 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 15 May 2013 09:24:51 -0700 Subject: [PATCH 3/4] Remove entry dup/free functions and fix comments This removes the functions to duplicate and free copies of a git_index_entry and updates the comments to explain that you should just use the public definition of the struct as needed. --- include/git2/index.h | 46 +++++++------------------------------- src/index.c | 45 ------------------------------------- tests-clar/index/tests.c | 48 ---------------------------------------- 3 files changed, 8 insertions(+), 131 deletions(-) diff --git a/include/git2/index.h b/include/git2/index.h index cfb55ae5b..d6aa183b4 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -34,6 +34,8 @@ GIT_BEGIN_DECL #define GIT_IDXENTRY_VALID (0x8000) #define GIT_IDXENTRY_STAGESHIFT 12 +#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) + /** * Bitmasks for on-disk fields of `git_index_entry` `flags_extended` * @@ -73,11 +75,6 @@ GIT_BEGIN_DECL #define GIT_IDXENTRY_UNPACKED (1 << 8) #define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) -#define GIT_IDXENTRY_ALLOCATED (1 << 10) -#define GIT_IDXENTRY_ALLOCATED_PATH (1 << 11) - -#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) - /** Time used in a git index entry */ typedef struct { git_time_t seconds; @@ -286,9 +283,9 @@ GIT_EXTERN(void) git_index_clear(git_index *index); /** * Get a pointer to one of the entries in the index * - * The entry is not modifiable and should not be freed. If you need a - * permanent copy of the entry, use `git_index_entry_dup()` (after which - * you will be responsible for calling `git_index_entry_free()`) + * The entry is not modifiable and should not be freed. Because the + * `git_index_entry` struct is a publicly defined struct, you should + * be able to make your own permanent copy of the data if necessary. * * @param index an existing index object * @param n the position of the entry @@ -300,9 +297,9 @@ GIT_EXTERN(const git_index_entry *) git_index_get_byindex( /** * Get a pointer to one of the entries in the index * - * The entry is not modifiable and should not be freed. If you need a - * permanent copy of the entry, use `git_index_entry_dup()` (after which - * you will be responsible for calling `git_index_entry_free()`). + * The entry is not modifiable and should not be freed. Because the + * `git_index_entry` struct is a publicly defined struct, you should + * be able to make your own permanent copy of the data if necessary. * * @param index an existing index object * @param path path to search @@ -361,33 +358,6 @@ GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_en */ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry); -/** - * Make a copy of an entry that you can keep - * - * The `git_index_entry` pointers that are returned by the accessor - * functions are `const git_index_entry *` so they can't be modified - * and their lifetime as objects matches that of the `git_index`. - * - * This function allows you to make a copy of those entries that can - * be modified and which you are responsible for freeing. - * - * @param entry The entry to be copied - * @returns Newly allocated entry (or NULL if allocation failure) - */ -GIT_EXTERN(git_index_entry *) git_index_entry_dup(const git_index_entry *entry); - -/** - * Release the memory for a git_index_entry - * - * You should only call this on `git_index_entry` objects that you have - * obtained through `git_index_entry_dup()`. It is an error to call this - * on the values returned by `git_index_get_byindex()` or - * `git_index_get_bypath()`. - * - * @param entry The entry to be freed - */ -GIT_EXTERN(void) git_index_entry_free(git_index_entry *entry); - /**@}*/ /** @name Workdir Index Entry Functions diff --git a/src/index.c b/src/index.c index f68c81769..f767dfab7 100644 --- a/src/index.c +++ b/src/index.c @@ -550,51 +550,6 @@ const git_index_entry *git_index_get_bypath( return git_index_get_byindex(index, pos); } -typedef struct { - git_index_entry entry; - char pathdata[GIT_FLEX_ARRAY]; -} git_index_entry_with_path; - -git_index_entry *git_index_entry_dup(const git_index_entry *src) -{ - git_index_entry_with_path *tgt; - size_t pathlen; - - if (!src) - return NULL; - - pathlen = strlen(src->path); - - tgt = git__calloc(sizeof(git_index_entry_with_path) + pathlen + 1, 1); - if (!tgt) - return NULL; - - memcpy(&tgt->entry, src, sizeof(tgt->entry)); - tgt->entry.flags_extended |= GIT_IDXENTRY_ALLOCATED; - - memcpy(tgt->pathdata, src->path, pathlen + 1); - tgt->entry.path = tgt->pathdata; - - return (git_index_entry *)tgt; -} - -void git_index_entry_free(git_index_entry *entry) -{ - assert(entry); - - if (!(entry->flags_extended & GIT_IDXENTRY_ALLOCATED)) - return; - - if ((entry->flags_extended & GIT_IDXENTRY_ALLOCATED_PATH) != 0 && - entry->path != ((git_index_entry_with_path *)entry)->pathdata) - git__free(entry->path); - - /* ward off accidental double free */ - entry->flags_extended = (entry->flags_extended & ~GIT_IDXENTRY_ALLOCATED); - - git__free(entry); -} - void git_index_entry__init_from_stat(git_index_entry *entry, struct stat *st) { entry->ctime.seconds = (git_time_t)st->st_ctime; diff --git a/tests-clar/index/tests.c b/tests-clar/index/tests.c index 565f11073..88e374e6e 100644 --- a/tests-clar/index/tests.c +++ b/tests-clar/index/tests.c @@ -416,51 +416,3 @@ void test_index_tests__remove_directory(void) git_repository_free(repo); cl_fixture_cleanup("index_test"); } - -void test_index_tests__dup_and_free_entries(void) -{ - git_repository *repo; - git_index *index; - const git_index_entry *entry; - git_index_entry *dup1, *dup2; - - cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - cl_git_pass(git_repository_index(&index, repo)); - - cl_assert(entry = git_index_get_bypath(index, "COPYING", 0)); - cl_assert((entry->flags_extended & GIT_IDXENTRY_ALLOCATED) == 0); - - cl_assert(dup1 = git_index_entry_dup(entry)); - cl_assert((dup1->flags_extended & GIT_IDXENTRY_ALLOCATED) != 0); - - cl_assert_equal_s(entry->path, dup1->path); - cl_assert(git_oid_equal(&entry->oid, &dup1->oid)); - - cl_assert(entry = git_index_get_byindex(index, 0)); - cl_assert((entry->flags_extended & GIT_IDXENTRY_ALLOCATED) == 0); - - cl_assert(dup2 = git_index_entry_dup(entry)); - cl_assert((dup2->flags_extended & GIT_IDXENTRY_ALLOCATED) != 0); - - cl_assert_equal_s(entry->path, dup2->path); - cl_assert(git_oid_equal(&entry->oid, &dup2->oid)); - - git_index_free(index); - git_repository_free(repo); - - /* entry is no longer pointing to valid memory, but dup1 and dup2 are */ - - cl_assert_equal_s("COPYING", dup1->path); - git_index_entry_free(dup1); - - cl_assert_equal_s(".HEADER", dup2->path); - - /* what would a binding that wanted to set the path do? */ - dup2->path = git__strdup("newpath"); - dup2->flags_extended |= GIT_IDXENTRY_ALLOCATED_PATH; - git_index_entry_free(dup2); - - /* at this point there should be no memory leaks nor double-frees in - * this function; that will have to be checked by an external tool. - */ -} From 89251b283b8dd0bba2062519d9f3f1b212f8a7a8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 15 May 2013 16:25:11 -0700 Subject: [PATCH 4/4] Update index.h docs Move the git_index_entry to the very top, since it provides the main structure that needs to be understood by the reader, then move the bitmasks for the flags and the flags_extended under that since they are details for looking at particular fields of the structure. --- include/git2/index.h | 127 ++++++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 56 deletions(-) diff --git a/include/git2/index.h b/include/git2/index.h index d6aa183b4..8a1ccce55 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -21,68 +21,29 @@ */ GIT_BEGIN_DECL -/** - * Bitmasks for on-disk fields of `git_index_entry` `flags` - * - * These bitmasks match the four fields in the `git_index_entry` `flags` - * value both in memory and on disk. You can use them to interpret the - * data in the `flags`. - */ -#define GIT_IDXENTRY_NAMEMASK (0x0fff) -#define GIT_IDXENTRY_STAGEMASK (0x3000) -#define GIT_IDXENTRY_EXTENDED (0x4000) -#define GIT_IDXENTRY_VALID (0x8000) -#define GIT_IDXENTRY_STAGESHIFT 12 - -#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) - -/** - * Bitmasks for on-disk fields of `git_index_entry` `flags_extended` - * - * In memory, the `flags_extended` fields are divided into two parts: the - * fields that are read from and written to disk, and other fields that - * in-memory only and used by libgit2. Only the flags in - * `GIT_IDXENTRY_EXTENDED_FLAGS` will get saved on-disk. - * - * These bitmasks match the three fields in the `git_index_entry` - * `flags_extended` value that belong on disk. You can use them to - * interpret the data in the `flags_extended`. - */ -#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13) -#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14) -/* GIT_IDXENTRY_EXTENDED2 is reserved for future extension */ -#define GIT_IDXENTRY_EXTENDED2 (1 << 15) - -#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) - -/** - * Bitmasks for in-memory only fields of `git_index_entry` `flags_extended` - * - * These bitmasks match the other fields in the `git_index_entry` - * `flags_extended` value that are only used in-memory by libgit2. You - * can use them to interpret the data in the `flags_extended`. - */ -#define GIT_IDXENTRY_UPDATE (1 << 0) -#define GIT_IDXENTRY_REMOVE (1 << 1) -#define GIT_IDXENTRY_UPTODATE (1 << 2) -#define GIT_IDXENTRY_ADDED (1 << 3) - -#define GIT_IDXENTRY_HASHED (1 << 4) -#define GIT_IDXENTRY_UNHASHED (1 << 5) -#define GIT_IDXENTRY_WT_REMOVE (1 << 6) /* remove in work directory */ -#define GIT_IDXENTRY_CONFLICTED (1 << 7) - -#define GIT_IDXENTRY_UNPACKED (1 << 8) -#define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) - -/** Time used in a git index entry */ +/** Time structure used in a git index entry */ typedef struct { git_time_t seconds; /* nsec should not be stored as time_t compatible */ unsigned int nanoseconds; } git_index_time; -/** Memory representation of a file entry in the index. */ +/** + * In-memory representation of a file entry in the index. + * + * This is a public structure that represents a file entry in the index. + * The meaning of the fields corresponds to core Git's documentation (in + * "Documentation/technical/index-format.txt"). + * + * The `flags` field consists of a number of bit fields which can be + * accessed via the first set of `GIT_IDXENTRY_...` bitmasks below. These + * flags are all read from and persisted to disk. + * + * The `flags_extended` field also has a number of bit fields which can be + * accessed via the later `GIT_IDXENTRY_...` bitmasks below. Some of + * these flags are read from and written to disk, but some are set aside + * for in-memory only reference. + */ typedef struct git_index_entry { git_index_time ctime; git_index_time mtime; @@ -102,6 +63,60 @@ typedef struct git_index_entry { char *path; } git_index_entry; +/** + * Bitmasks for on-disk fields of `git_index_entry`'s `flags` + * + * These bitmasks match the four fields in the `git_index_entry` `flags` + * value both in memory and on disk. You can use them to interpret the + * data in the `flags`. + */ +#define GIT_IDXENTRY_NAMEMASK (0x0fff) +#define GIT_IDXENTRY_STAGEMASK (0x3000) +#define GIT_IDXENTRY_EXTENDED (0x4000) +#define GIT_IDXENTRY_VALID (0x8000) +#define GIT_IDXENTRY_STAGESHIFT 12 + +#define GIT_IDXENTRY_STAGE(E) (((E)->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT) + +/** + * Bitmasks for on-disk fields of `git_index_entry`'s `flags_extended` + * + * In memory, the `flags_extended` fields are divided into two parts: the + * fields that are read from and written to disk, and other fields that + * in-memory only and used by libgit2. Only the flags in + * `GIT_IDXENTRY_EXTENDED_FLAGS` will get saved on-disk. + * + * These bitmasks match the three fields in the `git_index_entry` + * `flags_extended` value that belong on disk. You can use them to + * interpret the data in the `flags_extended`. + */ +#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13) +#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14) +/* GIT_IDXENTRY_EXTENDED2 is reserved for future extension */ +#define GIT_IDXENTRY_EXTENDED2 (1 << 15) + +#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) + +/** + * Bitmasks for in-memory only fields of `git_index_entry`'s `flags_extended` + * + * These bitmasks match the other fields in the `git_index_entry` + * `flags_extended` value that are only used in-memory by libgit2. You + * can use them to interpret the data in the `flags_extended`. + */ +#define GIT_IDXENTRY_UPDATE (1 << 0) +#define GIT_IDXENTRY_REMOVE (1 << 1) +#define GIT_IDXENTRY_UPTODATE (1 << 2) +#define GIT_IDXENTRY_ADDED (1 << 3) + +#define GIT_IDXENTRY_HASHED (1 << 4) +#define GIT_IDXENTRY_UNHASHED (1 << 5) +#define GIT_IDXENTRY_WT_REMOVE (1 << 6) /* remove in work directory */ +#define GIT_IDXENTRY_CONFLICTED (1 << 7) + +#define GIT_IDXENTRY_UNPACKED (1 << 8) +#define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) + /** Capabilities of system that affect index actions. */ typedef enum { GIT_INDEXCAP_IGNORE_CASE = 1,