diff -r 99a34860c105 -r d938228c382e src/server/plugins/postgresql/webdav.c --- a/src/server/plugins/postgresql/webdav.c Wed Nov 02 19:19:01 2022 +0100 +++ b/src/server/plugins/postgresql/webdav.c Sun Nov 06 15:53:32 2022 +0100 @@ -35,8 +35,9 @@ #include "../../daemon/http.h" // etag -#include -#include +#include +#include +#include #include @@ -238,14 +239,14 @@ * adds str to the buffer * some characters will be escaped: \,{} */ -static void buf_addstr_escaped(UcxBuffer *buf, const char *str) { +static void buf_addstr_escaped(CxBuffer *buf, const char *str) { size_t len = strlen(str); for(size_t i=0;iproperty; if(property && property->namespace && property->namespace->href && property->name) { buf_addstr_escaped(xmlns, (const char*)property->namespace->href); buf_addstr_escaped(pname, (const char*)property->name); if(plist->next) { - ucx_buffer_putc(xmlns, ','); - ucx_buffer_putc(pname, ','); + cxBufferPut(xmlns, ','); + cxBufferPut(pname, ','); } } plist = plist->next; } - int r1 = ucx_buffer_write("}\0", 2, 1, xmlns) == 0; - int r2 = ucx_buffer_write("}\0", 2, 1, pname) == 0; + int r1 = cxBufferWrite("}\0", 2, 1, xmlns) == 0; + int r2 = cxBufferWrite("}\0", 2, 1, pname) == 0; return r1+r2 != 0; } @@ -295,7 +296,7 @@ WSBool iscollection, PgPropfindExtCol *ext, size_t numext, - UcxBuffer *sql) + CxBuffer *sql) { PgWebdavBackend *pgdav = rq->dav->instance; PgRepository *repo = pgdav->repository; @@ -318,47 +319,47 @@ // CTE if(depth == -1) { - ucx_buffer_puts(sql, sql_propfind_cte_recursive); + cxBufferPutString(sql, sql_propfind_cte_recursive); } // select - ucx_buffer_puts(sql, sql_propfind_select); + cxBufferPutString(sql, sql_propfind_select); // ppath switch(depth) { - case 0: ucx_buffer_puts(sql, sql_propfind_ppath_depth0); break; - case 1: ucx_buffer_puts(sql, sql_propfind_ppath_depth1); break; - case -1: ucx_buffer_puts(sql, sql_propfind_ppath_depth_infinity); break; + case 0: cxBufferPutString(sql, sql_propfind_ppath_depth0); break; + case 1: cxBufferPutString(sql, sql_propfind_ppath_depth1); break; + case -1: cxBufferPutString(sql, sql_propfind_ppath_depth_infinity); break; } // cols - ucx_buffer_puts(sql, sql_propfind_cols); + cxBufferPutString(sql, sql_propfind_cols); // ext_cols if(ext) { if(rq->allprop) { for(int i=0;intables;i++) { - ucx_bprintf(sql, ",x%d.*\n", i); + cx_bprintf(sql, ",x%d.*\n", i); } } else { for(int i=0;itableindex, e.ext->column); + cx_bprintf(sql, ",x%d.%s\n", e.ext->tableindex, e.ext->column); } } } // from - ucx_buffer_puts(sql, depth == -1 ? sql_propfind_from_cte : sql_propfind_from_table); + cxBufferPutString(sql, depth == -1 ? sql_propfind_from_cte : sql_propfind_from_table); // prop join - ucx_buffer_puts(sql, rq->allprop ? sql_propfind_propjoin_allprop : sql_propfind_propjoin_plist); + cxBufferPutString(sql, rq->allprop ? sql_propfind_propjoin_allprop : sql_propfind_propjoin_plist); // ext_join if(ext) { if(rq->allprop) { for(int i=0;intables;i++) { - ucx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[i].table, i, i); + cx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[i].table, i, i); } } else { int tab = -1; @@ -366,7 +367,7 @@ PgPropfindExtCol e = ext[i]; if(e.ext->tableindex != tab) { tab = e.ext->tableindex; - ucx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[tab].table, tab, tab); + cx_bprintf(sql, "left join %s x%d on r.resource_id = x%d.resource_id\n", repo->tables[tab].table, tab, tab); } } } @@ -375,20 +376,20 @@ // where if(depth == 0) { - ucx_buffer_puts(sql, sql_propfind_where_depth0); + cxBufferPutString(sql, sql_propfind_where_depth0); } else if(depth == 1) { - ucx_buffer_puts(sql, sql_propfind_where_depth1); + cxBufferPutString(sql, sql_propfind_where_depth1); } // order if(depth == 1) { - ucx_buffer_puts(sql, sql_propfind_order_depth1); + cxBufferPutString(sql, sql_propfind_order_depth1); } else if(depth == -1) { - ucx_buffer_puts(sql, sql_propfind_order_depth_infinity); + cxBufferPutString(sql, sql_propfind_order_depth_infinity); } // end - ucx_buffer_puts(sql, ";\0"); + cxBufferWrite(";\0", 1, 2, sql); return 0; } @@ -400,6 +401,7 @@ WebdavPList **outplist) { PgWebdavBackend *pgdav = rq->dav->instance; + CxAllocator *a = pool_allocator(rq->sn->pool); // first, check if the resource exists // if it doesn't exist, we can return immediately @@ -432,7 +434,7 @@ // like to use it char resource_id_str[32]; snprintf(resource_id_str, 32, "%" PRId64, resource_id); - pblock_nvinsert("resource_id",resource_id_str, rq->rq->vars); + pblock_nvinsert("resource_id", resource_id_str, rq->rq->vars); // create a list of requsted extended properties PgPropfindExtCol *ext; @@ -442,16 +444,15 @@ ext = NULL; numext = 0; } else { - numext = pgdav->repository->prop_ext->count; + numext = pgdav->repository->prop_ext->size; ext = pool_calloc(rq->sn->pool, numext, sizeof(PgPropfindExtCol)); if(rq->allprop) { // the map pgdav->repository->prop_ext contains all property extensions // we can just convert the map to an array - UcxMapIterator i = ucx_map_iterator(pgdav->repository->prop_ext); - PgPropertyStoreExt *cfg_ext; + CxIterator i = cxMapIteratorValues(pgdav->repository->prop_ext); int j = 0; - UCX_MAP_FOREACH(key, cfg_ext, i) { + cx_foreach(PgPropertyStoreExt *, cfg_ext, i) { PgPropfindExtCol extcol; extcol.ext = cfg_ext; extcol.field_num = -1; // get the field_num after the PQexec @@ -464,9 +465,9 @@ while(webdav_plist_iterator_next(&i, &cur)) { WSNamespace *ns = cur->property->namespace; if(ns) { - UcxKey pkey = webdav_property_key((const char*)ns->href, cur->property->name); - PgPropertyStoreExt *cfg_ext = ucx_map_get(pgdav->repository->prop_ext, pkey); - free((void*)pkey.data); + CxHashKey pkey = webdav_property_key((const char*)ns->href, cur->property->name); + PgPropertyStoreExt *cfg_ext = cxMapGet(pgdav->repository->prop_ext, pkey); + free(pkey.data.bytes); if(cfg_ext) { PgPropfindExtCol extcol; extcol.ext = cfg_ext; @@ -485,11 +486,15 @@ // create sql query const char *query = NULL; - UcxBuffer *sql = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); - if(pg_create_propfind_query(rq, iscollection, ext, numext, sql)) { + CxBuffer sql; + if(cxBufferInit(&sql, NULL, 2048, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { return 1; } - query = sql->space; + + if(pg_create_propfind_query(rq, iscollection, ext, numext, &sql)) { + return 1; + } + query = sql.space; // get all resources and properties size_t href_len = strlen(href); @@ -501,32 +506,34 @@ href_param[href_len] = '\0'; // if allprop is false, create array pair for xmlns/property names - UcxBuffer *xmlns_buf = NULL; - UcxBuffer *pname_buf = NULL; + CxBuffer xmlns_buf; + CxBuffer pname_buf; + WSBool buf_initialized = FALSE; char *xmlns_param = NULL; char *pname_param = NULL; int nparam = 2; if(!rq->allprop) { size_t bufsize = rq->propcount < 200 ? 8 + rq->propcount * 32 : 4096; - xmlns_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND); - if(!xmlns_buf) { + if(cxBufferInit(&xmlns_buf, NULL, bufsize, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { return 1; } - pname_buf = ucx_buffer_new(NULL, bufsize, UCX_BUFFER_AUTOEXTEND); - if(!pname_buf) { - ucx_buffer_free(xmlns_buf); + if(cxBufferInit(&pname_buf, NULL, bufsize, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { + cxBufferDestroy(&xmlns_buf); return 1; } - if(pg_create_property_param_arrays(*outplist, xmlns_buf, pname_buf)) { - ucx_buffer_free(xmlns_buf); - ucx_buffer_free(pname_buf); + if(pg_create_property_param_arrays(*outplist, &xmlns_buf, &pname_buf)) { + cxBufferDestroy(&xmlns_buf); + cxBufferDestroy(&pname_buf); return 1; } - xmlns_param = xmlns_buf->space; - pname_param = pname_buf->space; + buf_initialized = TRUE; + xmlns_param = xmlns_buf.space; + pname_param = pname_buf.space; nparam = 4; } + + const char* params[4] = { resource_id_str, href_param, xmlns_param, pname_param }; PGresult *result = PQexecParams( pgdav->connection, @@ -539,9 +546,9 @@ 0); // 0: result in text format int nrows = PQntuples(result); pool_free(rq->sn->pool, href_param); - if(xmlns_buf) { - ucx_buffer_free(xmlns_buf); - ucx_buffer_free(pname_buf); + if(buf_initialized) { + cxBufferDestroy(&xmlns_buf); + cxBufferDestroy(&pname_buf); } if(nrows < 1) { // we resolved the path, so the resource exists and nrows should @@ -899,9 +906,9 @@ static PgPropertyStoreExt* pg_proppatch_prop_get_ext(PgWebdavBackend *pgdav, WebdavProperty *property) { - UcxKey pkey = webdav_property_key((const char*)property->namespace->href, property->name); - PgPropertyStoreExt *ext = ucx_map_get(pgdav->repository->prop_ext, pkey); - free((void*)pkey.data); + CxHashKey pkey = webdav_property_key((const char*)property->namespace->href, property->name); + PgPropertyStoreExt *ext = cxMapGet(pgdav->repository->prop_ext, pkey); + free(pkey.data.bytes); return ext; } @@ -923,14 +930,21 @@ ext_prop->column = ext; ext_prop->property = property; - UcxAllocator a = util_pool_allocator(pool); + CxAllocator *a = pool_allocator(pool); proppatch->ext[ext->tableindex].isused = TRUE; - UcxList **list = proppatch_op == PG_PROPPATCH_EXT_REMOVE - ? &proppatch->ext[ext->tableindex].remove - : &proppatch->ext[ext->tableindex].set; - *list = ucx_list_append_a(&a, *list, ext_prop); - + PgProppatchExtProp **list_begin; + PgProppatchExtProp **list_end; + if(proppatch_op == PG_PROPPATCH_EXT_SET) { + list_begin = &proppatch->ext[ext->tableindex].set_begin; + list_end = &proppatch->ext[ext->tableindex].set_end; + } else { + list_begin = &proppatch->ext[ext->tableindex].remove_begin; + list_end = &proppatch->ext[ext->tableindex].remove_end; + } + + cx_linked_list_add((void**)list_begin, (void**)list_end, -1, offsetof(PgProppatchExtProp, next), ext_prop); + proppatch->extensions_used = TRUE; return 0; @@ -1053,33 +1067,36 @@ * * Query: insert into (resource_id, col1, ...) values ($1, $2 ...); */ -static UcxBuffer* ext_row_create_insert_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) { +static CxBuffer* ext_row_create_insert_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) { pool_handle_t *pool = request->sn->pool; - UcxBuffer *sql = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); + CxBuffer *sql = pool_malloc(pool, sizeof(CxBuffer)); if(!sql) { return NULL; } + if(cxBufferInit(sql, NULL, 1024, pool_allocator(pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { + pool_free(pool, sql); + return NULL; + } - size_t pg_nparams = ucx_list_size(ext->set) + 1; + size_t pg_nparams = cx_linked_list_size(ext->set_begin, offsetof(PgProppatchExtProp, next)) + 1; char** pg_params = pool_calloc(pool, pg_nparams, sizeof(char*)); if(!pg_params) { - ucx_buffer_free(sql); + cxBufferDestroy(sql); + pool_free(pool, sql); return NULL; } - ucx_buffer_puts(sql, "insert into "); - ucx_buffer_puts(sql, table->table); - ucx_buffer_puts(sql, "(resource_id"); - UCX_FOREACH(elm, ext->set) { - PgProppatchExtProp *prop = elm->data; - ucx_bprintf(sql, ",%s", prop->column->name); + cxBufferPutString(sql, "insert into "); + cxBufferPutString(sql, table->table); + cxBufferPutString(sql, "(resource_id"); + for(PgProppatchExtProp *prop=ext->set_begin;prop;prop=prop->next) { + cx_bprintf(sql, ",%s", prop->column->name); } - ucx_buffer_puts(sql, ") values ($1\n"); + cxBufferPutString(sql, ") values ($1\n"); int i = 1; - UCX_FOREACH(elm, ext->set) { - PgProppatchExtProp *prop = elm->data; + for(PgProppatchExtProp *prop=ext->set_begin;prop;prop=prop->next) { WebdavProperty *property = prop->property; // convert the property value to WSXmlData // property->vtype == WS_VALUE_XML_NODE should always be true @@ -1091,15 +1108,15 @@ if(property_value->namespaces) { // currently only text data is supported pool_free(pool, params); - ucx_buffer_free(sql); + cxBufferDestroy(sql); return NULL; } } pg_params[i] = value_str; - ucx_bprintf(sql, ",$%d", ++i); + cx_bprintf(sql, ",$%d", ++i); } - ucx_buffer_puts(sql, ");"); + cxBufferPutString(sql, ");"); //printf("\n\n%.*s\n\n", (int)sql->size, sql->space); @@ -1122,28 +1139,32 @@ * ... * where resource_id = $1 ; */ -static UcxBuffer* ext_row_create_update_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) { +static CxBuffer* ext_row_create_update_query(WebdavProppatchRequest *request, PgProppatchExt *ext, PgExtTable *table, char *** params, size_t *nparams) { pool_handle_t *pool = request->sn->pool; - UcxBuffer *sql = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); + CxBuffer *sql = pool_malloc(pool, sizeof(CxBuffer)); if(!sql) { return NULL; } + if(cxBufferInit(sql, NULL, 1024, pool_allocator(pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { + pool_free(pool, sql); + return NULL; + } - ucx_buffer_puts(sql, "update "); - ucx_buffer_puts(sql, table->table); - ucx_buffer_puts(sql, " set\n"); + cxBufferPutString(sql, "update "); + cxBufferPutString(sql, table->table); + cxBufferPutString(sql, " set\n"); - size_t pg_nparams = ucx_list_size(ext->set) + 1; + size_t pg_nparams = cx_linked_list_size(ext->set_begin, offsetof(PgProppatchExtProp, next)) + 1; char** pg_params = pool_calloc(pool, pg_nparams, sizeof(char*)); if(!pg_params) { - ucx_buffer_free(sql); + cxBufferDestroy(sql); + pool_free(pool, sql); return NULL; } int i = 1; - UCX_FOREACH(elm, ext->set) { - PgProppatchExtProp *prop = elm->data; + for(PgProppatchExtProp *prop=ext->set_begin;prop;prop=prop->next) { WebdavProperty *property = prop->property; // convert the property value to WSXmlData // property->vtype == WS_VALUE_XML_NODE should always be true @@ -1155,23 +1176,22 @@ if(property_value->namespaces) { // currently only text data is supported pool_free(pool, params); - ucx_buffer_free(sql); + cxBufferDestroy(sql); return NULL; } } pg_params[i] = value_str; - ucx_bprintf(sql, " %s = $%d,\n", prop->column->name, ++i); + cx_bprintf(sql, " %s = $%d,\n", prop->column->name, ++i); } - UCX_FOREACH(elm, ext->remove) { - PgProppatchExtProp *prop = elm->data; - ucx_bprintf(sql, " %s = NULL,\n", prop->column->name); + for(PgProppatchExtProp *prop=ext->remove_begin;prop;prop=prop->next) { + cx_bprintf(sql, " %s = NULL,\n", prop->column->name); } // check if any write worked if(sql->pos == 0) { - ucx_buffer_free(sql); + cxBufferDestroy(sql); pool_free(pool, pg_params); return NULL; } @@ -1182,7 +1202,8 @@ sql->space[sql->pos-2] = ' '; } - ucx_bprintf(sql, "where resource_id = $1 ;\0"); + cxBufferPutString(sql, "where resource_id = $1 ;"); + cxBufferPut(sql, '\0'); //printf("\n\n%.*s\n\n", (int)sql->size, sql->space); //fflush(stdout); @@ -1203,7 +1224,7 @@ char **params; size_t nparam; - UcxBuffer *sql = ext_row_create_insert_query(request, ext, table, ¶ms, &nparam); + CxBuffer *sql = ext_row_create_insert_query(request, ext, table, ¶ms, &nparam); if(!sql) { return 1; } @@ -1222,7 +1243,7 @@ NULL, 0); // 0: result in text format - ucx_buffer_free(sql); + cxBufferDestroy(sql); int ret = 1; if(PQresultStatus(result) == PGRES_COMMAND_OK) { @@ -1252,7 +1273,7 @@ char **params; size_t nparam; - UcxBuffer *sql = ext_row_create_update_query(request, ext, table, ¶ms, &nparam); + CxBuffer *sql = ext_row_create_update_query(request, ext, table, ¶ms, &nparam); if(!sql) { return 1; } @@ -1271,7 +1292,7 @@ NULL, 0); // 0: result in text format - ucx_buffer_free(sql); + cxBufferDestroy(sql); int ret = 1; if(PQresultStatus(result) == PGRES_COMMAND_OK) {