diff options
Diffstat (limited to 'src/fileops.c')
-rw-r--r-- | src/fileops.c | 417 |
1 files changed, 79 insertions, 338 deletions
diff --git a/src/fileops.c b/src/fileops.c index 3f0198dc4..486ea3bbe 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -2,22 +2,45 @@ #include "fileops.h" #include <ctype.h> -int gitfo_mkdir_2file(const char *file_path) +int git_futils_mv_atomic(const char *from, const char *to) +{ +#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. + */ + 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)) { + p_unlink(from); + return GIT_SUCCESS; + } + + if (!rename(from, to)) + return GIT_SUCCESS; + + return GIT_ERROR; +#endif +} + +int git_futils_mkpath2file(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), file_path); + error = git_path_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); /* 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_futils_isdir(target_folder_path)) { + git_path_join(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */ /* Let's create the tree structure */ - error = gitfo_mkdir_recurs(target_folder_path, mode); + error = git_futils_mkdir_r(target_folder_path, mode); if (error < GIT_SUCCESS) return error; /* The callee already takes care of setting the correct error message. */ } @@ -25,7 +48,7 @@ int gitfo_mkdir_2file(const char *file_path) return GIT_SUCCESS; } -int gitfo_mktemp(char *path_out, const char *filename) +int git_futils_mktmp(char *path_out, const char *filename) { int fd; @@ -38,7 +61,7 @@ int gitfo_mktemp(char *path_out, const char *filename) 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); + fd = p_creat(path_out, 0744); #else fd = mkstemp(path_out); #endif @@ -46,79 +69,29 @@ int gitfo_mktemp(char *path_out, const char *filename) return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out); } -int gitfo_open(const char *path, int flags) +int git_futils_creat_withpath(const char *path, int mode) { - int fd = open(path, flags | O_BINARY); - return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to open %s", path); -} - -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); -} - -int gitfo_creat_force(const char *path, int mode) -{ - if (gitfo_mkdir_2file(path) < GIT_SUCCESS) + if (git_futils_mkpath2file(path) < GIT_SUCCESS) return git__throw(GIT_EOSERR, "Failed to create file %s", path); - return gitfo_creat(path, mode); + return p_creat(path, mode); } -int gitfo_creat_locked(const char *path, int mode) +int git_futils_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) +int git_futils_creat_locked_withpath(const char *path, int mode) { - if (gitfo_mkdir_2file(path) < GIT_SUCCESS) + if (git_futils_mkpath2file(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) -{ - 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) - break; - cnt -= r; - b += r; - } - return (int)(b - (char *)buf); -} - -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 git_futils_creat_locked(path, mode); } -int gitfo_isdir(const char *path) +int git_futils_isdir(const char *path) { struct stat st; int len, stat_error; @@ -132,10 +105,10 @@ int gitfo_isdir(const char *path) char *path_fixed = NULL; path_fixed = git__strdup(path); path_fixed[len - 1] = 0; - stat_error = gitfo_stat(path_fixed, &st); + stat_error = p_stat(path_fixed, &st); free(path_fixed); } else { - stat_error = gitfo_stat(path, &st); + stat_error = p_stat(path, &st); } if (stat_error < GIT_SUCCESS) @@ -147,15 +120,15 @@ int gitfo_isdir(const char *path) return GIT_SUCCESS; } -int gitfo_isfile(const char *path) +int git_futils_isfile(const char *path) { struct stat st; int stat_error; if (!path) - return git__throw(GIT_ENOTFOUND, "No path given to gitfo_isfile"); + return git__throw(GIT_ENOTFOUND, "No path given to git_futils_isfile"); - stat_error = gitfo_stat(path, &st); + stat_error = p_stat(path, &st); if (stat_error < GIT_SUCCESS) return git__throw(GIT_ENOTFOUND, "%s does not exist", path); @@ -166,21 +139,21 @@ int gitfo_isfile(const char *path) return GIT_SUCCESS; } -int gitfo_exists(const char *path) +int git_futils_exists(const char *path) { assert(path); return access(path, F_OK); } -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)) + if (p_fstat(fd, &sb)) return git__throw(GIT_EOSERR, "Failed to get size of file. File missing or corrupted"); return sb.st_size; } -int gitfo_read_file(gitfo_buf *obj, const char *path) +int git_futils_readbuffer(git_fbuffer *obj, const char *path) { git_file fd; size_t len; @@ -189,28 +162,28 @@ int gitfo_read_file(gitfo_buf *obj, const char *path) assert(obj && path && *path); - if ((fd = gitfo_open(path, O_RDONLY)) < 0) + if ((fd = p_open(path, O_RDONLY)) < 0) return git__throw(GIT_ERROR, "Failed to open %s for reading", path); - if (((size = gitfo_size(fd)) < 0) || !git__is_sizet(size+1)) { - gitfo_close(fd); + if (((size = git_futils_filesize(fd)) < 0) || !git__is_sizet(size+1)) { + p_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 ((buff = git__malloc(len + 1)) == NULL) { - gitfo_close(fd); + p_close(fd); return GIT_ENOMEM; } - if (gitfo_read(fd, buff, len) < 0) { - gitfo_close(fd); + if (p_read(fd, buff, len) < 0) { + p_close(fd); free(buff); return git__throw(GIT_ERROR, "Failed to read file `%s`", path); } buff[len] = '\0'; - gitfo_close(fd); + p_close(fd); obj->data = buff; obj->len = len; @@ -218,64 +191,33 @@ int gitfo_read_file(gitfo_buf *obj, const char *path) return GIT_SUCCESS; } -void gitfo_free_buf(gitfo_buf *obj) +void git_futils_freebuffer(git_fbuffer *obj) { assert(obj); free(obj->data); obj->data = NULL; } -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 (!rename(from, to)) - return GIT_SUCCESS; - - error = GIT_EOSERR; -#endif - - if (error < GIT_SUCCESS) - return git__throw(error, "Failed to move file from `%s` to `%s`", from, to); - - return GIT_SUCCESS; -} - -int gitfo_mv_force(const char *from, const char *to) +int git_futils_mv_withpath(const char *from, const char *to) { - if (gitfo_mkdir_2file(to) < GIT_SUCCESS) + if (git_futils_mkpath2file(to) < GIT_SUCCESS) return GIT_EOSERR; /* The callee already takes care of setting the correct error message. */ - return gitfo_mv(from, to); /* The callee already takes care of setting the correct error message. */ + return git_futils_mv_atomic(from, to); /* The callee already takes care of setting the correct error message. */ } -int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len) +int git_futils_mmap_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 p_mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin); } -void gitfo_free_map(git_map *out) +void git_futils_mmap_free(git_map *out) { - git__munmap(out); + p_munmap(out); } -int gitfo_dirent( +int git_futils_direach( char *path, size_t path_sz, int (*fn)(void *, char *), @@ -331,33 +273,14 @@ int gitfo_dirent( return GIT_SUCCESS; } -#if GIT_PLATFORM_PATH_SEP == '/' -void gitfo_posixify_path(char *GIT_UNUSED(path)) -{ - /* nothing to do*/ -} -#else -void gitfo_posixify_path(char *path) -{ - while (*path) { - if (*path == GIT_PLATFORM_PATH_SEP) - *path = '/'; - - path++; - } -} -#endif - -int gitfo_retrieve_path_root_offset(const char *path) +int git_futils_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] == ':')) offset += 2; - #endif if (*(path + offset) == '/') @@ -366,7 +289,7 @@ int gitfo_retrieve_path_root_offset(const char *path) 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 git_futils_mkdir_r(const char *path, int mode) { int error, root_path_offset; char *pp, *sp; @@ -378,14 +301,14 @@ int gitfo_mkdir_recurs(const char *path, int mode) error = GIT_SUCCESS; pp = path_copy; - root_path_offset = gitfo_retrieve_path_root_offset(pp); + root_path_offset = git_futils_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, '/')) != NULL) { - if (sp != pp && gitfo_isdir(path_copy) < GIT_SUCCESS) { + if (sp != pp && git_futils_isdir(path_copy) < GIT_SUCCESS) { *sp = 0; - error = gitfo_mkdir(path_copy, mode); + error = p_mkdir(path_copy, mode); /* Do not choke while trying to recreate an existing directory */ if (errno == EEXIST) @@ -398,7 +321,7 @@ int gitfo_mkdir_recurs(const char *path, int mode) } if (*pp != '\0' && error == GIT_SUCCESS) { - error = gitfo_mkdir(path, mode); + error = p_mkdir(path, mode); if (errno == EEXIST) error = GIT_SUCCESS; } @@ -415,7 +338,7 @@ static int retrieve_previous_path_component_start(const char *path) { int offset, len, root_offset, start = 0; - root_offset = gitfo_retrieve_path_root_offset(path); + root_offset = git_futils_root_offset(path); if (root_offset > -1) start += root_offset; @@ -440,7 +363,7 @@ static int retrieve_previous_path_component_start(const char *path) return offset; } -int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path, const char *base_path) +int git_futils_prettify_dir(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; char *current; @@ -450,10 +373,10 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path, con buffer_end = path + strlen(path); buffer_out_start = buffer_out; - root_path_offset = gitfo_retrieve_path_root_offset(path); + root_path_offset = git_futils_root_offset(path); if (root_path_offset < 0) { if (base_path == NULL) { - error = gitfo_getcwd(buffer_out, size); + error = p_getcwd(buffer_out, size); if (error < GIT_SUCCESS) return error; /* The callee already takes care of setting the correct error message. */ } else { @@ -461,8 +384,8 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path, con 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, ""); + git_path_mkposix(buffer_out); + git_path_join(buffer_out, buffer_out, ""); } len = strlen(buffer_out); @@ -527,7 +450,7 @@ int gitfo_prettify_dir_path(char *buffer_out, size_t size, const char *path, con return GIT_SUCCESS; } -int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path, const char *base_path) +int git_futils_prettyify_file(char *buffer_out, size_t size, const char *path, const char *base_path) { int error, path_len, i, root_offset; const char* pattern = "/.."; @@ -544,12 +467,12 @@ int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path, co 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, base_path); + error = git_futils_prettify_dir(buffer_out, size, path, base_path); if (error < GIT_SUCCESS) return error; /* The callee already takes care of setting the correct error message. */ path_len = strlen(buffer_out); - root_offset = gitfo_retrieve_path_root_offset(buffer_out) + 1; + root_offset = git_futils_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); @@ -559,7 +482,7 @@ int gitfo_prettify_file_path(char *buffer_out, size_t size, const char *path, co return GIT_SUCCESS; } -int gitfo_cmp_path(const char *name1, int len1, int isdir1, +int git_futils_cmp_path(const char *name1, int len1, int isdir1, const char *name2, int len2, int isdir2) { int len = len1 < len2 ? len1 : len2; @@ -577,185 +500,3 @@ int gitfo_cmp_path(const char *name1, int len1, int isdir1, return 0; } -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); -#endif - - if (cwd_buffer == NULL) - return git__throw(GIT_EOSERR, "Failed to retrieve current working directory"); - - gitfo_posixify_path(buffer_out); - - git__joinpath(buffer_out, buffer_out, ""); //Ensure the path ends with a trailing slash - - return GIT_SUCCESS; -} - -#ifdef GIT_WIN32 -GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft) -{ - long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; - winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ - winTime /= 10000000; /* Nano to seconds resolution */ - return (time_t)winTime; -} - -static int do_lstat(const char *file_name, struct stat *buf) -{ - WIN32_FILE_ATTRIBUTE_DATA fdata; - - if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) { - int fMode = S_IREAD; - - if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - fMode |= S_IFDIR; - else - fMode |= S_IFREG; - - if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) - fMode |= S_IWRITE; - - if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - fMode |= S_IFLNK; - - buf->st_ino = 0; - buf->st_gid = 0; - buf->st_uid = 0; - buf->st_nlink = 1; - buf->st_mode = (mode_t)fMode; - buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_dev = buf->st_rdev = (_getdrive() - 1); - buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); - buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); - buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); - return GIT_SUCCESS; - } - - switch (GetLastError()) { - case ERROR_ACCESS_DENIED: - case ERROR_SHARING_VIOLATION: - case ERROR_LOCK_VIOLATION: - case ERROR_SHARING_BUFFER_EXCEEDED: - return GIT_EOSERR; - - case ERROR_BUFFER_OVERFLOW: - case ERROR_NOT_ENOUGH_MEMORY: - return GIT_ENOMEM; - - default: - return GIT_EINVALIDPATH; - } -} - -int gitfo_lstat__w32(const char *file_name, struct stat *buf) -{ - int namelen, error; - char alt_name[GIT_PATH_MAX]; - - if ((error = do_lstat(file_name, buf)) == GIT_SUCCESS) - return GIT_SUCCESS; - - /* if file_name ended in a '/', Windows returned ENOENT; - * try again without trailing slashes - */ - if (error != GIT_EINVALIDPATH) - return git__throw(GIT_EOSERR, "Failed to lstat file"); - - namelen = strlen(file_name); - if (namelen && file_name[namelen-1] != '/') - return git__throw(GIT_EOSERR, "Failed to lstat file"); - - while (namelen && file_name[namelen-1] == '/') - --namelen; - - if (!namelen || namelen >= GIT_PATH_MAX) - return git__throw(GIT_ENOMEM, "Failed to lstat file"); - - memcpy(alt_name, file_name, namelen); - alt_name[namelen] = 0; - return do_lstat(alt_name, buf); -} - -int gitfo_readlink__w32(const char *link, char *target, size_t target_len) -{ - typedef DWORD (WINAPI *fpath_func)(HANDLE, LPTSTR, DWORD, DWORD); - static fpath_func pGetFinalPath = NULL; - HANDLE hFile; - DWORD dwRet; - - /* - * Try to load the pointer to pGetFinalPath dynamically, because - * it is not available in platforms older than Vista - */ - if (pGetFinalPath == NULL) { - HINSTANCE library = LoadLibrary("kernel32"); - - if (library != NULL) - pGetFinalPath = (fpath_func)GetProcAddress(library, "GetFinalPathNameByHandleA"); - - if (pGetFinalPath == NULL) - return git__throw(GIT_EOSERR, - "'GetFinalPathNameByHandleA' is not available in this platform"); - } - - hFile = CreateFile(link, // file to open - GENERIC_READ, // open for reading - FILE_SHARE_READ, // share for reading - NULL, // default security - OPEN_EXISTING, // existing file only - FILE_FLAG_BACKUP_SEMANTICS, // normal file - NULL); // no attr. template - - if (hFile == INVALID_HANDLE_VALUE) - return GIT_EOSERR; - - dwRet = pGetFinalPath(hFile, target, target_len, 0x0); - if (dwRet >= target_len) - return GIT_ENOMEM; - - CloseHandle(hFile); - - if (dwRet > 4) { - /* Skip first 4 characters if they are "\\?\" */ - if (target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') { - char tmp[GIT_PATH_MAX]; - unsigned int offset = 4; - dwRet -= 4; - - /* \??\UNC\ */ - if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') { - offset += 2; - dwRet -= 2; - target[offset] = '\\'; - } - - memcpy(tmp, target + offset, dwRet); - memcpy(target, tmp, dwRet); - } - } - - target[dwRet] = '\0'; - return dwRet; -} - -int gitfo_hide_directory__w32(const char *path) -{ - int error; - - error = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) != 0 ? - GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */ - - if (error < GIT_SUCCESS) - error = git__throw(GIT_EOSERR, "Failed to hide directory '%s'", path); - - return error; -} -#endif |