📄 filepath.c
字号:
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include "apr.h"#include "apr_private.h"#include "apr_arch_file_io.h"#include "apr_strings.h"#include "apr_lib.h"#include <string.h>#include <ctype.h>#ifdef NETWARE#include <unistd.h>#include <fsio.h>#endif /* 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, const char **inpath, apr_int32_t flags, apr_pool_t *p){ const char *testpath = *inpath; char *newpath;#ifdef NETWARE char seperator[2] = { 0, 0}; char server[APR_PATH_MAX+1]; char volume[APR_PATH_MAX+1]; char file[APR_PATH_MAX+1]; char *volsep = NULL; int elements; if (inpath && *inpath) volsep = strchr (*inpath, ':'); else return APR_EBADPATH; if (strlen(*inpath) > APR_PATH_MAX) { return APR_EBADPATH; } seperator[0] = (flags & APR_FILEPATH_NATIVE) ? '\\' : '/'; /* Allocate and initialize each of the segment buffers */ server[0] = volume[0] = file[0] = '\0'; /* If we don't have a volume separator then don't bother deconstructing the path since we won't use the deconstructed information anyway. */ if (volsep) { /* Split the inpath into its separate parts. */ deconstruct(testpath, server, volume, NULL, file, NULL, &elements, PATH_UNDEF); /* If we got a volume part then continue splitting out the root. Otherwise we either have an incomplete or relative path */ if (volume && strlen(volume) > 0) { newpath = apr_pcalloc(p, strlen(server)+strlen(volume)+5); construct(newpath, server, volume, NULL, NULL, NULL, PATH_NETWARE); /* NetWare doesn't add the root slash so we need to add it manually. */ strcat(newpath, seperator); *rootpath = newpath; /* Skip the inpath pointer down to the first non-root character */ newpath = volsep; do { ++newpath; } while (*newpath && ((*newpath == '/') || (*newpath == '\\'))); *inpath = newpath; /* Need to handle APR_FILEPATH_TRUENAME checking here. */ return APR_SUCCESS; } else return APR_EBADPATH; } else if ((**inpath == '/') || (**inpath == '\\')) { /* if we have a root path without a volume then just split in same manner as unix although this path will be incomplete. */ *rootpath = apr_pstrdup(p, seperator); do { ++(*inpath); } while ((**inpath == '/') || (**inpath == '\\')); } else return APR_ERELATIVE; return APR_EINCOMPLETE;#else /* ndef(NETWARE) */ char seperator[2]; const char *delim1; const char *delim2; seperator[0] = (flags & APR_FILEPATH_NATIVE) ? '\\' : '/'; seperator[1] = 0; if (testpath[0] == '/' || testpath[0] == '\\') { if (testpath[1] == '/' || testpath[1] == '\\') {#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] == ':') { apr_status_t rv; testpath += 4; /* given '//?/C: or //./C: let us try this * all over again from the drive designator */ rv = apr_filepath_root(rootpath, &testpath, flags, p); if (!rv || rv == APR_EINCOMPLETE) *inpath = testpath; return rv; } else if (strncasecmp(testpath + 4, "UNC", 3) == 0 && (testpath[7] == '/' || testpath[7] == '\\') && (testpath[2] == '?')) { /* given '//?/UNC/machine/share, a little magic * at the end makes this all work out by using * 'C/machine' as the starting point and replacing * the UNC delimiters with \'s, including the 'C' */ testpath += 6; } else /* This must not be a path to a file, but rather * a volume or device. Die for now. */ 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++))) return APR_EBADPATH; } while (*delim1 && *delim1 != '/' && *delim1 != '\\'); if (*delim1) { apr_status_t rv; delim2 = delim1 + 1; while (*delim2 && *delim2 != '/' && *delim2 != '\\') { /* Protect against //machine/X/ where X is illegal */ if (!IS_FNCHAR(*(delim2++))) return APR_EBADPATH; } /* Copy the '//machine/[share[/]]' path, always providing * an extra byte for the trailing slash. */ newpath = apr_pstrmemdup(p, testpath, delim2 - testpath + 1); if (delim2 == delim1 + 1) { /* We found simply \\machine\, so give up already */ *rootpath = newpath; *inpath = delim2; return APR_EINCOMPLETE; } if (flags & APR_FILEPATH_TRUENAME) { /* Validate the \\Machine\Share\ designation, * Win32 will argue about slashed in UNC paths, * so use backslashes till we finish testing, * and add the trailing backslash [required]. * apr_pstrmemdup above guarentees us the new * trailing null character. */ newpath[0] = '\\'; newpath[1] = '\\'; newpath[delim1 - testpath] = '\\'; newpath[delim2 - testpath] = '\\'; rv = filepath_root_test(newpath, p); if (rv) return rv; rv = filepath_root_case(&newpath, newpath, p); if (rv) return rv; newpath[0] = seperator[0]; newpath[1] = seperator[0]; newpath[delim1 - testpath] = seperator[0]; newpath[delim2 - testpath] = (*delim2 ? seperator[0] : '\0'); } else { /* Give back the caller's own choice of delimiters */ newpath[0] = testpath[0]; newpath[1] = testpath[1]; newpath[delim1 - testpath] = *delim1; newpath[delim2 - testpath] = *delim2; } /* If this root included the trailing / or \ designation * then lop off multiple trailing slashes and give back * appropriate delimiters. */ if (*delim2) { *inpath = delim2 + 1; while (**inpath == '/' || **inpath == '\\') ++*inpath; } else { *inpath = delim2; } *rootpath = newpath; return APR_SUCCESS; } /* Have path of '\\[machine]', if the machine is given, * append same trailing slash as the leading slash */ delim1 = strchr(testpath, '\0'); if (delim1 > testpath + 2) { newpath = apr_pstrndup(p, testpath, delim1 - testpath + 1); if (flags & APR_FILEPATH_TRUENAME) newpath[delim1 - testpath] = seperator[0]; else newpath[delim1 - testpath] = newpath[0]; newpath[delim1 - testpath + 1] = '\0'; } else { newpath = apr_pstrndup(p, testpath, delim1 - testpath); } if (flags & APR_FILEPATH_TRUENAME) { newpath[0] = seperator[0]; newpath[1] = seperator[0]; } *rootpath = newpath; *inpath = delim1; return APR_EINCOMPLETE; } /* Left with a path of '/', what drive are we asking about? */ *inpath = testpath + 1; newpath = apr_palloc(p, 2); if (flags & APR_FILEPATH_TRUENAME) newpath[0] = seperator[0]; else newpath[0] = testpath[0]; newpath[1] = '\0'; *rootpath = newpath; return APR_EINCOMPLETE; } /* Evaluate path of 'd:[/]' */ if (IS_FNCHAR(*testpath) && testpath[1] == ':') { apr_status_t rv; /* Validate that D:\ drive exists, test must be rooted * Note that posix/win32 insists a drive letter is upper case, * so who are we to argue with a 'feature'. * It is a safe fold, since only A-Z is legal, and has no * side effects of legal mis-mapped non-us-ascii codes. */ newpath = apr_palloc(p, 4); newpath[0] = testpath[0]; newpath[1] = testpath[1]; newpath[2] = seperator[0]; newpath[3] = '\0'; if (flags & APR_FILEPATH_TRUENAME) { newpath[0] = apr_toupper(newpath[0]); rv = filepath_root_test(newpath, p); if (rv) return rv; } /* Just give back the root the user handed to us. */ if (testpath[2] != '/' && testpath[2] != '\\') { newpath[2] = '\0'; *rootpath = newpath; *inpath = testpath + 2; return APR_EINCOMPLETE; } /* strip off remaining slashes that designate the root, * give the caller back their original choice of slash * unless this is TRUENAME'ed */ *inpath = testpath + 3; while (**inpath == '/' || **inpath == '\\') ++*inpath; if (!(flags & APR_FILEPATH_TRUENAME)) newpath[2] = testpath[2]; *rootpath = newpath; return APR_SUCCESS; } /* Nothing interesting */ return APR_ERELATIVE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -