mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-05 15:33:51 +00:00
Merge pull request #227 from Romain-Geissler/discovery-path-v2
Discovery path v2
This commit is contained in:
commit
793545ef2b
@ -132,6 +132,34 @@ GIT_EXTERN(int) git_repository_open3(git_repository **repository,
|
|||||||
const char *git_index_file,
|
const char *git_index_file,
|
||||||
const char *git_work_tree);
|
const char *git_work_tree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look for a git repository and copy its path in the given buffer. The lookup start
|
||||||
|
* from base_path and walk across parent directories if nothing has been found. The
|
||||||
|
* lookup ends when the first repository is found, or when reaching a directory
|
||||||
|
* referenced in ceiling_dirs or when the filesystem changes (in case across_fs
|
||||||
|
* is true).
|
||||||
|
*
|
||||||
|
* The method will automatically detect if the repository is bare (if there is
|
||||||
|
* a repository).
|
||||||
|
*
|
||||||
|
* @param repository_path The user allocated buffer which will contain the found path.
|
||||||
|
*
|
||||||
|
* @param size repository_path size
|
||||||
|
*
|
||||||
|
* @param start_path The base path where the lookup starts.
|
||||||
|
*
|
||||||
|
* @param across_fs If true, then the lookup will not stop when a filesystem device change
|
||||||
|
* is detected while exploring parent directories.
|
||||||
|
*
|
||||||
|
* @param ceiling_dirs A colon separated of absolute symbolic link free paths. The lookup will
|
||||||
|
* stop when any of this paths is reached. Note that the lookup always performs on start_path
|
||||||
|
* no matter start_path appears in ceiling_dirs
|
||||||
|
* ceiling_dirs might be NULL (which is equivalent to an empty string)
|
||||||
|
*
|
||||||
|
* @return 0 on success; error code otherwise
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the object database behind a Git repository
|
* Get the object database behind a Git repository
|
||||||
*
|
*
|
||||||
|
@ -41,16 +41,14 @@ static int lock_file(git_filebuf *file, int flags)
|
|||||||
|
|
||||||
/* create path to the file buffer is required */
|
/* create path to the file buffer is required */
|
||||||
if (flags & GIT_FILEBUF_FORCE) {
|
if (flags & GIT_FILEBUF_FORCE) {
|
||||||
file->fd = gitfo_creat_force(file->path_lock, 0644);
|
file->fd = gitfo_creat_locked_force(file->path_lock, 0644);
|
||||||
} else {
|
} else {
|
||||||
file->fd = gitfo_creat(file->path_lock, 0644);
|
file->fd = gitfo_creat_locked(file->path_lock, 0644);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->fd < 0)
|
if (file->fd < 0)
|
||||||
return git__throw(GIT_EOSERR, "Failed to create lock");
|
return git__throw(GIT_EOSERR, "Failed to create lock");
|
||||||
|
|
||||||
/* TODO: do a flock() in the descriptor file_lock */
|
|
||||||
|
|
||||||
if ((flags & GIT_FILEBUF_APPEND) && gitfo_exists(file->path_original) == 0) {
|
if ((flags & GIT_FILEBUF_APPEND) && gitfo_exists(file->path_original) == 0) {
|
||||||
git_file source;
|
git_file source;
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
|
@ -66,6 +66,20 @@ int gitfo_creat_force(const char *path, int mode)
|
|||||||
return gitfo_creat(path, mode);
|
return gitfo_creat(path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gitfo_creat_locked(const char *path, int mode)
|
||||||
|
{
|
||||||
|
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode);
|
||||||
|
return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create locked file. Could not open %s", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gitfo_creat_locked_force(const char *path, int mode)
|
||||||
|
{
|
||||||
|
if (gitfo_mkdir_2file(path) < GIT_SUCCESS)
|
||||||
|
return git__throw(GIT_EOSERR, "Failed to create locked file %s", path);
|
||||||
|
|
||||||
|
return gitfo_creat_locked(path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
int gitfo_read(git_file fd, void *buf, size_t cnt)
|
int gitfo_read(git_file fd, void *buf, size_t cnt)
|
||||||
{
|
{
|
||||||
char *b = buf;
|
char *b = buf;
|
||||||
@ -131,7 +145,26 @@ int gitfo_isdir(const char *path)
|
|||||||
return git__throw(GIT_ENOTFOUND, "%s does not exist", path);
|
return git__throw(GIT_ENOTFOUND, "%s does not exist", path);
|
||||||
|
|
||||||
if (!S_ISDIR(st.st_mode))
|
if (!S_ISDIR(st.st_mode))
|
||||||
return git__throw(GIT_ENOTFOUND, "%s is a file", path);
|
return git__throw(GIT_ENOTFOUND, "%s is not a directory", path);
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gitfo_isfile(const char *path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int stat_error;
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
return git__throw(GIT_ENOTFOUND, "No path given to gitfo_isfile");
|
||||||
|
|
||||||
|
stat_error = gitfo_stat(path, &st);
|
||||||
|
|
||||||
|
if (stat_error < GIT_SUCCESS)
|
||||||
|
return git__throw(GIT_ENOTFOUND, "%s does not exist", path);
|
||||||
|
|
||||||
|
if (!S_ISREG(st.st_mode))
|
||||||
|
return git__throw(GIT_ENOTFOUND, "%s is not a file", path);
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -301,8 +334,19 @@ int gitfo_dirent(
|
|||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gitfo_posixify_path(char *path)
|
||||||
|
{
|
||||||
|
#if GIT_PLATFORM_PATH_SEP != '/'
|
||||||
|
while (*path) {
|
||||||
|
if (*path == GIT_PLATFORM_PATH_SEP)
|
||||||
|
*path = '/';
|
||||||
|
|
||||||
int retrieve_path_root_offset(const char *path)
|
path++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int gitfo_retrieve_path_root_offset(const char *path)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
@ -320,7 +364,6 @@ int retrieve_path_root_offset(const char *path)
|
|||||||
return -1; /* Not a real error. Rather a signal than the path is not rooted */
|
return -1; /* Not a real error. Rather a signal than the path is not rooted */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int gitfo_mkdir_recurs(const char *path, int mode)
|
int gitfo_mkdir_recurs(const char *path, int mode)
|
||||||
{
|
{
|
||||||
int error, root_path_offset;
|
int error, root_path_offset;
|
||||||
@ -333,7 +376,7 @@ int gitfo_mkdir_recurs(const char *path, int mode)
|
|||||||
error = GIT_SUCCESS;
|
error = GIT_SUCCESS;
|
||||||
pp = path_copy;
|
pp = path_copy;
|
||||||
|
|
||||||
root_path_offset = retrieve_path_root_offset(pp);
|
root_path_offset = gitfo_retrieve_path_root_offset(pp);
|
||||||
if (root_path_offset > 0)
|
if (root_path_offset > 0)
|
||||||
pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
|
pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */
|
||||||
|
|
||||||
@ -367,7 +410,7 @@ static int retrieve_previous_path_component_start(const char *path)
|
|||||||
{
|
{
|
||||||
int offset, len, root_offset, start = 0;
|
int offset, len, root_offset, start = 0;
|
||||||
|
|
||||||
root_offset = retrieve_path_root_offset(path);
|
root_offset = gitfo_retrieve_path_root_offset(path);
|
||||||
if (root_offset > -1)
|
if (root_offset > -1)
|
||||||
start += root_offset;
|
start += root_offset;
|
||||||
|
|
||||||
@ -392,7 +435,7 @@ static int retrieve_previous_path_component_start(const char *path)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path, const char *base_path)
|
||||||
{
|
{
|
||||||
int len = 0, segment_len, only_dots, root_path_offset, error = GIT_SUCCESS;
|
int len = 0, segment_len, only_dots, root_path_offset, error = GIT_SUCCESS;
|
||||||
char *current;
|
char *current;
|
||||||
@ -402,11 +445,20 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
|||||||
buffer_end = path + strlen(path);
|
buffer_end = path + strlen(path);
|
||||||
buffer_out_start = buffer_out;
|
buffer_out_start = buffer_out;
|
||||||
|
|
||||||
root_path_offset = retrieve_path_root_offset(path);
|
root_path_offset = gitfo_retrieve_path_root_offset(path);
|
||||||
if (root_path_offset < 0) {
|
if (root_path_offset < 0) {
|
||||||
error = gitfo_getcwd(buffer_out, size);
|
if (base_path == NULL) {
|
||||||
if (error < GIT_SUCCESS)
|
error = gitfo_getcwd(buffer_out, size);
|
||||||
return error; /* The callee already takes care of setting the correct error message. */
|
if (error < GIT_SUCCESS)
|
||||||
|
return error; /* The callee already takes care of setting the correct error message. */
|
||||||
|
} else {
|
||||||
|
if (size < (strlen(base_path) + 1) * sizeof(char))
|
||||||
|
return git__throw(GIT_EOVERFLOW, "Failed to prettify dir path: the base path is too long for the buffer.");
|
||||||
|
|
||||||
|
strcpy(buffer_out, base_path);
|
||||||
|
gitfo_posixify_path(buffer_out);
|
||||||
|
git__joinpath(buffer_out, buffer_out, "");
|
||||||
|
}
|
||||||
|
|
||||||
len = strlen(buffer_out);
|
len = strlen(buffer_out);
|
||||||
buffer_out += len;
|
buffer_out += len;
|
||||||
@ -470,9 +522,9 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path)
|
|||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path)
|
int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path, const char *base_path)
|
||||||
{
|
{
|
||||||
int error, path_len, i;
|
int error, path_len, i, root_offset;
|
||||||
const char* pattern = "/..";
|
const char* pattern = "/..";
|
||||||
|
|
||||||
path_len = strlen(path);
|
path_len = strlen(path);
|
||||||
@ -487,12 +539,13 @@ int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path)
|
|||||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
|
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = gitfo_prettify_dir_path(buffer_out, size, path);
|
error = gitfo_prettify_dir_path(buffer_out, size, path, base_path);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return error; /* The callee already takes care of setting the correct error message. */
|
return error; /* The callee already takes care of setting the correct error message. */
|
||||||
|
|
||||||
path_len = strlen(buffer_out);
|
path_len = strlen(buffer_out);
|
||||||
if (path_len < 2) /* TODO: Fixme. We should also take of detecting Windows rooted path (probably through usage of retrieve_path_root_offset) */
|
root_offset = gitfo_retrieve_path_root_offset(buffer_out) + 1;
|
||||||
|
if (path_len == root_offset)
|
||||||
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
|
return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path);
|
||||||
|
|
||||||
/* Remove the trailing slash */
|
/* Remove the trailing slash */
|
||||||
@ -519,16 +572,6 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void posixify_path(char *path)
|
|
||||||
{
|
|
||||||
while (*path) {
|
|
||||||
if (*path == '\\')
|
|
||||||
*path = '/';
|
|
||||||
|
|
||||||
path++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int gitfo_getcwd(char *buffer_out, size_t size)
|
int gitfo_getcwd(char *buffer_out, size_t size)
|
||||||
{
|
{
|
||||||
char *cwd_buffer;
|
char *cwd_buffer;
|
||||||
@ -544,7 +587,7 @@ int gitfo_getcwd(char *buffer_out, size_t size)
|
|||||||
if (cwd_buffer == NULL)
|
if (cwd_buffer == NULL)
|
||||||
return git__throw(GIT_EOSERR, "Failed to retrieve current working directory");
|
return git__throw(GIT_EOSERR, "Failed to retrieve current working directory");
|
||||||
|
|
||||||
posixify_path(buffer_out);
|
gitfo_posixify_path(buffer_out);
|
||||||
|
|
||||||
git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash
|
git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash
|
||||||
|
|
||||||
|
@ -12,6 +12,14 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#define GIT_PATH_LIST_SEPARATOR ':'
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
#define GIT_PLATFORM_PATH_SEP '\\'
|
||||||
|
#else
|
||||||
|
#define GIT_PLATFORM_PATH_SEP '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GIT_WIN32
|
#ifdef GIT_WIN32
|
||||||
GIT_INLINE(int) link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new))
|
GIT_INLINE(int) link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new))
|
||||||
{
|
{
|
||||||
@ -57,8 +65,11 @@ extern int gitfo_exists(const char *path);
|
|||||||
extern int gitfo_open(const char *path, int flags);
|
extern int gitfo_open(const char *path, int flags);
|
||||||
extern int gitfo_creat(const char *path, int mode);
|
extern int gitfo_creat(const char *path, int mode);
|
||||||
extern int gitfo_creat_force(const char *path, int mode);
|
extern int gitfo_creat_force(const char *path, int mode);
|
||||||
|
extern int gitfo_creat_locked(const char *path, int mode);
|
||||||
|
extern int gitfo_creat_locked_force(const char *path, int mode);
|
||||||
extern int gitfo_mktemp(char *path_out, const char *filename);
|
extern int gitfo_mktemp(char *path_out, const char *filename);
|
||||||
extern int gitfo_isdir(const char *path);
|
extern int gitfo_isdir(const char *path);
|
||||||
|
extern int gitfo_isfile(const char *path);
|
||||||
extern int gitfo_mkdir_recurs(const char *path, int mode);
|
extern int gitfo_mkdir_recurs(const char *path, int mode);
|
||||||
extern int gitfo_mkdir_2file(const char *path);
|
extern int gitfo_mkdir_2file(const char *path);
|
||||||
#define gitfo_close(fd) close(fd)
|
#define gitfo_close(fd) close(fd)
|
||||||
@ -162,7 +173,7 @@ extern int gitfo_getcwd(char *buffer_out, size_t size);
|
|||||||
* - GIT_SUCCESS on success;
|
* - GIT_SUCCESS on success;
|
||||||
* - GIT_ERROR when the input path is invalid or escapes the current directory.
|
* - GIT_ERROR when the input path is invalid or escapes the current directory.
|
||||||
*/
|
*/
|
||||||
int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path);
|
int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path, const char *base_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up a provided absolute or relative file path.
|
* Clean up a provided absolute or relative file path.
|
||||||
@ -185,7 +196,10 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path);
|
|||||||
* - GIT_SUCCESS on success;
|
* - GIT_SUCCESS on success;
|
||||||
* - GIT_ERROR when the input path is invalid or escapes the current directory.
|
* - GIT_ERROR when the input path is invalid or escapes the current directory.
|
||||||
*/
|
*/
|
||||||
int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path);
|
int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path, const char *base_path);
|
||||||
|
|
||||||
|
void gitfo_posixify_path(char *path);
|
||||||
|
|
||||||
|
int gitfo_retrieve_path_root_offset(const char *path);
|
||||||
|
|
||||||
int retrieve_path_root_offset(const char *path);
|
|
||||||
#endif /* INCLUDE_fileops_h__ */
|
#endif /* INCLUDE_fileops_h__ */
|
||||||
|
276
src/repository.c
276
src/repository.c
@ -38,6 +38,9 @@
|
|||||||
#define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
|
#define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/"
|
||||||
#define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
|
#define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/"
|
||||||
|
|
||||||
|
#define GIT_FILE_CONTENT_PREFIX "gitdir: "
|
||||||
|
#define GIT_FILE_CONTENT_PREFIX_LENGTH 8
|
||||||
|
|
||||||
#define GIT_BRANCH_MASTER "master"
|
#define GIT_BRANCH_MASTER "master"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -65,7 +68,7 @@ static int assign_repository_dirs(
|
|||||||
if (git_dir == NULL)
|
if (git_dir == NULL)
|
||||||
return git__throw(GIT_ENOTFOUND, "Failed to open repository. Git dir not found");
|
return git__throw(GIT_ENOTFOUND, "Failed to open repository. Git dir not found");
|
||||||
|
|
||||||
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_dir);
|
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_dir, NULL);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to open repository");
|
return git__rethrow(error, "Failed to open repository");
|
||||||
|
|
||||||
@ -78,7 +81,7 @@ static int assign_repository_dirs(
|
|||||||
if (git_object_directory == NULL)
|
if (git_object_directory == NULL)
|
||||||
git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
|
git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR);
|
||||||
else {
|
else {
|
||||||
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_object_directory);
|
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_object_directory, NULL);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to open repository");
|
return git__rethrow(error, "Failed to open repository");
|
||||||
}
|
}
|
||||||
@ -92,7 +95,7 @@ static int assign_repository_dirs(
|
|||||||
if (git_work_tree == NULL)
|
if (git_work_tree == NULL)
|
||||||
repo->is_bare = 1;
|
repo->is_bare = 1;
|
||||||
else {
|
else {
|
||||||
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_work_tree);
|
error = gitfo_prettify_dir_path(path_aux, sizeof(path_aux), git_work_tree, NULL);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to open repository");
|
return git__rethrow(error, "Failed to open repository");
|
||||||
|
|
||||||
@ -105,7 +108,7 @@ static int assign_repository_dirs(
|
|||||||
if (git_index_file == NULL)
|
if (git_index_file == NULL)
|
||||||
git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);
|
git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE);
|
||||||
else {
|
else {
|
||||||
error = gitfo_prettify_file_path(path_aux, sizeof(path_aux), git_index_file);
|
error = gitfo_prettify_file_path(path_aux, sizeof(path_aux), git_index_file, NULL);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to open repository");
|
return git__rethrow(error, "Failed to open repository");
|
||||||
}
|
}
|
||||||
@ -268,6 +271,21 @@ cleanup:
|
|||||||
return git__rethrow(error, "Failed to open repository");
|
return git__rethrow(error, "Failed to open repository");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int discover_repository_dirs(git_repository *repo, const char *path)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = guess_repository_dirs(repo, path);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = check_repository_dirs(repo);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int git_repository_open(git_repository **repo_out, const char *path)
|
int git_repository_open(git_repository **repo_out, const char *path)
|
||||||
{
|
{
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
@ -279,11 +297,7 @@ int git_repository_open(git_repository **repo_out, const char *path)
|
|||||||
if (repo == NULL)
|
if (repo == NULL)
|
||||||
return GIT_ENOMEM;
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
error = guess_repository_dirs(repo, path);
|
error = discover_repository_dirs(repo, path);
|
||||||
if (error < GIT_SUCCESS)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
error = check_repository_dirs(repo);
|
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -299,6 +313,129 @@ cleanup:
|
|||||||
return git__rethrow(error, "Failed to open repository");
|
return git__rethrow(error, "Failed to open repository");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int abspath(char *buffer_out, size_t size, const char *path)
|
||||||
|
{
|
||||||
|
assert(buffer_out && size >= GIT_PATH_MAX);
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
if (_fullpath(buffer_out, path, size) == NULL)
|
||||||
|
return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out);
|
||||||
|
#else
|
||||||
|
if (realpath(path, buffer_out) == NULL)
|
||||||
|
return git__throw(GIT_EOSERR, "Failed to retrieve real path: %s causing errors", buffer_out);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gitfo_posixify_path(buffer_out);
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static dev_t retrieve_device(dev_t *device_out, const char *path)
|
||||||
|
{
|
||||||
|
struct stat path_info;
|
||||||
|
|
||||||
|
assert(device_out);
|
||||||
|
|
||||||
|
if (gitfo_stat(path, &path_info))
|
||||||
|
return git__throw(GIT_EOSERR, "Failed to get file informations: %s", path);
|
||||||
|
|
||||||
|
*device_out = path_info.st_dev;
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int retrieve_ceiling_directories_offset(const char *path, const char *ceiling_directories)
|
||||||
|
{
|
||||||
|
char buf[GIT_PATH_MAX + 1];
|
||||||
|
char buf2[GIT_PATH_MAX + 1];
|
||||||
|
const char *ceil, *sep;
|
||||||
|
int len, max_len = -1;
|
||||||
|
int min_len;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
min_len = gitfo_retrieve_path_root_offset(path) + 1;
|
||||||
|
|
||||||
|
if (ceiling_directories == NULL || min_len == 0)
|
||||||
|
return min_len;
|
||||||
|
|
||||||
|
for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) {
|
||||||
|
for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++);
|
||||||
|
len = sep - ceil;
|
||||||
|
|
||||||
|
if (len == 0 || len > GIT_PATH_MAX || gitfo_retrieve_path_root_offset(ceil) == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
strncpy(buf, ceil, len);
|
||||||
|
buf[len] = '\0';
|
||||||
|
|
||||||
|
gitfo_posixify_path(buf);
|
||||||
|
if (gitfo_prettify_dir_path(buf2, sizeof(buf2), buf, NULL) < GIT_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = strlen(buf2);
|
||||||
|
if (len > 0 && buf2[len-1] == '/')
|
||||||
|
buf[--len] = '\0';
|
||||||
|
|
||||||
|
if (!strncmp(path, buf2, len) &&
|
||||||
|
path[len] == '/' &&
|
||||||
|
len > max_len)
|
||||||
|
{
|
||||||
|
max_len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_len <= min_len ? min_len : max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_gitfile(char *path_out, size_t size, const char *file_path, const char *base_path)
|
||||||
|
{
|
||||||
|
gitfo_buf file;
|
||||||
|
int error, end_offset;
|
||||||
|
char *data;
|
||||||
|
|
||||||
|
assert(file_path && path_out && size > 0);
|
||||||
|
|
||||||
|
error = gitfo_read_file(&file, file_path);
|
||||||
|
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
data = (char*)(file.data);
|
||||||
|
|
||||||
|
if (git__prefixcmp(data, GIT_FILE_CONTENT_PREFIX)) {
|
||||||
|
gitfo_free_buf(&file);
|
||||||
|
return git__throw(GIT_ENOTFOUND, "Invalid gitfile format `%s`", file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
end_offset = strlen(data) - 1;
|
||||||
|
|
||||||
|
for (;data[end_offset] != '\r' && data[end_offset] != '\n'; --end_offset);
|
||||||
|
data[end_offset] = '\0';
|
||||||
|
|
||||||
|
if (GIT_FILE_CONTENT_PREFIX_LENGTH == end_offset) {
|
||||||
|
gitfo_free_buf(&file);
|
||||||
|
return git__throw(GIT_ENOTFOUND, "No path in git file `%s`", file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = gitfo_prettify_dir_path(path_out, size, data + GIT_FILE_CONTENT_PREFIX_LENGTH, base_path);
|
||||||
|
gitfo_free_buf(&file);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void git_repository__free_dirs(git_repository *repo)
|
||||||
|
{
|
||||||
|
free(repo->path_workdir);
|
||||||
|
repo->path_workdir = NULL;
|
||||||
|
free(repo->path_index);
|
||||||
|
repo->path_index = NULL;
|
||||||
|
free(repo->path_repository);
|
||||||
|
repo->path_repository = NULL;
|
||||||
|
free(repo->path_odb);
|
||||||
|
repo->path_odb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void git_repository_free(git_repository *repo)
|
void git_repository_free(git_repository *repo)
|
||||||
{
|
{
|
||||||
if (repo == NULL)
|
if (repo == NULL)
|
||||||
@ -306,11 +443,7 @@ void git_repository_free(git_repository *repo)
|
|||||||
|
|
||||||
git_cache_free(&repo->objects);
|
git_cache_free(&repo->objects);
|
||||||
git_repository__refcache_free(&repo->references);
|
git_repository__refcache_free(&repo->references);
|
||||||
|
git_repository__free_dirs(repo);
|
||||||
free(repo->path_workdir);
|
|
||||||
free(repo->path_index);
|
|
||||||
free(repo->path_repository);
|
|
||||||
free(repo->path_odb);
|
|
||||||
|
|
||||||
if (repo->db != NULL)
|
if (repo->db != NULL)
|
||||||
git_odb_close(repo->db);
|
git_odb_close(repo->db);
|
||||||
@ -318,6 +451,119 @@ void git_repository_free(git_repository *repo)
|
|||||||
free(repo);
|
free(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
|
||||||
|
{
|
||||||
|
git_repository repo;
|
||||||
|
int error, ceiling_offset;
|
||||||
|
char bare_path[GIT_PATH_MAX];
|
||||||
|
char normal_path[GIT_PATH_MAX];
|
||||||
|
char *found_path;
|
||||||
|
dev_t current_device;
|
||||||
|
|
||||||
|
assert(start_path && repository_path);
|
||||||
|
memset(&repo, 0x0, sizeof(git_repository));
|
||||||
|
|
||||||
|
error = abspath(bare_path, sizeof(bare_path), start_path);
|
||||||
|
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!across_fs) {
|
||||||
|
error = retrieve_device(¤t_device, bare_path);
|
||||||
|
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ceiling_offset = retrieve_ceiling_directories_offset(bare_path, ceiling_dirs);
|
||||||
|
git__joinpath(normal_path, bare_path, DOT_GIT);
|
||||||
|
|
||||||
|
while(1){
|
||||||
|
//look for .git file
|
||||||
|
if (gitfo_isfile(normal_path) == GIT_SUCCESS) {
|
||||||
|
error = read_gitfile(repository_path, size, normal_path, bare_path);
|
||||||
|
|
||||||
|
if (error < GIT_SUCCESS) {
|
||||||
|
git__rethrow(error, "Unable to read git file `%s`", normal_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = discover_repository_dirs(&repo, repository_path);
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
git_repository__free_dirs(&repo);
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//look for .git repository
|
||||||
|
error = discover_repository_dirs(&repo, normal_path);
|
||||||
|
if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (error == GIT_SUCCESS) {
|
||||||
|
found_path = normal_path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_repository__free_dirs(&repo);
|
||||||
|
|
||||||
|
//look for bare repository in current directory
|
||||||
|
error = discover_repository_dirs(&repo, bare_path);
|
||||||
|
if (error < GIT_SUCCESS && error != GIT_ENOTAREPO)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (error == GIT_SUCCESS) {
|
||||||
|
found_path = bare_path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
git_repository__free_dirs(&repo);
|
||||||
|
|
||||||
|
//nothing has been found, lets try the parent directory
|
||||||
|
if (bare_path[ceiling_offset] == '\0') {
|
||||||
|
error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git__dirname_r(normal_path, sizeof(normal_path), bare_path) < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!across_fs) {
|
||||||
|
dev_t new_device;
|
||||||
|
error = retrieve_device(&new_device, normal_path);
|
||||||
|
|
||||||
|
if (error < GIT_SUCCESS)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (current_device != new_device) {
|
||||||
|
error = git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n"
|
||||||
|
"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM_ENVIRONMENT not set).", bare_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
current_device = new_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(bare_path, normal_path);
|
||||||
|
git__joinpath(normal_path, bare_path, DOT_GIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < (strlen(found_path) + 1) * sizeof(char)) {
|
||||||
|
error = git__throw(GIT_EOVERFLOW, "The repository buffer is not long enough to handle the repository path `%s`", found_path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(repository_path, found_path);
|
||||||
|
git_repository__free_dirs(&repo);
|
||||||
|
|
||||||
|
return GIT_SUCCESS;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
git_repository__free_dirs(&repo);
|
||||||
|
return git__rethrow(error, "Failed to discover repository");
|
||||||
|
}
|
||||||
|
|
||||||
git_odb *git_repository_database(git_repository *repo)
|
git_odb *git_repository_database(git_repository *repo)
|
||||||
{
|
{
|
||||||
assert(repo);
|
assert(repo);
|
||||||
@ -390,7 +636,7 @@ static int repo_init_find_dir(repo_init *results, const char* path)
|
|||||||
char temp_path[GIT_PATH_MAX];
|
char temp_path[GIT_PATH_MAX];
|
||||||
int error = GIT_SUCCESS;
|
int error = GIT_SUCCESS;
|
||||||
|
|
||||||
error = gitfo_prettify_dir_path(temp_path, sizeof(temp_path), path);
|
error = gitfo_prettify_dir_path(temp_path, sizeof(temp_path), path, NULL);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to find directory to initialize repository");
|
return git__rethrow(error, "Failed to find directory to initialize repository");
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ int sha1_entry_pos(const void *table,
|
|||||||
unsigned lo, unsigned hi, unsigned nr,
|
unsigned lo, unsigned hi, unsigned nr,
|
||||||
const unsigned char *key)
|
const unsigned char *key)
|
||||||
{
|
{
|
||||||
const unsigned char *base = table;
|
const unsigned char *base = (const unsigned char*)table;
|
||||||
const unsigned char *hi_key, *lo_key;
|
const unsigned char *hi_key, *lo_key;
|
||||||
unsigned ofs_0;
|
unsigned ofs_0;
|
||||||
|
|
||||||
@ -192,5 +192,5 @@ int sha1_entry_pos(const void *table,
|
|||||||
lo_key = mi_key + elem_size;
|
lo_key = mi_key + elem_size;
|
||||||
}
|
}
|
||||||
} while (lo < hi);
|
} while (lo < hi);
|
||||||
return -lo-1;
|
return -((int)lo)-1;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ BEGIN_TEST(path2, "get the latest component in a path")
|
|||||||
#undef TOPDIR_TEST
|
#undef TOPDIR_TEST
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
typedef int (normalize_path)(char *, size_t, const char *);
|
typedef int (normalize_path)(char *, size_t, const char *, const char *);
|
||||||
|
|
||||||
/* Assert flags */
|
/* Assert flags */
|
||||||
#define CWD_AS_PREFIX 1
|
#define CWD_AS_PREFIX 1
|
||||||
@ -168,7 +168,7 @@ static int ensure_normalized(const char *input_path, const char *expected_path,
|
|||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = normalizer(buffer_out, sizeof(buffer_out), input_path);
|
error = normalizer(buffer_out, sizeof(buffer_out), input_path, NULL);
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -417,7 +417,7 @@ BEGIN_TEST(path7, "prevent a path which escapes the root directory from being pr
|
|||||||
for (i = 0; i < number_to_escape + 1; i++)
|
for (i = 0; i < number_to_escape + 1; i++)
|
||||||
git__joinpath(current_workdir, current_workdir, "../");
|
git__joinpath(current_workdir, current_workdir, "../");
|
||||||
|
|
||||||
must_fail(gitfo_prettify_dir_path(prettified, sizeof(prettified), current_workdir));
|
must_fail(gitfo_prettify_dir_path(prettified, sizeof(prettified), current_workdir, NULL));
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
typedef struct name_data {
|
typedef struct name_data {
|
||||||
|
Loading…
Reference in New Issue
Block a user