diff options
| author | Chris Young <chris@unsatisfactorysoftware.co.uk> | 2012-06-07 20:29:22 +0100 |
|---|---|---|
| committer | Chris Young <chris@unsatisfactorysoftware.co.uk> | 2012-06-07 20:29:22 +0100 |
| commit | c3f35902f3f951de5ce5193409f336ee45c682b6 (patch) | |
| tree | e7329cc1496e676a65fb108bb9e830437e5ced7f /src/fileops.c | |
| parent | cada414a8044307b28f7a4c75986e5473bb4bc1c (diff) | |
| parent | cddb8efe564738873a4cf9ac63b7976d74035ae9 (diff) | |
| download | libgit2-c3f35902f3f951de5ce5193409f336ee45c682b6.tar.gz | |
Merge remote-tracking branch 'source/development' into update-test
Merging main libgit2!
Conflicts:
CMakeLists.txt
src/unix/map.c
Diffstat (limited to 'src/fileops.c')
| -rw-r--r-- | src/fileops.c | 728 |
1 files changed, 329 insertions, 399 deletions
diff --git a/src/fileops.c b/src/fileops.c index 73939349d..95a65893c 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -1,350 +1,283 @@ +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ #include "common.h" #include "fileops.h" #include <ctype.h> -int gitfo_mkdir_2file(const char *file_path) +int git_futils_mkpath2file(const char *file_path, const mode_t mode) { - const int mode = 0755; /* or 0777 ? */ - int error = GIT_SUCCESS; - char target_folder_path[GIT_PATH_MAX]; + int result = 0; + git_buf target_folder = GIT_BUF_INIT; - error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path); - if (error < GIT_SUCCESS) - return git__throw(GIT_EINVALIDPATH, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path); + if (git_path_dirname_r(&target_folder, file_path) < 0) + return -1; /* Does the containing folder exist? */ - if (gitfo_isdir(target_folder_path)) { - git__joinpath(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */ - + if (git_path_isdir(target_folder.ptr) == false) /* Let's create the tree structure */ - error = gitfo_mkdir_recurs(target_folder_path, mode); - if (error < GIT_SUCCESS) - return error; /* The callee already takes care of setting the correct error message. */ - } + result = git_futils_mkdir_r(target_folder.ptr, NULL, mode); - return GIT_SUCCESS; + git_buf_free(&target_folder); + return result; } -int gitfo_mktemp(char *path_out, const char *filename) +int git_futils_mktmp(git_buf *path_out, const char *filename) { int fd; - strcpy(path_out, filename); - strcat(path_out, "_git2_XXXXXX"); - -#if defined(_MSC_VER) - /* FIXME: there may be race conditions when multi-threading - * with the library */ - if (_mktemp_s(path_out, GIT_PATH_MAX) != 0) - return git__throw(GIT_EOSERR, "Failed to make temporary file %s", path_out); - - fd = gitfo_creat(path_out, 0744); -#else - fd = mkstemp(path_out); -#endif + git_buf_sets(path_out, filename); + git_buf_puts(path_out, "_git2_XXXXXX"); - return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out); -} + if (git_buf_oom(path_out)) + return -1; -int gitfo_open(const char *path, int flags) -{ - int fd = open(path, flags | O_BINARY); - return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to open %s", path); -} + if ((fd = p_mkstemp(path_out->ptr)) < 0) { + giterr_set(GITERR_OS, + "Failed to create temporary file '%s'", path_out->ptr); + return -1; + } -int gitfo_creat(const char *path, int mode) -{ - int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); - return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create file. Could not open %s", path); + return fd; } -int gitfo_creat_force(const char *path, int mode) +int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode) { - if (gitfo_mkdir_2file(path) < GIT_SUCCESS) - return git__throw(GIT_EOSERR, "Failed to create file %s", path); + int fd; - return gitfo_creat(path, mode); -} + if (git_futils_mkpath2file(path, dirmode) < 0) + return -1; -int gitfo_read(git_file fd, void *buf, size_t cnt) -{ - char *b = buf; - while (cnt) { - ssize_t r = read(fd, b, cnt); - if (r < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - return git__throw(GIT_EOSERR, "Failed to read from file"); - } - if (!r) { - errno = EPIPE; - return git__throw(GIT_EOSERR, "Failed to read from file"); - } - cnt -= r; - b += r; + fd = p_creat(path, mode); + if (fd < 0) { + giterr_set(GITERR_OS, "Failed to create file '%s'", path); + return -1; } - return GIT_SUCCESS; -} -int gitfo_write(git_file fd, void *buf, size_t cnt) -{ - char *b = buf; - while (cnt) { - ssize_t r = write(fd, b, cnt); - if (r < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - return git__throw(GIT_EOSERR, "Failed to write to file"); - } - if (!r) { - errno = EPIPE; - return git__throw(GIT_EOSERR, "Failed to write to file"); - } - cnt -= r; - b += r; - } - return GIT_SUCCESS; + return fd; } -int gitfo_isdir(const char *path) +int git_futils_creat_locked(const char *path, const mode_t mode) { - struct stat st; - int len, stat_error; + int fd; - if (!path) - return git__throw(GIT_ENOTFOUND, "No path given to gitfo_isdir"); +#ifdef GIT_WIN32 + wchar_t* buf; - len = strlen(path); + buf = gitwin_to_utf16(path); + fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode); + git__free(buf); +#else + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode); +#endif - /* win32: stat path for folders cannot end in a slash */ - if (path[len - 1] == '/') { - char *path_fixed = NULL; - path_fixed = git__strdup(path); - path_fixed[len - 1] = 0; - stat_error = gitfo_stat(path_fixed, &st); - free(path_fixed); - } else { - stat_error = gitfo_stat(path, &st); + if (fd < 0) { + giterr_set(GITERR_OS, "Failed to create locked file '%s'", path); + return -1; } - if (stat_error < GIT_SUCCESS) - return git__throw(GIT_ENOTFOUND, "%s does not exist", path); + return fd; +} - if (!S_ISDIR(st.st_mode)) - return git__throw(GIT_ENOTFOUND, "%s is a file", path); +int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode) +{ + if (git_futils_mkpath2file(path, dirmode) < 0) + return -1; - return GIT_SUCCESS; + return git_futils_creat_locked(path, mode); } -int gitfo_exists(const char *path) +int git_futils_open_ro(const char *path) { - assert(path); - return access(path, F_OK); + int fd = p_open(path, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + fd = GIT_ENOTFOUND; + giterr_set(GITERR_OS, "Failed to open '%s'", path); + } + return fd; } -git_off_t gitfo_size(git_file fd) +git_off_t git_futils_filesize(git_file fd) { struct stat sb; - if (gitfo_fstat(fd, &sb)) - return git__throw(GIT_EOSERR, "Failed to get size of file. File missing or corrupted"); + + if (p_fstat(fd, &sb)) { + giterr_set(GITERR_OS, "Failed to stat file descriptor"); + return -1; + } + return sb.st_size; } -int gitfo_read_file(gitfo_buf *obj, const char *path) +mode_t git_futils_canonical_mode(mode_t raw_mode) +{ + if (S_ISREG(raw_mode)) + return S_IFREG | GIT_CANONICAL_PERMS(raw_mode); + else if (S_ISLNK(raw_mode)) + return S_IFLNK; + else if (S_ISGITLINK(raw_mode)) + return S_IFGITLINK; + else if (S_ISDIR(raw_mode)) + return S_IFDIR; + else + return 0; +} + +int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, int *updated) { git_file fd; size_t len; - git_off_t size; - unsigned char *buff; + struct stat st; - assert(obj && path && *path); + assert(buf && path && *path); - if ((fd = gitfo_open(path, O_RDONLY)) < 0) - return git__throw(GIT_ERROR, "Failed to open %s for reading", path); + if (updated != NULL) + *updated = 0; - if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) { - gitfo_close(fd); - return git__throw(GIT_ERROR, "Failed to read file `%s`. An error occured while calculating its size", path); - } - len = (size_t) size; + if ((fd = git_futils_open_ro(path)) < 0) + return fd; - if ((buff = git__malloc(len + 1)) == NULL) { - gitfo_close(fd); - return GIT_ENOMEM; + if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) { + p_close(fd); + giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path); + return -1; } - if (gitfo_read(fd, buff, len) < 0) { - gitfo_close(fd); - free(buff); - return git__throw(GIT_ERROR, "Failed to read file `%s`", path); + /* + * If we were given a time, we only want to read the file if it + * has been modified. + */ + if (mtime != NULL && *mtime >= st.st_mtime) { + p_close(fd); + return 0; } - buff[len] = '\0'; - gitfo_close(fd); + if (mtime != NULL) + *mtime = st.st_mtime; - obj->data = buff; - obj->len = len; + len = (size_t) st.st_size; - return GIT_SUCCESS; -} - -void gitfo_free_buf(gitfo_buf *obj) -{ - assert(obj); - free(obj->data); - obj->data = NULL; -} + git_buf_clear(buf); -int gitfo_mv(const char *from, const char *to) -{ - int error; - -#ifdef GIT_WIN32 - /* - * Win32 POSIX compilance my ass. If the destination - * file exists, the `rename` call fails. This is as - * close as it gets with the Win32 API. - */ - error = MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR; -#else - /* Don't even try this on Win32 */ - if (!link(from, to)) { - gitfo_unlink(from); - return GIT_SUCCESS; + if (git_buf_grow(buf, len + 1) < 0) { + p_close(fd); + return -1; } - if (!rename(from, to)) - return GIT_SUCCESS; + buf->ptr[len] = '\0'; - error = GIT_EOSERR; -#endif + while (len > 0) { + ssize_t read_size = p_read(fd, buf->ptr, len); - if (error < GIT_SUCCESS) - return git__throw(error, "Failed to move file from `%s` to `%s`", from, to); + if (read_size < 0) { + p_close(fd); + giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path); + return -1; + } - return GIT_SUCCESS; -} + len -= read_size; + buf->size += read_size; + } -int gitfo_mv_force(const char *from, const char *to) -{ - if (gitfo_mkdir_2file(to) < GIT_SUCCESS) - return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */ + p_close(fd); - return gitfo_mv(from, to); /* The callee already takes care of setting the correct error message. */ -} + if (updated != NULL) + *updated = 1; -int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len) -{ - if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < GIT_SUCCESS) - return GIT_EOSERR; - return GIT_SUCCESS; + return 0; } -void gitfo_free_map(git_map *out) +int git_futils_readbuffer(git_buf *buf, const char *path) { - git__munmap(out); + return git_futils_readbuffer_updated(buf, path, NULL, NULL); } -int gitfo_dirent( - char *path, - size_t path_sz, - int (*fn)(void *, char *), - void *arg) +int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode) { - size_t wd_len = strlen(path); - DIR *dir; - struct dirent *de; - - if (!wd_len || path_sz < wd_len + 2) - return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path); - - while (path[wd_len - 1] == '/') - wd_len--; - path[wd_len++] = '/'; - path[wd_len] = '\0'; - - dir = opendir(path); - if (!dir) - return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path); - - while ((de = readdir(dir)) != NULL) { - size_t de_len; - int result; - - /* always skip '.' and '..' */ - if (de->d_name[0] == '.') { - if (de->d_name[1] == '\0') - continue; - if (de->d_name[1] == '.' && de->d_name[2] == '\0') - continue; - } + if (git_futils_mkpath2file(to, dirmode) < 0) + return -1; - de_len = strlen(de->d_name); - if (path_sz < wd_len + de_len + 1) { - closedir(dir); - return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path); - } - - strcpy(path + wd_len, de->d_name); - result = fn(arg, path); - if (result < GIT_SUCCESS) { - closedir(dir); - return result; /* The callee is reponsible for setting the correct error message */ - } - if (result > 0) { - closedir(dir); - return result; - } + if (p_rename(from, to) < 0) { + giterr_set(GITERR_OS, "Failed to rename '%s' to '%s'", from, to); + return -1; } - closedir(dir); - return GIT_SUCCESS; + return 0; } - -int retrieve_path_root_offset(const char *path) +int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len) { - int offset = 0; - -#ifdef GIT_WIN32 + return p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin); +} - /* Does the root of the path look like a windows drive ? */ - if (isalpha(path[0]) && (path[1] == ':')) - offset += 2; +int git_futils_mmap_ro_file(git_map *out, const char *path) +{ + git_file fd = git_futils_open_ro(path); + git_off_t len; + int result; -#endif + if (fd < 0) + return fd; - if (*(path + offset) == '/') - return offset; + len = git_futils_filesize(fd); + if (!git__is_sizet(len)) { + giterr_set(GITERR_OS, "File `%s` too large to mmap", path); + return -1; + } - return -1; /* Not a real error. Rather a signal than the path is not rooted */ + result = git_futils_mmap_ro(out, fd, 0, (size_t)len); + p_close(fd); + return result; } +void git_futils_mmap_free(git_map *out) +{ + p_munmap(out); +} -int gitfo_mkdir_recurs(const char *path, int mode) +int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) { - int error, root_path_offset; + git_buf make_path = GIT_BUF_INIT; + size_t start = 0; char *pp, *sp; - char *path_copy = git__strdup(path); + bool failed = false; + + if (base != NULL) { + /* + * when a base is being provided, it is supposed to already exist. + * Therefore, no attempt is being made to recursively create this leading path + * segment. It's just skipped. */ + start = strlen(base); + if (git_buf_joinpath(&make_path, base, path) < 0) + return -1; + } else { + int root_path_offset; - if (path_copy == NULL) - return GIT_ENOMEM; + if (git_buf_puts(&make_path, path) < 0) + return -1; - error = GIT_SUCCESS; - pp = path_copy; + root_path_offset = git_path_root(make_path.ptr); + if (root_path_offset > 0) { + /* + * On Windows, will skip the drive name (eg. C: or D:) + * or the leading part of a network path (eg. //computer_name ) */ + start = root_path_offset; + } + } - root_path_offset = retrieve_path_root_offset(pp); - if (root_path_offset > 0) - pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */ + pp = make_path.ptr + start; - while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != 0) { - if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) { + while (!failed && (sp = strchr(pp, '/')) != NULL) { + if (sp != pp && git_path_isdir(make_path.ptr) == false) { *sp = 0; - error = gitfo_mkdir(path_copy, mode); /* Do not choke while trying to recreate an existing directory */ - if (errno == EEXIST) - error = GIT_SUCCESS; + if (p_mkdir(make_path.ptr, mode) < 0 && errno != EEXIST) + failed = true; *sp = '/'; } @@ -352,201 +285,198 @@ int gitfo_mkdir_recurs(const char *path, int mode) pp = sp + 1; } - if (*(pp - 1) != '/' && error == GIT_SUCCESS) - error = gitfo_mkdir(path, mode); + if (*pp != '\0' && !failed) { + if (p_mkdir(make_path.ptr, mode) < 0 && errno != EEXIST) + failed = true; + } - free(path_copy); + git_buf_free(&make_path); - if (error < GIT_SUCCESS) - return git__throw(error, "Failed to recursively create `%s` tree structure", path); + if (failed) { + giterr_set(GITERR_OS, + "Failed to create directory structure at '%s'", path); + return -1; + } - return GIT_SUCCESS; + return 0; } -static int retrieve_previous_path_component_start(const char *path) +static int _rmdir_recurs_foreach(void *opaque, git_buf *path) { - int offset, len, root_offset, start = 0; + git_directory_removal_type removal_type = *(git_directory_removal_type *)opaque; + + assert(removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY + || removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS + || removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS); - root_offset = retrieve_path_root_offset(path); - if (root_offset > -1) - start += root_offset; + if (git_path_isdir(path->ptr) == true) { + if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0) + return -1; - len = strlen(path); - offset = len - 1; + if (p_rmdir(path->ptr) < 0) { + if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && (errno == ENOTEMPTY || errno == EEXIST)) + return 0; + + giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr); + return -1; + } - /* Skip leading slash */ - if (path[start] == '/') - start++; + return 0; + } - /* Skip trailing slash */ - if (path[offset] == '/') - offset--; + if (removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS) { + if (p_unlink(path->ptr) < 0) { + giterr_set(GITERR_OS, "Could not remove directory. File '%s' cannot be removed", path->ptr); + return -1; + } - if (offset < root_offset) - return git__throw(GIT_ERROR, "Failed to retrieve path component. Wrong offset"); + return 0; + } - while (offset > start && path[offset-1] != '/') { - offset--; + if (removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY) { + giterr_set(GITERR_OS, "Could not remove directory. File '%s' still present", path->ptr); + return -1; } - return offset; + return 0; } -int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path) +int git_futils_rmdir_r(const char *path, git_directory_removal_type removal_type) { - int len = 0, segment_len, only_dots, root_path_offset, error = GIT_SUCCESS; - char *current; - const char *buffer_out_start, *buffer_end; - - current = (char *)path; - buffer_end = path + strlen(path); - buffer_out_start = buffer_out; - - root_path_offset = retrieve_path_root_offset(path); - if (root_path_offset < 0) { - error = gitfo_getcwd(buffer_out, size); - if (error < GIT_SUCCESS) - return error; /* The callee already takes care of setting the correct error message. */ - - len = strlen(buffer_out); - buffer_out += len; - } + int error; + git_buf p = GIT_BUF_INIT; - while (current < buffer_end) { - /* Prevent multiple slashes from being added to the output */ - if (*current == '/' && len > 0 && buffer_out_start[len - 1] == '/') { - current++; - continue; - } - - only_dots = 1; - segment_len = 0; - - /* Copy path segment to the output */ - while (current < buffer_end && *current != '/') - { - only_dots &= (*current == '.'); - *buffer_out++ = *current++; - segment_len++; - len++; - } + error = git_buf_sets(&p, path); + if (!error) + error = _rmdir_recurs_foreach(&removal_type, &p); + git_buf_free(&p); + return error; +} - /* Skip current directory */ - if (only_dots && segment_len == 1) - { - current++; - buffer_out -= segment_len; - len -= segment_len; - continue; - } +#ifdef GIT_WIN32 +struct win32_path { + wchar_t path[MAX_PATH]; + DWORD len; +}; - /* Handle the double-dot upward directory navigation */ - if (only_dots && segment_len == 2) - { - current++; - buffer_out -= segment_len; +static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ) +{ + s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH); + return s_root->len ? 0 : -1; +} - *buffer_out ='\0'; - len = retrieve_previous_path_component_start(buffer_out_start); +static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename) +{ + int error = 0; + size_t len; + wchar_t *file_utf16 = NULL; + char *file_utf8 = NULL; - /* Are we escaping out of the root dir? */ - if (len < 0) - return git__throw(GIT_EINVALIDPATH, "Failed to normalize path `%s`. The path escapes out of the root directory", path); + if (!root || !filename || (len = strlen(filename)) == 0) + return GIT_ENOTFOUND; - buffer_out = (char *)buffer_out_start + len; - continue; - } + /* allocate space for wchar_t path to file */ + file_utf16 = git__calloc(root->len + len + 2, sizeof(wchar_t)); + GITERR_CHECK_ALLOC(file_utf16); - /* Guard against potential multiple dot path traversal (cf http://cwe.mitre.org/data/definitions/33.html) */ - if (only_dots && segment_len > 0) - return git__throw(GIT_EINVALIDPATH, "Failed to normalize path `%s`. The path contains a segment with three `.` or more", path); + /* append root + '\\' + filename as wchar_t */ + memcpy(file_utf16, root->path, root->len * sizeof(wchar_t)); - *buffer_out++ = '/'; - len++; + if (*filename == '/' || *filename == '\\') + filename++; + + if (gitwin_append_utf16(file_utf16 + root->len - 1, filename, len + 1) != + (int)len + 1) { + error = -1; + goto cleanup; + } + + /* check access */ + if (_waccess(file_utf16, F_OK) < 0) { + error = GIT_ENOTFOUND; + goto cleanup; } - *buffer_out = '\0'; + /* convert to utf8 */ + if ((file_utf8 = gitwin_from_utf16(file_utf16)) == NULL) + error = -1; + else { + git_path_mkposix(file_utf8); + git_buf_attach(path, file_utf8, 0); + } - return GIT_SUCCESS; +cleanup: + git__free(file_utf16); + return error; } +#endif -int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path) +int git_futils_find_system_file(git_buf *path, const char *filename) { - int error, path_len, i; - const char* pattern = "/.."; - - path_len = strlen(path); - - /* Let's make sure the filename isn't empty nor a dot */ - if (path_len == 0 || (path_len == 1 && *path == '.')) - return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path is either empty or equals `.`", path); +#ifdef GIT_WIN32 + struct win32_path root; - /* Let's make sure the filename doesn't end with "/", "/." or "/.." */ - for (i = 1; path_len > i && i < 4; i++) { - if (!strncmp(path + path_len - i, pattern, i)) - return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path); + if (win32_expand_path(&root, L"%PROGRAMFILES%\\Git\\etc\\") < 0 || + root.path[0] == L'%') /* i.e. no expansion happened */ + { + giterr_set(GITERR_OS, "Cannot locate the system's Program Files directory"); + return -1; } - error = gitfo_prettify_dir_path(buffer_out, size, path); - if (error < GIT_SUCCESS) - return error; /* The callee already takes care of setting the correct error message. */ + if (win32_find_file(path, &root, filename) < 0) { + git_buf_clear(path); + return GIT_ENOTFOUND; + } - 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) */ - return git__throw(GIT_EINVALIDPATH, "Failed to normalize file path `%s`. The path points to a folder", path); + return 0; - /* Remove the trailing slash */ - buffer_out[path_len - 1] = '\0'; +#else + if (git_buf_joinpath(path, "/etc", filename) < 0) + return -1; - return GIT_SUCCESS; -} + if (git_path_exists(path->ptr) == true) + return 0; -int gitfo_cmp_path(const char *name1, int len1, int isdir1, - const char *name2, int len2, int isdir2) -{ - int len = len1 < len2 ? len1 : len2; - int cmp; - - cmp = memcmp(name1, name2, len); - if (cmp) - return cmp; - if (len1 < len2) - return ((!isdir1 && !isdir2) ? -1 : - (isdir1 ? '/' - name2[len1] : name2[len1] - '/')); - if (len1 > len2) - return ((!isdir1 && !isdir2) ? 1 : - (isdir2 ? name1[len2] - '/' : '/' - name1[len2])); - return 0; + git_buf_clear(path); + return GIT_ENOTFOUND; +#endif } -static void posixify_path(char *path) +int git_futils_find_global_file(git_buf *path, const char *filename) { - while (*path) { - if (*path == '\\') - *path = '/'; +#ifdef GIT_WIN32 + struct win32_path root; - path++; + if (win32_expand_path(&root, L"%USERPROFILE%\\") < 0 || + root.path[0] == L'%') /* i.e. no expansion happened */ + { + giterr_set(GITERR_OS, "Cannot locate the user's profile directory"); + return -1; } -} - -int gitfo_getcwd(char *buffer_out, size_t size) -{ - char *cwd_buffer; - assert(buffer_out && size > 0); + if (win32_find_file(path, &root, filename) < 0) { + git_buf_clear(path); + return GIT_ENOTFOUND; + } -#ifdef GIT_WIN32 - cwd_buffer = _getcwd(buffer_out, size); + return 0; #else - cwd_buffer = getcwd(buffer_out, size); -#endif + const char *home = getenv("HOME"); - if (cwd_buffer == NULL) - return git__throw(GIT_EOSERR, "Failed to retrieve current working directory"); + if (home == NULL) { + giterr_set(GITERR_OS, "Global file lookup failed. " + "Cannot locate the user's home directory"); + return -1; + } - posixify_path(buffer_out); + if (git_buf_joinpath(path, home, filename) < 0) + return -1; - git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash + if (git_path_exists(path->ptr) == false) { + git_buf_clear(path); + return GIT_ENOTFOUND; + } - return GIT_SUCCESS; + return 0; +#endif } |
