diff options
author | ivan <ivan@13f79535-47bb-0310-9956-ffa450edef68> | 2022-01-05 16:20:19 +0000 |
---|---|---|
committer | ivan <ivan@13f79535-47bb-0310-9956-ffa450edef68> | 2022-01-05 16:20:19 +0000 |
commit | 1608d55979a372c58958255ac15916ed97bc1e88 (patch) | |
tree | 41c973209bc1bb0293ee7cffb405c7fce28dc126 | |
parent | bd0ea8e717b83d913c3d24c6b5a0a0d301c24ac4 (diff) | |
download | libapr-1608d55979a372c58958255ac15916ed97bc1e88.tar.gz |
Fix a regression in apr_stat() for root path on Windows caused by the extended
symlink detection added in r1855949 (PR47630) [1].
See [2] for the detailed problem report and discussion.
The code before this patch performs FindFirstFile() whenever
APR_FINFO_LINK is passed. This is problematic for at least two reasons:
1) Any attempt to detect if the root is a symlink now fails because
FindFirstFile() cannot be called for the root directory
2) Any check that includes the APR_FINFO_LINK flag now calls FindFirstFile(),
which essentially is a "readdir". Previously, ordinary files could have
been processed with a much cheaper call to GetFileAttributesEx().
In other words, there is a significant performance penalty for
stat(... | APR_FINFO_LINK) in a common case.
Fix this by postponing a call to FindFirstFile() until we actually need the
file tag information to resolve the reparse point.
[1] https://bz.apache.org/bugzilla/show_bug.cgi?id=47630
[2] https://lists.apache.org/thread/18x2jb81nf6zrjsnwf1k2wwooprkp0p5
* file_io/win32/filestat.c
(apr_stat): Call FindFirstFile() only when asking for the true name with
APR_FINFO_NAME. Adjust the related check.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1896717 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | file_io/win32/filestat.c | 16 |
1 files changed, 6 insertions, 10 deletions
diff --git a/file_io/win32/filestat.c b/file_io/win32/filestat.c index 4c0b14795..0ab8b2923 100644 --- a/file_io/win32/filestat.c +++ b/file_io/win32/filestat.c @@ -640,7 +640,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 | APR_FINFO_LINK))) { + if (!(wanted & APR_FINFO_NAME)) { if (!GetFileAttributesExW(wfname, GetFileExInfoStandard, &FileInfo.i)) return apr_get_os_error(); @@ -650,6 +650,7 @@ 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; @@ -659,16 +660,11 @@ APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, return apr_get_os_error(); FindClose(hFind); 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); + if (unicode_to_utf8_path(tmpname, sizeof(tmpname), + FileInfo.w.cFileName)) { + return APR_ENAMETOOLONG; } + filename = apr_pstrdup(pool, tmpname); } if (ident_rv != APR_INCOMPLETE) { |