summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-08-04 15:59:29 +0200
committerDavid Robillard <d@drobilla.net>2020-08-06 15:25:57 +0200
commitdd521d78d1959d694e6e5a565a37e9693756cb00 (patch)
treeb04daac4f8bcebea861948163cac3aaeae0d6da5 /src
parent29bcb8c03925f069afa48c03ed12c400e8ea36f1 (diff)
downloadlilv-dd521d78d1959d694e6e5a565a37e9693756cb00.tar.gz
lilv-dd521d78d1959d694e6e5a565a37e9693756cb00.tar.bz2
lilv-dd521d78d1959d694e6e5a565a37e9693756cb00.zip
Separate filesystem utilities
Diffstat (limited to 'src')
-rw-r--r--src/filesystem.c405
-rw-r--r--src/filesystem.h129
-rw-r--r--src/lilv_internal.h19
-rw-r--r--src/node.c1
-rw-r--r--src/plugin.c1
-rw-r--r--src/state.c38
-rw-r--r--src/util.c384
-rw-r--r--src/world.c1
8 files changed, 568 insertions, 410 deletions
diff --git a/src/filesystem.c b/src/filesystem.c
new file mode 100644
index 0000000..dbb528f
--- /dev/null
+++ b/src/filesystem.c
@@ -0,0 +1,405 @@
+/*
+ Copyright 2007-2020 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#define _POSIX_C_SOURCE 200809L /* for fileno */
+#define _BSD_SOURCE 1 /* for realpath, symlink */
+#define _DEFAULT_SOURCE 1 /* for realpath, symlink */
+
+#ifdef __APPLE__
+# define _DARWIN_C_SOURCE 1 /* for flock */
+#endif
+
+#include "filesystem.h"
+#include "lilv_config.h"
+#include "lilv_internal.h"
+
+#ifdef _WIN32
+# include <windows.h>
+# include <direct.h>
+# include <io.h>
+# define F_OK 0
+# define mkdir(path, flags) _mkdir(path)
+#else
+# include <dirent.h>
+# include <unistd.h>
+#endif
+
+#if defined(HAVE_FLOCK) && defined(HAVE_FILENO)
+# include <sys/file.h>
+#endif
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PAGE_SIZE
+# define PAGE_SIZE 4096
+#endif
+
+static bool
+lilv_is_dir_sep(const char c)
+{
+ return c == '/' || c == LILV_DIR_SEP[0];
+}
+
+#ifdef _WIN32
+static inline bool
+is_windows_path(const char* path)
+{
+ return (isalpha(path[0]) && (path[1] == ':' || path[1] == '|') &&
+ (path[2] == '/' || path[2] == '\\'));
+}
+#endif
+
+bool
+lilv_path_is_absolute(const char* path)
+{
+ if (lilv_is_dir_sep(path[0])) {
+ return true;
+ }
+
+#ifdef _WIN32
+ if (is_windows_path(path)) {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+bool
+lilv_path_is_child(const char* path, const char* dir)
+{
+ if (path && dir) {
+ const size_t path_len = strlen(path);
+ const size_t dir_len = strlen(dir);
+ return dir && path_len >= dir_len && !strncmp(path, dir, dir_len);
+ }
+ return false;
+}
+
+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;
+ }
+}
+
+char*
+lilv_path_relative_to(const char* path, const char* base)
+{
+ const size_t path_len = strlen(path);
+ const size_t base_len = strlen(base);
+ const size_t min_len = (path_len < base_len) ? path_len : base_len;
+
+ // Find the last separator common to both paths
+ size_t last_shared_sep = 0;
+ for (size_t i = 0; i < min_len && path[i] == base[i]; ++i) {
+ if (lilv_is_dir_sep(path[i])) {
+ last_shared_sep = i;
+ }
+ }
+
+ if (last_shared_sep == 0) {
+ // No common components, return path
+ return lilv_strdup(path);
+ }
+
+ // Find the number of up references ("..") required
+ size_t up = 0;
+ for (size_t i = last_shared_sep + 1; i < base_len; ++i) {
+ if (lilv_is_dir_sep(base[i])) {
+ ++up;
+ }
+ }
+
+ // Write up references
+ const size_t suffix_len = path_len - last_shared_sep;
+ char* rel = (char*)calloc(1, suffix_len + (up * 3) + 1);
+ for (size_t i = 0; i < up; ++i) {
+ memcpy(rel + (i * 3), "../", 3);
+ }
+
+ // Write suffix
+ memcpy(rel + (up * 3), path + last_shared_sep + 1, suffix_len);
+ return rel;
+}
+
+char*
+lilv_dirname(const char* path)
+{
+ const char* s = path + strlen(path) - 1; // Last character
+ for (; s > path && lilv_is_dir_sep(*s); --s) {} // Last non-slash
+ for (; s > path && !lilv_is_dir_sep(*s); --s) {} // Last internal slash
+ for (; s > path && lilv_is_dir_sep(*s); --s) {} // Skip duplicates
+
+ if (s == path) { // Hit beginning
+ return lilv_is_dir_sep(*s) ? lilv_strdup("/") : lilv_strdup(".");
+ } else { // Pointing to the last character of the result (inclusive)
+ char* dirname = (char*)malloc(s - path + 2);
+ memcpy(dirname, path, s - path + 1);
+ dirname[s - path + 1] = '\0';
+ return dirname;
+ }
+}
+
+char*
+lilv_path_join(const char* a, const char* b)
+{
+ if (!a) {
+ return lilv_strdup(b);
+ }
+
+ const size_t a_len = strlen(a);
+ const size_t b_len = b ? strlen(b) : 0;
+ const size_t pre_len = a_len - (lilv_is_dir_sep(a[a_len - 1]) ? 1 : 0);
+ char* path = (char*)calloc(1, a_len + b_len + 2);
+ memcpy(path, a, pre_len);
+ path[pre_len] = '/';
+ if (b) {
+ memcpy(path + pre_len + 1,
+ b + (lilv_is_dir_sep(b[0]) ? 1 : 0),
+ lilv_is_dir_sep(b[0]) ? b_len - 1 : b_len);
+ }
+ return path;
+}
+
+char*
+lilv_dir_path(const char* path)
+{
+ if (!path) {
+ return NULL;
+ }
+
+ const size_t len = strlen(path);
+
+ if (lilv_is_dir_sep(path[len - 1])) {
+ return lilv_strdup(path);
+ }
+
+ char* dir_path = (char*)calloc(len + 2, 1);
+ memcpy(dir_path, path, len);
+ dir_path[len] = LILV_DIR_SEP[0];
+ return dir_path;
+}
+
+char*
+lilv_realpath(const char* path)
+{
+ if (!path) {
+ return NULL;
+ }
+
+#if defined(_WIN32)
+ char* out = (char*)malloc(MAX_PATH);
+ GetFullPathName(path, MAX_PATH, out, NULL);
+ return out;
+#else
+ char* real_path = realpath(path, NULL);
+ return real_path ? real_path : lilv_strdup(path);
+#endif
+}
+
+bool
+lilv_path_exists(const char* path)
+{
+#ifdef HAVE_LSTAT
+ struct stat st;
+ return !lstat(path, &st);
+#else
+ return !access(path, F_OK);
+#endif
+}
+
+int
+lilv_copy_file(const char* src, const char* dst)
+{
+ FILE* in = fopen(src, "r");
+ if (!in) {
+ return errno;
+ }
+
+ FILE* out = fopen(dst, "w");
+ if (!out) {
+ fclose(in);
+ return errno;
+ }
+
+ char* page = (char*)malloc(PAGE_SIZE);
+ size_t n_read = 0;
+ int st = 0;
+ while ((n_read = fread(page, 1, PAGE_SIZE, in)) > 0) {
+ if (fwrite(page, 1, n_read, out) != n_read) {
+ st = errno;
+ break;
+ }
+ }
+
+ if (!st && (ferror(in) || ferror(out))) {
+ st = EBADF;
+ }
+
+ free(page);
+ fclose(in);
+ fclose(out);
+
+ return st;
+}
+
+int
+lilv_symlink(const char* oldpath, const char* newpath)
+{
+ int ret = 0;
+ if (strcmp(oldpath, newpath)) {
+#ifdef _WIN32
+#ifdef HAVE_CREATESYMBOLICLINK
+ ret = !CreateSymbolicLink(newpath, oldpath, 0);
+#endif
+ if (ret) {
+ ret = !CreateHardLink(newpath, oldpath, 0);
+ }
+#else
+ ret = symlink(oldpath, newpath);
+#endif
+ }
+ return ret;
+}
+
+int
+lilv_flock(FILE* file, bool lock)
+{
+#if defined(HAVE_FLOCK) && defined(HAVE_FILENO)
+ return flock(fileno(file), lock ? LOCK_EX : LOCK_UN);
+#else
+ return 0;
+#endif
+}
+
+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) {
+ for (struct dirent* entry = NULL; (entry = readdir(dir));) {
+ f(path, entry->d_name, data);
+ }
+ closedir(dir);
+ }
+#endif
+}
+
+int
+lilv_mkdir_p(const char* dir_path)
+{
+ char* path = lilv_strdup(dir_path);
+ const size_t path_len = strlen(path);
+ size_t i = 1;
+
+#ifdef _WIN32
+ if (is_windows_path(dir_path)) {
+ i = 3;
+ }
+#endif
+
+ for (; i <= path_len; ++i) {
+ const char c = path[i];
+ if (c == LILV_DIR_SEP[0] || c == '/' || c == '\0') {
+ path[i] = '\0';
+ if (mkdir(path, 0755) && errno != EEXIST) {
+ free(path);
+ return errno;
+ }
+ path[i] = c;
+ }
+ }
+
+ free(path);
+ return 0;
+}
+
+static off_t
+lilv_file_size(const char* path)
+{
+ struct stat buf;
+ if (stat(path, &buf)) {
+ return 0;
+ }
+ return buf.st_size;
+}
+
+bool
+lilv_file_equals(const char* a_path, const char* b_path)
+{
+ if (!strcmp(a_path, b_path)) {
+ return true; // Paths match
+ }
+
+ bool match = false;
+ FILE* a_file = NULL;
+ FILE* b_file = NULL;
+ char* const a_real = lilv_realpath(a_path);
+ char* const b_real = lilv_realpath(b_path);
+ if (!strcmp(a_real, b_real)) {
+ match = true; // Real paths match
+ } else if (lilv_file_size(a_path) != lilv_file_size(b_path)) {
+ match = false; // Sizes differ
+ } else if (!(a_file = fopen(a_real, "rb")) ||
+ !(b_file = fopen(b_real, "rb"))) {
+ match = false; // Missing file matches nothing
+ } else {
+ // TODO: Improve performance by reading chunks
+ match = true;
+ while (!feof(a_file) && !feof(b_file)) {
+ if (fgetc(a_file) != fgetc(b_file)) {
+ match = false;
+ break;
+ }
+ }
+ }
+
+ if (a_file) {
+ fclose(a_file);
+ }
+ if (b_file) {
+ fclose(b_file);
+ }
+ free(a_real);
+ free(b_real);
+ return match;
+}
diff --git a/src/filesystem.h b/src/filesystem.h
new file mode 100644
index 0000000..de06214
--- /dev/null
+++ b/src/filesystem.h
@@ -0,0 +1,129 @@
+/*
+ Copyright 2007-2020 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <stdbool.h>
+#include <stdio.h>
+
+/// Return true iff `path` is an absolute path
+bool
+lilv_path_is_absolute(const char* path);
+
+/// Return true iff `path` is a child of `dir`
+bool
+lilv_path_is_child(const char* path, const char* dir);
+
+/**
+ Return `path` as an absolute path.
+
+ If `path` is absolute, an identical copy of it is returned. Otherwise, the
+ returned path is relative to the current working directory.
+*/
+char*
+lilv_path_absolute(const char* path);
+
+/**
+ Return `path` relative to `base` if possible.
+
+ If `path` is not within `base`, a copy is returned. Otherwise, an
+ equivalent path relative to `base` is returned (which may contain
+ up-references).
+*/
+char*
+lilv_path_relative_to(const char* path, const char* base);
+
+/**
+ Return the path to the directory that contains `path`.
+
+ Returns the root path if `path` is the root path.
+*/
+char*
+lilv_dirname(const char* path);
+
+/// Join path `a` and path `b` with a single directory separator between them
+char*
+lilv_path_join(const char* a, const char* b);
+
+/// Return `path` normalized to have a trailing directory separator
+char*
+lilv_dir_path(const char* path);
+
+/**
+ Return `path` as a canonicalized absolute path.
+
+ This expands all symbolic links, relative references, and removes extra
+ directory separators.
+*/
+char*
+lilv_realpath(const char* path);
+
+/// Return true iff `path` points to an existing file system entry
+bool
+lilv_path_exists(const char* path);
+
+/**
+ Copy the file at path `src` to path `dst`.
+
+ @return Zero on success, or a standard `errno` error code.
+*/
+int
+lilv_copy_file(const char* src, const char* dst);
+
+/**
+ Create a symlink at `newpath` that points to `oldpath`.
+
+ @return Zero on success, otherwise non-zero and `errno` is set.
+*/
+int
+lilv_symlink(const char* oldpath, const char* newpath);
+
+/**
+ Set or remove an advisory exclusive lock on `file`.
+
+ If the `lock` is true and the file is already locked, then this will not
+ succeed and non-zero will be returned.
+
+ @return Zero on success.
+*/
+int
+lilv_flock(FILE* file, bool lock);
+
+/**
+ Visit every file in the directory at `path`.
+
+ @param path A path to a directory.
+
+ @param data Opaque user data that is passed to `f`.
+
+ @param f A function called on every entry in the directory. The `path`
+ parameter is always the directory path passed to this function, the `name`
+ parameter is the name of the directory entry (not its full path).
+*/
+void
+lilv_dir_for_each(const char* path,
+ void* data,
+ void (*f)(const char* path, const char* name, void* data));
+
+/**
+ Create the directory `dir_path` and any parent directories if necessary.
+
+ @return Zero on success, or an `errno` error code.
+*/
+int
+lilv_mkdir_p(const char* dir_path);
+
+/// Return true iff the given paths point to files with identical contents
+bool
+lilv_file_equals(const char* a_path, const char* b_path);
diff --git a/src/lilv_internal.h b/src/lilv_internal.h
index 3a36837..212e41a 100644
--- a/src/lilv_internal.h
+++ b/src/lilv_internal.h
@@ -381,32 +381,13 @@ char* lilv_strjoin(const char* first, ...);
char* lilv_strdup(const char* str);
char* lilv_get_lang(void);
char* lilv_expand(const char* path);
-char* lilv_dirname(const char* path);
-char* lilv_dir_path(const char* path);
-int lilv_copy_file(const char* src, const char* dst);
-bool lilv_path_exists(const char* path, const void* ignored);
-char* lilv_path_absolute(const char* path);
-bool lilv_path_is_absolute(const char* path);
char* lilv_get_latest_copy(const char* path, const char* copy_path);
-char* lilv_path_relative_to(const char* path, const char* base);
-bool lilv_path_is_child(const char* path, const char* dir);
-int lilv_flock(FILE* file, bool lock);
-char* lilv_realpath(const char* path);
-int lilv_symlink(const char* oldpath, const char* newpath);
-int lilv_mkdir_p(const char* dir_path);
-char* lilv_path_join(const char* a, const char* b);
-bool lilv_file_equals(const char* a_path, const char* b_path);
char*
lilv_find_free_path(const char* in_path,
bool (*exists)(const char*, const void*),
const void* user_data);
-void
-lilv_dir_for_each(const char* path,
- void* data,
- void (*f)(const char* path, const char* name, void* data));
-
typedef void (*LilvVoidFunc)(void);
/** dlsym wrapper to return a function pointer (without annoying warning) */
diff --git a/src/node.c b/src/node.c
index 0ed733a..59b3353 100644
--- a/src/node.c
+++ b/src/node.c
@@ -14,6 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "filesystem.h"
#include "lilv_internal.h"
#include "lilv/lilv.h"
diff --git a/src/plugin.c b/src/plugin.c
index a6919d5..9e9eba1 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -14,7 +14,6 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "lilv_config.h"
#include "lilv_internal.h"
#include "lilv/lilv.h"
diff --git a/src/state.c b/src/state.c
index e4e381a..749316c 100644
--- a/src/state.c
+++ b/src/state.c
@@ -14,6 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "filesystem.h"
#include "lilv_internal.h"
#include "lilv/lilv.h"
@@ -228,6 +229,12 @@ retrieve_callback(LV2_State_Handle handle,
}
static bool
+path_exists(const char* path, const void* ignored)
+{
+ return lilv_path_exists(path);
+}
+
+static bool
lilv_state_has_path(const char* path, const void* state)
{
return lilv_state_rel2abs((const LilvState*)state, path) != path;
@@ -277,7 +284,7 @@ abstract_path(LV2_State_Map_Path_Handle handle,
if (!copy || !lilv_file_equals(real_path, copy)) {
// No recent enough copy, make a new one
free(copy);
- copy = lilv_find_free_path(cpath, lilv_path_exists, NULL);
+ copy = lilv_find_free_path(cpath, path_exists, NULL);
if ((st = lilv_copy_file(real_path, copy))) {
LILV_ERRORF("Error copying state file %s (%s)\n",
copy, strerror(st));
@@ -956,7 +963,7 @@ static bool
link_exists(const char* path, const void* data)
{
const char* target = (const char*)data;
- if (!lilv_path_exists(path, NULL)) {
+ if (!lilv_path_exists(path)) {
return false;
}
char* real_path = lilv_realpath(path);
@@ -968,7 +975,19 @@ link_exists(const char* path, const void* data)
static int
maybe_symlink(const char* oldpath, const char* newpath)
{
- return link_exists(newpath, oldpath) ? 0 : lilv_symlink(oldpath, newpath);
+ if (link_exists(newpath, oldpath)) {
+ return 0;
+ }
+
+ const int st = lilv_symlink(oldpath, newpath);
+ if (st) {
+ LILV_ERRORF("Failed to link %s => %s (%s)\n",
+ newpath,
+ oldpath,
+ strerror(errno));
+ }
+
+ return st;
}
static void
@@ -1125,8 +1144,13 @@ lilv_state_make_links(const LilvState* state, const char* dir)
} 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);
+ if (!lilv_path_exists(lpath)) {
+ if (lilv_symlink(pm->abs, lpath)) {
+ LILV_ERRORF("Failed to link %s => %s (%s)\n",
+ pm->abs,
+ lpath,
+ strerror(errno));
+ }
}
// Make a link in the save directory to the external link
@@ -1228,7 +1252,7 @@ static void
try_unlink(const char* state_dir, const char* path)
{
if (!strncmp(state_dir, path, strlen(state_dir))) {
- if (lilv_path_exists(path, NULL) && unlink(path)) {
+ if (lilv_path_exists(path) && unlink(path)) {
LILV_ERRORF("Failed to remove %s (%s)\n", path, strerror(errno));
}
}
@@ -1246,7 +1270,7 @@ lilv_state_delete(LilvWorld* world,
LilvNode* bundle = lilv_new_file_uri(world, NULL, state->dir);
LilvNode* manifest = lilv_world_get_manifest_uri(world, bundle);
char* manifest_path = lilv_node_get_path(manifest, NULL);
- const bool has_manifest = lilv_path_exists(manifest_path, NULL);
+ const bool has_manifest = lilv_path_exists(manifest_path);
SordModel* model = sord_new(world->world, SORD_SPO, false);
if (has_manifest) {
diff --git a/src/util.c b/src/util.c
index 6f9c2b3..987d1ee 100644
--- a/src/util.c
+++ b/src/util.c
@@ -14,35 +14,12 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define _POSIX_C_SOURCE 200809L /* for fileno */
-#define _BSD_SOURCE 1 /* for realpath, symlink */
-#define _DEFAULT_SOURCE 1 /* for realpath, symlink */
-
-#ifdef __APPLE__
-# define _DARWIN_C_SOURCE 1 /* for flock */
-#endif
-
-#include "lilv_config.h"
+#include "filesystem.h"
#include "lilv_internal.h"
#include "lilv/lilv.h"
#include "serd/serd.h"
-#ifdef _WIN32
-# include <windows.h>
-# include <direct.h>
-# include <io.h>
-# define F_OK 0
-# define mkdir(path, flags) _mkdir(path)
-#else
-# include <dirent.h>
-# include <unistd.h>
-#endif
-
-#if defined(HAVE_FLOCK) && defined(HAVE_FILENO)
-# include <sys/file.h>
-#endif
-
#include <sys/stat.h>
#include <sys/types.h>
@@ -56,10 +33,6 @@
#include <stdlib.h>
#include <string.h>
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
void
lilv_free(void* ptr)
{
@@ -240,60 +213,6 @@ lilv_expand(const char* path)
return out;
}
-static bool
-lilv_is_dir_sep(const char c)
-{
- return c == '/' || c == LILV_DIR_SEP[0];
-}
-
-char*
-lilv_dirname(const char* path)
-{
- const char* s = path + strlen(path) - 1; // Last character
- for (; s > path && lilv_is_dir_sep(*s); --s) {} // Last non-slash
- for (; s > path && !lilv_is_dir_sep(*s); --s) {} // Last internal slash
- for (; s > path && lilv_is_dir_sep(*s); --s) {} // Skip duplicates
-
- if (s == path) { // Hit beginning
- return lilv_is_dir_sep(*s) ? lilv_strdup("/") : lilv_strdup(".");
- } else { // Pointing to the last character of the result (inclusive)
- char* dirname = (char*)malloc(s - path + 2);
- memcpy(dirname, path, s - path + 1);
- dirname[s - path + 1] = '\0';
- return dirname;
- }
-}
-
-char*
-lilv_dir_path(const char* path)
-{
- if (!path) {
- return NULL;
- }
-
- const size_t len = strlen(path);
-
- if (lilv_is_dir_sep(path[len - 1])) {
- return lilv_strdup(path);
- }
-
- char* dir_path = (char*)calloc(len + 2, 1);
- memcpy(dir_path, path, len);
- dir_path[len] = LILV_DIR_SEP[0];
- return dir_path;
-}
-
-bool
-lilv_path_exists(const char* path, const void* ignored)
-{
-#ifdef HAVE_LSTAT
- struct stat st;
- return !lstat(path, &st);
-#else
- return !access(path, F_OK);
-#endif
-}
-
char*
lilv_find_free_path(const char* in_path,
bool (*exists)(const char*, const void*),
@@ -313,100 +232,6 @@ lilv_find_free_path(const char* in_path,
return NULL;
}
-int
-lilv_copy_file(const char* src, const char* dst)
-{
- FILE* in = fopen(src, "r");
- if (!in) {
- return errno;
- }
-
- FILE* out = fopen(dst, "w");
- if (!out) {
- fclose(in);
- return errno;
- }
-
- char* page = (char*)malloc(PAGE_SIZE);
- size_t n_read = 0;
- int st = 0;
- while ((n_read = fread(page, 1, PAGE_SIZE, in)) > 0) {
- if (fwrite(page, 1, n_read, out) != n_read) {
- st = errno;
- break;
- }
- }
-
- if (!st && (ferror(in) || ferror(out))) {
- st = EBADF;
- }
-
- free(page);
- fclose(in);
- fclose(out);
-
- return st;
-}
-
-#ifdef _WIN32
-static inline bool
-is_windows_path(const char* path)
-{
- return (isalpha(path[0]) && (path[1] == ':' || path[1] == '|') &&
- (path[2] == '/' || path[2] == '\\'));
-}
-#endif
-
-bool
-lilv_path_is_absolute(const char* path)
-{
- if (lilv_is_dir_sep(path[0])) {
- return true;
- }
-
-#ifdef _WIN32
- if (is_windows_path(path)) {
- return true;
- }
-#endif
-
- return false;
-}
-
-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;
- }
-}
-
-char*
-lilv_path_join(const char* a, const char* b)
-{
- if (!a) {
- return lilv_strdup(b);
- }
-
- const size_t a_len = strlen(a);
- const size_t b_len = b ? strlen(b) : 0;
- const size_t pre_len = a_len - (lilv_is_dir_sep(a[a_len - 1]) ? 1 : 0);
- char* path = (char*)calloc(1, a_len + b_len + 2);
- memcpy(path, a, pre_len);
- path[pre_len] = '/';
- if (b) {
- memcpy(path + pre_len + 1,
- b + (lilv_is_dir_sep(b[0]) ? 1 : 0),
- lilv_is_dir_sep(b[0]) ? b_len - 1 : b_len);
- }
- return path;
-}
-
typedef struct {
char* pattern;
time_t time;
@@ -456,210 +281,3 @@ lilv_get_latest_copy(const char* path, const char* copy_path)
return latest.latest;
}
-char*
-lilv_realpath(const char* path)
-{
- if (!path) {
- return NULL;
- }
-
-#if defined(_WIN32)
- char* out = (char*)malloc(MAX_PATH);
- GetFullPathName(path, MAX_PATH, out, NULL);
- return out;
-#else
- char* real_path = realpath(path, NULL);
- return real_path ? real_path : lilv_strdup(path);
-#endif
-}
-
-int
-lilv_symlink(const char* oldpath, const char* newpath)
-{
- int ret = 0;
- if (strcmp(oldpath, newpath)) {
-#ifdef _WIN32
-#ifdef HAVE_CREATESYMBOLICLINK
- ret = !CreateSymbolicLink(newpath, oldpath, 0);
-#endif
- if (ret) {
- ret = !CreateHardLink(newpath, oldpath, 0);
- }
-#else
- ret = symlink(oldpath, newpath);
-#endif
- }
- if (ret) {
- LILV_ERRORF("Failed to link %s => %s (%s)\n",
- newpath, oldpath, strerror(errno));
- }
- return ret;
-}
-
-char*
-lilv_path_relative_to(const char* path, const char* base)
-{
- const size_t path_len = strlen(path);
- const size_t base_len = strlen(base);
- const size_t min_len = (path_len < base_len) ? path_len : base_len;
-
- // Find the last separator common to both paths
- size_t last_shared_sep = 0;
- for (size_t i = 0; i < min_len && path[i] == base[i]; ++i) {
- if (lilv_is_dir_sep(path[i])) {
- last_shared_sep = i;
- }
- }
-
- if (last_shared_sep == 0) {
- // No common components, return path
- return lilv_strdup(path);
- }
-
- // Find the number of up references ("..") required
- size_t up = 0;
- for (size_t i = last_shared_sep + 1; i < base_len; ++i) {
- if (lilv_is_dir_sep(base[i])) {
- ++up;
- }
- }
-
- // Write up references
- const size_t suffix_len = path_len - last_shared_sep;
- char* rel = (char*)calloc(1, suffix_len + (up * 3) + 1);
- for (size_t i = 0; i < up; ++i) {
- memcpy(rel + (i * 3), "../", 3);
- }
-
- // Write suffix
- memcpy(rel + (up * 3), path + last_shared_sep + 1, suffix_len);
- return rel;
-}
-
-bool
-lilv_path_is_child(const char* path, const char* dir)
-{
- if (path && dir) {
- const size_t path_len = strlen(path);
- const size_t dir_len = strlen(dir);
- return dir && path_len >= dir_len && !strncmp(path, dir, dir_len);
- }
- return false;
-}
-
-int
-lilv_flock(FILE* file, bool lock)
-{
-#if defined(HAVE_FLOCK) && defined(HAVE_FILENO)
- return flock(fileno(file), lock ? LOCK_EX : LOCK_UN);
-#else
- return 0;
-#endif
-}
-
-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) {
- for (struct dirent* entry = NULL; (entry = readdir(dir));) {
- f(path, entry->d_name, data);
- }
- closedir(dir);
- }
-#endif
-}
-
-int
-lilv_mkdir_p(const char* dir_path)
-{
- char* path = lilv_strdup(dir_path);
- const size_t path_len = strlen(path);
- size_t i = 1;
-
-#ifdef _WIN32
- if (is_windows_path(dir_path)) {
- i = 3;
- }
-#endif
-
- for (; i <= path_len; ++i) {
- const char c = path[i];
- if (c == LILV_DIR_SEP[0] || c == '/' || c == '\0') {
- path[i] = '\0';
- if (mkdir(path, 0755) && errno != EEXIST) {
- free(path);
- return errno;
- }
- path[i] = c;
- }
- }
-
- free(path);
- return 0;
-}
-
-static off_t
-lilv_file_size(const char* path)
-{
- struct stat buf;
- if (stat(path, &buf)) {
- LILV_ERRORF("stat(%s) (%s)\n", path, strerror(errno));
- return 0;
- }
- return buf.st_size;
-}
-
-bool
-lilv_file_equals(const char* a_path, const char* b_path)
-{
- if (!strcmp(a_path, b_path)) {
- return true; // Paths match
- }
-
- bool match = false;
- FILE* a_file = NULL;
- FILE* b_file = NULL;
- char* const a_real = lilv_realpath(a_path);
- char* const b_real = lilv_realpath(b_path);
- if (!strcmp(a_real, b_real)) {
- match = true; // Real paths match
- } else if (lilv_file_size(a_path) != lilv_file_size(b_path)) {
- match = false; // Sizes differ
- } else if (!(a_file = fopen(a_real, "rb")) ||
- !(b_file = fopen(b_real, "rb"))) {
- match = false; // Missing file matches nothing
- } else {
- // TODO: Improve performance by reading chunks
- match = true;
- while (!feof(a_file) && !feof(b_file)) {
- if (fgetc(a_file) != fgetc(b_file)) {
- match = false;
- break;
- }
- }
- }
-
- if (a_file) {
- fclose(a_file);
- }
- if (b_file) {
- fclose(b_file);
- }
- free(a_real);
- free(b_real);
- return match;
-}
diff --git a/src/world.c b/src/world.c
index 2650490..17896ee 100644
--- a/src/world.c
+++ b/src/world.c
@@ -14,6 +14,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "filesystem.h"
#include "lilv_config.h"
#include "lilv_internal.h"