Sun, 15 Jun 2014 16:07:11 +0200
added push command for dav-sync
dav/db.c | file | annotate | diff | comparison | revisions | |
dav/scfg.c | file | annotate | diff | comparison | revisions | |
dav/sync.c | file | annotate | diff | comparison | revisions | |
dav/sync.h | file | annotate | diff | comparison | revisions | |
libidav/webdav.c | file | annotate | diff | comparison | revisions |
--- a/dav/db.c Fri Jun 13 13:52:59 2014 +0200 +++ b/dav/db.c Sun Jun 15 16:07:11 2014 +0200 @@ -34,6 +34,9 @@ #include <libidav/utils.h> +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> + #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) @@ -50,9 +53,16 @@ xmlTextReaderPtr reader = xmlReaderForFile(db_file, NULL, 0); if(!reader) { - fprintf(stderr, "Cannot open database file: %s\n", db_file); + 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); + } + xmlFreeDoc(doc); free(db_file); - return NULL; + return db; } free(db_file); @@ -107,7 +117,7 @@ int b = 0; switch(field) { case 0: { - res->name = strdup((char*)value); + res->path = strdup((char*)value); break; } case 1: { @@ -115,7 +125,17 @@ break; } case 2: { - res->last_modified = util_parse_lastmodified((char*)value); + //res->last_modified = util_parse_lastmodified((char*)value); + //res->last_modified = atoi((char*)value); + char *endptr = (char*)value; + time_t t = strtoll((char*)value, &endptr, 10); + if(endptr == (char*)value) { + fprintf( + stderr, + "lastmodified contains not a number: %s\n", value); + } else { + res->last_modified = t; + } break; } case 3: { @@ -132,7 +152,7 @@ } } - if(!res->name || !res->path || res->last_modified == 0) { + if(!res->path || res->last_modified == 0) { // TODO: free res return NULL; } else { @@ -141,6 +161,89 @@ } int store_db(UcxMap *db, char *name) { - // TODO: + // open writer + char *dav_dir = util_concat_path(ENV_HOME, ".dav"); + char *db_file = util_concat_path(dav_dir, name); + free(dav_dir); + xmlTextWriterPtr writer = xmlNewTextWriterFilename(db_file, 0); + if(!writer) { + fprintf(stderr, "Cannot write db file: %s\n", db_file); + free(db_file); + return -1; + } + free(db_file); + + // start document + int r = 0; + r = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); + if(r < 0) { + xmlFreeTextWriter(writer); + return -1; + } + xmlTextWriterStartElement(writer, BAD_CAST "directory"); + // write all resource entries + UcxMapIterator i = ucx_map_iterator(db); + LocalResource *res; + UCX_MAP_FOREACH(key, res, i) { + // <resource> + xmlTextWriterStartElement(writer, BAD_CAST "resource"); + + r = xmlTextWriterWriteElement( + writer, + BAD_CAST "path", + BAD_CAST res->path); + if(r < 0) { + fprintf(stderr, "Cannot write path: %s\n", res->path); + xmlFreeTextWriter(writer); + return -1; + } + + if(res->etag) { + r = xmlTextWriterWriteElement( + writer, + BAD_CAST "etag", + BAD_CAST res->etag); + if(r < 0) { + fprintf(stderr, "Cannot write etag: %s\n", res->etag); + xmlFreeTextWriter(writer); + return -1; + } + } + + r = xmlTextWriterWriteFormatElement( + writer, + BAD_CAST "lastmodified", + "%" PRId64, + (int64_t)res->last_modified); + if(r < 0) { + fprintf(stderr, "Cannot write lastmodified\n"); + xmlFreeTextWriter(writer); + return -1; + } + + r = xmlTextWriterWriteFormatElement( + writer, + BAD_CAST "size", + "%" PRId64, + (int64_t)res->size); + if(r < 0) { + fprintf(stderr, "Cannot write size\n"); + xmlFreeTextWriter(writer); + return -1; + } + + // </resource> + xmlTextWriterEndElement(writer); + } + + // end + xmlTextWriterEndElement(writer); + r = xmlTextWriterEndDocument(writer); + if(r < 0) { + xmlFreeTextWriter(writer); + return -1; + } + xmlFreeTextWriter(writer); + return 0; }
--- a/dav/scfg.c Fri Jun 13 13:52:59 2014 +0200 +++ b/dav/scfg.c Sun Jun 15 16:07:11 2014 +0200 @@ -141,7 +141,7 @@ fprintf(stderr, " <!-- repository name specified in config.xml -->\n"); fprintf(stderr, " <repository>server</repository>\n\n"); fprintf(stderr, " <!-- database file name -->\n"); - fprintf(stderr, " <database>documents.db</database>\n"); + fprintf(stderr, " <database>documents-db.xml</database>\n"); fprintf(stderr, " </directory>\n"); fprintf(stderr, "</configuration>\n"); }
--- a/dav/sync.c Fri Jun 13 13:52:59 2014 +0200 +++ b/dav/sync.c Sun Jun 15 16:07:11 2014 +0200 @@ -79,7 +79,7 @@ if(!strcmp(cmd, "pull")) { ret = cmd_pull(args); } else if(!strcmp(cmd, "push")) { - ret = cmd_pull(args); + ret = cmd_push(args); } else if(!strcmp(cmd, "sync")) { ret = cmd_sync(args); } @@ -152,8 +152,13 @@ } } + // TODO: cleanup + // store db - + if(store_db(db, dir->database)) { + fprintf(stderr, "Cannot store sync db\n"); + return -1; + } return 0; } @@ -186,15 +191,30 @@ printf("get %s\n", res->path); if(dav_get_content(res, out, (dav_write_func)fwrite)) { ret = -1; - } else { - if(local) { - if(local->etag) { - free(local->etag); - } - local->etag = etag; - } } 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) { + local = calloc(1, sizeof(LocalResource)); + local->path = strdup(res->path); + ucx_map_cstr_put(db, local->path, local); + } + + if(local->etag) { + free(local->etag); + } + local->etag = etag; + local->last_modified = s.st_mtim.tv_sec; + local->size = s.st_size; + } } free(local_path); @@ -202,9 +222,189 @@ } int cmd_push(CmdArgs *a) { + if(a->argc != 1) { + fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); + return -1; + } + + SyncDirectory *dir = scfg_get_dir(a->argv[0]); + if(!dir) { + fprintf(stderr, "Unknown sync dir: %s\n", a->argv[0]); + return -1; + } + + Repository *repo = get_repository(sstr(dir->repository)); + if(!repo) { + fprintf(stderr, "Unkown repository %s\n", dir->name); + return -1; + } + + UcxMap *db = load_db(dir->database); + if(!db) { + fprintf(stderr, "Cannot load database file: %s\n", dir->database); + return -1; + } + + DavSession *sn = dav_session_new_auth( + ctx, + repo->url, + repo->user, + repo->password); + dav_session_set_flags(sn, get_repository_flags(repo)); + sn->key = dav_context_get_key(ctx, repo->default_key); + + UcxList *resources = local_scan(dir, db); + UCX_FOREACH(elm, resources) { + char *path = elm->data; + printf("put: %s\n", path); + DavResource *res = dav_resource_new(sn, path); + sync_put_resource(dir, res, db); + dav_resource_free(res); + free(path); + } + ucx_list_free(resources); + + // store db + if(store_db(db, dir->database)) { + fprintf(stderr, "Cannot store sync db\n"); + return -1; + } + return 0; } +UcxList* local_scan(SyncDirectory *dir, UcxMap *db) { + UcxList *resources = NULL; + + char *path = strdup("/"); + UcxList *stack = ucx_list_prepend(NULL, path); + while(stack) { + // get a directory path from the stack and read all entries + // if an entry is a directory, put it on the stack + // otherwise compare the metadata with the db content + + char *p = stack->data; + stack = ucx_list_remove(stack, stack); + char *local_path = util_concat_path(dir->path, p); + DIR *local_dir = opendir(local_path); + + if(!local_dir) { + fprintf(stderr, "Cannot open directory %s\n", local_path); + } else { + long namemax = namemax = pathconf(path, _PC_NAME_MAX); + if(namemax == 0) { + namemax = 255; + } + struct dirent *ent = malloc(sizeof(struct dirent) + namemax + 1); + struct dirent *res = NULL; + while(!readdir_r(local_dir, ent, &res) && res) { + if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { + continue; + } + + char *new_path = util_concat_path(p, ent->d_name); + char *file_path = util_concat_path(dir->path, new_path); + struct stat s; + if(stat(file_path, &s)) { + fprintf(stderr, "Cannot stat file %s\n", file_path); + free(new_path); + free(file_path); + continue; + } + free(file_path); + + if(S_ISDIR(s.st_mode)) { + stack = ucx_list_prepend(stack, new_path); + } else { + LocalResource *res = ucx_map_cstr_get(db, new_path); + if(res) { + // the file is already in the database + // compare length and lastmodified date + + if(res->last_modified == s.st_mtim.tv_sec + && res->size == s.st_size) + { + // skip this file + free(new_path); + } else { + // add file to list + resources = ucx_list_append( + resources, + new_path); + + // update db entries + res->size = s.st_size; + res->last_modified = s.st_mtim.tv_sec; + } + } else { + // add file to list + LocalResource *res = calloc(1, sizeof(LocalResource)); + res->path = strdup(new_path); + res->etag = NULL; + res->last_modified = s.st_mtim.tv_sec; + res->size = s.st_size; + ucx_map_cstr_put(db, res->path, res); + resources = ucx_list_append(resources, new_path); + } + } + } + closedir(local_dir); + free(ent); + } + free(local_path); + free(p); + } + + return resources; +} + +int sync_put_resource(SyncDirectory *dir, DavResource *res, UcxMap *db) { + char *local_path = util_concat_path(dir->path, res->path); + FILE *in = fopen(local_path, "r"); + 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; + } + if(dav_store(res)) { + break; + } + if(dav_load(res)) { + break; + } + ret = 0; + break; + } + + if(ret == 0) { + LocalResource *local_res = ucx_map_cstr_get(db, res->path); + if(local_res->etag) { + free(local_res->etag); + } + char *etag = dav_get_property(res, "D:getetag"); + if(etag) { + local_res->etag = strdup(dav_get_property(res, "D:getetag")); + } else { + local_res->etag = NULL; + } + } + + fclose(in); + + return 0; +} + + + int cmd_sync(CmdArgs *a) { return 0; }
--- a/dav/sync.h Fri Jun 13 13:52:59 2014 +0200 +++ b/dav/sync.h Sun Jun 15 16:07:11 2014 +0200 @@ -31,6 +31,7 @@ #include <curl/curl.h> #include <libidav/webdav.h> +#include <ucx/list.h> #include "sopt.h" @@ -46,6 +47,10 @@ int sync_get_resource(SyncDirectory *dir, DavResource *res, UcxMap *db); +UcxList* local_scan(SyncDirectory *dir, UcxMap *db); + +int sync_put_resource(SyncDirectory *dir, DavResource *res, UcxMap *db); + #ifdef __cplusplus }
--- a/libidav/webdav.c Fri Jun 13 13:52:59 2014 +0200 +++ b/libidav/webdav.c Sun Jun 15 16:07:11 2014 +0200 @@ -290,7 +290,7 @@ UcxList* parse_properties_string(DavContext *context, sstr_t str) { UcxList *proplist = NULL; - size_t nprops; + size_t nprops = 0; sstr_t *props = sstrsplit(str, S(","), &nprops); for(int i=0;i<nprops;i++) { sstr_t s = props[i];