diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c index e9bc64a5f..a1ecce435 100644 --- a/src/win32/path_w32.c +++ b/src/win32/path_w32.c @@ -330,9 +330,7 @@ int git_win32_path_dirload_with_stat( const char *repo_path = path + prefix_len; size_t repo_path_len = strlen(repo_path); char work_path[PATH__MAX_UNC_LEN]; - git_win32_path target; size_t path_len; - int fMode; if (!git_win32__findfirstfile_filter(pathw, path)) { error = -1; @@ -374,46 +372,19 @@ int git_win32_path_dirload_with_stat( cmp_len = min(start_len, path_len); if (!(cmp_len && strncomp(work_path, start_stat, cmp_len) < 0)) { cmp_len = min(end_len, path_len); + if (!(cmp_len && strncomp(work_path, end_stat, cmp_len) > 0)) { - fMode = S_IREAD; - - if (dir->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - fMode |= S_IFDIR; - else - fMode |= S_IFREG; - - if (!(dir->f.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) - fMode |= S_IWRITE; - ps = git__calloc(1, sizeof(git_path_with_stat) + path_len + 2); + + if ((error = git_win32__file_attribute_to_stat(&ps->st, + (WIN32_FILE_ATTRIBUTE_DATA *)&dir->f, + NULL)) < 0) { + git__free(ps); + goto clean_up_and_exit; + } + memcpy(ps->path, work_path, path_len + 1); ps->path_len = path_len; - ps->st.st_atime = filetime_to_time_t(&dir->f.ftLastAccessTime); - ps->st.st_ctime = filetime_to_time_t(&dir->f.ftCreationTime); - ps->st.st_mtime = filetime_to_time_t(&dir->f.ftLastWriteTime); - ps->st.st_size = dir->f.nFileSizeHigh; - ps->st.st_size <<= 32; - ps->st.st_size |= dir->f.nFileSizeLow; - ps->st.st_dev = ps->st.st_rdev = (_getdrive() - 1); - ps->st.st_mode = (mode_t)fMode; - ps->st.st_ino = 0; - ps->st.st_gid = 0; - ps->st.st_uid = 0; - ps->st.st_nlink = 1; - - if (dir->f.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - if (git_win32_path_readlink_w(target, dir->f.cFileName) >= 0) { - ps->st.st_mode = (ps->st.st_mode & ~S_IFMT) | S_IFLNK; - - /* st_size gets the UTF-8 length of the target name, in bytes, - * not counting the NULL terminator */ - if ((ps->st.st_size = git__utf16_to_8(NULL, 0, target)) < 0) { - error = -1; - giterr_set(GITERR_OS, "Could not manage reparse link '%s'", dir->f.cFileName); - goto clean_up_and_exit; - } - } - } if (S_ISDIR(ps->st.st_mode)) { ps->path[ps->path_len++] = '/'; diff --git a/src/win32/posix.h b/src/win32/posix.h index 1a1ae76b2..bf35c8125 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -52,12 +52,4 @@ extern int p_lstat_posixly(const char *filename, struct stat *buf); extern struct tm * p_localtime_r(const time_t *timer, struct tm *result); extern struct tm * p_gmtime_r(const time_t *timer, struct tm *result); -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; -} - #endif diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 1c490a8e9..332ea233c 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -140,44 +140,10 @@ static int lstat_w( WIN32_FILE_ATTRIBUTE_DATA fdata; if (GetFileAttributesExW(path, GetFileExInfoStandard, &fdata)) { - int fMode = S_IREAD; - if (!buf) return 0; - if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - fMode |= S_IFDIR; - else - fMode |= S_IFREG; - - if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) - fMode |= S_IWRITE; - - 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 = ((git_off_t)fdata.nFileSizeHigh << 32) + fdata.nFileSizeLow; - 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)); - - if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - git_win32_path target; - - if (git_win32_path_readlink_w(target, path) >= 0) { - buf->st_mode = (buf->st_mode & ~S_IFMT) | S_IFLNK; - - /* st_size gets the UTF-8 length of the target name, in bytes, - * not counting the NULL terminator */ - if ((buf->st_size = git__utf16_to_8(NULL, 0, target)) < 0) - return -1; - } - } - - return 0; + return git_win32__file_attribute_to_stat(buf, &fdata, path); } errno = ENOENT; diff --git a/src/win32/w32_util.h b/src/win32/w32_util.h index 9c1b94359..8cb0f5b94 100644 --- a/src/win32/w32_util.h +++ b/src/win32/w32_util.h @@ -9,8 +9,21 @@ #define INCLUDE_w32_util_h__ #include "utf-conv.h" +#include "posix.h" #include "path_w32.h" +/* + +#include "common.h" +#include "path.h" +#include "path_w32.h" +#include "utf-conv.h" +#include "posix.h" +#include "reparse.h" +#include "dir.h" +*/ + + GIT_INLINE(bool) git_win32__isalpha(wchar_t c) { return ((c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z')); @@ -52,4 +65,63 @@ size_t git_win32__path_trim_end(wchar_t *str, size_t len); */ size_t git_win32__canonicalize_path(wchar_t *str, size_t len); +/** + * Converts a FILETIME structure to a time_t. + * + * @param FILETIME A pointer to a FILETIME + * @return A time_t containing the same time + */ +GIT_INLINE(time_t) git_win32__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; +} + +GIT_INLINE(int) git_win32__file_attribute_to_stat( + struct stat *st, + const WIN32_FILE_ATTRIBUTE_DATA *attrdata, + const wchar_t *path) +{ + mode_t mode = S_IREAD; + + if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + mode |= S_IFDIR; + else + mode |= S_IFREG; + + if ((attrdata->dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) + mode |= S_IWRITE; + + st->st_ino = 0; + st->st_gid = 0; + st->st_uid = 0; + st->st_nlink = 1; + st->st_mode = mode; + st->st_size = ((git_off_t)attrdata->nFileSizeHigh << 32) + attrdata->nFileSizeLow; + st->st_dev = _getdrive() - 1; + st->st_rdev = st->st_dev; + st->st_atime = git_win32__filetime_to_time_t(&(attrdata->ftLastAccessTime)); + st->st_mtime = git_win32__filetime_to_time_t(&(attrdata->ftLastWriteTime)); + st->st_ctime = git_win32__filetime_to_time_t(&(attrdata->ftCreationTime)); + + if (attrdata->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && path) { + git_win32_path target; + + if (git_win32_path_readlink_w(target, path) >= 0) { + st->st_mode = (st->st_mode & ~S_IFMT) | S_IFLNK; + + /* st_size gets the UTF-8 length of the target name, in bytes, + * not counting the NULL terminator */ + if ((st->st_size = git__utf16_to_8(NULL, 0, target)) < 0) { + giterr_set(GITERR_OS, "Could not convert reparse point name for '%s'", path); + return -1; + } + } + } + + return 0; +} + #endif