dav/sync.c

changeset 46
0542668d0f26
child 47
fbbbeed4ba8f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/sync.c	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,211 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <libxml/xmlerror.h>
+#include <sys/types.h>
+#include <ucx/string.h>
+#include <dirent.h>
+
+#include <libidav/webdav.h>
+#include <libidav/utils.h>
+
+#include "config.h"
+#include "scfg.h"
+#include "sopt.h"
+#include "db.h"
+
+#include "sync.h"
+
+static DavContext *ctx;
+
+static void xmlerrorfnc(void * c, const char * msg, ... ) {
+    // nothing
+}
+
+int main(int argc, char **argv) {
+    if(argc < 2) {
+        fprintf(stderr, "Missing command\n");
+        print_usage(argv[0]);
+        return -1;
+    }
+    
+    char *cmd = argv[1];
+    CmdArgs *args = cmd_parse_args(argc - 2, argv + 2);
+    if(!args) {
+        print_usage(argv[0]);
+        return -1;
+    }
+    
+    xmlGenericErrorFunc fnc = xmlerrorfnc;
+    initGenericErrorDefaultFunc(&fnc);
+    ctx = dav_context_new();
+    load_config(ctx);
+    if(load_sync_config()) {
+        return EXIT_FAILURE;
+    }
+    
+    int ret = EXIT_FAILURE;
+    if(!strcmp(cmd, "pull")) {
+        ret = cmd_pull(args);
+    } else if(!strcmp(cmd, "push")) {
+        ret = cmd_pull(args);
+    } else if(!strcmp(cmd, "sync")) {
+        ret = cmd_sync(args);
+    }
+    
+    return ret;
+}
+
+void print_usage(char *cmd) {
+    
+}
+
+int cmd_pull(CmdArgs *a) {
+    if(a->argc != 1) {
+        fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
+        return -1;
+    }
+    
+    SyncDirectory *dir = scfg_get_dir(a->argv[0]);
+    if(!dir) {
+        fprintf(stderr, "Unknown sync dir: %s\n", a->argv[0]);
+        return -1;
+    }
+    
+    Repository *repo = get_repository(sstr(dir->repository));
+    if(!repo) {
+        fprintf(stderr, "Unkown repository %s\n", dir->name);
+        return -1;
+    }
+    
+    UcxMap *db = load_db(dir->database);
+    if(!db) {
+        fprintf(stderr, "Cannot load database file: %s\n", dir->database);
+        return -1;
+    }
+    
+    DavSession *sn = dav_session_new_auth(
+            ctx,
+            repo->url,
+            repo->user,
+            repo->password);
+    dav_session_set_flags(sn, get_repository_flags(repo));
+    sn->key = dav_context_get_key(ctx, repo->default_key);
+    
+    DavResource *ls = dav_query(sn, "get D:getetag from / where lastmodified > 0 with depth -1");
+    if(!ls) {
+        fprintf(stderr, "Error\n");
+        // TODO: free
+        return -1;
+    }
+    
+    if(!ls->children) {
+        // TODO: free
+        return 0; // empty repository
+    }
+    
+    UcxList *stack = ucx_list_prepend(NULL, ls->children);
+    while(stack) {
+        DavResource *res = stack->data;
+        stack = ucx_list_remove(stack, stack);
+        
+        while(res) {
+            if(sync_get_resource(dir, res, db)) {
+                fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
+            }
+            
+            if(res->children) {
+                stack = ucx_list_prepend(stack, res->children);
+            }
+            res = res->next;
+        }
+    }
+    
+    // store db
+    
+    
+    return 0;
+}
+
+int sync_get_resource(SyncDirectory *dir, DavResource *res, UcxMap *db) {
+    LocalResource *local = ucx_map_cstr_get(db, res->path);
+    char *etag = dav_get_property(res, "D:getetag");
+    if(local) {
+        if(local->etag && !strcmp(etag, local->etag)) {
+            // resource is already up-to-date on the client
+            return 0;
+        }
+    }
+    
+    char *local_path = util_concat_path(dir->path, res->path);
+    int ret = 0;
+    if(res->iscollection) {
+        mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+        printf("mkdir %s\n", local_path);
+        if(util_mkdir(local_path, mode) && errno != EEXIST) {
+            ret = -1;
+        }
+    } else {
+        FILE *out = fopen(local_path, "w");
+        if(!out) {
+            fprintf(stderr, "cannot open output file: %s\n", local_path);
+            free(local_path);
+            return -1;
+        }
+        printf("get %s\n", res->path);
+        if(dav_get_content(res, out, (dav_write_func)fwrite)) {
+            ret = -1;
+        } else {
+            if(local) {
+                if(local->etag) {
+                    free(local->etag);
+                }
+                local->etag = etag;
+            }
+        }
+        fclose(out);
+    }
+    
+    free(local_path);
+    return ret;
+}
+
+int cmd_push(CmdArgs *a) {
+    return 0;
+}
+
+int cmd_sync(CmdArgs *a) {
+    return 0;
+}
+

mercurial