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

📄 repos.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:

#if DAV_DEBUG
    if (src->hooks != dst->hooks) {
        /*
        ** ### strictly speaking, this is a design error; we should not
        ** ### have reached this point.
        */
        return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
                             "DESIGN ERROR: a mix of repositories "
                             "was passed to copy_resource.");
    }
#endif

    if ((err = dav_fs_copymove_resource(0, src, dst, depth,
                                        response)) == NULL) {

        /* update state of destination resource to show it exists */
        dst->exists = 1;
        dst->collection = src->collection;
    }

    return err;
}

static dav_error * dav_fs_move_resource(
    dav_resource *src,
    dav_resource *dst,
    dav_response **response)
{
    dav_resource_private *srcinfo = src->info;
    dav_resource_private *dstinfo = dst->info;
    dav_error *err;
    int can_rename = 0;

#if DAV_DEBUG
    if (src->hooks != dst->hooks) {
        /*
        ** ### strictly speaking, this is a design error; we should not
        ** ### have reached this point.
        */
        return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
                             "DESIGN ERROR: a mix of repositories "
                             "was passed to move_resource.");
    }
#endif

    /* determine whether a simple rename will work.
     * Assume source exists, else we wouldn't get called.
     */
    if (dstinfo->finfo.filetype != 0) {
        if (dstinfo->finfo.device == srcinfo->finfo.device) {
            /* target exists and is on the same device. */
            can_rename = 1;
        }
    }
    else {
        const char *dirpath;
        apr_finfo_t finfo;
        apr_status_t rv;

        /* destination does not exist, but the parent directory should,
         * so try it
         */
        dirpath = ap_make_dirstr_parent(dstinfo->pool, dstinfo->pathname);
        /* 
         * XXX: If missing dev ... then what test?
         * Really need a try and failover for those platforms.
         * 
         */
        rv = apr_stat(&finfo, dirpath, APR_FINFO_DEV, dstinfo->pool);
        if ((rv == APR_SUCCESS || rv == APR_INCOMPLETE)
            && (finfo.valid & srcinfo->finfo.valid & APR_FINFO_DEV)
            && (finfo.device == srcinfo->finfo.device)) {
            can_rename = 1;
        }
    }

    /* if we can't simply rename, then do it the hard way... */
    if (!can_rename) {
        if ((err = dav_fs_copymove_resource(1, src, dst, DAV_INFINITY,
                                            response)) == NULL) {
            /* update resource states */
            dst->exists = 1;
            dst->collection = src->collection;
            src->exists = 0;
            src->collection = 0;
        }

        return err;
    }

    /* a rename should work. do it, and move properties as well */

    /* no multistatus response */
    *response = NULL;

    /* ### APR has no rename? */
    if (apr_file_rename(srcinfo->pathname, dstinfo->pathname,
                       srcinfo->pool) != APR_SUCCESS) {
        /* ### should have a better error than this. */
        return dav_new_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
                             "Could not rename resource.");
    }

    /* update resource states */
    dst->exists = 1;
    dst->collection = src->collection;
    src->exists = 0;
    src->collection = 0;

    if ((err = dav_fs_copymoveset(1, src->info->pool,
                                  src, dst, NULL)) == NULL) {
        /* no error. we're done. go ahead and return now. */
        return NULL;
    }

    /* error occurred during properties move; try to put resource back */
    if (apr_file_rename(dstinfo->pathname, srcinfo->pathname,
                       srcinfo->pool) != APR_SUCCESS) {
        /* couldn't put it back! */
        return dav_push_error(srcinfo->pool,
                              HTTP_INTERNAL_SERVER_ERROR, 0,
                              "The resource was moved, but a failure "
                              "occurred during the move of its "
                              "properties. The resource could not be "
                              "restored to its original location. The "
                              "server is now in an inconsistent state.",
                              err);
    }

    /* update resource states again */
    src->exists = 1;
    src->collection = dst->collection;
    dst->exists = 0;
    dst->collection = 0;

    /* resource moved back, but properties may be inconsistent */
    return dav_push_error(srcinfo->pool,
                          HTTP_INTERNAL_SERVER_ERROR, 0,
                          "The resource was moved, but a failure "
                          "occurred during the move of its properties. "
                          "The resource was moved back to its original "
                          "location, but its properties may have been "
                          "partially moved. The server may be in an "
                          "inconsistent state.",
                          err);
}

static dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype)
{
    dav_resource_private *info = wres->resource->info;

    /* do not attempt to remove a null resource,
     * or a collection with children
     */
    if (wres->resource->exists &&
        (!wres->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) {
        /* try to remove the resource */
        apr_status_t result;

        result = wres->resource->collection
            ? apr_dir_remove(info->pathname, wres->pool)
            : apr_file_remove(info->pathname, wres->pool);

        /*
        ** If an error occurred, then add it to multistatus response.
        ** Note that we add it for the root resource, too. It is quite
        ** possible to delete the whole darn tree, yet fail on the root.
        **
        ** (also: remember we are deleting via a postfix traversal)
        */
        if (result != APR_SUCCESS) {
            /* ### assume there is a permissions problem */

            /* ### use errno to generate DAV:responsedescription? */
            dav_add_response(wres, HTTP_FORBIDDEN, NULL);
        }
    }

    return NULL;
}

static dav_error * dav_fs_remove_resource(dav_resource *resource,
                                          dav_response **response)
{
    dav_resource_private *info = resource->info;

    *response = NULL;

    /* if a collection, recursively remove it and its children,
     * including the state dirs
     */
    if (resource->collection) {
        dav_walk_params params = { 0 };
        dav_error *err = NULL;
        dav_response *multi_status;

        params.walk_type = (DAV_WALKTYPE_NORMAL
                            | DAV_WALKTYPE_HIDDEN
                            | DAV_WALKTYPE_POSTFIX);
        params.func = dav_fs_delete_walker;
        params.pool = info->pool;
        params.root = resource;

        if ((err = dav_fs_walk(&params, DAV_INFINITY,
                               &multi_status)) != NULL) {
            /* on a "real" error, then just punt. nothing else to do. */
            return err;
        }

        if ((*response = multi_status) != NULL) {
            /* some multistatus responses exist. wrap them in a 207 */
            return dav_new_error(info->pool, HTTP_MULTI_STATUS, 0,
                                 "Error(s) occurred on some resources during "
                                 "the deletion process.");
        }

        /* no errors... update resource state */
        resource->exists = 0;
        resource->collection = 0;

        return NULL;
    }

    /* not a collection; remove the file and its properties */
    if (apr_file_remove(info->pathname, info->pool) != APR_SUCCESS) {
        /* ### put a description in here */
        return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, NULL);
    }

    /* update resource state */
    resource->exists = 0;
    resource->collection = 0;

    /* remove properties and return its result */
    return dav_fs_deleteset(info->pool, resource);
}

/* ### move this to dav_util? */
/* Walk recursively down through directories, *
 * including lock-null resources as we go.    */
static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth)
{
    const dav_walk_params *params = fsctx->params;
    apr_pool_t *pool = params->pool;
    dav_error *err = NULL;
    int isdir = fsctx->res1.collection;
    apr_finfo_t dirent;
    apr_dir_t *dirp;

    /* ensure the context is prepared properly, then call the func */
    err = (*params->func)(&fsctx->wres,
                          isdir
                          ? DAV_CALLTYPE_COLLECTION
                          : DAV_CALLTYPE_MEMBER);
    if (err != NULL) {
        return err;
    }

    if (depth == 0 || !isdir) {
        return NULL;
    }

    /* put a trailing slash onto the directory, in preparation for appending
     * files to it as we discovery them within the directory */
    dav_check_bufsize(pool, &fsctx->path1, DAV_BUFFER_PAD);
    fsctx->path1.buf[fsctx->path1.cur_len++] = '/';
    fsctx->path1.buf[fsctx->path1.cur_len] = '\0';        /* in pad area */

    /* if a secondary path is present, then do that, too */
    if (fsctx->path2.buf != NULL) {
        dav_check_bufsize(pool, &fsctx->path2, DAV_BUFFER_PAD);
        fsctx->path2.buf[fsctx->path2.cur_len++] = '/';
        fsctx->path2.buf[fsctx->path2.cur_len] = '\0';        /* in pad area */
    }

    /* Note: the URI should ALREADY have a trailing "/" */

    /* for this first pass of files, all resources exist */
    fsctx->res1.exists = 1;

    /* a file is the default; we'll adjust if we hit a directory */
    fsctx->res1.collection = 0;
    fsctx->res2.collection = 0;

    /* open and scan the directory */
    if ((apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) {
        /* ### need a better error */
        return dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL);
    }
    while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) {
        apr_size_t len;
        apr_status_t status;

        len = strlen(dirent.name);

        /* avoid recursing into our current, parent, or state directories */
        if (dirent.name[0] == '.' 
              && (len == 1 || (dirent.name[1] == '.' && len == 2))) {
            continue;
        }

        if (params->walk_type & DAV_WALKTYPE_AUTH) {
            /* ### need to authorize each file */
            /* ### example: .htaccess is normally configured to fail auth */

            /* stuff in the state directory is never authorized! */
            if (!strcmp(dirent.name, DAV_FS_STATE_DIR)) {
                continue;
            }
        }
        /* skip the state dir unless a HIDDEN is performed */
        if (!(params->walk_type & DAV_WALKTYPE_HIDDEN)
            && !strcmp(dirent.name, DAV_FS_STATE_DIR)) {
            continue;
        }

        /* append this file onto the path buffer (copy null term) */
        dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0);


        /* ### Optimize me, dirent can give us what we need! */
        status = apr_lstat(&fsctx->info1.finfo, fsctx->path1.buf, 
                           APR_FINFO_NORM, pool);
        if (status != APR_SUCCESS && status != APR_INCOMPLETE) {
            /* woah! where'd it go? */
            /* ### should have a better error here */
            err = dav_new_error(pool, HTTP_NOT_FOUND, 0, NULL);
            break;
        }

        /* copy the file to the URI, too. NOTE: we will pad an extra byte
           for the trailing slash later. */
        dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1);

        /* if there is a secondary path, then do that, too */
        if (fsctx->path2.buf != NULL) {
            dav_buffer_place_mem(pool, &fsctx->path2, dirent.name, len + 1, 0);
        }

        /* set up the (internal) pathnames for the two resources */
        fsctx->info1.pathname = fsctx->path1.buf;
        fsctx->info2.pathname = fsctx->path2.buf;

        /* set up the URI for the current resource */
        fsctx->res1.uri = fsctx->uri_buf.buf;

        /* ### for now, only process regular files (e.g. skip symlinks) */
        if (fsctx->info1.finfo.filetype == APR_REG) {
            /* call the function for the specified dir + file */
            if ((err = (*params->func)(&fsctx->wres,
                                       DAV_CALLTYPE_MEMBER)) != NULL) {
                /* ### maybe add a higher-level description? */
                break;
            }
        }
        else if (fsctx->info1.finfo.filetype == APR_DIR) {
            apr_size_t save_path_len = fsctx->path1.cur_len;
            apr_size_t save_uri_len = fsctx->uri_buf.cur_len;
            apr_size_t save_path2_len = fsctx->path2.cur_len;

            /* adjust length to incorporate the subdir name */
            fsctx->path1.cur_len += len;
            fsctx->path2.cur_len += len;

            /* adjust URI length to incorporate subdir and a slash */
            fsctx->uri_buf.cur_len += len + 1;
            fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/';
            fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0';

            /* switch over to a collection */
            fsctx->res1.collection = 1;
            fsctx->res2.collection = 1;

            /* recurse on the subdir */
            /* ### don't always want to quit on error from single child */
            if ((err = dav_fs_walker(fsctx, depth - 1)) != NULL) {
                /* ### maybe add a higher-level description? */

⌨️ 快捷键说明

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