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

📄 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 页
字号:

APR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, 
                                             const char *basepath, 
                                             const char *addpath, 
                                             apr_int32_t flags,
                                             apr_pool_t *p)
{
    char path[APR_PATH_MAX]; /* isn't null term */
    const char *baseroot = NULL;
    const char *addroot;
    apr_size_t rootlen; /* the length of the root portion of path, d:/ is 3 */
    apr_size_t baselen; /* the length of basepath (excluding baseroot) */
    apr_size_t keptlen; /* the length of the retained basepath (incl root) */
    apr_size_t pathlen; /* the length of the result path */
    apr_size_t segend;  /* the end of the current segment */
    apr_size_t seglen;  /* the length of the segment (excl trailing chars) */
    apr_status_t basetype = 0; /* from parsing the basepath's baseroot */
    apr_status_t addtype;      /* from parsing the addpath's addroot */
    apr_status_t rv;
#ifndef NETWARE
    int fixunc = 0;  /* flag to complete an incomplete UNC basepath */
#endif
    
    /* Treat null as an empty path, otherwise split addroot from the addpath
     */
    if (!addpath) {
        addpath = addroot = "";
        addtype = APR_ERELATIVE;
    }
    else {
        /* This call _should_ test the path
         */
        addtype = apr_filepath_root(&addroot, &addpath, 
                                    APR_FILEPATH_TRUENAME
                                    | (flags & APR_FILEPATH_NATIVE),
                                    p);
        if (addtype == APR_SUCCESS) {
            addtype = APR_EABSOLUTE;
        }
        else if (addtype == APR_ERELATIVE) {
            addroot = "";
        }
        else if (addtype != APR_EINCOMPLETE) {
            /* apr_filepath_root was incomprehensible so fail already
             */
            return addtype;
        }
    }

    /* If addpath is (even partially) rooted, then basepath is
     * unused.  Ths violates any APR_FILEPATH_SECUREROOTTEST 
     * and APR_FILEPATH_NOTABSOLUTE flags specified.
     */
    if (addtype == APR_EABSOLUTE || addtype == APR_EINCOMPLETE)
    {
        if (flags & APR_FILEPATH_SECUREROOTTEST)
            return APR_EABOVEROOT;
        if (flags & APR_FILEPATH_NOTABSOLUTE)
            return addtype;
    }

    /* Optimized tests before we query the current working path
     */
    if (!basepath) {

        /* If APR_FILEPATH_NOTABOVEROOT wasn't specified,
         * we won't test the root again, it's ignored.
         * Waste no CPU retrieving the working path.
         */
        if (addtype == APR_EABSOLUTE && !(flags & APR_FILEPATH_NOTABOVEROOT)) {
            basepath = baseroot = "";
            basetype = APR_ERELATIVE;
        }

        /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller 
         * requires an absolutely relative result, So do not retrieve 
         * the working path.
         */
        if (addtype == APR_ERELATIVE && (flags & APR_FILEPATH_NOTABSOLUTE)) {
            basepath = baseroot = "";
            basetype = APR_ERELATIVE;
        }
    }

    if (!basepath) 
    {
        /* Start with the current working path.  This is bass akwards,
         * but required since the compiler (at least vc) doesn't like
         * passing the address of a char const* for a char** arg.
         * We must grab the current path of the designated drive 
         * if addroot is given in drive-relative form (e.g. d:foo)
         */
        char *getpath;
#ifndef NETWARE
        if (addtype == APR_EINCOMPLETE && addroot[1] == ':')
            rv = filepath_drive_get(&getpath, addroot[0], flags, p);
        else
#endif
            rv = apr_filepath_get(&getpath, flags, p);
        if (rv != APR_SUCCESS)
            return rv;
        basepath = getpath;
    }

    if (!baseroot) {
        /* This call should _not_ test the path
         */
        basetype = apr_filepath_root(&baseroot, &basepath,
                                     (flags & APR_FILEPATH_NATIVE), p);
        if (basetype == APR_SUCCESS) {
            basetype = APR_EABSOLUTE;
        }
        else if (basetype == APR_ERELATIVE) {
            baseroot = "";
        }
        else if (basetype != APR_EINCOMPLETE) {
            /* apr_filepath_root was incomprehensible so fail already
             */
            return basetype;
        }
    }
    baselen = strlen(basepath);

    /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller 
     * requires an absolutely relative result.  If the given 
     * basepath is not relative then fail.
     */
    if ((flags & APR_FILEPATH_NOTABSOLUTE) && basetype != APR_ERELATIVE)
        return basetype;

    /* The Win32 nightmare on unc street... start combining for
     * many possible root combinations.
     */
    if (addtype == APR_EABSOLUTE)
    {
        /* Ignore the given root path, and start with the addroot
         */
        if ((flags & APR_FILEPATH_NOTABOVEROOT) 
                && strncmp(baseroot, addroot, strlen(baseroot)))
            return APR_EABOVEROOT;
        keptlen = 0;
        rootlen = pathlen = strlen(addroot);
        memcpy(path, addroot, pathlen);
    }
    else if (addtype == APR_EINCOMPLETE)
    {
        /* There are several types of incomplete paths, 
         *     incomplete UNC paths         (//foo/ or //),
         *     drives without rooted paths  (d: as in d:foo), 
         * and simple roots                 (/ as in /foo).
         * Deal with these in significantly different manners...
         */
#ifndef NETWARE
        if ((addroot[0] == '/' || addroot[0] == '\\') &&
            (addroot[1] == '/' || addroot[1] == '\\')) 
        {
            /* Ignore the given root path if the incomplete addpath is UNC,
             * (note that the final result will be incomplete).
             */
            if (flags & APR_FILEPATH_NOTRELATIVE)
                return addtype;
            if ((flags & APR_FILEPATH_NOTABOVEROOT) 
                    && strncmp(baseroot, addroot, strlen(baseroot)))
                return APR_EABOVEROOT;
            fixunc = 1;
            keptlen = 0;
            rootlen = pathlen = strlen(addroot);
            memcpy(path, addroot, pathlen);
        }
        else
#endif            
        if ((addroot[0] == '/' || addroot[0] == '\\') && !addroot[1]) 
        {
            /* Bring together the drive or UNC root from the baseroot
             * if the addpath is a simple root and basepath is rooted,
             * otherwise disregard the basepath entirely.
             */
            if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE))
                return basetype;
            if (basetype != APR_ERELATIVE) {
#ifndef NETWARE
                if (basetype == APR_INCOMPLETE 
                        && (baseroot[0] == '/' || baseroot[0] == '\\')
                        && (baseroot[1] == '/' || baseroot[1] == '\\'))
                    fixunc = 1;
#endif
                keptlen = rootlen = pathlen = strlen(baseroot);
                memcpy(path, baseroot, pathlen);
            }
            else {
                if (flags & APR_FILEPATH_NOTABOVEROOT)
                    return APR_EABOVEROOT;
                keptlen = 0;
                rootlen = pathlen = strlen(addroot);
                memcpy(path, addroot, pathlen);
            }
        }
#ifdef NETWARE
        else if (filepath_has_drive(addroot, DRIVE_ONLY, p)) 
        {
            /* If the addroot is a drive (without a volume root)
             * use the basepath _if_ it matches this drive letter!
             * Otherwise we must discard the basepath.
             */
            if (!filepath_compare_drive(addroot, baseroot, p) && 
                filepath_has_drive(baseroot, 0, p)) {
#else
        else if (addroot[0] && addroot[1] == ':' && !addroot[2]) 
        {
            /* If the addroot is a drive (without a volume root)
             * use the basepath _if_ it matches this drive letter!
             * Otherwise we must discard the basepath.
             */
            if (addroot[0] == baseroot[0] && baseroot[1] == ':') {
#endif
                /* Base the result path on the basepath
                 */
                if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE))
                    return basetype;
                rootlen = strlen(baseroot);
                keptlen = pathlen = rootlen + baselen;
                if (keptlen >= sizeof(path))
                    return APR_ENAMETOOLONG;
                memcpy(path, baseroot, rootlen);
                memcpy(path + rootlen, basepath, baselen);
            } 
            else {
                if (flags & APR_FILEPATH_NOTRELATIVE)
                    return addtype;
                if (flags & APR_FILEPATH_NOTABOVEROOT)
                    return APR_EABOVEROOT;
                keptlen = 0;
                rootlen = pathlen = strlen(addroot);
                memcpy(path, addroot, pathlen);
            }
        }
        else {
            /* Now this is unexpected, we aren't aware of any other
             * incomplete path forms!  Fail now.
             */
            return APR_EBADPATH;
        }
    }
    else { /* addtype == APR_ERELATIVE */
        /* If both paths are relative, fail early
         */
        if (basetype != APR_EABSOLUTE && (flags & APR_FILEPATH_NOTRELATIVE))
            return basetype;

#ifndef NETWARE
        /* An incomplete UNC path must be completed
         */
        if (basetype == APR_INCOMPLETE 
                && (baseroot[0] == '/' || baseroot[0] == '\\')
                && (baseroot[1] == '/' || baseroot[1] == '\\'))
            fixunc = 1;
#endif

        /* Base the result path on the basepath
         */
        rootlen = strlen(baseroot);
        keptlen = pathlen = rootlen + baselen;
        if (keptlen >= sizeof(path))
            return APR_ENAMETOOLONG;
        memcpy(path, baseroot, rootlen);
        memcpy(path + rootlen, basepath, baselen);
    }

    /* '/' terminate the given root path unless it's already terminated
     * or is an incomplete drive root.  Correct the trailing slash unless
     * we have an incomplete UNC path still to fix.
     */
    if (pathlen && path[pathlen - 1] != ':') {
        if (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\') {
            if (pathlen + 1 >= sizeof(path))
                return APR_ENAMETOOLONG;
        
            path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) ? '\\' : '/');
        }
    /*  XXX: wrong, but gotta figure out what I intended;
     *  else if (!fixunc)
     *      path[pathlen++] = ((flags & APR_FILEPATH_NATIVE) ? '\\' : '/');
     */
    }

    while (*addpath) 
    {
        /* Parse each segment, find the closing '/' 
         */
        seglen = 0;
        while (addpath[seglen] && addpath[seglen] != '/'
                               && addpath[seglen] != '\\')
            ++seglen;

        /* Truncate all trailing spaces and all but the first two dots */
        segend = seglen;
        while (seglen && (addpath[seglen - 1] == ' ' 
                       || addpath[seglen - 1] == '.')) {
            if (seglen > 2 || addpath[seglen - 1] != '.' || addpath[0] != '.')
                --seglen;
            else
                break;
        }

        if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) 
        {
            /* NOTE: win32 _hates_ '/ /' and '/. /' (yes, with spaces in there)
             * so eliminate all preconceptions that it is valid.
             */
            if (seglen < segend)
                return APR_EBADPATH;

#ifndef NETWARE
            /* This isn't legal unless the unc path is completed
             */
            if (fixunc)
                return APR_EBADPATH;
#endif

            /* Otherwise, this is a noop segment (/ or ./) so ignore it 
             */
        }
        else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') 
        {
            /* NOTE: win32 _hates_ '/.. /' (yes, with a space in there)
             * and '/..../', some functions treat it as ".", and some 
             * fail! Eliminate all preconceptions that they are valid.
             */
            if (seglen < segend && (seglen != 3 || addpath[2] != '.'))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -