LILV_API int lilv_state_save(LilvWorld* world, LV2_URID_Map* map, LV2_URID_Unmap* unmap, const LilvState* state, const char* uri, const char* dir, const char* filename) { if (!filename || !dir || lilv_mkdir_p(dir)) { return 1; } char* abs_dir = absolute_dir(dir); char* const path = lilv_path_join(abs_dir, filename); FILE* fd = fopen(path, "w"); if (!fd) { LILV_ERRORF("Failed to open %s (%s)\n", path, strerror(errno)); free(abs_dir); free(path); return 4; } // FIXME: make parameter non-const? if (state->dir && strcmp(state->dir, abs_dir)) { free(state->dir); ((LilvState*)state)->dir = lilv_strdup(abs_dir); } // Create symlinks to files if necessary lilv_state_make_links(state, abs_dir); // Write state to Turtle file SerdNode file = serd_node_new_file_uri(USTR(path), NULL, NULL, false); SerdEnv* env = NULL; SerdWriter* writer = ttl_file_writer(fd, &file, &env); SerdNode node = uri ? serd_node_from_string(SERD_URI, USTR(uri)) : file; int ret = lilv_state_write( world, map, unmap, state, writer, (const char*)node.buf, dir); serd_node_free(&file); serd_writer_free(writer); serd_env_free(env); fclose(fd); char* const manifest = lilv_path_join(abs_dir, "manifest.ttl"); add_state_to_manifest(state->plugin_uri, manifest, uri, path); free(manifest); free(abs_dir); free(path); return ret; }
void lilv_dir_for_each(const char* path, void* data, void (*f)(const char* path, const char* name, void* data)) { #ifdef _WIN32 char* pat = lilv_path_join(path, "*"); WIN32_FIND_DATA fd; HANDLE fh = FindFirstFile(pat, &fd); if (fh != INVALID_HANDLE_VALUE) { do { f(path, fd.cFileName, data); } while (FindNextFile(fh, &fd)); } free(pat); #else DIR* dir = opendir(path); if (dir) { struct dirent entry; struct dirent* result; while (!readdir_r(dir, &entry, &result) && result) { f(path, entry.d_name, data); } closedir(dir); } #endif }
static char* absolute_dir(const char* path) { char* abs_path = lilv_path_absolute(path); char* base = lilv_path_join(abs_path, NULL); free(abs_path); return base; }
static char* abstract_path(LV2_State_Map_Path_Handle handle, const char* abs_path) { LilvState* state = (LilvState*)handle; char* path = NULL; char* real_path = lilv_realpath(abs_path); const PathMap key = { (char*)real_path, NULL }; ZixTreeIter* iter = NULL; if (abs_path[0] == '\0') { return lilv_strdup(abs_path); } else if (!zix_tree_find(state->abs2rel, &key, &iter)) { // Already mapped path in a previous call PathMap* pm = (PathMap*)zix_tree_get(iter); free(real_path); return lilv_strdup(pm->rel); } else if (lilv_path_is_child(real_path, state->dir)) { // File in state directory (loaded, or created by plugin during save path = lilv_path_relative_to(real_path, state->dir); } else if (lilv_path_is_child(real_path, state->file_dir)) { // File created by plugin earlier path = lilv_path_relative_to(real_path, state->file_dir); if (state->copy_dir) { if (!lilv_path_exists(state->copy_dir, NULL)) { lilv_mkdir_p(state->copy_dir); } char* cpath = lilv_path_join(state->copy_dir, path); char* copy = lilv_get_latest_copy(real_path, cpath); if (!copy || !lilv_file_equals(real_path, copy)) { // No recent enough copy, make a new one copy = lilv_find_free_path(cpath, lilv_path_exists, NULL); lilv_copy_file(real_path, copy); } free(real_path); free(cpath); // Refer to the latest copy in plugin state real_path = copy; } } else { // New path outside state directory const char* slash = strrchr(real_path, '/'); const char* name = slash ? (slash + 1) : real_path; // Find a free name in the (virtual) state directory path = lilv_find_free_path(name, lilv_state_has_path, state); } // Add record to path mapping PathMap* pm = (PathMap*)malloc(sizeof(PathMap)); pm->abs = real_path; pm->rel = lilv_strdup(path); zix_tree_insert(state->abs2rel, pm, NULL); zix_tree_insert(state->rel2abs, pm, NULL); return path; }
static char* make_path(LV2_State_Make_Path_Handle handle, const char* path) { LilvState* state = (LilvState*)handle; if (!lilv_path_exists(state->dir, NULL)) { lilv_mkdir_p(state->dir); } return lilv_path_join(state->dir, path); }
static void lilv_state_make_links(const LilvState* state, const char* dir) { // Create symlinks to files for (ZixTreeIter* i = zix_tree_begin(state->abs2rel); i != zix_tree_end(state->abs2rel); i = zix_tree_iter_next(i)) { const PathMap* pm = (const PathMap*)zix_tree_get(i); char* path = lilv_path_join(dir, pm->rel); if (lilv_path_is_child(pm->abs, state->copy_dir) && strcmp(state->copy_dir, dir)) { // Link directly to snapshot in the copy directory char* target = lilv_path_relative_to(pm->abs, dir); lilv_symlink(target, path); free(target); } else if (!lilv_path_is_child(pm->abs, dir)) { const char* link_dir = state->link_dir ? state->link_dir : dir; char* pat = lilv_path_join(link_dir, pm->rel); if (!strcmp(dir, link_dir)) { // Link directory is save directory, make link at exact path remove(pat); lilv_symlink(pm->abs, pat); } else { // Make a link in the link directory to external file char* lpath = lilv_find_free_path(pat, link_exists, pm->abs); if (!lilv_path_exists(lpath, NULL)) { lilv_symlink(pm->abs, lpath); } // Make a link in the save directory to the external link char* target = lilv_path_relative_to(lpath, dir); lilv_symlink(target, path); free(target); free(lpath); } free(pat); } free(path); } }
char* lilv_path_absolute(const char* path) { if (lilv_path_is_absolute(path)) { return lilv_strdup(path); } else { char* cwd = getcwd(NULL, 0); char* abs_path = lilv_path_join(cwd, path); free(cwd); return abs_path; } }
static void update_latest(const char* path, const char* name, void* data) { Latest* latest = (Latest*)data; char* entry_path = lilv_path_join(path, name); unsigned num; if (sscanf(entry_path, latest->pattern, &num) == 1) { off_t entry_size = 0; time_t entry_time = 0; lilv_size_mtime(entry_path, &entry_size, &entry_time); if (entry_size == latest->orig_size && entry_time >= latest->time) { free(latest->latest); latest->latest = entry_path; } } if (entry_path != latest->latest) { free(entry_path); } }
static char* absolute_path(LV2_State_Map_Path_Handle handle, const char* state_path) { LilvState* state = (LilvState*)handle; char* path = NULL; if (lilv_path_is_absolute(state_path)) { // Absolute path, return identical path path = lilv_strdup(state_path); } else if (state->dir) { // Relative path inside state directory path = lilv_path_join(state->dir, state_path); } else { // State has not been saved, unmap path = lilv_strdup(lilv_state_rel2abs(state, state_path)); } return path; }