dav/sync.c

changeset 611
a7c48e0dca88
parent 608
3e4c0285a868
child 613
f6072141f5ee
--- a/dav/sync.c	Fri Aug 02 21:40:05 2019 +0200
+++ b/dav/sync.c	Fri Aug 02 22:04:00 2019 +0200
@@ -136,6 +136,7 @@
     
     xmlGenericErrorFunc fnc = xmlerrorfnc;
     initGenericErrorDefaultFunc(&fnc);
+    sys_init();
     ctx = dav_context_new();
     int cfgret = load_config(ctx) || load_sync_config();
     
@@ -212,6 +213,8 @@
     curl_global_cleanup();
     xmlCleanupParser();
     
+    sys_uninit();
+    
     return ret;
 }
 
@@ -716,13 +719,16 @@
     // the first thing we need are all directories to put the files in
     UCX_FOREACH(elm, res_mkdir) {
         DavResource *res = elm->data;
+        char *res_path = resource_local_path(res);
         char *local_path = create_local_path(dir, res->path);
+        free(res_path);
         if(sys_mkdir(local_path) && errno != EEXIST) {
             fprintf(stderr,
                     "Cannot create directory %s: %s",
                     local_path, strerror(errno));
         }
         free(local_path);
+        // TODO: create localres for dir
     }
     
     // we need a map for all conflicts for fast lookups
@@ -757,7 +763,7 @@
                 continue;
             }
             
-            char *local_path = util_concat_path(dir->path, local->path);
+            char *local_path = util_concat_path(dir->path, local_resource_path(local));
             int staterr = sys_stat(local_path, &s);
             free(local_path);
             if(staterr) {
@@ -840,7 +846,9 @@
         LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
         if(local) {
             printf("update: %s\n", res->path);
+            char *res_path = resource_local_path(res);
             char *local_path = create_local_path(dir, res->path);
+            free(res_path);
             if(sync_store_metadata(dir, local_path, local, res)) {
                 fprintf(stderr, "Metadata update failed: %s\n", res->path);
                 sync_error++;
@@ -1223,7 +1231,7 @@
     renamefunc fn = copy ? copy_file : sys_rename;
     
     char *new_path = util_concat_path(dir->path, res->path);
-    char *old_path = util_concat_path(dir->path, content->path);
+    char *old_path = util_concat_path(dir->path, local_resource_path(content));
     
     printf("%s: %s -> %s\n", copy?"copy":"move", content->path, res->path);
     if(fn(old_path, new_path)) {
@@ -1287,12 +1295,20 @@
         SyncDatabase *db,
         int *counter)
 { 
-    LocalResource *local = ucx_map_cstr_get(db->resources, path);
-    char *local_path = create_local_path(dir, path);
-    
     char *link = SYNC_SYMLINK(dir) ?
             dav_get_string_property_ns(res, DAV_PROPS_NS, "link") : NULL;
     
+    LocalResource *local = ucx_map_cstr_get(db->resources, path);
+    
+    char *local_path;
+    if(link) {
+        char *res_path = resource_local_path(res);
+        local_path = create_local_path(dir, res_path);
+        free(res_path);
+    } else {
+        local_path = create_local_path(dir, path);
+    }
+    
     char *etag = dav_get_string_property(res, "D:getetag");
     SYS_STAT s;
     memset(&s, 0, sizeof(SYS_STAT));
@@ -1821,7 +1837,7 @@
                 continue;
             }
             
-            char *local_path = util_concat_path(dir->path, local->path);
+            char *local_path = util_concat_path(dir->path, local_resource_path(local));
             char *hash = util_file_hash(local_path);
             local->hash = hash;
             // check if a file with this hash already exists
@@ -2504,29 +2520,38 @@
         res->isdirectory = 1;
     }
     
-    if(S_ISLNK(s.st_mode)) {
-        off_t l_sz = s.st_size + 16;
-        size_t lnksize = l_sz > 256 ? l_sz : 256;
-        char *lnkbuf = malloc(lnksize);
+    if(SYS_ISLINK(file_path, s)) {
+        char *lnkbuf = sys_readlink(file_path, &s);
+#ifdef SYS_LINK_EXT
+        // on Windows, we interpret .lnk files as links
+        // we dont want resource names with this extension
+        // and possibly sync this to other operating systems
+        // therefore we remove the .lnk extension from the file name
+        // change res->path
+        // we only do this, if there isn't any other file with this name
+        sstr_t fpath = sstr(file_path);
+        sstr_t rpath = sstr(path);
+        // remove last 4 chars (.lnk)
+        sstr_t new_file_path = sstrdup(sstrsubsl(fpath, 0 , fpath.length-4));
+        // check if a file with this name exists
+        SYS_STAT nfp_s;
+        if(!sys_stat(new_file_path.ptr, &nfp_s)) {
+            // we can't upload the link without the file extension, because
+            // there is another file with this name
+            free(lnkbuf);
+            lnkbuf = NULL;
+        } else {
+            sstr_t new_path = sstrdup(sstrsubsl(rpath, 0, rpath.length-4));
+            res->local_path = res->path;
+            res->path = new_path.ptr; // remove .lnk  ext from resource path
+        }
+        free(new_file_path.ptr);
+#endif
         
-        ssize_t len = 0;
-        for(int i=0;i<4;i++) {
-            // we try to read the link at most 4 times
-            // only repeat if the buffer is too small
-            len = sys_readlink(file_path, lnkbuf, lnksize);
-            if(len != lnksize) {
-                break;
-            }
-            lnksize *= 2;
-            lnkbuf = realloc(lnkbuf, lnksize);
-        }
-        
-        if(len > 0) {
-            // readlink successful
-            lnkbuf[len] = 0;
-            
+        if(lnkbuf) {
+            // readlink successful           
             char *normalized = NULL;
-            if(lnkbuf[0] != '/') {
+            if(!util_path_isabsolut(lnkbuf)) {
                 char *link_parent = util_parent_path(res->path);
                 char *abs_link_parent = util_concat_path(dir->path, link_parent);
                 char *link = util_concat_path(abs_link_parent, lnkbuf);
@@ -2538,15 +2563,16 @@
                 normalized = util_path_normalize(lnkbuf);
             }
             
-            if(util_path_isrelated(dir->path, normalized)) {
+            char *dirpath = util_path_normalize(dir->path);
+            if(util_path_isrelated(dirpath, normalized)) {
                 // the link points to a file inside the syncdir
                 char *rel = util_create_relative_path(normalized, file_path);
                 res->link_target = rel;
             }
+            free(dirpath);
             free(normalized);
+            free(lnkbuf);
         }
-        
-        free(lnkbuf);
     }
     
     free(file_path);
@@ -2554,6 +2580,10 @@
     return res;
 }
 
+char* local_resource_path(LocalResource *res) {
+    return res->local_path ? res->local_path : res->path;
+}
+
 int local_resource_is_changed(
         SyncDirectory *dir,
         SyncDatabase *db,
@@ -2712,6 +2742,20 @@
     return ret;
 }
 
+char* resource_local_path(DavResource *res) {
+#ifdef SYS_LINK_EXT
+    // on Windows, add .lnk extension to links
+    if(dav_get_property_ns(res, DAV_PROPS_NS, "link")) {
+        return ucx_sprintf("%s%s", res->path, SYS_LINK_EXT).ptr;
+    } else {
+        // not a link
+        return strdup(res->path);
+    }
+#else
+    return strdup(res->path);
+#endif
+}
+
 size_t resource_get_blocksize(SyncDirectory *dir, LocalResource *local, DavResource *res, off_t filesize) {
     size_t local_blocksize = 0;
     if(local->blocksize < 0) {
@@ -3066,7 +3110,7 @@
     UcxBuffer *buf = NULL;
     if(dir->tagconfig->store == TAG_STORE_XATTR) {
         ssize_t tag_length = 0;
-        char *local_path = create_local_path(dir, res->path);
+        char *local_path = create_local_path(dir, local_resource_path(res));
         char* tag_data = xattr_get(
                 local_path,
                 dir->tagconfig->xattr_name,
@@ -3560,7 +3604,7 @@
         LocalResource *local,
         int *counter)
 {
-    char *local_path = create_local_path(dir, res->path);
+    char *local_path = create_local_path(dir, local_resource_path(local));
     
     SYS_STAT s;
     if(sys_stat(local_path, &s)) {

mercurial