diff options
-rw-r--r-- | apr.dsp | 4 | ||||
-rw-r--r-- | file_io/win32/filepath.c | 233 | ||||
-rw-r--r-- | file_io/win32/filesys.c | 261 | ||||
-rw-r--r-- | include/arch/win32/fileio.h | 32 | ||||
-rw-r--r-- | libapr.dsp | 4 |
5 files changed, 321 insertions, 213 deletions
@@ -117,6 +117,10 @@ SOURCE=.\file_io\win32\filestat.c # End Source File # Begin Source File +SOURCE=.\file_io\win32\filesys.c +# End Source File +# Begin Source File + SOURCE=.\file_io\win32\flock.c # End Source File # Begin Source File 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'? diff --git a/file_io/win32/filesys.c b/file_io/win32/filesys.c new file mode 100644 index 000000000..1e94b0624 --- /dev/null +++ b/file_io/win32/filesys.c @@ -0,0 +1,261 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2001 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +#include "apr.h" +#include "fileio.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. + * The * ? < > codes all have wildcard side effects + * The " / \ : are exclusively component separator tokens + * The system doesn't accept | for any (known) purpose + * Oddly, \x7f _is_ acceptable ;) + */ + +const char c_is_fnchar[256] = +{/* Reject all ctrl codes... */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + /* " * / : < > ? */ + 1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0, + /* \ */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1, + /* : | */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1, + /* High bit codes are accepted (subject to utf-8->Unicode xlation) */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + + +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_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; +} + + +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_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; +} + + +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; +} + + diff --git a/include/arch/win32/fileio.h b/include/arch/win32/fileio.h index 164651fd7..afb4ab905 100644 --- a/include/arch/win32/fileio.h +++ b/include/arch/win32/fileio.h @@ -212,6 +212,38 @@ struct apr_dir_t { }; }; +/* There are many goofy characters we can't accept. Here's the list. + */ +extern const char c_is_fnchar[256]; + +#define IS_FNCHAR(c) c_is_fnchar[(unsigned char)c] + + +/* If the user passes APR_FILEPATH_TRUENAME to either + * apr_filepath_root or apr_filepath_merge, this fn determines + * that the root really exists. It's expensive, wouldn't want + * to do this too frequenly. + */ +apr_status_t filepath_root_test(char *path, apr_pool_t *p); + + +/* The apr_filepath_merge wants to canonicalize the cwd to the + * addpath if the user passes NULL as the old root path (this + * isn't true of an empty string "", which won't be concatinated. + * + * But we need to figure out what the cwd of a given volume is, + * when the user passes D:foo. This fn will determine D:'s cwd. + */ +apr_status_t filepath_drive_get(char **rootpath, char drive, apr_pool_t *p); + + +/* If the user passes d: vs. D: (or //mach/share vs. //MACH/SHARE), + * we need to fold the case to canonical form. This function is + * supposed to do so. + */ +apr_status_t filepath_root_case(char **rootpath, char *root, apr_pool_t *p); + + apr_status_t file_cleanup(void *); /** diff --git a/libapr.dsp b/libapr.dsp index ab30ce46c..b3aa21db9 100644 --- a/libapr.dsp +++ b/libapr.dsp @@ -123,6 +123,10 @@ SOURCE=.\file_io\win32\filestat.c # End Source File # Begin Source File +SOURCE=.\file_io\win32\filesys.c +# End Source File +# Begin Source File + SOURCE=.\file_io\win32\flock.c # End Source File # Begin Source File |