⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filepath.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -