diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2015-03-18 04:59:16 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2015-03-18 04:59:16 +0100 |
commit | 83ad46f7269aa9768c768a366f5cc3912f84a421 (patch) | |
tree | c88e81545510f33d013e6fc316464a7bacaf8a9f /src | |
parent | 4c2e6b1e871aaee3de35862da5dd0135fbcd5ec7 (diff) | |
parent | 4196dd8e8fceaaa42ad5854e1ce362c14b8c0bf6 (diff) | |
download | libgit2-83ad46f7269aa9768c768a366f5cc3912f84a421.tar.gz |
Merge remote-tracking branch 'ethomson/submodule_8dot3'
Diffstat (limited to 'src')
-rw-r--r-- | src/path.c | 39 | ||||
-rw-r--r-- | src/repository.c | 147 | ||||
-rw-r--r-- | src/repository.h | 42 |
3 files changed, 167 insertions, 61 deletions
diff --git a/src/path.c b/src/path.c index 64c7b7e12..993fcf60f 100644 --- a/src/path.c +++ b/src/path.c @@ -1351,30 +1351,31 @@ static bool verify_dotgit_hfs(const char *path, size_t len) GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size_t len) { - const char *shortname = NULL; - size_t i, start, shortname_len = 0; - - /* See if the repo has a custom shortname (not "GIT~1") */ - if (repo && - (shortname = git_repository__8dot3_name(repo)) && - shortname != git_repository__8dot3_default) - shortname_len = strlen(shortname); - - if (len >= 4 && strncasecmp(path, ".git", 4) == 0) - start = 4; - else if (len >= git_repository__8dot3_default_len && - strncasecmp(path, git_repository__8dot3_default, git_repository__8dot3_default_len) == 0) - start = git_repository__8dot3_default_len; - else if (shortname_len && len >= shortname_len && - strncasecmp(path, shortname, shortname_len) == 0) - start = shortname_len; - else + git_buf *reserved = git_repository__reserved_names_win32; + size_t reserved_len = git_repository__reserved_names_win32_len; + size_t start = 0, i; + + if (repo) + git_repository__reserved_names(&reserved, &reserved_len, repo, true); + + for (i = 0; i < reserved_len; i++) { + git_buf *r = &reserved[i]; + + if (len >= r->size && + strncasecmp(path, r->ptr, r->size) == 0) { + start = r->size; + break; + } + } + + if (!start) return true; - /* Reject paths beginning with ".git\" */ + /* Reject paths like ".git\" */ if (path[start] == '\\') return false; + /* Reject paths like '.git ' or '.git.' */ for (i = start; i < len; i++) { if (path[i] != ' ' && path[i] != '.') return true; diff --git a/src/repository.c b/src/repository.c index b1f94f0e2..6a80070d1 100644 --- a/src/repository.c +++ b/src/repository.c @@ -38,8 +38,16 @@ #define GIT_REPO_VERSION 0 -const char *git_repository__8dot3_default = "GIT~1"; -size_t git_repository__8dot3_default_len = 5; +git_buf git_repository__reserved_names_win32[] = { + { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, + { GIT_DIR_SHORTNAME, 0, CONST_STRLEN(GIT_DIR_SHORTNAME) } +}; +size_t git_repository__reserved_names_win32_len = 2; + +git_buf git_repository__reserved_names_posix[] = { + { DOT_GIT, 0, CONST_STRLEN(DOT_GIT) }, +}; +size_t git_repository__reserved_names_posix_len = 1; static void set_odb(git_repository *repo, git_odb *odb) { @@ -111,6 +119,8 @@ void git_repository__cleanup(git_repository *repo) void git_repository_free(git_repository *repo) { + size_t i; + if (repo == NULL) return; @@ -121,10 +131,12 @@ void git_repository_free(git_repository *repo) git_diff_driver_registry_free(repo->diff_drivers); repo->diff_drivers = NULL; + for (i = 0; i < repo->reserved_names.size; i++) + git_buf_free(git_array_get(repo->reserved_names, i)); + git__free(repo->path_repository); git__free(repo->workdir); git__free(repo->namespace); - git__free(repo->name_8dot3); git__free(repo->ident_name); git__free(repo->ident_email); @@ -156,18 +168,26 @@ static bool valid_repository_path(git_buf *repository_path) static git_repository *repository_alloc(void) { git_repository *repo = git__calloc(1, sizeof(git_repository)); - if (!repo) - return NULL; - if (git_cache_init(&repo->objects) < 0) { - git__free(repo); - return NULL; - } + if (repo == NULL || + git_cache_init(&repo->objects) < 0) + goto on_error; + + git_array_init_to_size(repo->reserved_names, 4); + if (!repo->reserved_names.ptr) + goto on_error; /* set all the entries in the cvar cache to `unset` */ git_repository__cvar_cache_clear(repo); return repo; + +on_error: + if (repo) + git_cache_free(&repo->objects); + + git__free(repo); + return NULL; } int git_repository_new(git_repository **out) @@ -327,6 +347,7 @@ static int read_gitfile(git_buf *path_out, const char *file_path) static int find_repo( git_buf *repo_path, git_buf *parent_path, + git_buf *link_path, const char *start_path, uint32_t flags, const char *ceiling_dirs) @@ -369,9 +390,14 @@ static int find_repo( git_buf repo_link = GIT_BUF_INIT; if (!(error = read_gitfile(&repo_link, path.ptr))) { - if (valid_repository_path(&repo_link)) + if (valid_repository_path(&repo_link)) { git_buf_swap(repo_path, &repo_link); + if (link_path) + error = git_buf_put(link_path, + path.ptr, path.size); + } + git_buf_free(&repo_link); break; } @@ -458,13 +484,16 @@ int git_repository_open_ext( const char *ceiling_dirs) { int error; - git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT; + git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT, + link_path = GIT_BUF_INIT; git_repository *repo; if (repo_ptr) *repo_ptr = NULL; - error = find_repo(&path, &parent, start_path, flags, ceiling_dirs); + error = find_repo( + &path, &parent, &link_path, start_path, flags, ceiling_dirs); + if (error < 0 || !repo_ptr) return error; @@ -474,6 +503,11 @@ int git_repository_open_ext( repo->path_repository = git_buf_detach(&path); GITERR_CHECK_ALLOC(repo->path_repository); + if (link_path.size) { + repo->path_gitlink = git_buf_detach(&link_path); + GITERR_CHECK_ALLOC(repo->path_gitlink); + } + if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) repo->is_bare = 1; else { @@ -525,7 +559,7 @@ int git_repository_discover( git_buf_sanitize(out); - return find_repo(out, NULL, start_path, flags, ceiling_dirs); + return find_repo(out, NULL, NULL, start_path, flags, ceiling_dirs); } static int load_config( @@ -810,27 +844,88 @@ const char *git_repository_get_namespace(git_repository *repo) return repo->namespace; } -const char *git_repository__8dot3_name(git_repository *repo) +#ifdef GIT_WIN32 +static int reserved_names_add8dot3(git_repository *repo, const char *path) { - if (!repo->has_8dot3) { - repo->has_8dot3 = 1; + char *name = git_win32_path_8dot3_name(path); + const char *def = GIT_DIR_SHORTNAME; + size_t name_len, def_len = CONST_STRLEN(GIT_DIR_SHORTNAME); + git_buf *buf; -#ifdef GIT_WIN32 + if (!name) + return 0; + + name_len = strlen(name); + + if (name_len == def_len && memcmp(name, def, def_len) == 0) { + git__free(name); + return 0; + } + + if ((buf = git_array_alloc(repo->reserved_names)) == NULL) + return -1; + + git_buf_attach(buf, name, name_len); + return true; +} + +bool git_repository__reserved_names( + git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs) +{ + GIT_UNUSED(include_ntfs); + + if (repo->reserved_names.size == 0) { + git_buf *buf; + size_t i; + + /* Add the static defaults */ + for (i = 0; i < git_repository__reserved_names_win32_len; i++) { + if ((buf = git_array_alloc(repo->reserved_names)) == NULL) + goto on_error; + + buf->ptr = git_repository__reserved_names_win32[i].ptr; + buf->size = git_repository__reserved_names_win32[i].size; + } + + /* Try to add any repo-specific reserved names */ if (!repo->is_bare) { - repo->name_8dot3 = git_win32_path_8dot3_name(repo->path_repository); + const char *reserved_path = repo->path_gitlink ? + repo->path_gitlink : repo->path_repository; - /* We anticipate the 8.3 name is "GIT~1", so use a static for - * easy testing in the common case */ - if (repo->name_8dot3 && - strcasecmp(repo->name_8dot3, git_repository__8dot3_default) == 0) - repo->has_8dot3_default = 1; + if (reserved_names_add8dot3(repo, reserved_path) < 0) + goto on_error; } -#endif } - return repo->has_8dot3_default ? - git_repository__8dot3_default : repo->name_8dot3; + *out = repo->reserved_names.ptr; + *outlen = repo->reserved_names.size; + + return true; + + /* Always give good defaults, even on OOM */ +on_error: + *out = git_repository__reserved_names_win32; + *outlen = git_repository__reserved_names_win32_len; + + return false; } +#else +bool git_repository__reserved_names( + git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs) +{ + GIT_UNUSED(repo); + + if (include_ntfs) { + *out = git_repository__reserved_names_win32; + *outlen = git_repository__reserved_names_win32_len; + } else { + *out = git_repository__reserved_names_posix; + *outlen = git_repository__reserved_names_posix_len; + } + + return true; +} +#endif static int check_repositoryformatversion(git_config *config) { diff --git a/src/repository.h b/src/repository.h index 56d443d3c..253287368 100644 --- a/src/repository.h +++ b/src/repository.h @@ -14,6 +14,7 @@ #include "git2/object.h" #include "git2/config.h" +#include "array.h" #include "cache.h" #include "refs.h" #include "buffer.h" @@ -27,6 +28,9 @@ #define GIT_DIR_MODE 0755 #define GIT_BARE_DIR_MODE 0777 +/* Default DOS-compatible 8.3 "short name" for a git repository, "GIT~1" */ +#define GIT_DIR_SHORTNAME "GIT~1" + /** Cvar cache identifiers */ typedef enum { GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */ @@ -124,16 +128,17 @@ struct git_repository { git_diff_driver_registry *diff_drivers; char *path_repository; + char *path_gitlink; char *workdir; char *namespace; - char *name_8dot3; char *ident_name; char *ident_email; - unsigned is_bare:1, - has_8dot3:1, - has_8dot3_default:1; + git_array_t(git_buf) reserved_names; + + unsigned is_bare:1; + unsigned int lru_counter; git_atomic attr_session_key; @@ -188,19 +193,24 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len); -/* - * Gets the DOS-compatible 8.3 "short name". This will return only the - * short name for the repository directory (ie, "git~1" for ".git"). This - * will always return a pointer to `git_repository__8dot3_default` when - * "GIT~1" is the short name. This will return NULL for bare repositories, - * and systems that do not have a short name. - */ -const char *git_repository__8dot3_name(git_repository *repo); +/* The default "reserved names" for a repository */ +extern git_buf git_repository__reserved_names_win32[]; +extern size_t git_repository__reserved_names_win32_len; + +extern git_buf git_repository__reserved_names_posix[]; +extern size_t git_repository__reserved_names_posix_len; -/* The default DOS-compatible 8.3 "short name" for a git repository, - * "GIT~1". +/* + * Gets any "reserved names" in the repository. This will return paths + * that should not be allowed in the repository (like ".git") to avoid + * conflicting with the repository path, or with alternate mechanisms to + * the repository path (eg, "GIT~1"). Every attempt will be made to look + * up all possible reserved names - if there was a conflict for the shortname + * GIT~1, for example, this function will try to look up the alternate + * shortname. If that fails, this function returns false, but out and outlen + * will still be populated with good defaults. */ -extern const char *git_repository__8dot3_default; -extern size_t git_repository__8dot3_default_len; +bool git_repository__reserved_names( + git_buf **out, size_t *outlen, git_repository *repo, bool include_ntfs); #endif |