diff -r 0542668d0f26 -r fbbbeed4ba8f dav/sync.c --- 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; }