summaryrefslogtreecommitdiff
path: root/refs/files-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'refs/files-backend.c')
-rw-r--r--refs/files-backend.c228
1 files changed, 136 insertions, 92 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 6f6f76a8d8..240d3c3b26 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -354,13 +354,11 @@ static int for_each_root_ref(struct files_ref_store *refs,
void *cb_data)
{
struct strbuf path = STRBUF_INIT, refname = STRBUF_INIT;
- const char *dirname = refs->loose->root->name;
struct dirent *de;
- size_t dirnamelen;
int ret;
DIR *d;
- files_ref_path(refs, &path, dirname);
+ files_ref_path(refs, &path, "");
d = opendir(path.buf);
if (!d) {
@@ -368,9 +366,6 @@ static int for_each_root_ref(struct files_ref_store *refs,
return -1;
}
- strbuf_addstr(&refname, dirname);
- dirnamelen = refname.len;
-
while ((de = readdir(d)) != NULL) {
unsigned char dtype;
@@ -378,6 +373,8 @@ static int for_each_root_ref(struct files_ref_store *refs,
continue;
if (ends_with(de->d_name, ".lock"))
continue;
+
+ strbuf_reset(&refname);
strbuf_addstr(&refname, de->d_name);
dtype = get_dtype(de, &path, 1);
@@ -386,8 +383,6 @@ static int for_each_root_ref(struct files_ref_store *refs,
if (ret)
goto done;
}
-
- strbuf_setlen(&refname, dirnamelen);
}
ret = 0;
@@ -3720,64 +3715,50 @@ static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
struct fsck_options *o,
const char *refname,
- struct dir_iterator *iter);
+ const char *path,
+ int mode);
-static int files_fsck_symref_target(struct fsck_options *o,
+static int files_fsck_symref_target(struct ref_store *ref_store,
+ struct fsck_options *o,
struct fsck_ref_report *report,
+ const char *refname,
struct strbuf *referent,
unsigned int symbolic_link)
{
- int is_referent_root;
char orig_last_byte;
size_t orig_len;
int ret = 0;
orig_len = referent->len;
orig_last_byte = referent->buf[orig_len - 1];
- if (!symbolic_link)
- strbuf_rtrim(referent);
-
- is_referent_root = is_root_ref(referent->buf);
- if (!is_referent_root &&
- !starts_with(referent->buf, "refs/") &&
- !starts_with(referent->buf, "worktrees/")) {
- ret = fsck_report_ref(o, report,
- FSCK_MSG_SYMREF_TARGET_IS_NOT_A_REF,
- "points to non-ref target '%s'", referent->buf);
-
- }
- if (!is_referent_root && check_refname_format(referent->buf, 0)) {
- ret = fsck_report_ref(o, report,
- FSCK_MSG_BAD_REFERENT_NAME,
- "points to invalid refname '%s'", referent->buf);
- goto out;
- }
+ if (!symbolic_link) {
+ strbuf_rtrim(referent);
- if (symbolic_link)
- goto out;
+ if (referent->len == orig_len ||
+ (referent->len < orig_len && orig_last_byte != '\n')) {
+ ret |= fsck_report_ref(o, report,
+ FSCK_MSG_REF_MISSING_NEWLINE,
+ "misses LF at the end");
+ }
- if (referent->len == orig_len ||
- (referent->len < orig_len && orig_last_byte != '\n')) {
- ret = fsck_report_ref(o, report,
- FSCK_MSG_REF_MISSING_NEWLINE,
- "misses LF at the end");
+ if (referent->len != orig_len && referent->len != orig_len - 1) {
+ ret |= fsck_report_ref(o, report,
+ FSCK_MSG_TRAILING_REF_CONTENT,
+ "has trailing whitespaces or newlines");
+ }
}
- if (referent->len != orig_len && referent->len != orig_len - 1) {
- ret = fsck_report_ref(o, report,
- FSCK_MSG_TRAILING_REF_CONTENT,
- "has trailing whitespaces or newlines");
- }
+ ret |= refs_fsck_symref(ref_store, o, report, refname, referent->buf);
-out:
- return ret;
+ return ret ? -1 : 0;
}
static int files_fsck_refs_content(struct ref_store *ref_store,
struct fsck_options *o,
const char *target_name,
- struct dir_iterator *iter)
+ const char *path,
+ int mode)
{
struct strbuf ref_content = STRBUF_INIT;
struct strbuf abs_gitdir = STRBUF_INIT;
@@ -3791,7 +3772,7 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
report.path = target_name;
- if (S_ISLNK(iter->st.st_mode)) {
+ if (S_ISLNK(mode)) {
const char *relative_referent_path = NULL;
ret = fsck_report_ref(o, &report,
@@ -3803,7 +3784,7 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
if (!is_dir_sep(abs_gitdir.buf[abs_gitdir.len - 1]))
strbuf_addch(&abs_gitdir, '/');
- strbuf_add_real_path(&ref_content, iter->path.buf);
+ strbuf_add_real_path(&ref_content, path);
skip_prefix(ref_content.buf, abs_gitdir.buf,
&relative_referent_path);
@@ -3812,11 +3793,12 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
else
strbuf_addbuf(&referent, &ref_content);
- ret |= files_fsck_symref_target(o, &report, &referent, 1);
+ ret |= files_fsck_symref_target(ref_store, o, &report,
+ target_name, &referent, 1);
goto cleanup;
}
- if (strbuf_read_file(&ref_content, iter->path.buf, 0) < 0) {
+ if (strbuf_read_file(&ref_content, path, 0) < 0) {
/*
* Ref file could be removed by another concurrent process. We should
* ignore this error and continue to the next ref.
@@ -3824,7 +3806,7 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
if (errno == ENOENT)
goto cleanup;
- ret = error_errno(_("cannot read ref file '%s'"), iter->path.buf);
+ ret = error_errno(_("cannot read ref file '%s'"), path);
goto cleanup;
}
@@ -3851,8 +3833,11 @@ static int files_fsck_refs_content(struct ref_store *ref_store,
"has trailing garbage: '%s'", trailing);
goto cleanup;
}
+
+ ret = refs_fsck_ref(ref_store, o, &report, target_name, &oid);
} else {
- ret = files_fsck_symref_target(o, &report, &referent, 0);
+ ret = files_fsck_symref_target(ref_store, o, &report,
+ target_name, &referent, 0);
goto cleanup;
}
@@ -3866,21 +3851,25 @@ cleanup:
static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
struct fsck_options *o,
const char *refname,
- struct dir_iterator *iter)
+ const char *path,
+ int mode UNUSED)
{
struct strbuf sb = STRBUF_INIT;
+ const char *filename;
int ret = 0;
+ filename = basename((char *) path);
+
/*
* Ignore the files ending with ".lock" as they may be lock files
* However, do not allow bare ".lock" files.
*/
- if (iter->basename[0] != '.' && ends_with(iter->basename, ".lock"))
+ if (filename[0] != '.' && ends_with(filename, ".lock"))
+ goto cleanup;
+
+ if (is_root_ref(refname))
goto cleanup;
- /*
- * This works right now because we never check the root refs.
- */
if (check_refname_format(refname, 0)) {
struct fsck_ref_report report = { 0 };
@@ -3895,11 +3884,44 @@ cleanup:
return ret;
}
+static const files_fsck_refs_fn fsck_refs_fn[]= {
+ files_fsck_refs_name,
+ files_fsck_refs_content,
+ NULL,
+};
+
+static int files_fsck_ref(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refname,
+ const char *path,
+ int mode)
+{
+ int ret = 0;
+
+ if (o->verbose)
+ fprintf_ln(stderr, "Checking %s", refname);
+
+ if (!S_ISREG(mode) && !S_ISLNK(mode)) {
+ struct fsck_ref_report report = { .path = refname };
+
+ if (fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_FILETYPE,
+ "unexpected file type"))
+ ret = -1;
+ goto out;
+ }
+
+ for (size_t i = 0; fsck_refs_fn[i]; i++)
+ if (fsck_refs_fn[i](ref_store, o, refname, path, mode))
+ ret = -1;
+
+out:
+ return ret;
+}
+
static int files_fsck_refs_dir(struct ref_store *ref_store,
struct fsck_options *o,
- const char *refs_check_dir,
- struct worktree *wt,
- files_fsck_refs_fn *fsck_refs_fn)
+ struct worktree *wt)
{
struct strbuf refname = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT;
@@ -3907,7 +3929,7 @@ static int files_fsck_refs_dir(struct ref_store *ref_store,
int iter_status;
int ret = 0;
- strbuf_addf(&sb, "%s/%s", ref_store->gitdir, refs_check_dir);
+ strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
iter = dir_iterator_begin(sb.buf, 0);
if (!iter) {
@@ -3919,31 +3941,17 @@ static int files_fsck_refs_dir(struct ref_store *ref_store,
}
while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
- if (S_ISDIR(iter->st.st_mode)) {
+ if (S_ISDIR(iter->st.st_mode))
continue;
- } else if (S_ISREG(iter->st.st_mode) ||
- S_ISLNK(iter->st.st_mode)) {
- strbuf_reset(&refname);
- if (!is_main_worktree(wt))
- strbuf_addf(&refname, "worktrees/%s/", wt->id);
- strbuf_addf(&refname, "%s/%s", refs_check_dir,
- iter->relative_path);
+ strbuf_reset(&refname);
+ if (!is_main_worktree(wt))
+ strbuf_addf(&refname, "worktrees/%s/", wt->id);
+ strbuf_addf(&refname, "refs/%s", iter->relative_path);
- if (o->verbose)
- fprintf_ln(stderr, "Checking %s", refname.buf);
-
- for (size_t i = 0; fsck_refs_fn[i]; i++) {
- if (fsck_refs_fn[i](ref_store, o, refname.buf, iter))
- ret = -1;
- }
- } else {
- struct fsck_ref_report report = { .path = iter->basename };
- if (fsck_report_ref(o, &report,
- FSCK_MSG_BAD_REF_FILETYPE,
- "unexpected file type"))
- ret = -1;
- }
+ if (files_fsck_ref(ref_store, o, refname.buf,
+ iter->path.buf, iter->st.st_mode) < 0)
+ ret = -1;
}
if (iter_status != ITER_DONE)
@@ -3956,17 +3964,35 @@ out:
return ret;
}
-static int files_fsck_refs(struct ref_store *ref_store,
- struct fsck_options *o,
- struct worktree *wt)
+struct files_fsck_root_ref_data {
+ struct files_ref_store *refs;
+ struct fsck_options *o;
+ struct worktree *wt;
+ struct strbuf refname;
+ struct strbuf path;
+};
+
+static int files_fsck_root_ref(const char *refname, void *cb_data)
{
- files_fsck_refs_fn fsck_refs_fn[]= {
- files_fsck_refs_name,
- files_fsck_refs_content,
- NULL,
- };
+ struct files_fsck_root_ref_data *data = cb_data;
+ struct stat st;
- return files_fsck_refs_dir(ref_store, o, "refs", wt, fsck_refs_fn);
+ strbuf_reset(&data->refname);
+ if (!is_main_worktree(data->wt))
+ strbuf_addf(&data->refname, "worktrees/%s/", data->wt->id);
+ strbuf_addstr(&data->refname, refname);
+
+ strbuf_reset(&data->path);
+ strbuf_addf(&data->path, "%s/%s", data->refs->gitcommondir, data->refname.buf);
+
+ if (stat(data->path.buf, &st)) {
+ if (errno == ENOENT)
+ return 0;
+ return error_errno("failed to read ref: '%s'", data->path.buf);
+ }
+
+ return files_fsck_ref(&data->refs->base, data->o, data->refname.buf,
+ data->path.buf, st.st_mode);
}
static int files_fsck(struct ref_store *ref_store,
@@ -3975,9 +4001,27 @@ static int files_fsck(struct ref_store *ref_store,
{
struct files_ref_store *refs =
files_downcast(ref_store, REF_STORE_READ, "fsck");
+ struct files_fsck_root_ref_data data = {
+ .refs = refs,
+ .o = o,
+ .wt = wt,
+ .refname = STRBUF_INIT,
+ .path = STRBUF_INIT,
+ };
+ int ret = 0;
+
+ if (files_fsck_refs_dir(ref_store, o, wt) < 0)
+ ret = -1;
+
+ if (for_each_root_ref(refs, files_fsck_root_ref, &data) < 0)
+ ret = -1;
+
+ if (refs->packed_ref_store->be->fsck(refs->packed_ref_store, o, wt) < 0)
+ ret = -1;
- return files_fsck_refs(ref_store, o, wt) |
- refs->packed_ref_store->be->fsck(refs->packed_ref_store, o, wt);
+ strbuf_release(&data.refname);
+ strbuf_release(&data.path);
+ return ret;
}
struct ref_storage_be refs_be_files = {