dav-sync detects broken uploads

Sat, 03 Oct 2015 13:33:15 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 03 Oct 2015 13:33:15 +0200
changeset 144
c2c02c9b3be4
parent 143
d8b01bed3d83
child 145
82475dc12dd4

dav-sync detects broken uploads

dav/db.c file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
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/sync.h file | annotate | diff | comparison | revisions
libidav/davqlexec.c file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
--- a/dav/db.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/db.c	Sat Oct 03 13:33:15 2015 +0200
@@ -127,7 +127,7 @@
             }
         } else if(type == XML_READER_TYPE_TEXT) {
             const xmlChar *value = xmlTextReaderConstValue(reader);
-            int b = 0;
+            //int b = 0;
             switch(field) {
                 case 0: {
                     res->path = strdup((char*)value);
--- a/dav/main.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/main.c	Sat Oct 03 13:33:15 2015 +0200
@@ -398,7 +398,6 @@
         }
         
         // parameters
-        int show_all = cmd_getoption(a, "all") ? 1 : 0;
         void (*print_func)(DavResource*, CmdArgs *);
         if(cmd_getoption(a, "list")) {
             print_func = ls_print_list_elm;
@@ -419,7 +418,7 @@
     free(path);
     //free(base);
     
-    //dav_session_destroy(sn);
+    dav_session_destroy(sn);
     
     return ret;
 }
--- a/dav/scfg.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/scfg.c	Sat Oct 03 13:33:15 2015 +0200
@@ -146,6 +146,7 @@
     dir->collection = collection ? strdup(collection) : NULL;
     dir->repository = strdup(repository);
     dir->database = strdup(database);
+    dir->max_retry = DAV_MAX_RETRY;
     if (include) {
         dir->include = include;
     } else {
--- a/dav/scfg.h	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/scfg.h	Sat Oct 03 13:33:15 2015 +0200
@@ -38,6 +38,8 @@
 extern "C" {
 #endif
 
+#define DAV_MAX_RETRY 1
+    
 typedef struct SyncDirectory {
     char *name;
     char *path;
@@ -47,6 +49,7 @@
     char *database;
     UcxList *include;
     UcxList *exclude;
+    int max_retry;
 } SyncDirectory;
 
 int load_sync_config();
--- a/dav/sopt.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/sopt.c	Sat Oct 03 13:33:15 2015 +0200
@@ -46,7 +46,7 @@
     const char *NOARG = "";
     
     char *option = NULL;
-    char optchar = 0;
+    //char optchar = 0;
     for(int i=0;i<argc;i++) {
         char *arg = argv[i];
         size_t len = strlen(arg);
--- a/dav/sync.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/sync.c	Sat Oct 03 13:33:15 2015 +0200
@@ -182,7 +182,7 @@
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
     }
     
-    DavResource *ls = dav_query(sn, "select D:getetag from / depth -1 where lastmodified > 0 with");
+    DavResource *ls = dav_query(sn, "select D:getetag,idav:status from / with depth = infinity");
     if(!ls) {
         fprintf(stderr, "Error\n");
         // TODO: free
@@ -207,6 +207,12 @@
                 continue;
             }
             
+            char *status = dav_get_property(res, "idav:status");
+            if(status && !strcmp(status, "broken")) {
+                res = res->next;
+                continue;
+            }
+            
             // download the resource
             if(sync_get_resource(a, dir, res, db)) {
                 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
@@ -665,53 +671,99 @@
 }
 
 
+int sync_set_status(DavResource *res, char *status) {
+    DavResource *resource = dav_resource_new(res->session, res->path);
+    dav_set_property(resource, "idav:status", status);
+    int ret = dav_store(resource);
+    dav_resource_free(resource);
+    return ret;
+}
+
+int sync_remove_status(DavResource *res) {
+    DavResource *resource = dav_resource_new(res->session, res->path);
+    dav_remove_property(resource, "idav:status");
+    int ret = dav_store(resource);
+    dav_resource_free(resource);
+    return ret;
+}
+
 int sync_put_resource(SyncDirectory *dir, DavResource *res, LocalResource *local) {
     char *local_path = util_concat_path(dir->path, res->path);
+    
+    struct stat s;
+    if(stat(local_path, &s)) {
+        fprintf(stderr, "cannot stat file: %s\n", local_path);
+        perror("");
+        free(local_path);
+        return -1;
+    }
+    
     FILE *in = fopen(local_path, "rb");
     if(!in) {
         fprintf(stderr, "Cannot open file %s\n", local_path);
         free(local_path);
         return -1;
     }
-    free(local_path);
     
     dav_set_content(res, in, (dav_read_func)fread);
     
     int ret = -1;
-    for(;;) {
-        if(dav_create(res)) {
-            break;
+    int created = 0;
+    for(int i=0;i<dir->max_retry;i++) {
+        if(!created && dav_create(res)) {
+            continue;
         }
+        created = 1;
         if(dav_store(res)) {
-            break;
+            continue;
         }
         ret = 0;
         break;
     }
     
+
+
     if(ret == 0) {      
-        // get new etag
+        // check contentlength and get new etag
         DavResource *up_res = dav_get(res->session, res->path, "D:getetag");
-        char *etag = dav_get_property(up_res, "D:getetag");
-        if(etag) {
-            if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
-                etag = etag + 2;
-            } 
-        }
         
-        if(local->etag) {
-            free(local->etag);
+        if(up_res) {
+            // the new content length must be equal or greater than the file size
+            if(up_res->contentlength < s.st_size) {
+                fprintf(stderr, "Incomplete Upload: %s", local_path);
+                ret = -1;
+                // try to set the resource status to 'broken'
+                sync_set_status(res, "broken");
+            } else {
+                // everything seems fine, we can update the local resource
+                char *etag = dav_get_property(up_res, "D:getetag");
+                if(etag) {
+                    if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
+                        etag = etag + 2;
+                    } 
+                }
+
+                if(local->etag) {
+                    free(local->etag);
+                }
+
+                if(etag) {
+                    local->etag = strdup(etag);
+                } else {
+                    local->etag = NULL;
+                }
+                dav_resource_free(up_res);
+                
+                sync_remove_status(res);
+            }
         }
-        
-        if(etag) {
-            local->etag = strdup(etag);
-        } else {
-            local->etag = NULL;
-        }
-        dav_resource_free(up_res);
+    } else {
+        ret = -1;
+        sync_set_status(res, "broken");
     }
     
     fclose(in);
+    free(local_path);
     
     return ret;
 }
--- a/dav/sync.h	Sat Oct 03 00:09:23 2015 +0200
+++ b/dav/sync.h	Sat Oct 03 13:33:15 2015 +0200
@@ -56,6 +56,8 @@
 LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path, int *isdir);
 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res);
 
+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_delete_remote_resource(DavSession *sn, LocalResource *res);
 
--- a/libidav/davqlexec.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/libidav/davqlexec.c	Sat Oct 03 13:33:15 2015 +0200
@@ -674,6 +674,7 @@
                     ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode);
                     break;
                 }
+                default: break;
             }
             break;
         }
@@ -709,6 +710,7 @@
                     cmd.type = DAVQL_CMD_OP_BINARY_XOR;
                     break;
                 }
+                default: break;
             }
             ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode);
             break;
@@ -793,6 +795,7 @@
                     ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode);
                     break;
                 }
+                default: break;
             }
             break;
         }
@@ -827,6 +830,7 @@
                     numcmd += add_cmd(ctx, a, bcode, expr->right, ap);
                     break;
                 }
+                default: break;
             }
             break;
         }
--- a/libidav/resource.c	Sat Oct 03 00:09:23 2015 +0200
+++ b/libidav/resource.c	Sat Oct 03 13:33:15 2015 +0200
@@ -639,7 +639,7 @@
     CURL *handle = sn->handle;
     util_set_url(res->session, dav_resource_get_href(res));
     
-    // check encryptions
+    // check encryption
     AESDecrypter *dec = NULL;
     if(DAV_DECRYPT_CONTENT(sn)) {
         char *keyname = dav_get_property_ns(res, DAV_NS, "crypto-key");

mercurial