diff options
Diffstat (limited to 'src/fileops.c')
| -rw-r--r-- | src/fileops.c | 131 |
1 files changed, 104 insertions, 27 deletions
diff --git a/src/fileops.c b/src/fileops.c index 76e689e8a..5dd4a3806 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -2,13 +2,13 @@ #include "fileops.h" #include <ctype.h> -static int force_path(const char *to) +int gitfo_mkdir_2file(const char *file_path) { const int mode = 0755; /* or 0777 ? */ int error = GIT_SUCCESS; char target_folder_path[GIT_PATH_MAX]; - error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to); + error = git__dirname_r(target_folder_path, sizeof(target_folder_path), file_path); if (error < GIT_SUCCESS) return error; @@ -25,6 +25,27 @@ static int force_path(const char *to) return GIT_SUCCESS; } +int gitfo_mktemp(char *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_EOSERR; + + fd = gitfo_creat(path_out, 0744); +#else + fd = mkstemp(path_out); +#endif + + return fd >= 0 ? fd : GIT_EOSERR; +} + int gitfo_open(const char *path, int flags) { int fd = open(path, flags | O_BINARY); @@ -39,7 +60,7 @@ int gitfo_creat(const char *path, int mode) int gitfo_creat_force(const char *path, int mode) { - if (force_path(path) < GIT_SUCCESS) + if (gitfo_mkdir_2file(path) < GIT_SUCCESS) return GIT_EOSERR; return gitfo_creat(path, mode); @@ -117,6 +138,7 @@ int gitfo_isdir(const char *path) int gitfo_exists(const char *path) { + assert(path); return access(path, F_OK); } @@ -181,7 +203,7 @@ int gitfo_mv(const char *from, const char *to) * file exists, the `rename` call fails. This is as * close as it gets with the Win32 API. */ - return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) ? GIT_SUCCESS : GIT_EOSERR; + return 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)) { @@ -198,7 +220,7 @@ int gitfo_mv(const char *from, const char *to) int gitfo_mv_force(const char *from, const char *to) { - if (force_path(to) < GIT_SUCCESS) + if (gitfo_mkdir_2file(to) < GIT_SUCCESS) return GIT_EOSERR; return gitfo_mv(from, to); @@ -361,22 +383,29 @@ int gitfo_dirent( return GIT_SUCCESS; } -#ifdef GIT_WIN32 -static int is_windows_rooted_path(const char *path) +int retrieve_path_root_offset(const char *path) { + int offset = 0; + +#ifdef GIT_WIN32 + /* Does the root of the path look like a windows drive ? */ if (isalpha(path[0]) && (path[1] == ':')) - return GIT_SUCCESS; + offset += 2; + +#endif + + if (*(path + offset) == '/') + return offset; return GIT_ERROR; } -#endif int gitfo_mkdir_recurs(const char *path, int mode) { - int error; + int error, root_path_offset; char *pp, *sp; char *path_copy = git__strdup(path); @@ -386,12 +415,9 @@ int gitfo_mkdir_recurs(const char *path, int mode) error = GIT_SUCCESS; pp = path_copy; -#ifdef GIT_WIN32 - - if (!is_windows_rooted_path(pp)) - pp += 2; /* Skip the drive name (eg. C: or D:) */ - -#endif + 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:) */ while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != 0) { if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) { @@ -417,8 +443,12 @@ int gitfo_mkdir_recurs(const char *path, int mode) static int retrieve_previous_path_component_start(const char *path) { - int offset, len, start = 0; - + int offset, len, root_offset, start = 0; + + root_offset = retrieve_path_root_offset(path); + if (root_offset > -1) + start += root_offset; + len = strlen(path); offset = len - 1; @@ -430,7 +460,7 @@ static int retrieve_previous_path_component_start(const char *path) if (path[offset] == '/') offset--; - if (offset < 0) + if (offset < root_offset) return GIT_ERROR; while (offset > start && path[offset-1] != '/') { @@ -440,15 +470,25 @@ static int retrieve_previous_path_component_start(const char *path) return offset; } -int gitfo_prettify_dir_path(char *buffer_out, const char *path) +int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path) { - int len = 0, segment_len, only_dots; + int len = 0, segment_len, only_dots, root_path_offset, error = GIT_SUCCESS; char *current; const char *buffer_out_start, *buffer_end; - buffer_out_start = buffer_out; 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; + + len = strlen(buffer_out); + buffer_out += len; + } while (current < buffer_end) { /* Prevent multiple slashes from being added to the output */ @@ -461,7 +501,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) segment_len = 0; /* Copy path segment to the output */ - while (current < buffer_end && *current !='/') + while (current < buffer_end && *current != '/') { only_dots &= (*current == '.'); *buffer_out++ = *current++; @@ -486,7 +526,9 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) *buffer_out ='\0'; len = retrieve_previous_path_component_start(buffer_out_start); - if (len < GIT_SUCCESS) + + /* Are we escaping out of the root dir? */ + if (len < 0) return GIT_EINVALIDPATH; buffer_out = (char *)buffer_out_start + len; @@ -494,7 +536,7 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) } /* Guard against potential multiple dot path traversal (cf http://cwe.mitre.org/data/definitions/33.html) */ - if (only_dots &&segment_len > 0) + if (only_dots && segment_len > 0) return GIT_EINVALIDPATH; *buffer_out++ = '/'; @@ -506,20 +548,24 @@ int gitfo_prettify_dir_path(char *buffer_out, const char *path) return GIT_SUCCESS; } -int gitfo_prettify_file_path(char *buffer_out, const char *path) +int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path) { 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_EINVALIDPATH; + /* 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_EINVALIDPATH; } - error = gitfo_prettify_dir_path(buffer_out, path); + error = gitfo_prettify_dir_path(buffer_out, size, path); if (error < GIT_SUCCESS) return error; @@ -551,3 +597,34 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1, return 0; } +static void posixify_path(char *path) +{ + while (*path) { + if (*path == '\\') + *path = '/'; + + path++; + } +} + +int gitfo_getcwd(char *buffer_out, size_t size) +{ + char *cwd_buffer; + + assert(buffer_out && size > 0); + +#ifdef GIT_WIN32 + cwd_buffer = _getcwd(buffer_out, size); +#else + cwd_buffer = getcwd(buffer_out, size); //TODO: Fixme. Ensure the required headers are correctly included +#endif + + if (cwd_buffer == NULL) + return GIT_EOSERR; + + posixify_path(buffer_out); + + git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash + + return GIT_SUCCESS; +} |
