dav-sync detects locally removed files

Thu, 03 Jul 2014 15:50:13 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 03 Jul 2014 15:50:13 +0200
changeset 49
c5759ac76c1b
parent 48
08d5544c92fb
child 50
9c486ea25161

dav-sync detects locally removed files

dav/db.c file | annotate | diff | comparison | revisions
dav/db.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
--- a/dav/db.c	Sun Jun 15 20:12:48 2014 +0200
+++ b/dav/db.c	Thu Jul 03 15:50:13 2014 +0200
@@ -46,19 +46,23 @@
 #define ENV_HOME getenv("HOME")
 #endif /* _WIN32 */
 
-UcxMap* load_db(char *name) {
+SyncDatabase* load_db(char *name) {
     char *dav_dir = util_concat_path(ENV_HOME, ".dav");
     char *db_file = util_concat_path(dav_dir, name);
     free(dav_dir);
     
+    SyncDatabase *db = malloc(sizeof(SyncDatabase));
     xmlTextReaderPtr reader = xmlReaderForFile(db_file, NULL, 0);
     if(!reader) {
         xmlDoc *doc =  doc = xmlNewDoc(BAD_CAST "1.0");
         xmlNode *root = xmlNewNode(NULL, BAD_CAST "directory");
         xmlDocSetRootElement(doc, root);
-        UcxMap *db = NULL;
         if(xmlSaveFormatFileEnc(db_file, doc, "UTF-8", 1) != -1) {
-            db = ucx_map_new(2048);
+            db->resources = ucx_map_new(2048);
+            db->remove = ucx_map_new(8);
+        } else {
+            free(db);
+            db = NULL;
         }
         xmlFreeDoc(doc);
         free(db_file);
@@ -66,7 +70,8 @@
     }
     free(db_file);
     
-    UcxMap *map = ucx_map_new(2048);
+    db->resources = ucx_map_new(2048);
+    db->remove = ucx_map_new(16);
     int error = 0;
     while(xmlTextReaderRead(reader)) {
         int type = xmlTextReaderNodeType(reader);
@@ -76,7 +81,15 @@
             if(xstreq(name, "resource")) {
                 LocalResource *res = process_resource(reader);
                 if(res) {
-                    ucx_map_cstr_put(map, res->path, res);
+                    ucx_map_cstr_put(db->resources, res->path, res);
+                } else {
+                    error = 1;
+                    break;
+                }
+            } else if(xstreq(name, "remove")) {
+                LocalResource *res = process_remove(reader);
+                if(res) {
+                    ucx_map_cstr_put(db->remove, res->path, res);
                 } else {
                     error = 1;
                     break;
@@ -90,7 +103,7 @@
         // TODO: free resources and map
         return NULL;
     } else {
-        return map;
+        return db;
     }
 }
 
@@ -160,7 +173,39 @@
     }
 }
 
-int store_db(UcxMap *db, char *name) {
+LocalResource* process_remove(xmlTextReaderPtr reader) {
+    LocalResource *res = calloc(1, sizeof(LocalResource));
+    
+    int path = 0;
+    while(xmlTextReaderRead(reader)) {
+        int type = xmlTextReaderNodeType(reader);
+        const xmlChar *name = xmlTextReaderConstName(reader);
+        
+        if(type == XML_READER_TYPE_ELEMENT) {
+            if(xstreq(name, "path")) {
+                path = 1;
+            }
+        } else if(type == XML_READER_TYPE_TEXT && path) {
+            const xmlChar *value = xmlTextReaderConstValue(reader);
+            res->path = strdup((char*)value);
+        } else if(XML_READER_TYPE_END_ELEMENT) {
+            if(xstreq(name, "remove")) {
+                break;
+            } else {
+                path = 0;
+            }
+        }
+    }
+    
+    if(!res->path) {
+        // TODO: free res
+        return NULL;
+    } else {
+        return res;
+    }
+}
+
+int store_db(SyncDatabase *db, char *name) {
     // open writer
     char *dav_dir = util_concat_path(ENV_HOME, ".dav");
     char *db_file = util_concat_path(dav_dir, name);
@@ -183,7 +228,7 @@
     xmlTextWriterStartElement(writer, BAD_CAST "directory");
     
     // write all resource entries
-    UcxMapIterator i = ucx_map_iterator(db);
+    UcxMapIterator i = ucx_map_iterator(db->resources);
     LocalResource *res;
     UCX_MAP_FOREACH(key, res, i) {
         // <resource>
@@ -237,6 +282,21 @@
         xmlTextWriterEndElement(writer);
     }
     
+    // write all remove entries
+    i = ucx_map_iterator(db->remove);
+    UCX_MAP_FOREACH(key, res, i) {
+        // <remove>
+        xmlTextWriterStartElement(writer, BAD_CAST "remove");
+        
+        xmlTextWriterWriteElement(
+                    writer,
+                    BAD_CAST "path",
+                    BAD_CAST res->path);
+        
+        // </remove>
+        xmlTextWriterEndElement(writer);
+    }
+    
     // end
     xmlTextWriterEndElement(writer);
     r = xmlTextWriterEndDocument(writer);
--- a/dav/db.h	Sun Jun 15 20:12:48 2014 +0200
+++ b/dav/db.h	Thu Jul 03 15:50:13 2014 +0200
@@ -39,7 +39,8 @@
 extern "C" {
 #endif
 
-typedef struct LocalResource LocalResource;    
+typedef struct LocalResource LocalResource;   
+typedef struct SyncDatabase  SyncDatabase;
 
 struct LocalResource {
     char    *name;
@@ -49,10 +50,16 @@
     off_t  size;
 };
 
-UcxMap* load_db(char *name);
-int store_db(UcxMap *db, char *name);
+struct SyncDatabase {
+    UcxMap *resources;
+    UcxMap *remove;
+};
+
+SyncDatabase* load_db(char *name);
+int store_db(SyncDatabase *db, char *name);
 
 LocalResource* process_resource(xmlTextReaderPtr reader);
+LocalResource* process_remove(xmlTextReaderPtr reader);
 
 
 #ifdef	__cplusplus
--- a/dav/sync.c	Sun Jun 15 20:12:48 2014 +0200
+++ b/dav/sync.c	Thu Jul 03 15:50:13 2014 +0200
@@ -109,7 +109,7 @@
         return -1;
     }
     
-    UcxMap *db = load_db(dir->database);
+    SyncDatabase *db = load_db(dir->database);
     if(!db) {
         fprintf(stderr, "Cannot load database file: %s\n", dir->database);
         return -1;
@@ -134,12 +134,12 @@
         // 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);
@@ -163,10 +163,28 @@
     return 0;
 }
 
-int sync_get_resource(SyncDirectory *dir, DavResource *res, UcxMap *db) {
-    LocalResource *local = ucx_map_cstr_get(db, res->path);
+int sync_get_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db) {
+    LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
+    char *local_path = util_concat_path(dir->path, res->path);
+    
     char *etag = dav_get_property(res, "D:getetag");
+    struct stat s;
     if(local) {
+        if(stat(local_path, &s)) {
+            if(errno == ENOENT) {
+                printf("removed %s\n", res->path);
+                // the file is in the database, but doesn't exists
+                // mark the file as removed to delete it on next push
+                ucx_map_cstr_remove(db->resources, local->path);
+                ucx_map_cstr_put(db->remove, local->path, local);
+                return 0;
+            } else {
+                fprintf(stderr, "stat failed: %s\n", local_path);
+                free(local_path);
+                return -1;
+            }
+        }
+        
         if(local->etag) {
             sstr_t e = sstr(etag);
             if(sstrprefix(e, S("W/"))) {
@@ -179,7 +197,6 @@
         }
     }
     
-    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;
@@ -201,22 +218,17 @@
         fclose(out);
         
         if(ret == 0) {
-            // get file informations for db update
-            struct stat s;
-            if(stat(local_path, &s)) {
-                fprintf(stderr, "stat failed: %s\n", local_path);
-                ret = -1;
-            }
-            
             if(!local) {
+                // new local resource
                 local = calloc(1, sizeof(LocalResource));
                 local->path = strdup(res->path);
-                ucx_map_cstr_put(db, local->path, local);
+                ucx_map_cstr_put(db->resources, local->path, local);
             }
             
             if(local->etag) {
                 free(local->etag);
             }
+            // set metadata from stat
             local->etag = etag;
             local->last_modified = s.st_mtim.tv_sec;
             local->size = s.st_size;
@@ -245,7 +257,7 @@
         return -1;
     }
     
-    UcxMap *db = load_db(dir->database);
+    SyncDatabase *db = load_db(dir->database);
     if(!db) {
         fprintf(stderr, "Cannot load database file: %s\n", dir->database);
         return -1;
@@ -279,7 +291,7 @@
     return 0;
 }
 
-UcxList* local_scan(SyncDirectory *dir, UcxMap *db) {
+UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) {
     UcxList *resources = NULL;
     
     char *path = strdup("/");
@@ -322,7 +334,9 @@
                 if(S_ISDIR(s.st_mode)) {
                     stack = ucx_list_prepend(stack, new_path);
                 } else {
-                    LocalResource *res = ucx_map_cstr_get(db, new_path);
+                    LocalResource *res = ucx_map_cstr_get(
+                            db->resources,
+                            new_path);
                     if(res) {
                         // the file is already in the database
                         // compare length and lastmodified date
@@ -349,7 +363,7 @@
                         res->etag = NULL;
                         res->last_modified = s.st_mtim.tv_sec;
                         res->size = s.st_size;
-                        ucx_map_cstr_put(db, res->path, res);
+                        ucx_map_cstr_put(db->resources, res->path, res);
                         resources = ucx_list_append(resources, new_path);
                     }
                 }
@@ -364,7 +378,7 @@
     return resources;
 }
 
-int sync_put_resource(SyncDirectory *dir, DavResource *res, UcxMap *db) {
+int sync_put_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db) {
     char *local_path = util_concat_path(dir->path, res->path);
     FILE *in = fopen(local_path, "r");
     if(!in) {
@@ -389,25 +403,22 @@
     }
     
     if(ret == 0) {
-        LocalResource *local_res = ucx_map_cstr_get(db, res->path);
+        LocalResource *local_res = ucx_map_cstr_get(db->resources, res->path);
         if(local_res->etag) {
             free(local_res->etag);
         }
         
         DavResource *up_res = dav_get(res->session, res->path, "D:getetag");
-        char *etag_str = dav_get_property(up_res, "D:getetag");
-        sstr_t etag;
-        etag.ptr = NULL;
-        if(etag_str) {
-            etag = sstr(etag_str);
-        }
-        if(sstrprefix(etag, S("W/"))) {
-            etag = sstrsubs(etag, 2);
+        char *etag = dav_get_property(up_res, "D:getetag");
+        if(etag) {
+            if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
+                etag = etag + 2;
+            } 
         }
         
         
-        if(etag.ptr) {
-            local_res->etag = strdup(etag.ptr);
+        if(etag) {
+            local_res->etag = strdup(etag);
         } else {
             local_res->etag = NULL;
         }
--- a/dav/sync.h	Sun Jun 15 20:12:48 2014 +0200
+++ b/dav/sync.h	Thu Jul 03 15:50:13 2014 +0200
@@ -45,11 +45,11 @@
 int cmd_push(CmdArgs *args);
 int cmd_sync(CmdArgs *args);
 
-int sync_get_resource(SyncDirectory *dir, DavResource *res, UcxMap *db);
+int sync_get_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db);
 
-UcxList* local_scan(SyncDirectory *dir, UcxMap *db);
+UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db);
 
-int sync_put_resource(SyncDirectory *dir, DavResource *res, UcxMap *db);
+int sync_put_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db);
 
 
 #ifdef	__cplusplus

mercurial