checkout: cache system attributes file location
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
diff --git a/src/attr.c b/src/attr.c
index df139e0..020bb1c 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -249,6 +249,46 @@ static int preload_attr_file(
return error;
}
+static int system_attr_file(
+ git_buf *out,
+ git_repository *repo,
+ git_attr_session *attr_session)
+{
+ int error;
+
+ if (!attr_session) {
+ error = git_sysdir_find_system_file(out, GIT_ATTR_FILE_SYSTEM);
+
+ if (error == GIT_ENOTFOUND)
+ giterr_clear();
+
+ return error;
+ }
+
+ if (!attr_session->init_sysdir) {
+ error = git_sysdir_find_system_file(&attr_session->sysdir, GIT_ATTR_FILE_SYSTEM);
+
+ if (error == GIT_ENOTFOUND)
+ giterr_clear();
+ else if (error)
+ return error;
+
+ attr_session->init_sysdir = 1;
+ }
+
+ if (attr_session->sysdir.size == 0)
+ return GIT_ENOTFOUND;
+
+ /* We can safely provide a git_buf with no allocation (asize == 0) to
+ * a consumer. This allows them to treat this as a regular `git_buf`,
+ * but their call to `git_buf_free` will not attempt to free it.
+ */
+ out->ptr = attr_session->sysdir.ptr;
+ out->size = attr_session->sysdir.size;
+ out->asize = 0;
+ return 0;
+}
+
static int attr_setup(git_repository *repo, git_attr_session *attr_session)
{
int error = 0;
@@ -256,7 +296,7 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
git_index *idx = NULL;
git_buf sys = GIT_BUF_INIT;
- if (attr_session && attr_session->setup)
+ if (attr_session && attr_session->init_setup)
return 0;
if ((error = git_attr_cache__init(repo)) < 0)
@@ -266,18 +306,15 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
* definitions will be available for later file parsing
*/
- if (!(error = git_sysdir_find_system_file(&sys, GIT_ATTR_FILE_SYSTEM))) {
+ error = system_attr_file(&sys, repo, attr_session);
+
+ if (error == 0)
error = preload_attr_file(
repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
- git_buf_free(&sys);
- }
- if (error < 0) {
- if (error == GIT_ENOTFOUND) {
- giterr_clear();
- error = 0;
- } else
- return error;
- }
+ else if (error != GIT_ENOTFOUND)
+ return error;
+
+ git_buf_free(&sys);
if ((error = preload_attr_file(
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
@@ -300,7 +337,7 @@ static int attr_setup(git_repository *repo, git_attr_session *attr_session)
return error;
if (attr_session)
- attr_session->setup = 1;
+ attr_session->init_setup = 1;
return error;
}
@@ -489,15 +526,14 @@ static int collect_attr_files(
}
if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
- error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
+ error = system_attr_file(&dir, repo, attr_session);
+
if (!error)
error = push_attr_file(
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
NULL, dir.ptr);
- else if (error == GIT_ENOTFOUND) {
- giterr_clear();
+ else if (error == GIT_ENOTFOUND)
error = 0;
- }
}
cleanup:
diff --git a/src/attr_file.c b/src/attr_file.c
index 9896df4..2ebd3b9 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -854,3 +854,13 @@ int git_attr_session__init(git_attr_session *session, git_repository *repo)
return 0;
}
+
+void git_attr_session__free(git_attr_session *session)
+{
+ if (!session)
+ return;
+
+ git_buf_free(&session->sysdir);
+
+ memset(session, 0, sizeof(git_attr_session));
+}
diff --git a/src/attr_file.h b/src/attr_file.h
index b8e3725..5c64f7c 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -111,7 +111,9 @@ typedef struct {
typedef struct {
int key;
- unsigned int setup;
+ unsigned int init_setup:1,
+ init_sysdir:1;
+ git_buf sysdir;
} git_attr_session;
extern int git_attr_session__init(git_attr_session *attr_session, git_repository *repo);