{"thread":{"id":"3627","subject":"[PATCH 3/6] http-push: refactor remote file/directory processing","startedAt":"2006-03-11T04:18:08Z","lastAt":"2006-03-11T04:18:08Z","messageCount":1,"participants":["Nick Hengeveld"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"17448","messageId":"20060311041808.GE3997@reactrix.com","threadId":"3627","inReplyTo":null,"subject":"[PATCH 3/6] http-push: refactor remote file/directory processing","fromName":"Nick Hengeveld","fromEmail":"nickh@reactrix.com","sentAt":"2006-03-11T04:18:08Z","receivedAt":"2006-03-11T04:18:08Z","isPatch":true,"sender":{"key":"nickh@reactrix.com","avatar":null},"body":"Replace single-use functions with one that can get a list of remote\ncollections and pass file/directory information to user-defined functions\nfor processing.\n\n---\n\n http-push.c |  245 ++++++++++++++++++++++++++---------------------------------\n 1 files changed, 107 insertions(+), 138 deletions(-)\n\n05c0fc457388309cf12f3647a48071845acc2c70\ndiff --git a/http-push.c b/http-push.c\nindex 1b0b3a8..755bcb8 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -140,11 +140,23 @@ struct remote_lock\n \tstruct remote_lock *next;\n };\n \n-struct remote_dentry\n+/* Flags that control remote_ls processing */\n+#define PROCESS_FILES (1u << 0)\n+#define PROCESS_DIRS  (1u << 1)\n+#define RECURSIVE     (1u << 2)\n+\n+/* Flags that remote_ls passes to callback functions */\n+#define IS_DIR (1u << 0)\n+\n+struct remote_ls_ctx\n {\n-\tchar *base;\n-\tchar *name;\n-\tint is_dir;\n+\tchar *path;\n+\tvoid (*userFunc)(struct remote_ls_ctx *ls);\n+\tvoid *userData;\n+\tint flags;\n+\tchar *dentry_name;\n+\tint dentry_flags;\n+\tstruct remote_ls_ctx *parent;\n };\n \n static void finish_request(struct transfer_request *request);\n@@ -812,55 +824,6 @@ static void handle_new_lock_ctx(struct x\n }\n \n static void one_remote_ref(char *refname);\n-static void crawl_remote_refs(char *path);\n-\n-static void handle_crawl_ref_ctx(struct xml_ctx *ctx, int tag_closed)\n-{\n-\tstruct remote_dentry *dentry = (struct remote_dentry *)ctx->userData;\n-\n-\n-\tif (tag_closed) {\n-\t\tif (!strcmp(ctx->name, DAV_PROPFIND_RESP) && dentry->name) {\n-\t\t\tif (dentry->is_dir) {\n-\t\t\t\tif (strcmp(dentry->name, dentry->base)) {\n-\t\t\t\t\tcrawl_remote_refs(dentry->name);\n-\t\t\t\t}\n-\t\t\t} else {\n-\t\t\t\tone_remote_ref(dentry->name);\n-\t\t\t}\n-\t\t} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {\n-\t\t\tdentry->name = xmalloc(strlen(ctx->cdata) -\n-\t\t\t\t\t       remote->path_len + 1);\n-\t\t\tstrcpy(dentry->name,\n-\t\t\t       ctx->cdata + remote->path_len);\n-\t\t} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {\n-\t\t\tdentry->is_dir = 1;\n-\t\t}\n-\t} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {\n-\t\tdentry->name = NULL;\n-\t\tdentry->is_dir = 0;\n-\t}\n-}\n-\n-static void handle_remote_object_list_ctx(struct xml_ctx *ctx, int tag_closed)\n-{\n-\tchar *path;\n-\tchar *obj_hex;\n-\n-\tif (tag_closed) {\n-\t\tif (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {\n-\t\t\tpath = ctx->cdata + remote->path_len;\n-\t\t\tif (strlen(path) != 50)\n-\t\t\t\treturn;\n-\t\t\tpath += 9;\n-\t\t\tobj_hex = xmalloc(strlen(path));\n-\t\t\tstrncpy(obj_hex, path, 2);\n-\t\t\tstrcpy(obj_hex + 2, path + 3);\n-\t\t\tone_remote_object(obj_hex);\n-\t\t\tfree(obj_hex);\n-\t\t}\n-\t}\n-}\n \n static void\n xml_start_tag(void *userData, const char *name, const char **atts)\n@@ -1101,91 +1064,83 @@ static int unlock_remote(struct remote_l\n \treturn rc;\n }\n \n-static void crawl_remote_refs(char *path)\n-{\n-\tchar *url;\n-\tstruct active_request_slot *slot;\n-\tstruct slot_results results;\n-\tstruct buffer in_buffer;\n-\tstruct buffer out_buffer;\n-\tchar *in_data;\n-\tchar *out_data;\n-\tXML_Parser parser = XML_ParserCreate(NULL);\n-\tenum XML_Status result;\n-\tstruct curl_slist *dav_headers = NULL;\n-\tstruct xml_ctx ctx;\n-\tstruct remote_dentry dentry;\n-\n-\tfprintf(stderr, \"  %s\\n\", path);\n+static void remote_ls(const char *path, int flags,\n+\t\t      void (*userFunc)(struct remote_ls_ctx *ls),\n+\t\t      void *userData);\n \n-\tdentry.base = path;\n-\tdentry.name = NULL;\n-\tdentry.is_dir = 0;\n-\n-\turl = xmalloc(strlen(remote->url) + strlen(path) + 1);\n-\tsprintf(url, \"%s%s\", remote->url, path);\n+static void process_ls_object(struct remote_ls_ctx *ls)\n+{\n+\tunsigned int *parent = (unsigned int *)ls->userData;\n+\tchar *path = ls->dentry_name;\n+\tchar *obj_hex;\n \n-\tout_buffer.size = strlen(PROPFIND_ALL_REQUEST);\n-\tout_data = xmalloc(out_buffer.size + 1);\n-\tsnprintf(out_data, out_buffer.size + 1, PROPFIND_ALL_REQUEST);\n-\tout_buffer.posn = 0;\n-\tout_buffer.buffer = out_data;\n+\tif (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {\n+\t\tremote_dir_exists[*parent] = 1;\n+\t\treturn;\n+\t}\n \n-\tin_buffer.size = 4096;\n-\tin_data = xmalloc(in_buffer.size);\n-\tin_buffer.posn = 0;\n-\tin_buffer.buffer = in_data;\n+\tif (strlen(path) != 49)\n+\t\treturn;\n+\tpath += 8;\n+\tobj_hex = xmalloc(strlen(path));\n+\tstrncpy(obj_hex, path, 2);\n+\tstrcpy(obj_hex + 2, path + 3);\n+\tone_remote_object(obj_hex);\n+\tfree(obj_hex);\n+}\n \n-\tdav_headers = curl_slist_append(dav_headers, \"Depth: 1\");\n-\tdav_headers = curl_slist_append(dav_headers, \"Content-Type: text/xml\");\n+static void process_ls_ref(struct remote_ls_ctx *ls)\n+{\n+\tif (!strcmp(ls->path, ls->dentry_name) && (ls->dentry_flags & IS_DIR)) {\n+\t\tfprintf(stderr, \"  %s\\n\", ls->dentry_name);\n+\t\treturn;\n+\t}\n \n-\tslot = get_active_slot();\n-\tslot->results = &results;\n-\tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_URL, url);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);\n-\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n+\tif (!(ls->dentry_flags & IS_DIR))\n+\t\tone_remote_ref(ls->dentry_name);\n+}\n \n-\tif (start_active_slot(slot)) {\n-\t\trun_active_slot(slot);\n-\t\tif (results.curl_result == CURLE_OK) {\n-\t\t\tctx.name = xcalloc(10, 1);\n-\t\t\tctx.len = 0;\n-\t\t\tctx.cdata = NULL;\n-\t\t\tctx.userFunc = handle_crawl_ref_ctx;\n-\t\t\tctx.userData = &dentry;\n-\t\t\tXML_SetUserData(parser, &ctx);\n-\t\t\tXML_SetElementHandler(parser, xml_start_tag,\n-\t\t\t\t\t      xml_end_tag);\n-\t\t\tXML_SetCharacterDataHandler(parser, xml_cdata);\n-\t\t\tresult = XML_Parse(parser, in_buffer.buffer,\n-\t\t\t\t\t   in_buffer.posn, 1);\n-\t\t\tfree(ctx.name);\n+static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)\n+{\n+\tstruct remote_ls_ctx *ls = (struct remote_ls_ctx *)ctx->userData;\n \n-\t\t\tif (result != XML_STATUS_OK) {\n-\t\t\t\tfprintf(stderr, \"XML error: %s\\n\",\n-\t\t\t\t\tXML_ErrorString(\n-\t\t\t\t\t\tXML_GetErrorCode(parser)));\n+\tif (tag_closed) {\n+\t\tif (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {\n+\t\t\tif (ls->dentry_flags & IS_DIR) {\n+\t\t\t\tif (ls->flags & PROCESS_DIRS) {\n+\t\t\t\t\tls->userFunc(ls);\n+\t\t\t\t}\n+\t\t\t\tif (strcmp(ls->dentry_name, ls->path) &&\n+\t\t\t\t    ls->flags & RECURSIVE) {\n+\t\t\t\t\tremote_ls(ls->dentry_name,\n+\t\t\t\t\t\t  ls->flags,\n+\t\t\t\t\t\t  ls->userFunc,\n+\t\t\t\t\t\t  ls->userData);\n+\t\t\t\t}\n+\t\t\t} else if (ls->flags & PROCESS_FILES) {\n+\t\t\t\tls->userFunc(ls);\n \t\t\t}\n+\t\t} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {\n+\t\t\tls->dentry_name = xmalloc(strlen(ctx->cdata) -\n+\t\t\t\t\t\t  remote->path_len + 1);\n+\t\t\tstrcpy(ls->dentry_name, ctx->cdata + remote->path_len);\n+\t\t} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {\n+\t\t\tls->dentry_flags |= IS_DIR;\n \t\t}\n-\t} else {\n-\t\tfprintf(stderr, \"Unable to start request\\n\");\n+\t} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {\n+\t\tif (ls->dentry_name) {\n+\t\t\tfree(ls->dentry_name);\n+\t\t}\n+\t\tls->dentry_name = NULL;\n+\t\tls->dentry_flags = 0;\n \t}\n-\n-\tfree(url);\n-\tfree(out_data);\n-\tfree(in_buffer.buffer);\n-\tcurl_slist_free_all(dav_headers);\n }\n \n-static void get_remote_object_list(unsigned char parent)\n+static void remote_ls(const char *path, int flags,\n+\t\t      void (*userFunc)(struct remote_ls_ctx *ls),\n+\t\t      void *userData)\n {\n-\tchar *url;\n+\tchar *url = xmalloc(strlen(remote->url) + strlen(path) + 1);\n \tstruct active_request_slot *slot;\n \tstruct slot_results results;\n \tstruct buffer in_buffer;\n@@ -1196,13 +1151,15 @@ static void get_remote_object_list(unsig\n \tenum XML_Status result;\n \tstruct curl_slist *dav_headers = NULL;\n \tstruct xml_ctx ctx;\n-\tchar path[] = \"/objects/XX/\";\n-\tstatic const char hex[] = \"0123456789abcdef\";\n-\tunsigned int val = parent;\n+\tstruct remote_ls_ctx ls;\n+\n+\tls.flags = flags;\n+\tls.path = strdup(path);\n+\tls.dentry_name = NULL;\n+\tls.dentry_flags = 0;\n+\tls.userData = userData;\n+\tls.userFunc = userFunc;\n \n-\tpath[9] = hex[val >> 4];\n-\tpath[10] = hex[val & 0xf];\n-\turl = xmalloc(strlen(remote->url) + strlen(path) + 1);\n \tsprintf(url, \"%s%s\", remote->url, path);\n \n \tout_buffer.size = strlen(PROPFIND_ALL_REQUEST);\n@@ -1218,7 +1175,7 @@ static void get_remote_object_list(unsig\n \n \tdav_headers = curl_slist_append(dav_headers, \"Depth: 1\");\n \tdav_headers = curl_slist_append(dav_headers, \"Content-Type: text/xml\");\n-\n+\t\n \tslot = get_active_slot();\n \tslot->results = &results;\n \tcurl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);\n@@ -1234,11 +1191,11 @@ static void get_remote_object_list(unsig\n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n \t\tif (results.curl_result == CURLE_OK) {\n-\t\t\tremote_dir_exists[parent] = 1;\n \t\t\tctx.name = xcalloc(10, 1);\n \t\t\tctx.len = 0;\n \t\t\tctx.cdata = NULL;\n-\t\t\tctx.userFunc = handle_remote_object_list_ctx;\n+\t\t\tctx.userFunc = handle_remote_ls_ctx;\n+\t\t\tctx.userData = &ls;\n \t\t\tXML_SetUserData(parser, &ctx);\n \t\t\tXML_SetElementHandler(parser, xml_start_tag,\n \t\t\t\t\t      xml_end_tag);\n@@ -1252,19 +1209,31 @@ static void get_remote_object_list(unsig\n \t\t\t\t\tXML_ErrorString(\n \t\t\t\t\t\tXML_GetErrorCode(parser)));\n \t\t\t}\n-\t\t} else {\n-\t\t\tremote_dir_exists[parent] = 0;\n \t\t}\n \t} else {\n-\t\tfprintf(stderr, \"Unable to start request\\n\");\n+\t\tfprintf(stderr, \"Unable to start PROPFIND request\\n\");\n \t}\n \n+\tfree(ls.path);\n \tfree(url);\n \tfree(out_data);\n \tfree(in_buffer.buffer);\n \tcurl_slist_free_all(dav_headers);\n }\n \n+static void get_remote_object_list(unsigned char parent)\n+{\n+\tchar path[] = \"objects/XX/\";\n+\tstatic const char hex[] = \"0123456789abcdef\";\n+\tunsigned int val = parent;\n+\n+\tpath[8] = hex[val >> 4];\n+\tpath[9] = hex[val & 0xf];\n+\tremote_dir_exists[val] = 0;\n+\tremote_ls(path, (PROCESS_FILES | PROCESS_DIRS),\n+\t\t  process_ls_object, &val);\n+}\n+\n static int locking_available(void)\n {\n \tstruct active_request_slot *slot;\n@@ -1534,7 +1503,7 @@ static void get_local_heads(void)\n static void get_dav_remote_heads(void)\n {\n \tremote_tail = &remote_refs;\n-\tcrawl_remote_refs(\"refs/\");\n+\tremote_ls(\"refs/\", (PROCESS_FILES | PROCESS_DIRS | RECURSIVE), process_ls_ref, NULL);\n }\n \n static int is_zero_sha1(const unsigned char *sha1)\n-- \n1.2.4.g8e81-dirty\n"}]}