using locks in dav-sync

Fri, 18 Mar 2016 15:08:30 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 18 Mar 2016 15:08:30 +0100
changeset 221
e22c29b7ee2f
parent 220
f1b3873a6525
child 222
7b73058d782e

using locks in dav-sync

Locking can be configured in sync.xml with <lock-pull>true|false<lock-pull> and <lock-push>true|false</lock-push>. By default lock-pull is false and lock-push is true.

dav/scfg.c file | annotate | diff | comparison | revisions
dav/scfg.h file | annotate | diff | comparison | revisions
dav/sopt.c file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/version.h file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
--- a/dav/scfg.c	Fri Mar 18 13:00:00 2016 +0100
+++ b/dav/scfg.c	Fri Mar 18 15:08:30 2016 +0100
@@ -129,6 +129,8 @@
     UcxList *exclude = NULL;
     int max_retry = DAV_MAX_RETRY;
     bool backuppull = false;
+    bool lockpull = false;
+    bool lockpush = true;
     
     node = node->children;
     while(node) {
@@ -162,6 +164,10 @@
                 }
             } else if(xstreq(node->name, "backup-on-pull")) {
                 backuppull = util_getboolean(value);
+            } else if(xstreq(node->name, "lock-pull")) {
+                lockpull = util_getboolean(value);
+            } else if(xstreq(node->name, "lock-push")) {
+                lockpush = util_getboolean(value);
             }
         }
         node = node->next;
@@ -192,6 +198,8 @@
     dir->database = strdup(database);
     dir->max_retry = max_retry;
     dir->backuppull = backuppull;
+    dir->lockpull = lockpull;
+    dir->lockpush = lockpush;
     if (include) {
         dir->include = include;
     } else {
--- a/dav/scfg.h	Fri Mar 18 13:00:00 2016 +0100
+++ b/dav/scfg.h	Fri Mar 18 15:08:30 2016 +0100
@@ -51,6 +51,8 @@
     UcxList *exclude;
     int max_retry;
     bool backuppull;
+    bool lockpull;
+    bool lockpush;
 } SyncDirectory;
 
 int load_sync_config();
--- a/dav/sopt.c	Fri Mar 18 13:00:00 2016 +0100
+++ b/dav/sopt.c	Fri Mar 18 15:08:30 2016 +0100
@@ -81,6 +81,14 @@
                         ucx_map_cstr_put(a->options, "conflict", NOARG);
                         break;
                     }
+                    case 'l': {
+                        ucx_map_cstr_put(a->options, "lock", NOARG);
+                        break;
+                    }
+                    case 'd': {
+                        ucx_map_cstr_put(a->options, "nolock", NOARG);
+                        break;
+                    }
                     case 'r': {
                         ucx_map_cstr_put(a->options, "read", NOARG);
                         break;
--- a/dav/sync.c	Fri Mar 18 13:00:00 2016 +0100
+++ b/dav/sync.c	Fri Mar 18 15:08:30 2016 +0100
@@ -121,8 +121,8 @@
     fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd);
     
     fprintf(stderr, "Commands:\n");
-    fprintf(stderr, "        pull [-c] <directory>\n");
-    fprintf(stderr, "        push [-c] <directory>\n");
+    fprintf(stderr, "        pull [-cld] <directory>\n");
+    fprintf(stderr, "        push [-cld] <directory>\n");
     fprintf(stderr, "        resolve-conflicts <directory>\n");
     fprintf(stderr, "        delete-conflicts <directory>\n");
     fprintf(stderr, "        trash-info <directory>\n");
@@ -130,6 +130,8 @@
     
     fprintf(stderr, "Options:\n");
     fprintf(stderr, "        -c         Disable conflict detection\n");
+    fprintf(stderr, "        -l         Lock the repository before access\n");
+    fprintf(stderr, "        -d         Don't lock the repository\n");
     //fprintf(stderr, "        -r         Read changes from stdin\n\n");
     fprintf(stderr, "        -v         verbose output (all commands)\n\n");
     
@@ -223,9 +225,30 @@
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
     }
     
+    // lock repository
+    DavBool locked = FALSE;
+    DavResource *root = dav_resource_new(sn, "/");
+    root->iscollection = TRUE;
+    if((dir->lockpush || cmd_getoption(a, "lock")) && !cmd_getoption(a, "nolock")) {
+        if(dav_lock(root)) {
+            print_resource_error(sn, "/");
+            dav_session_destroy(sn);
+            fprintf(stderr, "Abort\n");
+            return -1;
+        }
+        locked = TRUE;
+    }
+    
+    int ret = 0;
     DavResource *ls = dav_query(sn, "select D:getetag,idav:status from / with depth = infinity");
     if(!ls) {
         print_resource_error(sn, "/");
+        if(locked) {
+            if(dav_unlock(root)) {
+                print_resource_error(sn, "/");
+            }
+        }
+        
         fprintf(stderr, "Abort\n");
         
         dav_session_destroy(sn);
@@ -240,6 +263,11 @@
     if(!ls->children) {
         // TODO: free
         fprintf(stderr, "Repository is empty\n");
+        if(locked) {
+            if(dav_unlock(root)) {
+                print_resource_error(sn, "/");
+            }
+        }
         return 0; // empty repository
     }
     
@@ -305,26 +333,35 @@
     ucx_map_free(db->resources);
     db->resources = svrres;
     
+    // unlock repository
+    if(locked) {
+        if(dav_unlock(root)) {
+            print_resource_error(sn, "/");
+            ret = -1;
+        }
+    }
+    
     // store db
     if(store_db(db, dir->database)) {
         fprintf(stderr, "Cannot store sync db\n");
-        fprintf(stderr, "Abort\n");
-        return -1; // TODO: don't return here
+        ret = -1;
     }
     
     // TODO: cleanup - BUT DONT CLEANUP SYNC CONFIG (do this in main!)
     dav_session_destroy(sn);
     
     // Report
-    char *str_success = sync_success == 1 ? "file" : "files";
-    char *str_delete = sync_delete == 1 ? "file" : "files";
-    char *str_error = sync_error == 1 ? "error" : "errors";
-    printf("Result: %d %s pulled, %d %s deleted, %d %s\n",
-            sync_success, str_success,
-            sync_delete,str_delete,
-            sync_error, str_error);
+    if(ret == 0) {
+        char *str_success = sync_success == 1 ? "file" : "files";
+        char *str_delete = sync_delete == 1 ? "file" : "files";
+        char *str_error = sync_error == 1 ? "error" : "errors";
+        printf("Result: %d %s pulled, %d %s deleted, %d %s\n",
+                sync_success, str_success,
+                sync_delete,str_delete,
+                sync_error, str_error);
+    }
     
-    return 0;
+    return ret;
 }
 
 int sync_get_resource(
@@ -666,8 +703,8 @@
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
     }
     
-    DavResource *testsvr = dav_query(sn, "select - from / with depth = 0");
-    if(!testsvr) {
+    DavResource *root = dav_query(sn, "select - from / with depth = 0");
+    if(!root) {
         print_resource_error(sn, "/");
         dav_session_destroy(sn);
         fprintf(stderr, "Abort\n");
@@ -676,6 +713,18 @@
     
     int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection
     
+    // lock repository
+    DavBool locked = FALSE;
+    if((dir->lockpush || cmd_getoption(a, "lock")) && !cmd_getoption(a, "nolock")) {
+        if(dav_lock(root)) {
+            print_resource_error(sn, "/");
+            dav_session_destroy(sn);
+            fprintf(stderr, "Abort\n");
+            return -1;
+        }
+        locked = TRUE;
+    }
+    
     int sync_success = 0;
     int sync_delete = 0;
     int sync_skipped = 0;
@@ -759,26 +808,37 @@
     ucx_map_free(db->resources);
     db->resources = lclres;
     
+    // unlock repository
+    if(locked) {
+        if(dav_unlock(root)) {
+            print_resource_error(sn, "/");
+            ret = -1;
+        }
+    }
+    
     // store db
     if(store_db(db, dir->database)) {
         fprintf(stderr, "Cannot store sync db\n");
-        return -1;
+        ret = -1;
     }
     
-    // TODO: free res
+    // cleanup
+    dav_session_destroy(sn);
     
     // Report
-    char *str_success = sync_success == 1 ? "file" : "files";
-    char *str_delete = sync_delete == 1 ? "file" : "files";
-    char *str_skipped = sync_delete == 1 ? "file" : "files";
-    char *str_error = sync_error == 1 ? "error" : "errors";
-    printf("Result: %d %s pushed, %d %s deleted, %d %s skipped, %d %s\n",
-            sync_success, str_success,
-            sync_delete,str_delete,
-            sync_skipped,str_skipped,
-            sync_error, str_error);
+    if(ret == 0) {
+        char *str_success = sync_success == 1 ? "file" : "files";
+        char *str_delete = sync_delete == 1 ? "file" : "files";
+        char *str_skipped = sync_delete == 1 ? "file" : "files";
+        char *str_error = sync_error == 1 ? "error" : "errors";
+        printf("Result: %d %s pushed, %d %s deleted, %d %s skipped, %d %s\n",
+                sync_success, str_success,
+                sync_delete,str_delete,
+                sync_skipped,str_skipped,
+                sync_error, str_error);
+    }
     
-    return 0;
+    return ret;
 }
 
 UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) {
@@ -905,7 +965,6 @@
         res->isdirectory = 1;
         return res;
     }
-    return NULL;
 }
 
 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) {
--- a/dav/version.h	Fri Mar 18 13:00:00 2016 +0100
+++ b/dav/version.h	Fri Mar 18 15:08:30 2016 +0100
@@ -29,7 +29,7 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define DAV_VERSION "0.9.7 dev"
+#define DAV_VERSION "0.9.8 dev"
 
 #endif /* VERSION_H */
 
--- a/libidav/webdav.h	Fri Mar 18 13:00:00 2016 +0100
+++ b/libidav/webdav.h	Fri Mar 18 15:08:30 2016 +0100
@@ -43,12 +43,12 @@
 
 typedef int DavBool;
 #ifndef TRUE
-#define TRUE 0
+#define TRUE 1
 #endif
 #ifndef FALSE
 #define FALSE 0
 #endif
-    
+
 typedef struct DavContext    DavContext;
 typedef struct DavProxy      DavProxy;
 typedef struct DavSession    DavSession;

mercurial