📄 repos.c
字号:
/* ** ### 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(¶ms, 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_stat(&fsctx->info1.finfo, fsctx->path1.buf, APR_FINFO_NORM | APR_FINFO_LINK, 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? */ break; } /* put the various information back */ fsctx->path1.cur_len = save_path_len; fsctx->path2.cur_len = save_path2_len; fsctx->uri_buf.cur_len = save_uri_len; fsctx->res1.collection = 0; fsctx->res2.collection = 0; /* assert: res1.exists == 1 */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -