<pre style='margin:0'>
Mihai Moldovan (Ionic) pushed a commit to branch master
in repository macports-base.
</pre>
<p><a href="https://github.com/macports/macports-base/commit/bd36a3b185e0a8f1db5a15634bb88b9ed280f224">https://github.com/macports/macports-base/commit/bd36a3b185e0a8f1db5a15634bb88b9ed280f224</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit bd36a3b185e0a8f1db5a15634bb88b9ed280f224
</span>Author: Mihai Moldovan <ionic@ionic.de>
AuthorDate: Tue Feb 21 06:51:49 2017 +0100
<span style='display:block; white-space:pre;color:#404040;'> pextlib1.0: implement mount point FS case-sensitivity caching.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> The implementation is done in Pextlib itself, with Tracelib using an
</span><span style='display:block; white-space:pre;color:#404040;'> opaque pointer, fetching a new data structure and clearing it via
</span><span style='display:block; white-space:pre;color:#404040;'> Pextlib's implementation on-demand.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> No sophistication: we just insert mount points as string and the value
</span><span style='display:block; white-space:pre;color:#404040;'> directly, then check mount point values via strcmp later. The caching
</span><span style='display:block; white-space:pre;color:#404040;'> data is allocated in Pextlib as necessary, with one big block allocated
</span><span style='display:block; white-space:pre;color:#404040;'> for pointers to the actual entries. Every addition yields a realloc()
</span><span style='display:block; white-space:pre;color:#404040;'> call for the pointers block.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> Since mount point counts are generally small (normally users have one or
</span><span style='display:block; white-space:pre;color:#404040;'> two different mount points that might be accessed), using more
</span><span style='display:block; white-space:pre;color:#404040;'> complicated data structures is not necessary.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> Caching is completely disabled on systems that do not have an API for
</span><span style='display:block; white-space:pre;color:#404040;'> easily getting the mount point associated with a specific file. This
</span><span style='display:block; white-space:pre;color:#404040;'> holds true for Linux, as well. While it would be possible to get the
</span><span style='display:block; white-space:pre;color:#404040;'> associated mount point via a chain of stat() - working our way up the
</span><span style='display:block; white-space:pre;color:#404040;'> directory hierarchy - and getmntent() calls, just doing the three
</span><span style='display:block; white-space:pre;color:#404040;'> non-caching lstat() calls in the fallback function is probably faster
</span><span style='display:block; white-space:pre;color:#404040;'> than getting the mount point by brute force.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> BSD-based systems, including OS X, luckily expose this information
</span><span style='display:block; white-space:pre;color:#404040;'> directly in their statfs structure.
</span>---
src/pextlib1.0/Pextlib.c | 263 ++++++++++++++++++++++++++++++++++++++++++----
src/pextlib1.0/Pextlib.h | 9 +-
src/pextlib1.0/tracelib.c | 22 +++-
3 files changed, 271 insertions(+), 23 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/Pextlib.c b/src/pextlib1.0/Pextlib.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 0a125cf..328076b 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/Pextlib.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/Pextlib.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -53,6 +53,7 @@
</span> #include <sys/stat.h>
#include <sys/wait.h>
#include <sys/param.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/mount.h>
</span> #include <ctype.h>
#include <errno.h>
#include <fcntl.h>
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -67,6 +68,7 @@
</span> #include <string.h>
#include <strings.h>
#include <unistd.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <assert.h>
</span>
#ifdef __MACH__
#include <mach-o/loader.h>
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -649,10 +651,188 @@ int SetMaxOpenFilesCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int obj
</span> return TCL_OK;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Mount point file system case-sensitivity caching infrastructure. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct _mount_cs_cache_entry {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *mountpoint;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int case_sensitive;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} mount_cs_cache_entry_t, *mount_cs_cache_entry_list_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct _mount_cs_cache {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size_t count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache_entry_t **entries;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Returns a new pre-allocated mount_cs_cache_t object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mount_cs_cache_t* new_mount_cs_cache() {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache_t *ret = malloc(sizeof(mount_cs_cache_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret->count = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret->entries = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Resets a mount cache object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void reset_mount_cs_cache(mount_cs_cache_t *cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Assume that if the count of cached entries is zero,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the entries handle is set to NULL as well. Likewise,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * if the count is non-zero, the entries pointer should
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * be non-NULL. Any other combination probably means
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * something is very, very wrong.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ assert((!cache->count && !cache->entries) || (cache->count && cache->entries));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (size_t i = 0; i < cache->count; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(cache->entries[i]->mountpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries[i]->mountpoint = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(cache->entries[i]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries[i] = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(cache->entries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Rollback mount cache object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void rollback_mount_cs_cache(Tcl_Interp *interp, mount_cs_cache_t *cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache_entry_t **rollback_data = realloc(cache->entries, (cache->count) * sizeof(mount_cs_cache_entry_list_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!rollback_data) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "pextlib: unable to roll changes to FS cache back.");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries[cache->count++] = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries = rollback_data;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Adds a new entry to a mount cache object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Returns zero on success, -1 on failure.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int add_to_mount_cs_cache(Tcl_Interp *interp, mount_cs_cache_t *cache, const char *mountpoint, int case_sensitive) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((cache) && (mountpoint)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Go the greedy road and resize as needed. Good enough probably, since
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * systems normally don't have a huge amount of mounts to start with.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache_entry_t **new_data = realloc(cache->entries, (cache->count + 1) * sizeof(mount_cs_cache_entry_list_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!new_data) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "pextlib: unable to reallocate FS cache entries list, leaving untouched.");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries = new_data;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache_entry_t *new_entry = malloc(sizeof(mount_cs_cache_entry_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!new_entry) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "pextlib: unable to create new FS cache entry, leaving untouched and rolling back.");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rollback_mount_cs_cache(interp, cache);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_entry->mountpoint = strdup(mountpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!new_entry->mountpoint) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_info(interp, "pextlib: unable to copy mountpoint value to new FS cache entry, leaving untouched and rolling back.");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rollback_mount_cs_cache(interp, cache);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(new_entry);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_entry->case_sensitive = case_sensitive;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cache->entries[cache->count++] = new_entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Looks up a cached mountpoint case-sensitivity value.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Returns 1 if the mountpoint's FS is case-sensitive,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 0 if it's case-insensitive and -1 on error or if
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * no such entry was found.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int lookup_mount_cs_cache(mount_cs_cache_t *cache, const char *mountpoint) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* No specified mount point doesn't make sense, so assert it. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ assert(mountpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cache && mountpoint) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (size_t i = 0; i < cache->count; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((cache->entries[i]) && (cache->entries[i]->mountpoint)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (0 == strcmp(cache->entries[i]->mountpoint, mountpoint)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return cache->entries[i]->case_sensitive;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Gets the corresponding mount point for a file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Returns NULL if looking up the mount point was not possible.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char* get_mntpoint(const char *path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *ret = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct statfs f = { 0 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (-1 != statfs(path, &f)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (f.f_mntonname) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = strdup(f.f_mntonname);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Systems like Solaris, IRIX, True64, AIX and others have no way to get this information easily.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Neither does Linux. We could go ahead and try to "compute" the mount point
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * using a series of stat calls and the like, but it doesn't make any sense.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Running our three lstat() calls should be less resource hungry than getting
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the mount point on this system, so disable caching there as well.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #ifdef __APPLE__
#include <sys/attr.h>
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <sys/mount.h>
</span>
typedef struct volcaps {
u_int32_t size;
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -663,38 +843,59 @@ typedef struct volcaps {
</span> * Default function for determining the FS case sensitivity on Darwin.
* Using getattrlist().
*/
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int fs_case_sensitive_darwin(const char *path) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* TODO: cache mount point CS value. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fs_case_sensitive_darwin(Tcl_Interp *interp, const char *path, mount_cs_cache_t *cache) {
</span> int ret = -1;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- struct statfs f = { 0 };
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- struct attrlist attrlist = { 0 };
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- volcaps_t volcaps = { 0 };
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span> if (!path) {
return ret;
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (-1 == statfs(path, &f)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *mntpoint = get_mntpoint(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!mntpoint) {
</span> return ret;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = lookup_mount_cs_cache(cache, mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (-1 != ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct attrlist attrlist = { 0 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ volcaps_t volcaps = { 0 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
attrlist.volattr = ATTR_VOL_CAPABILITIES;
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (-1 == getattrlist(f.f_mntonname, &attrlist, &volcaps, sizeof(volcaps), 0)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (-1 == getattrlist(mntpoint, &attrlist, &volcaps, sizeof(volcaps), 0)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span> return ret;
}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if ((attrlist.volattr & ATTR_VOL_CAPABILITIES) == 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return ret;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (-1 == ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((attrlist.volattr & ATTR_VOL_CAPABILITIES) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* In case entry is not cached, fetch value, if possible. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((volcaps.volcaps.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* capabilities bit for case-sensitivity valid */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = (volcaps.volcaps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE) != 0;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if ((volcaps.volcaps.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE)) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* capabilities bit for case-sensitivity valid */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- ret = (volcaps.volcaps.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_CASE_SENSITIVE) != 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Note that we only add a new entry if the case-sensitivity value could be determined.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * In case of errors, let the code try again - the failure might have been temporary.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ add_to_mount_cs_cache(interp, cache, mntpoint, ret);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span> return ret;
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -710,9 +911,22 @@ int fs_case_sensitive_darwin(const char *path) {
</span> * In case of errors (e.g., if the original file does not exist),
* -1 is returned.
*/
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int fs_case_sensitive_fallback(const char *path) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /* TODO: fetch mount point and cache mount point CS value. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fs_case_sensitive_fallback(Tcl_Interp *interp, const char *path, mount_cs_cache_t *cache) {
</span> int ret = -1;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *mntpoint = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mntpoint = get_mntpoint(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mntpoint) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = lookup_mount_cs_cache(cache, mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (-1 != ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span>
if (!path) {
return ret;
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -725,6 +939,8 @@ int fs_case_sensitive_fallback(const char *path) {
</span> free(lowercase_path);
free(uppercase_path);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> return ret;
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -745,6 +961,8 @@ int fs_case_sensitive_fallback(const char *path) {
</span> free(lowercase_path);
free(uppercase_path);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> return ret;
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -803,9 +1021,16 @@ int fs_case_sensitive_fallback(const char *path) {
</span> }
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (-1 != ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* No error if cache or mntpoint are NULL, the called function shall catch that. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ add_to_mount_cs_cache(interp, cache, mntpoint, ret);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> free(lowercase_path);
free(uppercase_path);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mntpoint);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> return ret;
}
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -826,11 +1051,11 @@ int FSCaseSensitiveCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int obj
</span> char *path = Tcl_GetString(objv[1]);
#ifdef __APPLE__
<span style='display:block; white-space:pre;background:#ffe0e0;'>- ret = fs_case_sensitive_darwin(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = fs_case_sensitive_darwin(interp, path, NULL);
</span> #endif /* __APPLE__ */
if (-1 == ret) {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- ret = fs_case_sensitive_fallback(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = fs_case_sensitive_fallback(interp, path, NULL);
</span> }
if (-1 == ret) {
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/Pextlib.h b/src/pextlib1.0/Pextlib.h
</span><span style='display:block; white-space:pre;color:#808080;'>index aaee1fa..2b6b1d2 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/Pextlib.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/Pextlib.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -36,8 +36,13 @@ void ui_notice(Tcl_Interp *interp, const char *format, ...) __attribute__((forma
</span> void ui_info(Tcl_Interp *interp, const char *format, ...) __attribute__((format(printf, 2, 3)));
void ui_debug(Tcl_Interp *interp, const char *format, ...) __attribute__((format(printf, 2, 3)));
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Mount point file system case-sensitivity caching infrastructure. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct _mount_cs_cache mount_cs_cache_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mount_cs_cache_t* new_mount_cs_cache();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+void reset_mount_cs_cache(mount_cs_cache_t *cache);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #ifdef __APPLE__
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int fs_case_sensitive_darwin(const char *path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fs_case_sensitive_darwin(Tcl_Interp *interp, const char *path, mount_cs_cache_t *cache);
</span> #endif /* __APPLE__ */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int fs_case_sensitive_fallback(const char *path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fs_case_sensitive_fallback(Tcl_Interp *interp, const char *path, mount_cs_cache_t *cache);
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/pextlib1.0/tracelib.c b/src/pextlib1.0/tracelib.c
</span><span style='display:block; white-space:pre;color:#808080;'>index cb9c146..1706c5f 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/pextlib1.0/tracelib.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/pextlib1.0/tracelib.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -110,6 +110,8 @@ static int selfpipe[2];
</span> static int enable_fence = 0;
static Tcl_Interp *interp;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+static mount_cs_cache_t *mount_cs_cache;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /**
* Mutex that shall be acquired to exclusively lock checking and acting upon
* the value of kq, indicating whether the event loop has started. If it has
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -616,11 +618,11 @@ static void dep_check(int sock, char *path) {
</span> }
#ifdef __APPLE__
<span style='display:block; white-space:pre;background:#ffe0e0;'>- fs_cs = fs_case_sensitive_darwin(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fs_cs = fs_case_sensitive_darwin(interp, path, mount_cs_cache);
</span> #endif /* __APPLE__ */
if (-1 == fs_cs) {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- fs_cs = fs_case_sensitive_fallback(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fs_cs = fs_case_sensitive_fallback(interp, path, mount_cs_cache);
</span> }
if (-1 == fs_cs) {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -727,6 +729,14 @@ static int TracelibRunCmd(Tcl_Interp *in) {
</span> int opensockcount = 0;
bool break_eventloop = false;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* (Re-)initialize mount point FS case-sensitivity cache. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mount_cs_cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ reset_mount_cs_cache(mount_cs_cache);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache = new_mount_cs_cache();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> pthread_mutex_lock(&evloop_mutex);
/* bring all variables into a defined state so the cleanup code can be
* called from anywhere */
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -932,6 +942,14 @@ error_locked:
</span> // wake up any waiting threads in TracelibCloseSocketCmd
pthread_cond_broadcast(&evloop_signal);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Free mount_cs_cache object. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mount_cs_cache) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ reset_mount_cs_cache(mount_cs_cache);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(mount_cs_cache);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mount_cs_cache = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> return retval;
}
</pre><pre style='margin:0'>
</pre>