summaryrefslogtreecommitdiff
path: root/file_io/win32/filepath.c
diff options
context:
space:
mode:
Diffstat (limited to 'file_io/win32/filepath.c')
-rw-r--r--file_io/win32/filepath.c233
1 files changed, 20 insertions, 213 deletions
diff --git a/file_io/win32/filepath.c b/file_io/win32/filepath.c
index 0f4a386d4..3e3096d33 100644
--- a/file_io/win32/filepath.c
+++ b/file_io/win32/filepath.c
@@ -54,222 +54,17 @@
#include "apr.h"
#include "fileio.h"
-#include "apr_file_io.h"
#include "apr_strings.h"
-/* Win32 Exceptions:
- *
- * Note that trailing spaces and trailing periods are never recorded
- * in the file system, except by a very obscure bug where any file
- * that is created with a trailing space or period, followed by the
- * ':' stream designator on an NTFS volume can never be accessed again.
- * In other words, don't ever accept them when designating a stream!
- *
- * An interesting side effect is that two or three periods are both
- * treated as the parent directory, although the fourth and on are
- * not [strongly suggest all trailing periods are trimmed off, or
- * down to two if there are no other characters.]
- *
- * Leading spaces and periods are accepted, however.
- */
-static int is_fnchar(char ch)
-{
- /* No control code between 0 and 31 is allowed
- * The * ? < > codes all have wildcard effects
- * The " / \ : are exlusively separator tokens
- * The system doesn't accept | for any purpose.
- * Oddly, \x7f _is_ acceptable.
- */
- if (ch >= 0 && ch < 32)
- return 0;
-
- if (ch == '\"' || ch == '*' || ch == '/'
- || ch == ':' || ch == '<' || ch == '>'
- || ch == '?' || ch == '\\' || ch == '|')
- return 0;
-
- return 1;
-}
-
-
-static apr_status_t filepath_root_test(char *path,
- apr_pool_t *p)
-{
- apr_status_t rv;
-#if APR_HAS_UNICODE_FS
- apr_oslevel_e os_level;
- if (!apr_get_oslevel(p, &os_level) && os_level >= APR_WIN_NT)
- {
- apr_wchar_t wpath[APR_PATH_MAX];
- if (rv = utf8_to_unicode_path(wpath, sizeof(wpath)
- / sizeof(apr_wchar_t), path))
- return rv;
- rv = GetDriveTypeW(wpath);
- }
- else
-#endif
- rv = GetDriveType(path);
-
- if (rv == DRIVE_UNKNOWN || rv == DRIVE_NO_ROOT_DIR)
- return APR_EBADPATH;
- return APR_SUCCESS;
-}
-
-
-APR_DECLARE(apr_status_t) apr_filepath_get(char **rootpath,
- apr_pool_t *p)
-{
- char path[APR_PATH_MAX];
-#if APR_HAS_UNICODE_FS
- apr_oslevel_e os_level;
- if (!apr_get_oslevel(p, &os_level) && os_level >= APR_WIN_NT)
- {
- apr_wchar_t wpath[APR_PATH_MAX];
- apr_status_t rv;
- if (!GetCurrentDirectoryW(sizeof(wpath) / sizeof(apr_wchar_t), wpath))
- return apr_get_os_error();
- if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath)))
- return rv;
- }
- else
-#endif
- {
- if (!GetCurrentDirectory(sizeof(path), path))
- return apr_get_os_error();
- }
- /* ###: We really should consider adding a flag to allow the user
- * to have the APR_FILEPATH_NATIVE result
- */
- for (*rootpath = path; **rootpath; ++*rootpath) {
- if (**rootpath == '\\')
- **rootpath = '/';
- }
- *rootpath = apr_pstrdup(p, path);
- return APR_SUCCESS;
-}
-
-
-static apr_status_t filepath_drive_get(char **rootpath,
- char drive,
- apr_pool_t *p)
-{
- char path[APR_PATH_MAX];
-#if APR_HAS_UNICODE_FS
- apr_oslevel_e os_level;
- if (!apr_get_oslevel(p, &os_level) && os_level >= APR_WIN_NT)
- {
- apr_wchar_t *ignored;
- apr_wchar_t wdrive[8];
- apr_wchar_t wpath[APR_PATH_MAX];
- apr_status_t rv;
- /* ???: This needs review, apparently "\\?\d:." returns "\\?\d:"
- * as if that is useful for anything.
- */
- wcscpy(wdrive, L"D:.");
- wdrive[0] = (apr_wchar_t)(unsigned char)drive;
- if (!GetFullPathNameW(wdrive, sizeof(wpath) / sizeof(apr_wchar_t), wpath, &ignored))
- return apr_get_os_error();
- if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath)))
- return rv;
- }
- else
-#endif
- {
- char *ignored;
- char drivestr[4];
- drivestr[0] = drive;
- drivestr[1] = ':';
- drivestr[2] = '.';;
- drivestr[3] = '\0';
- if (!GetFullPathName(drivestr, sizeof(path), path, &ignored))
- return apr_get_os_error();
- }
- /* ###: We really should consider adding a flag to allow the user
- * to have the APR_FILEPATH_NATIVE result
- */
- for (*rootpath = path; **rootpath; ++*rootpath) {
- if (**rootpath == '\\')
- **rootpath = '/';
- }
- *rootpath = apr_pstrdup(p, path);
- return APR_SUCCESS;
-}
-
-
-static apr_status_t filepath_root_case(char **rootpath,
- char *root,
- apr_pool_t *p)
-{
-#if APR_HAS_UNICODE_FS
- apr_oslevel_e os_level;
- if (!apr_get_oslevel(p, &os_level) && os_level >= APR_WIN_NT)
- {
- apr_wchar_t *ignored;
- apr_wchar_t wpath[APR_PATH_MAX];
- apr_status_t rv;
- /* ???: This needs review, apparently "\\?\d:." returns "\\?\d:"
- * as if that is useful for anything.
- */
- {
- apr_wchar_t wroot[APR_PATH_MAX];
- if (rv = utf8_to_unicode_path(wroot, sizeof(wroot)
- / sizeof(apr_wchar_t), root))
- return rv;
- if (!GetFullPathNameW(wroot, sizeof(wpath) / sizeof(apr_wchar_t), wpath, &ignored))
- return apr_get_os_error();
- }
- {
- char path[APR_PATH_MAX];
- if ((rv = unicode_to_utf8_path(path, sizeof(path), wpath)))
- return rv;
- *rootpath = apr_pstrdup(p, path);
- }
- }
- else
-#endif
- {
- char path[APR_PATH_MAX];
- char *ignored;
- if (!GetFullPathName(root, sizeof(path), path, &ignored))
- return apr_get_os_error();
- *rootpath = apr_pstrdup(p, path);
- }
- return APR_SUCCESS;
-}
-
-
-APR_DECLARE(apr_status_t) apr_filepath_set(const char *rootpath,
- apr_pool_t *p)
-{
-#if APR_HAS_UNICODE_FS
- apr_oslevel_e os_level;
- if (!apr_get_oslevel(p, &os_level) && os_level >= APR_WIN_NT)
- {
- apr_wchar_t wpath[APR_PATH_MAX];
- apr_status_t rv;
- if (rv = utf8_to_unicode_path(wpath, sizeof(wpath)
- / sizeof(apr_wchar_t), rootpath))
- return rv;
- if (!SetCurrentDirectoryW(wpath))
- return apr_get_os_error();
- }
- else
-#endif
- {
- if (!SetCurrentDirectory(rootpath))
- return apr_get_os_error();
- }
- return APR_SUCCESS;
-}
-
-
-/* WinNT accepts several odd forms of a 'root' path. Under Unicode
+ /* WinNT accepts several odd forms of a 'root' path. Under Unicode
* calls (ApiFunctionW) the //?/C:/foo or //?/UNC/mach/share/foo forms
* are accepted. Ansi and Unicode functions both accept the //./C:/foo
* form under WinNT/2K. Since these forms are handled in the utf-8 to
* unicode translation phase, we don't want the user confused by them, so
* we will accept them but always return the canonical C:/ or //mach/share/
+ *
+ * OS2 appears immune from the nonsense :)
*/
APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
@@ -284,10 +79,11 @@ APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
if (testpath[0] == '/' || testpath[0] == '\\') {
if (testpath[1] == '/' || testpath[1] == '\\') {
- /* //server/share isn't the only // delimited syntax */
+
+#ifdef WIN32 /* //server/share isn't the only // delimited syntax */
if ((testpath[2] == '?' || testpath[2] == '.')
&& (testpath[3] == '/' || testpath[3] == '\\')) {
- if (is_fnchar(testpath[4]) && testpath[5] == ':')
+ if (IS_FNCHAR(testpath[4]) && testpath[5] == ':')
{
apr_status_t rv;
testpath += 4;
@@ -315,12 +111,13 @@ APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
*/
return APR_EBADPATH;
}
+#endif /* WIN32 (non - //server/share syntax) */
/* Evaluate path of '//[machine/[share[/]]]' */
delim1 = testpath + 2;
do {
/* Protect against //X/ where X is illegal */
- if (*delim1 && !is_fnchar(*(delim1++)))
+ if (*delim1 && !IS_FNCHAR(*(delim1++)))
return APR_EBADPATH;
} while (*delim1 && *delim1 != '/' && *delim1 != '\\');
@@ -329,7 +126,7 @@ APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
delim2 = delim1 + 1;
while (*delim2 && *delim2 != '/' && *delim2 != '\\') {
/* Protect against //machine/X/ where X is illegal */
- if (!is_fnchar(*(delim2++)))
+ if (!IS_FNCHAR(*(delim2++)))
return APR_EBADPATH;
}
@@ -418,7 +215,7 @@ APR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath,
}
/* Evaluate path of 'd:[/]' */
- if (is_fnchar(*testpath) && testpath[1] == ':')
+ if (IS_FNCHAR(*testpath) && testpath[1] == ':')
{
apr_status_t rv;
/* Validate that D:\ drive exists, test must be rooted
@@ -935,6 +732,14 @@ APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath,
if ((rv = apr_stat(&finfo, path, APR_FINFO_TYPE | APR_FINFO_NAME, p))
== APR_SUCCESS) {
size_t namelen = strlen(finfo.name);
+
+#ifdef OS2 /* only has case folding, never aliases that change the length */
+
+ if (memcmp(finfo.name, path + keptlen, seglen) != 0) {
+ memcpy(path + keptlen, finfo.name, namelen);
+ }
+#else /* WIN32; here there be aliases that gire and gimble and change length */
+
if ((namelen != seglen) ||
(memcmp(finfo.name, path + keptlen, seglen) != 0))
{
@@ -961,6 +766,8 @@ APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath,
seglen = namelen;
}
}
+#endif /* !OS2 (Whatever that alias was we're over it) */
+
/* That's it, the rest is path info.
* I don't know how we aught to handle this. Should
* we define a new error to indicate 'more info'?