static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data) { char *objects_dir; int error; git_buf buf = GIT_BUF_INIT; struct foreach_state state; loose_backend *backend = (loose_backend *) _backend; assert(backend && cb); objects_dir = backend->objects_dir; git_buf_sets(&buf, objects_dir); git_path_to_dir(&buf); if (git_buf_oom(&buf)) return -1; memset(&state, 0, sizeof(state)); state.cb = cb; state.data = data; state.dir_len = git_buf_len(&buf); error = git_path_direach(&buf, 0, foreach_cb, &state); git_buf_dispose(&buf); return error; }
int git_path_find_dir(git_buf *dir, const char *path, const char *base) { int error = GIT_SUCCESS; if (base != NULL && git_path_root(path) < 0) error = git_buf_joinpath(dir, base, path); else error = git_buf_sets(dir, path); if (error == GIT_SUCCESS) { char buf[GIT_PATH_MAX]; if (p_realpath(dir->ptr, buf) != NULL) error = git_buf_sets(dir, buf); } /* call dirname if this is not a directory */ if (error == GIT_SUCCESS && git_path_isdir(dir->ptr) != GIT_SUCCESS) if (git_path_dirname_r(dir, dir->ptr) < GIT_SUCCESS) error = git_buf_lasterror(dir); if (error == GIT_SUCCESS) error = git_path_to_dir(dir); return error; }
const char *cl_git_sandbox_path(int is_dir, ...) { const char *path = NULL; static char _temp[GIT_PATH_MAX]; git_buf buf = GIT_BUF_INIT; va_list arg; cl_git_pass(git_buf_sets(&buf, clar_sandbox_path())); va_start(arg, is_dir); while ((path = va_arg(arg, const char *)) != NULL) { cl_git_pass(git_buf_joinpath(&buf, buf.ptr, path)); } va_end(arg); cl_git_pass(git_path_prettify(&buf, buf.ptr, NULL)); if (is_dir) git_path_to_dir(&buf); /* make sure we won't truncate */ cl_assert(git_buf_len(&buf) < sizeof(_temp)); git_buf_copy_cstr(_temp, sizeof(_temp), &buf); git_buf_dispose(&buf); return _temp; }
static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path) { int error; const git_config_entry *ce; git_buf worktree = GIT_BUF_INIT; if (repo->is_bare) return 0; if ((error = git_config__lookup_entry( &ce, config, "core.worktree", false)) < 0) return error; if (ce && ce->value) { if ((error = git_path_prettify_dir( &worktree, ce->value, repo->path_repository)) < 0) return error; repo->workdir = git_buf_detach(&worktree); } else if (parent_path && git_path_isdir(parent_path->ptr)) repo->workdir = git_buf_detach(parent_path); else { if (git_path_dirname_r(&worktree, repo->path_repository) < 0 || git_path_to_dir(&worktree) < 0) return -1; repo->workdir = git_buf_detach(&worktree); } GITERR_CHECK_ALLOC(repo->workdir); return 0; }
static int load_workdir(git_repository *repo, git_buf *parent_path) { int error; git_config *config; const char *worktree; git_buf worktree_buf = GIT_BUF_INIT; if (repo->is_bare) return 0; if (git_repository_config__weakptr(&config, repo) < 0) return -1; error = git_config_get_string(&worktree, config, "core.worktree"); if (!error && worktree != NULL) repo->workdir = git__strdup(worktree); else if (error != GIT_ENOTFOUND) return error; else { giterr_clear(); if (parent_path && git_path_isdir(parent_path->ptr)) repo->workdir = git_buf_detach(parent_path); else { git_path_dirname_r(&worktree_buf, repo->path_repository); git_path_to_dir(&worktree_buf); repo->workdir = git_buf_detach(&worktree_buf); } } GITERR_CHECK_ALLOC(repo->workdir); return 0; }
int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base) { int error = git_path_prettify(path_out, path, base); if (error == GIT_SUCCESS) error = git_path_to_dir(path_out); return error; }
int git_path_direach( git_buf *path, int (*fn)(void *, git_buf *), void *arg) { ssize_t wd_len; DIR *dir; struct dirent *de, *de_buf; if (git_path_to_dir(path) < 0) return -1; wd_len = git_buf_len(path); if ((dir = opendir(path->ptr)) == NULL) { giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr); return -1; } #ifdef __sun de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); #endif while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) continue; if (git_buf_puts(path, de->d_name) < 0) { closedir(dir); git__free(de_buf); return -1; } result = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ if (result < 0) { closedir(dir); git__free(de_buf); return -1; } } closedir(dir); git__free(de_buf); return 0; }
static void check_path_to_dir( const char* path, const char* expected) { git_buf tgt = GIT_BUF_INIT; git_buf_sets(&tgt, path); cl_git_pass(git_path_to_dir(&tgt)); cl_assert_equal_s(expected, tgt.ptr); git_buf_dispose(&tgt); }
int git_path_find_dir(git_buf *dir, const char *path, const char *base) { int error = git_path_join_unrooted(dir, path, base, NULL); if (!error) { char buf[GIT_PATH_MAX]; if (p_realpath(dir->ptr, buf) != NULL) error = git_buf_sets(dir, buf); } /* call dirname if this is not a directory */ if (!error) /* && git_path_isdir(dir->ptr) == false) */ error = (git_path_dirname_r(dir, dir->ptr) < 0) ? -1 : 0; if (!error) error = git_path_to_dir(dir); return error; }
static int object_file_name( git_buf *name, const loose_backend *be, const git_oid *id) { size_t alloclen; /* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ GITERR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_HEXSZ); GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3); if (git_buf_grow(name, alloclen) < 0) return -1; git_buf_set(name, be->objects_dir, be->objects_dirlen); git_path_to_dir(name); /* loose object filename: aa/aaa... (41 bytes) */ git_oid_pathfmt(name->ptr + name->size, id); name->size += GIT_OID_HEXSZ + 1; name->ptr[name->size] = '\0'; return 0; }
int git_path_direach( git_buf *path, int (*fn)(void *, git_buf *), void *arg) { ssize_t wd_len; DIR *dir; struct dirent *de; if (git_path_to_dir(path) < GIT_SUCCESS) return git_buf_lasterror(path); wd_len = path->size; dir = opendir(path->ptr); if (!dir) return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path->ptr); while ((de = readdir(dir)) != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) continue; if (git_buf_puts(path, de->d_name) < GIT_SUCCESS) return git_buf_lasterror(path); result = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ if (result != GIT_SUCCESS) { closedir(dir); return result; /* The callee is reponsible for setting the correct error message */ } } closedir(dir); return GIT_SUCCESS; }
int git_path_prettify_dir(git_buf *path_out, const char *path, const char *base) { int error = git_path_prettify(path_out, path, base); return (error < 0) ? error : git_path_to_dir(path_out); }
int git_path_direach( git_buf *path, uint32_t flags, int (*fn)(void *, git_buf *), void *arg) { int error = 0; ssize_t wd_len; DIR *dir; struct dirent *de; #ifdef GIT_USE_ICONV git_path_iconv_t ic = GIT_PATH_ICONV_INIT; #endif GIT_UNUSED(flags); if (git_path_to_dir(path) < 0) return -1; wd_len = git_buf_len(path); if ((dir = opendir(path->ptr)) == NULL) { giterr_set(GITERR_OS, "Failed to open directory '%s'", path->ptr); if (errno == ENOENT) return GIT_ENOTFOUND; return -1; } #ifdef GIT_USE_ICONV if ((flags & GIT_PATH_DIR_PRECOMPOSE_UNICODE) != 0) (void)git_path_iconv_init_precompose(&ic); #endif while ((de = readdir(dir)) != NULL) { char *de_path = de->d_name; size_t de_len = strlen(de_path); if (git_path_is_dot_or_dotdot(de_path)) continue; #ifdef GIT_USE_ICONV if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0) break; #endif if ((error = git_buf_put(path, de_path, de_len)) < 0) break; giterr_clear(); error = fn(arg, path); git_buf_truncate(path, wd_len); /* restore path */ /* Only set our own error if the callback did not set one already */ if (error != 0) { if (!giterr_last()) giterr_set_after_callback(error); break; } } closedir(dir); #ifdef GIT_USE_ICONV git_path_iconv_clear(&ic); #endif return error; }
/* Locate an object matching a given short oid */ static int locate_object_short_oid( git_buf *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, size_t len) { char *objects_dir = backend->objects_dir; size_t dir_len = strlen(objects_dir), alloc_len; loose_locate_object_state state; int error; /* prealloc memory for OBJ_DIR/xx/xx..38x..xx */ GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3); if (git_buf_grow(object_location, alloc_len) < 0) return -1; git_buf_set(object_location, objects_dir, dir_len); git_path_to_dir(object_location); /* save adjusted position at end of dir so it can be restored later */ dir_len = git_buf_len(object_location); /* Convert raw oid to hex formatted oid */ git_oid_fmt((char *)state.short_oid, short_oid); /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */ if (git_buf_put(object_location, (char *)state.short_oid, 3) < 0) return -1; object_location->ptr[object_location->size - 1] = '/'; /* Check that directory exists */ if (git_path_isdir(object_location->ptr) == false) return git_odb__error_notfound("no matching loose object for prefix", short_oid, len); state.dir_len = git_buf_len(object_location); state.short_oid_len = len; state.found = 0; /* Explore directory to find a unique object matching short_oid */ error = git_path_direach( object_location, 0, fn_locate_object_short_oid, &state); if (error < 0 && error != GIT_EAMBIGUOUS) return error; if (!state.found) return git_odb__error_notfound("no matching loose object for prefix", short_oid, len); if (state.found > 1) return git_odb__error_ambiguous("multiple matches in loose objects"); /* Convert obtained hex formatted oid to raw */ error = git_oid_fromstr(res_oid, (char *)state.res_oid); if (error) return error; /* Update the location according to the oid obtained */ GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2); git_buf_truncate(object_location, dir_len); if (git_buf_grow(object_location, alloc_len) < 0) return -1; git_oid_pathfmt(object_location->ptr + dir_len, res_oid); object_location->size += GIT_OID_HEXSZ + 1; object_location->ptr[object_location->size] = '\0'; return 0; }
static int find_repo( git_buf *repo_path, git_buf *parent_path, const char *start_path, uint32_t flags, const char *ceiling_dirs) { int error; git_buf path = GIT_BUF_INIT; struct stat st; dev_t initial_device = 0; bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE) != 0); int ceiling_offset; git_buf_free(repo_path); if ((error = git_path_prettify(&path, start_path, NULL)) < 0) return error; ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); if (!try_with_dot_git && (error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) return error; while (!error && !git_buf_len(repo_path)) { if (p_stat(path.ptr, &st) == 0) { /* check that we have not crossed device boundaries */ if (initial_device == 0) initial_device = st.st_dev; else if (st.st_dev != initial_device && (flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0) break; if (S_ISDIR(st.st_mode)) { if (valid_repository_path(&path)) { git_path_to_dir(&path); git_buf_set(repo_path, path.ptr, path.size); break; } } else if (S_ISREG(st.st_mode)) { git_buf repo_link = GIT_BUF_INIT; if (!(error = read_gitfile(&repo_link, path.ptr))) { if (valid_repository_path(&repo_link)) git_buf_swap(repo_path, &repo_link); git_buf_free(&repo_link); break; } git_buf_free(&repo_link); } } /* move up one directory level */ if (git_path_dirname_r(&path, path.ptr) < 0) { error = -1; break; } if (try_with_dot_git) { /* if we tried original dir with and without .git AND either hit * directory ceiling or NO_SEARCH was requested, then be done. */ if (path.ptr[ceiling_offset] == '\0' || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0) break; /* otherwise look first for .git item */ error = git_buf_joinpath(&path, path.ptr, DOT_GIT); } try_with_dot_git = !try_with_dot_git; } if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { if (!git_buf_len(repo_path)) git_buf_clear(parent_path); else { git_path_dirname_r(parent_path, path.ptr); git_path_to_dir(parent_path); } if (git_buf_oom(parent_path)) return -1; } git_buf_free(&path); if (!git_buf_len(repo_path) && !error) { giterr_set(GITERR_REPOSITORY, "Could not find repository from '%s'", start_path); error = GIT_ENOTFOUND; } return error; }