diff options
-rw-r--r-- | CHANGES | 4 | ||||
-rw-r--r-- | file_io/win32/dir.c | 2 | ||||
-rw-r--r-- | file_io/win32/filestat.c | 103 | ||||
-rw-r--r-- | include/arch/win32/apr_arch_file_io.h | 3 |
4 files changed, 97 insertions, 15 deletions
@@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes for APR 2.0.0 + *) apr_file_info: [Win32 only] Treat only "name surrogate" reparse points + as symlinks, and not other reparse tag types. PR47630 + [Oleg Liatte <olegliatte gmail.com>] + *) Test %ld vs. %lld to avoid compiler emits using APR_OFF_T_FMT, in the case of apparently equivilant long and long long types. [William Rowe] diff --git a/file_io/win32/dir.c b/file_io/win32/dir.c index 5c30af8fd..8c8b74546 100644 --- a/file_io/win32/dir.c +++ b/file_io/win32/dir.c @@ -210,7 +210,7 @@ APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, #endif fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->w.entry, - 0, wanted); + 0, 1, fname, wanted); finfo->pool = thedir->pool; finfo->valid |= APR_FINFO_NAME; diff --git a/file_io/win32/filestat.c b/file_io/win32/filestat.c index ba4160785..904124db7 100644 --- a/file_io/win32/filestat.c +++ b/file_io/win32/filestat.c @@ -210,6 +210,71 @@ static apr_status_t guess_protection_bits(apr_finfo_t *finfo, return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS); } +static int reparse_point_is_link(WIN32_FILE_ATTRIBUTE_DATA *wininfo, + int finddata, const char *fname) +{ + int tag = 0; + + if (!(wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + { + return 0; + } + + if (finddata) + { + // no matter A or W as we don't need file name + tag = ((WIN32_FIND_DATAA*)wininfo)->dwReserved0; + } + else + { + if (test_safe_name(fname) != APR_SUCCESS) { + return 0; + } + +#if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { + apr_wchar_t wfname[APR_PATH_MAX]; + HANDLE hFind; + WIN32_FIND_DATAW fd; + + if (utf8_to_unicode_path(wfname, APR_PATH_MAX, fname) != APR_SUCCESS) { + return 0; + } + + hFind = FindFirstFileW(wfname, &fd); + if (hFind == INVALID_HANDLE_VALUE) { + return 0; + } + + FindClose(hFind); + + tag = fd.dwReserved0; + } +#endif +#if APR_HAS_ANSI_FS || 1 + ELSE_WIN_OS_IS_ANSI + { + HANDLE hFind; + WIN32_FIND_DATAA fd; + + hFind = FindFirstFileA(fname, &fd); + if (hFind == INVALID_HANDLE_VALUE) { + return 0; + } + + FindClose(hFind); + + tag = fd.dwReserved0; + } +#endif + } + + // Test "Name surrogate bit" to detect any kind of symbolic link + // See https://docs.microsoft.com/en-us/windows/desktop/fileio/reparse-point-tags + return tag & 0x20000000; +} + apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, apr_int32_t wanted, int whatfile) { @@ -351,7 +416,10 @@ apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, */ int fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo, - int byhandle, apr_int32_t wanted) + int byhandle, + int finddata, + const char *fname, + apr_int32_t wanted) { DWORD *sizes = &wininfo->nFileSizeHigh + byhandle; int warn = 0; @@ -372,7 +440,7 @@ int fillin_fileinfo(apr_finfo_t *finfo, #endif if (wanted & APR_FINFO_LINK && - wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + reparse_point_is_link(wininfo, finddata, fname)) { finfo->filetype = APR_LNK; } else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { @@ -449,7 +517,7 @@ APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo, apr_int32_t want return apr_get_os_error(); } - fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1, wanted); + fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1, 0, thefile->fname, wanted); if (finfo->filetype == APR_REG) { @@ -520,6 +588,7 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, WIN32_FIND_DATAA n; WIN32_FILE_ATTRIBUTE_DATA i; } FileInfo; + int finddata = 0; /* Catch fname length == MAX_PATH since GetFileAttributesEx fails * with PATH_NOT_FOUND. We would rather indicate length error than @@ -555,7 +624,7 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname) / sizeof(apr_wchar_t), fname))) return rv; - if (!(wanted & APR_FINFO_NAME)) { + if (!(wanted & (APR_FINFO_NAME | APR_FINFO_LINK))) { if (!GetFileAttributesExW(wfname, GetFileExInfoStandard, &FileInfo.i)) return apr_get_os_error(); @@ -565,7 +634,6 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, * since we want the true name, and set aside a long * enough string to handle the longest file name. */ - char tmpname[APR_FILE_MAX * 3 + 1]; HANDLE hFind; if ((rv = test_safe_name(fname)) != APR_SUCCESS) { return rv; @@ -574,11 +642,17 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, if (hFind == INVALID_HANDLE_VALUE) return apr_get_os_error(); FindClose(hFind); - if (unicode_to_utf8_path(tmpname, sizeof(tmpname), - FileInfo.w.cFileName)) { - return APR_ENAMETOOLONG; + finddata = 1; + + if (wanted & APR_FINFO_NAME) + { + char tmpname[APR_FILE_MAX * 3 + 1]; + if (unicode_to_utf8_path(tmpname, sizeof(tmpname), + FileInfo.w.cFileName)) { + return APR_ENAMETOOLONG; + } + filename = apr_pstrdup(pool, tmpname); } - filename = apr_pstrdup(pool, tmpname); } } #endif @@ -590,7 +664,7 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, rv = apr_filepath_root(&root, &test, APR_FILEPATH_NATIVE, pool); isroot = (root && *root && !(*test)); - if ((apr_os_level >= APR_WIN_98) && (!(wanted & APR_FINFO_NAME) || isroot)) + if ((apr_os_level >= APR_WIN_98) && (!(wanted & (APR_FINFO_NAME | APR_FINFO_LINK)) || isroot)) { /* cannot use FindFile on a Win98 root, it returns \* * GetFileAttributesExA is not available on Win95 @@ -632,16 +706,19 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, hFind = FindFirstFileA(fname, &FileInfo.n); if (hFind == INVALID_HANDLE_VALUE) { return apr_get_os_error(); - } + } FindClose(hFind); - filename = apr_pstrdup(pool, FileInfo.n.cFileName); + finddata = 1; + if (wanted & APR_FINFO_NAME) { + filename = apr_pstrdup(pool, FileInfo.n.cFileName); + } } } #endif if (ident_rv != APR_INCOMPLETE) { if (fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, - 0, wanted)) + 0, finddata, fname, wanted)) { /* Go the extra mile to assure we have a file. WinNT/2000 seems * to reliably translate char devices to the path '\\.\device' diff --git a/include/arch/win32/apr_arch_file_io.h b/include/arch/win32/apr_arch_file_io.h index 7c5996cab..5302a15be 100644 --- a/include/arch/win32/apr_arch_file_io.h +++ b/include/arch/win32/apr_arch_file_io.h @@ -135,7 +135,8 @@ void *res_name_from_filename(const char *file, int global, apr_pool_t *pool); /* Private function for apr_stat/lstat/getfileinfo/dir_read */ int fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo, - int byhandle, apr_int32_t wanted); + int byhandle, int finddata, const char *fname, + apr_int32_t wanted); /* Private function that extends apr_stat/lstat/getfileinfo/dir_read */ apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, |