# HG changeset patch # User Olaf Wintermann # Date 1404395413 -7200 # Node ID c5759ac76c1b7216706ea1ef2aa6ce5d0368eb2d # Parent 08d5544c92fb3ad2c28b12614608d21a58129334 dav-sync detects locally removed files diff -r 08d5544c92fb -r c5759ac76c1b dav/db.c --- 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) { // @@ -237,6 +282,21 @@ xmlTextWriterEndElement(writer); } + // write all remove entries + i = ucx_map_iterator(db->remove); + UCX_MAP_FOREACH(key, res, i) { + // + xmlTextWriterStartElement(writer, BAD_CAST "remove"); + + xmlTextWriterWriteElement( + writer, + BAD_CAST "path", + BAD_CAST res->path); + + // + xmlTextWriterEndElement(writer); + } + // end xmlTextWriterEndElement(writer); r = xmlTextWriterEndDocument(writer); diff -r 08d5544c92fb -r c5759ac76c1b dav/db.h --- 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 diff -r 08d5544c92fb -r c5759ac76c1b dav/sync.c --- 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; } diff -r 08d5544c92fb -r c5759ac76c1b dav/sync.h --- 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