diff options
Diffstat (limited to 'refs/files-backend.c')
| -rw-r--r-- | refs/files-backend.c | 228 |
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 = { |
