dav-sync can create and delete empty directories now

Fri, 12 Feb 2016 18:26:58 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 12 Feb 2016 18:26:58 +0100
changeset 190
a76e43d89f55
parent 189
0d04ccf6747b
child 191
0e45b04236a7

dav-sync can create and delete empty directories now

dav/db.h file | annotate | diff | comparison | revisions
dav/main.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
dav/version.h file | annotate | diff | comparison | revisions
--- a/dav/db.h	Wed Feb 10 12:32:07 2016 +0100
+++ b/dav/db.h	Fri Feb 12 18:26:58 2016 +0100
@@ -46,8 +46,9 @@
     char    *name;
     char    *path;
     char    *etag;
-    time_t last_modified;
-    off_t  size;
+    time_t  last_modified;
+    off_t   size;
+    DavBool isdirectory;
 };
 
 struct SyncDatabase {
--- a/dav/main.h	Wed Feb 10 12:32:07 2016 +0100
+++ b/dav/main.h	Fri Feb 12 18:26:58 2016 +0100
@@ -33,7 +33,7 @@
 #include "optparser.h"
 #include <libidav/webdav.h>
 
-#define DAV_VERSION "0.9.1"
+#include "version.h"
 
 #ifdef	__cplusplus
 extern "C" {
--- a/dav/sync.c	Wed Feb 10 12:32:07 2016 +0100
+++ b/dav/sync.c	Fri Feb 12 18:26:58 2016 +0100
@@ -88,6 +88,12 @@
         ret = cmd_pull(args);
     } else if(!strcmp(cmd, "push")) {
         ret = cmd_push(args);
+    } else if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version") || !strcasecmp(cmd, "--version")) {
+#ifdef DEBUG
+        fprintf(stderr, "dav-synv %s unstable\n", DAV_VERSION);
+#else
+        fprintf(stderr, "dav-sync %s\n", DAV_VERSION);
+#endif
     }
     
     // TODO: cleanup sync config (don't forget to call regfree for regex)
@@ -236,12 +242,19 @@
     // delete every remotely removed resource
     UcxMapIterator i = ucx_map_iterator(db->resources);
     LocalResource *local;
+    UcxList *rmdirs = NULL;
     UCX_MAP_FOREACH(key, local, i) {
         if (res_matches_filter(dir, local->path)) {
             continue;
         }
         // sync_remove_resource does all necessary tests
-        sync_remove_local_resource(dir, local);
+        if(sync_remove_local_resource(dir, local)) {
+            rmdirs = ucx_list_append(rmdirs, local);
+        }
+    }
+    UCX_FOREACH(elm, rmdirs) {
+        LocalResource *local_dir = elm->data;
+        sync_remove_local_directory(dir, local_dir);
     }
     ucx_map_free(db->resources);
     db->resources = svrres;
@@ -265,7 +278,7 @@
     
     char *etag = dav_get_property(res, "D:getetag");
     struct stat s;
-    if(local) {
+    if(local && !res->iscollection) {
         int exists = 1;
         if(stat(local_path, &s)) {
             // Ignore the fact, that the file is locally removed. If the
@@ -315,6 +328,16 @@
         if(util_mkdir(local_path, mode) && errno != EEXIST) {
             ret = -1;
         }
+        
+        if(ret == 0) {
+            if(!local) {
+                // new local resource
+                local = calloc(1, sizeof(LocalResource));
+                local->path = util_concat_path(res->path, "/");
+                local->last_modified = s.st_mtime;
+                ucx_map_cstr_put(db->resources, local->path, local);
+            }
+        }
     } else {
         if(!tmp_path) {
             fprintf(stderr, "Cannot create tmp path for %s\n", local_path);
@@ -381,17 +404,22 @@
     return ret;
 }
 
-void sync_remove_local_resource(SyncDirectory *dir, LocalResource *res) {
+int sync_remove_local_resource(SyncDirectory *dir, LocalResource *res) {
     char *local_path = util_concat_path(dir->path, res->path);
     struct stat s;
     if(stat(local_path, &s)) {
         free(local_path);
-        return;
+        return 0;
+    }
+    
+    if(S_ISDIR(s.st_mode)) {
+        free(local_path);
+        return 1;
     }
     
     if(s.st_mtime != res->last_modified) {
         free(local_path);
-        return;
+        return 0;
     }
     
     printf("delete: %s\n", res->path);
@@ -402,6 +430,19 @@
         fprintf(stderr, "Cannot remove file %s\n", local_path);
     }
     free(local_path);
+    
+    return 0;
+}
+
+void sync_remove_local_directory(SyncDirectory *dir, LocalResource *res) {
+    char *local_path = util_concat_path(dir->path, res->path);
+    
+    printf("delete: %s\n", res->path);
+    if(rmdir(local_path)) {
+        // TODO
+    }
+    
+    free(local_path);
 }
 
 void rename_local_file(SyncDirectory *dir, SyncDatabase *db, char *path) {
@@ -549,10 +590,18 @@
         if (!res_matches_filter(dir, local_res->path+1)) {
             // upload every changed file
             if (local_resource_is_changed(dir, db, local_res)) {
-                printf("put: %s\n", local_res->path);
                 DavResource *res = dav_resource_new(sn, local_res->path);
-                if(sync_put_resource(dir, res, local_res)) {
-                    // TODO: I don't know what to do now
+                
+                if(local_res->isdirectory) {
+                    printf("mkcol: %s\n", local_res->path);
+                    if(sync_mkdir(dir, res, local_res)) {
+                        // TODO: I don't know what to do now
+                    }
+                } else {
+                    printf("put: %s\n", local_res->path);
+                    if(sync_put_resource(dir, res, local_res)) {
+                        // TODO: I don't know what to do now
+                    }
                 }
                 dav_resource_free(res);
             }
@@ -616,6 +665,7 @@
                 int isdir;
                 LocalResource *res = local_resource_new(dir, db, new_path, &isdir);
                 if(isdir) {
+                    resources = ucx_list_append(resources, res);
                     stack = ucx_list_prepend(stack, new_path);
                 } else if(res) {
                     resources = ucx_list_append(resources, res);
@@ -706,6 +756,11 @@
         return res;
     } else {
         *isdir = 1;
+        LocalResource *res = calloc(1, sizeof(LocalResource));
+        res->path = util_concat_path(path, "/");
+        res->last_modified = s.st_mtime;
+        res->isdirectory = 1;
+        return res;
     }
     return NULL;
 }
@@ -822,31 +877,52 @@
     return ret;
 }
 
+int sync_mkdir(SyncDirectory *dir, DavResource *res, LocalResource *local) {
+    res->iscollection = 1;
+    int ret = -1;
+    for(int i=0;i<dir->max_retry;i++) {
+        if(dav_create(res)) {
+            continue;
+        }
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
 int sync_delete_remote_resource(DavSession *sn, LocalResource *local_res) {
     DavResource *res = dav_get(sn, local_res->path, "D:getetag");
     if(!res) {
         return sn->error == DAV_NOT_FOUND ? 0 : 1;
     }
     
-    char *etag = dav_get_property(res, "D:getetag");
-    if(etag) {
-        if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
-            etag = etag + 2;
-        } 
-    }
-    
     int ret = 0;
-    if(etag && !strcmp(etag, local_res->etag)) {
-        // local resource metadata == remote resource metadata
-        // resource can be deleted
+    if(res->iscollection) {
         printf("delete: %s\n", res->path);
         if(dav_delete(res)) {
-            if(sn->error != DAV_NOT_FOUND) {
-                fprintf(stderr, "Cannot delete resource %s\n", res->path);
-            }
+            ret = 1;
+            fprintf(stderr, "Cannot delete resource %s\n", res->path);
         }
     } else {
-        ret = 1;
+        char *etag = dav_get_property(res, "D:getetag");
+        if(etag) {
+            if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
+                etag = etag + 2;
+            } 
+        }
+
+        if(etag && !strcmp(etag, local_res->etag)) {
+            // local resource metadata == remote resource metadata
+            // resource can be deleted
+            printf("delete: %s\n", res->path);
+            if(dav_delete(res)) {
+                if(sn->error != DAV_NOT_FOUND) {
+                    fprintf(stderr, "Cannot delete resource %s\n", res->path);
+                }
+            }
+        } else {
+            ret = 1;
+        }
     }
     
     // cleanup
--- a/dav/sync.h	Wed Feb 10 12:32:07 2016 +0100
+++ b/dav/sync.h	Fri Feb 12 18:26:58 2016 +0100
@@ -35,6 +35,8 @@
 
 #include "sopt.h"
 
+#include "version.h"
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -48,7 +50,8 @@
 int cmd_sync(CmdArgs *args);
 
 int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db);
-void sync_remove_local_resource(SyncDirectory *dir, LocalResource *res);
+int sync_remove_local_resource(SyncDirectory *dir, LocalResource *res);
+void sync_remove_local_directory(SyncDirectory *dir, LocalResource *res);
 void rename_local_file(SyncDirectory *dir, SyncDatabase *db, char *path);
 char* create_tmp_download_path(char *path);
 void move_to_trash(SyncDirectory *dir, char *path);
@@ -60,6 +63,7 @@
 int sync_set_status(DavResource *res, char *status);
 int sync_remove_status(DavResource *res);
 int sync_put_resource(SyncDirectory *dir, DavResource *res, LocalResource *local);
+int sync_mkdir(SyncDirectory *dir, DavResource *res, LocalResource *local);
 int sync_delete_remote_resource(DavSession *sn, LocalResource *res);
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/version.h	Fri Feb 12 18:26:58 2016 +0100
@@ -0,0 +1,35 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2016 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.
+ */
+
+#ifndef VERSION_H
+#define VERSION_H
+
+#define DAV_VERSION "0.9.2"
+
+#endif /* VERSION_H */
+

mercurial