📄 filepath.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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;
#endif /* ndef(NETWARE) */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -