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");