📄 repos.c
字号:
** 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; 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! */ if (apr_lstat(&fsctx->info1.finfo, fsctx->path1.buf, APR_FINFO_NORM, pool) != APR_SUCCESS) { /* 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 */ } } /* ### check the return value of this? */ apr_dir_close(dirp); if (err != NULL) return err; if (params->walk_type & DAV_WALKTYPE_LOCKNULL) { apr_size_t offset = 0; /* null terminate the directory name */ fsctx->path1.buf[fsctx->path1.cur_len - 1] = '\0'; /* Include any lock null resources found in this collection */ fsctx->res1.collection = 1; if ((err = dav_fs_get_locknull_members(&fsctx->res1, &fsctx->locknull_buf)) != NULL) { /* ### maybe add a higher-level description? */ return err; } /* put a slash back on the end of the directory */ fsctx->path1.buf[fsctx->path1.cur_len - 1] = '/'; /* these are all non-existant (files) */ fsctx->res1.exists = 0; fsctx->res1.collection = 0; memset(&fsctx->info1.finfo, 0, sizeof(fsctx->info1.finfo)); while (offset < fsctx->locknull_buf.cur_len) { apr_size_t len = strlen(fsctx->locknull_buf.buf + offset); dav_lock *locks = NULL; /* ** Append the locknull file to the paths and the URI. Note that ** we don't have to pad the URI for a slash since a locknull ** resource is not a collection. */ dav_buffer_place_mem(pool, &fsctx->path1, fsctx->locknull_buf.buf + offset, len + 1, 0); dav_buffer_place_mem(pool, &fsctx->uri_buf, fsctx->locknull_buf.buf + offset, len + 1, 0); if (fsctx->path2.buf != NULL) { dav_buffer_place_mem(pool, &fsctx->path2, fsctx->locknull_buf.buf + offset, 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; /* ** To prevent a PROPFIND showing an expired locknull ** resource, query the lock database to force removal ** of both the lock entry and .locknull, if necessary.. ** Sure, the query in PROPFIND would do this.. after ** the locknull resource was already included in the ** return. ** ** NOTE: we assume the caller has opened the lock database ** if they have provided DAV_WALKTYPE_LOCKNULL. */ /* ### we should also look into opening it read-only and ### eliding timed-out items from the walk, yet leaving ### them in the locknull database until somebody opens ### the thing writable. */ /* ### probably ought to use has_locks. note the problem ### mentioned above, though... we would traverse this as ### a locknull, but then a PROPFIND would load the lock ### info, causing a timeout and the locks would not be ### reported. Therefore, a null resource would be returned ### in the PROPFIND. ### ### alternative: just load unresolved locks. any direct ### locks will be timed out (correct). any indirect will ### not (correct; consider if a parent timed out -- the ### timeout routines do not walk and remove indirects; ### even the resolve func would probably fail when it ### tried to find a timed-out direct lock). */ if ((err = dav_lock_query(params->lockdb, &fsctx->res1, &locks)) != NULL) { /* ### maybe add a higher-level description? */ return err; } /* call the function for the specified dir + file */ if (locks != NULL && (err = (*params->func)(&fsctx->wres, DAV_CALLTYPE_LOCKNULL)) != NULL) { /* ### maybe add a higher-level description? */ return err; } offset += len + 1; } /* reset the exists flag */ fsctx->res1.exists = 1; } if (params->walk_type & DAV_WALKTYPE_POSTFIX) { /* replace the dirs' trailing slashes with null terms */ fsctx->path1.buf[--fsctx->path1.cur_len] = '\0'; fsctx->uri_buf.buf[--fsctx->uri_buf.cur_len] = '\0'; if (fsctx->path2.buf != NULL) { fsctx->path2.buf[--fsctx->path2.cur_len] = '\0'; } /* this is a collection which exists */ fsctx->res1.collection = 1; return (*params->func)(&fsctx->wres, DAV_CALLTYPE_POSTFIX); } return NULL;}static dav_error * dav_fs_internal_walk(const dav_walk_params *params, int depth, int is_move, const dav_resource *root_dst, dav_response **response){ dav_fs_walker_context fsctx = { 0 }; dav_error *err; dav_fs_copymove_walk_ctx cm_ctx = { 0 };#if DAV_DEBUG if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0 && params->lockdb == NULL) { return dav_new_error(params->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DESIGN ERROR: walker called to walk locknull " "resources, but a lockdb was not provided."); }#endif fsctx.params = params; fsctx.wres.walk_ctx = params->walk_ctx; fsctx.wres.pool = params->pool; /* ### zero out versioned, working, baselined? */ fsctx.res1 = *params->root; fsctx.res1.pool = params->pool; fsctx.res1.info = &fsctx.info1; fsctx.info1 = *params->root->info; /* the pathname is stored in the path1 buffer */ dav_buffer_init(params->pool, &fsctx.path1, fsctx.info1.pathname); fsctx.info1.pathname = fsctx.path1.buf; if (root_dst != NULL) { /* internal call from the COPY/MOVE code. set it up. */ fsctx.wres.walk_ctx = &cm_ctx; cm_ctx.is_move = is_move; cm_ctx.res_dst = &fsctx.res2; cm_ctx.root = params->root; cm_ctx.pool = params->pool; fsctx.res2 = *root_dst; fsctx.res2.exists = 0; fsctx.res2.collection = 0; fsctx.res2.uri = NULL; /* we don't track this */ fsctx.res2.pool = params->pool; fsctx.res2.info = &fsctx.info2; fsctx.info2 = *root_dst->info; /* res2 does not exist -- clear its finfo structure */ memset(&fsctx.info2.finfo, 0, sizeof(fsctx.info2.finfo)); /* the pathname is stored in the path2 buffer */ dav_buffer_init(params->pool, &fsctx.path2, fsctx.info2.pathname); fsctx.info2.pathname = fsctx.path2.buf; } /* prep the URI buffer */ dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri); /* if we have a directory, then ensure the URI has a trailing "/" */ if (fsctx.res1.collection && fsctx.uri_buf.buf[fsctx.uri_buf.cur_len - 1] != '/') { /* this will fall into the pad area */ fsctx.uri_buf.buf[fsctx.uri_buf.cur_len++] = '/';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -