# HG changeset patch # User Olaf Wintermann # Date 1522579248 -7200 # Node ID 2e15ff88a0ab49f9256379143cea76faf0966b1f # Parent 604e7e335b3b0eb316b4003d842e052025a8cbd8 adds tag management commands to dav-sync diff -r 604e7e335b3b -r 2e15ff88a0ab dav/sopt.c --- a/dav/sopt.c Sun Feb 04 15:58:07 2018 +0100 +++ b/dav/sopt.c Sun Apr 01 12:40:48 2018 +0200 @@ -97,6 +97,10 @@ ucx_map_cstr_put(a->options, "verbose", NOARG); break; } + case 's': { + ucx_map_cstr_put(a->options, "syncdir", NOARG); + break; + } } } } else if(option) { diff -r 604e7e335b3b -r 2e15ff88a0ab dav/sync.c --- a/dav/sync.c Sun Feb 04 15:58:07 2018 +0100 +++ b/dav/sync.c Sun Apr 01 12:40:48 2018 +0200 @@ -128,6 +128,12 @@ ret = cmd_trash_info(args); } else if(!strcmp(cmd, "empty-trash")) { ret = cmd_empty_trash(args); + } else if(!strcmp(cmd, "add-tag")) { + ret = cmd_add_tag(args); + } else if(!strcmp(cmd, "remove-tag")) { + ret = cmd_remove_tag(args); + } else if(!strcmp(cmd, "update-tags")) { + ret = cmd_update_tags(args); } else if(!strcmp(cmd, "add-dir") || !strcmp(cmd, "add-directory")) { ret = cmd_add_directory(args); @@ -165,7 +171,10 @@ fprintf(stderr, " resolve-conflicts \n"); fprintf(stderr, " delete-conflicts \n"); fprintf(stderr, " trash-info \n"); - fprintf(stderr, " empty-trash \n\n"); + fprintf(stderr, " empty-trash \n"); + fprintf(stderr, " add-tag [-s ] \n"); + fprintf(stderr, " remove-tag [-s ] \n"); + fprintf(stderr, " update-tags [-s ] [tags]\n\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -c Disable conflict detection\n"); @@ -1386,6 +1395,14 @@ return 0; } + int ret = sync_store_tags_local(dir, local, path, tags); + + // TODO: free stuff + + return ret; +} + +int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, UcxList *tags) { int ret = 0; if(dir->tagconfig->store == TAG_STORE_XATTR) { UcxBuffer *data = NULL; @@ -1408,8 +1425,16 @@ if(data) { char *data_hash = dav_create_hash(data->space, data->size); - if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) { - printf("update: %s\n", local->path); + int update = 1; + if(local) { + if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) { + printf("update: %s\n", local->path); + // TODO: update hash in localres?? + } else { + update = 0; + } + } + if(update) { ret = xattr_set(path, dir->tagconfig->xattr_name, data->space, data->pos); } ucx_buffer_free(data); @@ -1422,8 +1447,6 @@ } } - // TODO: free stuff - return ret; } @@ -1458,6 +1481,10 @@ UcxList *tags = NULL; + if(!res) { + return NULL; + } + if(!dir->tagconfig) { return NULL; } @@ -2042,6 +2069,195 @@ return 0; } +#define CMD_TAG_ADD 0 +#define CMD_TAG_REMOVE 1 +#define CMD_TAG_UPDATE 2 +int cmd_add_tag(CmdArgs *args) { + if(args->argc != 2) { + fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); + return -1; + } + return cmd_tagopt(args, CMD_TAG_ADD); +} + +int cmd_remove_tag(CmdArgs *args) { + if(args->argc != 2) { + fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); + return -1; + } + return cmd_tagopt(args, CMD_TAG_REMOVE); +} + +int cmd_update_tags(CmdArgs *args) { + if(args->argc < 1 || args->argc > 2) { + fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many"); + return -1; + } + return cmd_tagopt(args, CMD_TAG_UPDATE); +} + +int cmd_tagopt(CmdArgs *args, int cmd) { + SyncFile file; + int ret = 0; + char *path = args->argv[0]; + + int err = sync_get_file(args, path, NULL, &file); + if(err) { + fprintf(stderr, "err: %d\n", err); // TODO: print nice err msg + return -1; + } + + if(!file.dir->tagconfig) { + fprintf(stderr, "Tags are not supported for this sync directory\n"); + return -1; + } + + SyncDatabase *db = load_db(file.dir->database); + if(!db) { + fprintf(stderr, "Cannot load sync directory database\n"); + return -1; + } + + LocalResource *localres = ucx_map_cstr_get(db->resources, file.path); + UcxList *tags = NULL; + DavBool store_tags = FALSE; + + if(cmd == CMD_TAG_ADD || cmd == CMD_TAG_REMOVE) { + char *tag = args->argv[1]; + char *tagcolor = NULL; // TODO: get color + + tags = sync_get_file_tags(file.dir, localres, NULL); + UcxList *x = NULL; + UCX_FOREACH(elm, tags) { + DavTag *t = elm->data; + if(!strcmp(t->name, tag)) { + x = elm; + break; + } + } + + if(cmd == CMD_TAG_ADD) { + if(!x) { + DavTag *newtag = malloc(sizeof(DavTag)); + newtag->name = tag; + newtag->color = tagcolor; + tags = ucx_list_append(tags, newtag); + store_tags = TRUE; + } + } else { + if(tags) { + tags = ucx_list_remove(tags, x); + } + store_tags = TRUE; + } + } else { + if(args->argc == 2) { + char *tags_str = args->argv[1]; + tags = parse_csv_taglist(tags_str, strlen(tags_str)); + // TODO: read from stdin if tags_str is "-" + } + } + + if(store_tags) { + if(sync_store_tags_local(file.dir, NULL, path, tags)) { + fprintf(stderr, "Cannot store tags\n"); + } + if(localres) { + localres->tags_updated = TRUE; + } + } + + // store db + if(store_db(db, file.dir->database)) { + fprintf(stderr, "Cannot store sync db\n"); + ret = -2; + } + + free(file.path); + return ret; +} + +static int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) { + char *fullpath; + if(path[0] != '/') { + size_t wdlen = 1024; + char *wd = malloc(1024); + while(!getcwd(wd, wdlen)) { + if(errno == ERANGE) { + wdlen *= 2; + wd = realloc(wd, wdlen); + } else { + free(wd); + return 0; + } + } + + fullpath = util_concat_path(wd, path); + } else { + fullpath = strdup(path); + } + + // TODO: normalize path + + if(!sstrprefix(sstr((char*)fullpath), sstr(dir->path))) { + free(fullpath); + return 0; + } + + // TODO: check filter + + f->dir = dir; + f->path = util_concat_path("/", fullpath + strlen(dir->path)); + + free(fullpath); + return 1; +} + +int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f) { + struct stat s; + if(stat(path, &s)) { + switch(errno) { + case EACCES: return 2; + case ENOENT: return 1; + default: return 3; + } + } + + char *sdir = cmd_getoption(args, "syncdir"); + + if(sdir) { + SyncDirectory *dir = scfg_get_dir(sdir); + if(!dir) { + return 6; + } + if(!isfileindir(dir, path, f)) { + return 4; + } + } else { + SyncDirectory *target = NULL; + + UcxMapIterator i = scfg_directory_iterator(); + UcxKey k; + SyncDirectory *dir; + UCX_MAP_FOREACH(key, dir, i) { + if(isfileindir(dir, path, f)) { + if(target) { + return 5; + } else { + target = dir; + } + } + } + + if(!target) { + return 4; + } + } + + return 0; +} + + int cmd_add_directory(CmdArgs *args) { if(!get_repositories()) { fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n"); diff -r 604e7e335b3b -r 2e15ff88a0ab dav/sync.h --- a/dav/sync.h Sun Feb 04 15:58:07 2018 +0100 +++ b/dav/sync.h Sun Apr 01 12:40:48 2018 +0200 @@ -51,6 +51,11 @@ #define STDIN_BUF_SIZE 2048 +typedef struct SyncFile { + SyncDirectory *dir; + char *path; +} SyncFile; + void print_usage(char *cmd); pthread_t start_sighandler(pthread_mutex_t *mutex) ; @@ -87,6 +92,7 @@ UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed); UcxList* sync_merge_tags(UcxList *tags1, UcxList *tags2); int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res); +int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, UcxList *tags); int sync_put_resource( SyncDirectory *dir, DavResource *res, @@ -103,6 +109,25 @@ int cmd_trash_info(CmdArgs *args); int cmd_empty_trash(CmdArgs *args); + +int cmd_add_tag(CmdArgs *args); +int cmd_remove_tag(CmdArgs *args); +int cmd_update_tags(CmdArgs *args); +int cmd_tagopt(CmdArgs *args, int cmd); + +/* + * gets the syncdir and resource path for a given file path + * + * returns 0 or error code: + * 1: file not found + * 2: file permission error + * 3: stat error + * 4: file is not in any syncdir + * 5: file is in multiple syncdirs + * 6: syncdir not found + */ +int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f); + int cmd_add_directory(CmdArgs *args); int cmd_list_dirs(); int cmd_check_repositories(); diff -r 604e7e335b3b -r 2e15ff88a0ab libidav/utils.c --- a/libidav/utils.c Sun Feb 04 15:58:07 2018 +0100 +++ b/libidav/utils.c Sun Apr 01 12:40:48 2018 +0200 @@ -357,11 +357,11 @@ #endif } -char* util_concat_path(char *url_base, char *p) { - sstr_t base = sstr(url_base); +char* util_concat_path(const char *url_base, const char *p) { + sstr_t base = sstr((char*)url_base); sstr_t path; if(p) { - path = sstr(p); + path = sstr((char*)p); } else { path = sstrn("", 0); } diff -r 604e7e335b3b -r 2e15ff88a0ab libidav/utils.h --- a/libidav/utils.h Sun Feb 04 15:58:07 2018 +0100 +++ b/libidav/utils.h Sun Apr 01 12:40:48 2018 +0200 @@ -68,7 +68,7 @@ char* util_url_path(char *url); char* util_url_decode(DavSession *sn, char *url); char* util_resource_name(char *url); -char* util_concat_path(char *url_base, char *path); +char* util_concat_path(const char *url_base, const char *path); char* util_get_url(DavSession *sn, char *href); void util_set_url(DavSession *sn, char *href);