static dav_error * dav_rainx_deliver_SPECIAL(const dav_resource *resource, ap_filter_t *output) { const char *result; int result_len; apr_status_t status; apr_pool_t *pool; apr_bucket_brigade *bb; apr_bucket *bkt; DAV_XDEBUG_RES(resource, 0, "%s()", __FUNCTION__); pool = resource->info->request->pool; /* Check resource type */ if (resource->type != DAV_RESOURCE_TYPE_PRIVATE) return server_create_and_stat_error(resource_get_server_config(resource), pool, HTTP_CONFLICT, 0, apr_pstrdup(pool, "Cannot GET this type of resource.")); if (resource->collection) return server_create_and_stat_error(resource_get_server_config(resource), pool, HTTP_CONFLICT, 0, apr_pstrdup(pool,"No GET on collections")); /* Generate the output */ result = resource->info->generator(resource, pool); result_len = strlen(result); /* We must reply a buffer */ bkt = apr_bucket_heap_create(result, result_len, NULL, output->c->bucket_alloc); bb = apr_brigade_create(pool, output->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bkt); /* Nothing more to reply */ bkt = apr_bucket_eos_create(output->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bkt); DAV_XDEBUG_RES(resource, 0, "%s : ready to deliver", __FUNCTION__); if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) return server_create_and_stat_error(resource_get_server_config(resource), pool, HTTP_FORBIDDEN, 0, apr_pstrdup(pool,"Could not write contents to filter.")); server_inc_stat(resource_get_server_config(resource), RAWX_STATNAME_REP_2XX, 0); /* HERE ADD request counter */ switch(resource->info->type) { case STAT: server_inc_request_stat(resource_get_server_config(resource), RAWX_STATNAME_REQ_STAT, request_get_duration(resource->info->request)); break; case INFO: server_inc_request_stat(resource_get_server_config(resource), RAWX_STATNAME_REQ_INFO, request_get_duration(resource->info->request)); break; default: break; } return NULL; }
/* JFS : walks are not managed by this rawx */ static dav_error * dav_rawx_walk(const dav_walk_params *params, int depth, dav_response **response) { dav_walk_resource wres; dav_error *err; (void) depth; err = NULL; memset(&wres, 0x00, sizeof(wres)); wres.walk_ctx = params->walk_ctx; wres.pool = params->pool; wres.resource = params->root; DAV_XDEBUG_RES(params->root, 0, "sanity checks for %s(%s)", __FUNCTION__, resource_get_pathname(wres.resource)); if (wres.resource->type != DAV_RESOURCE_TYPE_REGULAR) return server_create_and_stat_error(resource_get_server_config(params->root), params->root->pool, HTTP_CONFLICT, 0, "Only regular resources can be deleted with RAWX"); if (wres.resource->collection) return server_create_and_stat_error(resource_get_server_config(params->root), params->root->pool, HTTP_CONFLICT, 0, "Collection resources canot be deleted with RAWX"); if (!wres.resource->exists) return server_create_and_stat_error(resource_get_server_config(params->root), params->root->pool, HTTP_NOT_FOUND, 0, "Resource not found (no chunk)"); DAV_DEBUG_RES(params->root, 0, "ready for %s(%s)", __FUNCTION__, resource_get_pathname(wres.resource)); err = (*params->func)(&wres, DAV_CALLTYPE_MEMBER); *response = wres.response; return err; }
static dav_error * dav_rawx_get_parent_resource(const dav_resource *resource, dav_resource **result_parent) { apr_pool_t *pool; dav_resource *parent; (void) resource; (void) result_parent; pool = resource->pool; DAV_XDEBUG_RES(resource, 0, "%s(%s)", __FUNCTION__, resource_get_pathname(resource)); /* Build a fake root */ parent = apr_pcalloc(resource->pool, sizeof(*resource)); parent->exists = 1; parent->collection = 1; parent->uri = "/"; parent->type = DAV_RESOURCE_TYPE_WORKING; parent->info = NULL; parent->hooks = &dav_hooks_repository_rawx; parent->pool = pool; *result_parent = parent; return NULL; }
static int dav_rainx_is_same_resource_SPECIAL(const dav_resource *res1, const dav_resource *res2) { (void) res1; (void) res2; DAV_XDEBUG_RES(res1, 0, "%s(...)", __FUNCTION__); return (res1->type == res2->type) && (res1->hooks == res2->hooks); }
static int dav_rawx_is_parent_resource(const dav_resource *res1, const dav_resource *res2) { (void) res1; (void) res2; DAV_XDEBUG_RES(res1, 0, "%s(%s,%s)", __FUNCTION__, resource_get_pathname(res1), resource_get_pathname(res2)); return 0; }
static int dav_rawx_is_same_resource(const dav_resource *res1, const dav_resource *res2) { dav_resource_private *ctx1 = res1->info; dav_resource_private *ctx2 = res2->info; DAV_XDEBUG_RES(res1, 0, "%s(%s,%s)", __FUNCTION__, resource_get_pathname(res1), resource_get_pathname(res2)); return (res1->type == res2->type) && (0 == apr_strnatcasecmp(ctx1->hex_chunkid, ctx2->hex_chunkid)) && (0 == apr_strnatcasecmp(ctx1->dirname, ctx2->dirname)) && (0 == apr_strnatcasecmp(ctx1->file_extension, ctx2->file_extension)); }
static dav_error * dav_rawx_remove_resource(dav_resource *resource, dav_response **response) { char buff[128]; apr_pool_t *pool; apr_status_t status; dav_error *e = NULL; DAV_XDEBUG_RES(resource, 0, "%s(%s)", __FUNCTION__, resource_get_pathname(resource)); pool = resource->pool; *response = NULL; if (DAV_RESOURCE_TYPE_REGULAR != resource->type) { e = server_create_and_stat_error(resource_get_server_config(resource), pool, HTTP_CONFLICT, 0, "Cannot DELETE this type of resource."); goto end_remove; } if (resource->collection) { e = server_create_and_stat_error(resource_get_server_config(resource), pool, HTTP_CONFLICT, 0, "No DELETE on collections"); goto end_remove; } status = apr_file_remove(resource_get_pathname(resource), pool); if (APR_SUCCESS != status) { e = server_create_and_stat_error(resource_get_server_config(resource), pool, HTTP_FORBIDDEN, 0, apr_pstrcat(pool, "Failed to DELETE this chunk : ", apr_strerror(status, buff, sizeof(buff)), NULL)); goto end_remove; } send_chunk_event("storage.chunk.deleted", resource); resource->exists = 0; resource->collection = 0; server_inc_stat(resource_get_server_config(resource), RAWX_STATNAME_REP_2XX, 0); end_remove: /* Now we pass here even if an error occured, for process request duration */ server_inc_request_stat(resource_get_server_config(resource), RAWX_STATNAME_REQ_CHUNKDEL, request_get_duration(resource->info->request)); return e; }
static int dav_rainx_is_parent_resource_SPECIAL(const dav_resource *res1, const dav_resource *res2) { DAV_XDEBUG_RES(res1, 0, "%s(...)", __FUNCTION__); return dav_rainx_is_same_resource_SPECIAL(res1, res2); }
static dav_error * dav_rawx_deliver(const dav_resource *resource, ap_filter_t *output) { dav_rawx_server_conf *conf; apr_pool_t *pool; apr_bucket_brigade *bb = NULL; apr_status_t status; apr_bucket *bkt = NULL; dav_resource_private *ctx; dav_error *e = NULL; apr_finfo_t info; DAV_XDEBUG_RES(resource, 0, "%s(%s)", __FUNCTION__, resource_get_pathname(resource)); pool = resource->pool; conf = resource_get_server_config(resource); /* Check resource type */ if (DAV_RESOURCE_TYPE_REGULAR != resource->type) { e = server_create_and_stat_error(conf, pool, HTTP_CONFLICT, 0, "Cannot GET this type of resource."); goto end_deliver; } if (resource->collection) { e = server_create_and_stat_error(conf, pool, HTTP_CONFLICT, 0, "No GET on collections"); goto end_deliver; } ctx = resource->info; if (ctx->update_only) { /* Check if it is not a busy file. We accept reads during * compression but not attr updates. */ char *pending_file = apr_pstrcat(pool, resource_get_pathname(resource), ".pending", NULL); status = apr_stat(&info, pending_file, APR_FINFO_ATIME, pool); if (status == APR_SUCCESS) { e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, "File in pending mode."); goto end_deliver; } GError *error_local = NULL; /* UPDATE chunk attributes and go on */ const char *path = resource_get_pathname(resource); FILE *f = NULL; f = fopen(path, "r"); /* Try to open the file but forbids a creation */ if (!set_rawx_info_to_fd(fileno(f), &error_local, &(ctx->chunk))) { fclose(f); e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, apr_pstrdup(pool, gerror_get_message(error_local))); g_clear_error(&error_local); goto end_deliver; } fclose(f); } else { bb = apr_brigade_create(pool, output->c->bucket_alloc); if (!ctx->compression){ apr_file_t *fd = NULL; /* Try to open the file but forbids a creation */ status = apr_file_open(&fd, resource_get_pathname(resource), APR_READ|APR_BINARY|APR_BUFFERED, 0, pool); if (APR_SUCCESS != status) { e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, "File permissions deny server access."); goto end_deliver; } /* FIXME this does not handle large files. but this is test code anyway */ bkt = apr_bucket_file_create(fd, 0, (apr_size_t)resource->info->finfo.size, pool, output->c->bucket_alloc); } else { DAV_DEBUG_RES(resource, 0, "Building a compressed resource bucket"); gint i64; i64 = g_ascii_strtoll(ctx->cp_chunk.uncompressed_size, NULL, 10); /* creation of compression specific bucket */ bkt = apr_pcalloc(pool, sizeof(struct apr_bucket)); bkt->type = &chunk_bucket_type; bkt->length = i64; bkt->start = 0; bkt->data = ctx; bkt->free = chunk_bucket_free_noop; bkt->list = output->c->bucket_alloc; } APR_BRIGADE_INSERT_TAIL(bb, bkt); /* as soon as the chunk has been sent, end of stream!*/ bkt = apr_bucket_eos_create(output->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bkt); if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS){ e = server_create_and_stat_error(conf, pool, HTTP_FORBIDDEN, 0, "Could not write contents to filter."); /* close file */ if (ctx->cp_chunk.fd) { fclose(ctx->cp_chunk.fd); } goto end_deliver; } if (ctx->cp_chunk.buf){ g_free(ctx->cp_chunk.buf); ctx->cp_chunk.buf = NULL; } if (ctx->cp_chunk.uncompressed_size){ g_free(ctx->cp_chunk.uncompressed_size); ctx->cp_chunk.uncompressed_size = NULL; } /* close file */ if (ctx->cp_chunk.fd) { fclose(ctx->cp_chunk.fd); } server_inc_stat(conf, RAWX_STATNAME_REP_2XX, 0); server_add_stat(conf, RAWX_STATNAME_REP_BWRITTEN, resource->info->finfo.size, 0); } end_deliver: if (bb) { apr_brigade_destroy(bb); bb = NULL; } /* Now we pass here even if an error occured, for process request duration */ server_inc_request_stat(resource_get_server_config(resource), RAWX_STATNAME_REQ_CHUNKGET, request_get_duration(resource->info->request)); return e; }