<pre style='margin:0'>
Clemens Lang (neverpanic) pushed a commit to branch master
in repository macports-base.

</pre>
<p><a href="https://github.com/macports/macports-base/commit/eee415ad29ec3c9535ad02cd1d52d9f853c32b85">https://github.com/macports/macports-base/commit/eee415ad29ec3c9535ad02cd1d52d9f853c32b85</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit eee415ad29ec3c9535ad02cd1d52d9f853c32b85
</span>Author: Clemens Lang <cal@macports.org>
AuthorDate: Fri Dec 18 15:24:06 2020 +0100

<span style='display:block; white-space:pre;color:#404040;'>    darwintrace: Support arbitrary path lengths
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    darwintrace.dylib did occasionally crash in __darwintrace_is_in_sandbox
</span><span style='display:block; white-space:pre;color:#404040;'>    due to stack canary violations, because the reimplementation of realpath
</span><span style='display:block; white-space:pre;color:#404040;'>    and splitting into path components assumed that paths will not be longer
</span><span style='display:block; white-space:pre;color:#404040;'>    than MAXPATHLEN. In practice, this assumption was wrong, and many build
</span><span style='display:block; white-space:pre;color:#404040;'>    systems will invoke file system operations with paths longer than that.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Switch to dynamically allocated strings and arrays and resize the
</span><span style='display:block; white-space:pre;color:#404040;'>    buffers as necessary. This also simplifies the code significantly and
</span><span style='display:block; white-space:pre;color:#404040;'>    fixes a number of corner cases that were previously not handled
</span><span style='display:block; white-space:pre;color:#404040;'>    correctly, such as walking up past the root directory or multiple
</span><span style='display:block; white-space:pre;color:#404040;'>    slashes in a row.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    With these changes, quassel builds successfully in trace mode – without
</span><span style='display:block; white-space:pre;color:#404040;'>    them, the build abort(3)s.
</span>---
 src/darwintracelib1.0/darwintrace.c | 569 ++++++++++++++++++++++++------------
 1 file changed, 375 insertions(+), 194 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/darwintracelib1.0/darwintrace.c b/src/darwintracelib1.0/darwintrace.c
</span><span style='display:block; white-space:pre;color:#808080;'>index cbc92b3bc..71ba17e1d 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/darwintracelib1.0/darwintrace.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/darwintracelib1.0/darwintrace.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -713,66 +713,300 @@ static inline bool __darwintrace_sandbox_check(const char *path, int flags) {
</span>   return false;
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* Private struct for __darwintrace_is_in_sandbox */
</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;'>+ * Structure to represent a filesystem path component, i.e., a single level of a path.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span> typedef struct {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        char *start;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *path;
</span>   size_t len;
 } path_component_t;
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/*
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * Helper function for __darwintrace_is_in_sandbox.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Structure to represent a normalized filesystem path.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t num;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t capacity;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path_component_t *components;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} path_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define PATH_INITIAL_CAPACITY (PATH_MAX / 4 + 2)
</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;'>+ * Allocate a new filesystem path structure.
</span>  *
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * \param[in] token path to parse
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * \param[in] dst write position in normPath buffer
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * \param[in] numComponents number of parsed components
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * \param[in,out] pathComponents array of parsed components
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * \param[out] normPath output buffer
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * \return next numComponents
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-static size_t __parse_path_normalize(const char *token, char *dst, size_t numComponents, path_component_t *pathComponents, char *normPath) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   size_t idx;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   while ((idx = strcspn(token, "/")) > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           // found a token, process it
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           if (token[0] == '\0' || token[0] == '/') {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // empty entry, ignore
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           } else if (token[0] == '.' && (token[1] == '\0' || token[1] == '/')) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // reference to current directory, ignore
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           } else if (token[0] == '.' && token[1] == '.' && (token[2] == '\0' || token[2] == '/')) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // walk up one directory, but not if it's the last one, because /.. -> /
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (numComponents > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           numComponents--;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           if (numComponents > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   // move dst back to the previous entry
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   path_component_t *lastComponent = pathComponents + (numComponents - 1);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   dst = lastComponent->start + lastComponent->len + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   // we're at the top, move dst back to the beginning
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   dst = normPath + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return Pointer to the new path_t on success, NULL on error.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static path_t *path_new() {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path_t *path = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path = malloc(sizeof(path_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto out;
</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;'>+   path->num = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path->capacity = PATH_INITIAL_CAPACITY;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path->components = malloc(sizeof(path_component_t) * path->capacity);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!path->components) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           path = 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;'>+out:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return path;
</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;'>+ * Free a filesystem path structure.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path to release.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void path_free(path_t *path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (size_t idx = 0; idx < path->num; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(path->components[idx].path);
</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(path->components);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(path);
</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;'>+ * Append a component (given as string) to an existing filesystem path while
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * preserving normality.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * If the given component is empty, or ".", the path will remain unmodified. If
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the given component is "..", the last component of the path is deleted.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Otherwise, the new component is appended to the end of the path. Note that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * component must NOT contain slashes.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path to which the component should be appended.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] component The path component to append.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return true on success, false when memory allocation fails.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static bool path_append(path_t *path, const char *component) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (*component == '\0') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // ignore empty path components, i.e., consecutive slashes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else if (component[0] == '.' && component[1] == '\0') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // ignore self-referencing path components
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else if (component[0] == '.' && component[1] == '.' && component[2] == '\0') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // walk up one path component, if possible
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (path->num > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(path->components[path->num - 1].path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path->num--;
</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;'>+           if (path->num >= path->capacity) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   // need more space for components, realloc to make that space
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   size_t new_capacity = path->capacity + (PATH_INITIAL_CAPACITY / 2);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path_component_t *new_components = realloc(path->components, sizeof(path_component_t) * new_capacity);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!new_components) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           return false;
</span>                   }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // copy token to normPath buffer (and null-terminate it)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   strlcpy(dst, token, idx + 1);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   dst[idx] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // add descriptor entry for new token
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   pathComponents[numComponents].start = dst;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   pathComponents[numComponents].len   = idx;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   numComponents++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // advance destination
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   dst += idx + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path->capacity = new_capacity;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path->components = new_components;
</span>           }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if (token[idx] == '\0') {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // initialize new path_component_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           size_t len = strlen(component);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           path_component_t *new_component = &path->components[path->num];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           new_component->len = len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           new_component->path = malloc(len + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!new_component->path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           strlcpy(new_component->path, component, len + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           path->num++;
</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 true;
</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;'>+ * Take the given input path as string, tokenize it into separate path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * components, then append them to the given path, normalizing the path in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * process. Modifies the given inpath string.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path to which the new components should be appended.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] inpath The string input path which will be tokenized and normalized.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return true on success, false on memory allocation failure.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static bool path_tokenize(path_t *path, char *inpath) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *pos = inpath;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   const char *token;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   while ((token = strsep(&pos, "/")) != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!path_append(path, token)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return false;
</span>           }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                token += idx + 1;
</span>   }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        return numComponents;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return true;
</span> }
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/**
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The the given symbolic link as string, tokenize it into separate path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * components and normalize it in the context of the given path. If the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * symbolic link is absolute, this will replace the entire path, otherwise
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * normalize the symlink relative to the current path. Modifies the given link.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path relative to which the symlink should be interpreted.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] link The symbolic link contents obtained from readlink(2).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return true on success, false on memory allocation failure.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static bool path_tokenize_symlink(path_t *path, char *link) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (*link == '/') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // symlink is absolute, start fresh
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           for (size_t idx = 0; idx < path->num; idx++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(path->components[idx].path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           path->num = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return path_tokenize(path, link + 1);
</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;'>+   // symlink is relative, remove last component
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (path->num > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(path->components[path->num - 1].path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           path->num--;
</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 path_tokenize(path, link);
</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;'>+ * Strip a resource fork from the end of the path, if present.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path which should be checked for resource forks
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void path_strip_resource_fork(path_t *path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (path->num >= 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (   strcmp(path->components[path->num - 2].path, "..namedfork") == 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   && strcmp(path->components[path->num - 1].path, "rsrc") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(path->components[path->num - 2].path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(path->components[path->num - 1].path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path->num -= 2;
</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 the length of the given path when represented as a native filesystem
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * path with "/" separators, excluding the terminating \0 byte.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path whose length should be determined.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return The length of the path.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static size_t path_len(const path_t *path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // One slash for each component
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t len = path->num;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Plus the length for each component
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (size_t idx = 0; idx < path->num; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           len += path->components[idx].len;
</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 len;
</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;'>+ * Convert the given path into a string. The returned pointer is allocated and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * must be released with free(3).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path to convert to a string.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return An allocated string representation of the path on success, NULL on error.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char *path_str(const path_t *path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t len = path_len(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *out = malloc(len + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!out) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return 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;'>+   out[0] = '/';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   out[1] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *pos = out;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (size_t idx = 0; idx < path->num; idx++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           *pos = '/';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           pos++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           path_component_t *component = &path->components[idx];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           strlcpy(pos, component->path, component->len + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           pos += component->len;
</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 out;
</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;'>+ * Check whether the given path is a volfs path (i.e., /.vol/$fsnum/$inode),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * and return a non-volfs path if possible.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * If the return value is not the argument, the argument was correctly freed.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Always use this function as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   path = path_resolve_volfs(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * for this reason.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @param[in] path The path to check for volfs paths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @return The orginal path if no modification was required or expansion
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *         failed. A fresh path if the path was a volfs path and was expanded.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static path_t *path_resolve_volfs(path_t *path) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef ATTR_CMN_FULLPATH
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (path->num >= 3 && strcmp(path->components[0].path, ".vol") == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct attrlist attrlist;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.reserved = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.commonattr = ATTR_CMN_FULLPATH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.volattr = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.dirattr = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.fileattr = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrlist.forkattr = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char attrbuf[sizeof(uint32_t) + sizeof(attrreference_t) + (PATH_MAX + 1)];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*           attrlength         attrref_t for the name     UTF-8 name up to PATH_MAX chars */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char *path_native = path_str(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!path_native) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto out;
</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;'>+           if (-1 == (getattrlist(path_native, &attrlist, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("darwintrace: getattrlist");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   // ignore and just return the /.vol/ path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path_t *newpath = path_new();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!newpath) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto out;
</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;'>+                   attrreference_t *nameAttrRef = (attrreference_t *) (attrbuf + sizeof(uint32_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!path_tokenize(newpath, ((char *) nameAttrRef) + nameAttrRef->attr_dataoffset)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           path_free(newpath);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto out;
</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;'>+                   path_free(path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path = newpath;
</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;'>+out:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(path_native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* defined(ATTR_CMN_FULLPATH) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return path;
</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> /**
  * Check a path against the current sandbox
  *
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -795,27 +1029,24 @@ bool __darwintrace_is_in_sandbox(const char *path, int flags) {
</span>           return true;
        }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        char normPath[MAXPATHLEN];
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   normPath[0] = '/';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   normPath[1] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   path_component_t pathComponents[MAXPATHLEN / 2 + 2];
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   size_t numComponents = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   // Make sure the path is absolute.
</span>   if (path == NULL || *path == '\0') {
                // this is most certainly invalid, let the syscall deal with it
                return true;
        }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        char *dst = NULL;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   const char *token = NULL;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   size_t idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path_t *normPath = path_new();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!normPath) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("darwintrace: path_new");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           abort();
</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;'>+   size_t offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span>   if (*path != '/') {
                /*
                 * The path isn't absolute, start by populating pathcomponents with the
                 * current working directory.
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                 * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            *
</span>            * However, we avoid getcwd(3) if we can and use getattrlist(2) with
                 * ATTR_CMN_FULLPATH instead, because getcwd(3) will open all parent
                 * directories, read them, search for the current component using its
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -833,134 +1064,68 @@ bool __darwintrace_is_in_sandbox(const char *path, int flags) {
</span>           attrlist.fileattr = 0;
                attrlist.forkattr = 0;
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                char attrbuf[sizeof(uint32_t) + sizeof(attrreference_t) + (PATH_MAX + 1)];
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           /*           attrlength         attrref_t for the name     UTF-8 name up to PATH_MAX chars */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           size_t attrbufSize = sizeof(uint32_t) + sizeof(attrreference_t) + (PATH_MAX + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*                   attrlength         attrref_t for the name     UTF-8 name up to PATH_MAX chars */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char *attrbuf = malloc(attrbufSize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (attrbuf == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("darwintrace: malloc");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span> 
                // FIXME This sometimes violates the stack canary
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if (-1 == (getattrlist(".", &attrlist, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (-1 == (getattrlist(".", &attrlist, attrbuf, attrbufSize, FSOPT_NOFOLLOW))) {
</span>                   perror("darwintrace: getattrlist");
                        abort();
                }
                attrreference_t *nameAttrRef = (attrreference_t *) (attrbuf + sizeof(uint32_t));
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                strlcpy(normPath, ((char *) nameAttrRef) + nameAttrRef->attr_dataoffset, sizeof(normPath));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!path_tokenize(normPath, ((char *) nameAttrRef) + nameAttrRef->attr_dataoffset)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("darwintrace: path_tokenize");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span> #         else /* defined(ATTR_CMN_FULLPATH) */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if (getcwd(normPath, sizeof(normPath)) == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char *cwd = getcwd(NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (cwd == NULL) {
</span>                   perror("darwintrace: getcwd");
                        abort();
                }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#               endif /* defined(ATTR_CMN_FULLPATH) */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           char *writableToken = normPath + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           while ((idx = strcspn(writableToken, "/")) > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // found a token, tokenize and store it
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   pathComponents[numComponents].start = writableToken;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   pathComponents[numComponents].len   = idx;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   numComponents++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   bool final = writableToken[idx] == '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   writableToken[idx] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (final) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           break;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // advance token
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   writableToken += idx + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           // copy path after the CWD into the buffer and normalize it
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           if (numComponents > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   path_component_t *lastComponent = pathComponents + (numComponents - 1);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   dst = lastComponent->start + lastComponent->len + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   dst = normPath + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!path_tokenize(normPath, cwd)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   perror("darwintrace: path_tokenize");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   abort();
</span>           }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           // continue parsing at the begin of path
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           token = path;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(cwd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#          endif /* defined(ATTR_CMN_FULLPATH) */
</span>   } else {
                // skip leading '/'
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                dst = normPath + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           *dst = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           token = path + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           offset = 1;
</span>   }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        /* Make sure the path is normalized. NOTE: Do _not_ use realpath(3) here.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    * Doing so _will_ lead to problems. This is essentially a very simple
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    * re-implementation of realpath(3). */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   numComponents = __parse_path_normalize(token, dst, numComponents, pathComponents, normPath);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   // strip off resource forks
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   if (numComponents >= 2 &&
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           strcmp("..namedfork", pathComponents[numComponents - 2].start) == 0 &&
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           strcmp("rsrc", pathComponents[numComponents - 1].start) == 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           numComponents -= 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *pathcopy = strdup(path + offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!pathcopy) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("darwintrace: strdup");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           abort();
</span>   }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        if (!path_tokenize(normPath, pathcopy)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("darwintrace: path_tokenize");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(pathcopy);
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#       ifdef ATTR_CMN_FULLPATH
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   if (numComponents >= 3 && strncmp(".vol", pathComponents[0].start, pathComponents[0].len) == 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           // path in VOLFS, try to get inode -> name lookup from getattrlist(2).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Handle resource forks (we ignore them)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path_strip_resource_fork(normPath);
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                // Add the slashes and the terminating \0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           for (size_t i = 0; i < numComponents; ++i) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (i == numComponents - 1) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pathComponents[i].start[pathComponents[i].len] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pathComponents[i].start[pathComponents[i].len] = '/';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           struct attrlist attrlist;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.reserved = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.commonattr = ATTR_CMN_FULLPATH;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.volattr = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.dirattr = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.fileattr = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           attrlist.forkattr = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           char attrbuf[sizeof(uint32_t) + sizeof(attrreference_t) + (PATH_MAX + 1)];
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           /*           attrlength         attrref_t for the name     UTF-8 name up to PATH_MAX chars */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           if (-1 == (getattrlist(normPath, &attrlist, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   perror("darwintrace: getattrlist");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   // ignore and just return the /.vol/ path
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   attrreference_t *nameAttrRef = (attrreference_t *) (attrbuf + sizeof(uint32_t));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   strlcpy(normPath, ((char *) nameAttrRef) + nameAttrRef->attr_dataoffset, sizeof(normPath));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   numComponents = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   char *writableToken = normPath + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   while ((idx = strcspn(writableToken, "/")) > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           // found a token, tokenize and store it
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pathComponents[numComponents].start = writableToken;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pathComponents[numComponents].len   = idx;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           numComponents++;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           bool final = writableToken[idx] == '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           writableToken[idx] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           if (final) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   break;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           // advance token
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           writableToken += idx + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#  endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Handle /.vol/$devid/$inode volfs paths
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   normPath = path_resolve_volfs(normPath);
</span> 
        bool pathIsSymlink;
        size_t loopCount = 0;
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        char *path_native = path_str(normPath);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!path_native) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           perror("darwintrace: path_str");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span>   do {
                pathIsSymlink = false;
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                // Add the slashes and the terminating \0
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           for (size_t i = 0; i < numComponents; ++i) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (i == numComponents - 1) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pathComponents[i].start[pathComponents[i].len] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pathComponents[i].start[pathComponents[i].len] = '/';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span>           if ((flags & DT_FOLLOWSYMS) == 0) {
                        // only expand symlinks when the DT_FOLLOWSYMS flags is set;
                        // otherwise just ignore whether this path is a symlink or not to
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -978,46 +1143,62 @@ bool __darwintrace_is_in_sandbox(const char *path, int flags) {
</span>           // whether it is in the sandbox, expand it and do the same thing again.
                struct stat st;
                //debug_printf("checking for symlink: %s\n", normPath);
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                if (lstat(normPath, &st) != -1 && S_ISLNK(st.st_mode)) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (!__darwintrace_sandbox_check(normPath, flags)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (lstat(path_native, &st) != -1 && S_ISLNK(st.st_mode)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!__darwintrace_sandbox_check(path_native, flags)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           free(path_native);
</span>                           return false;
                        }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        char link[MAXPATHLEN];
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   pathIsSymlink = true;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   ssize_t linksize;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (-1 == (linksize = readlink(normPath, link, sizeof(link)))) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           perror("darwintrace: readlink");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   size_t maxLinkLength = MAXPATHLEN / 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   char *link = malloc(maxLinkLength);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (link == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           free(path_native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           perror("darwintrace: malloc");
</span>                           abort();
                        }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        link[linksize] = '\0';
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   //debug_printf("readlink(%s) = %s\n", normPath, link);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if (*link == '/') {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           // symlink is absolute, start fresh
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           numComponents = 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           token = link + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           dst = normPath + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           // symlink is relative, remove last component
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           token = link;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           if (numComponents > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   numComponents--;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   if (numComponents > 0) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           // move dst back to the previous entry
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           path_component_t *lastComponent = pathComponents + (numComponents - 1);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           dst = lastComponent->start + lastComponent->len + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           // we're at the top, move dst back to the beginning
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           dst = normPath + 1;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   pathIsSymlink = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   while (true) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           ssize_t linksize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (-1 == (linksize = readlink(path_native, link, maxLinkLength - 1))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   free(path_native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   perror("darwintrace: readlink");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           link[linksize] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if ((size_t) linksize < maxLinkLength - 1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   // The link did fit the buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   break;
</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;'>+                           maxLinkLength += MAXPATHLEN;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           char *newlink = realloc(link, maxLinkLength);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (!newlink) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   free(path_native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   free(link);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   perror("darwintrace: realloc");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   abort();
</span>                           }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+                                link = newlink;
</span>                   }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        numComponents = __parse_path_normalize(token, dst, numComponents, pathComponents, normPath);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!path_tokenize_symlink(normPath, link)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           perror("darwintrace: path_tokenize_symlink");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           abort();
</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(link);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(path_native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   path_native = path_str(normPath);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!path_native) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           perror("darwintrace: path_str");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span>           }
        } while (pathIsSymlink);
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        return __darwintrace_sandbox_check(normPath, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   bool result = __darwintrace_sandbox_check(path_native, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(path_native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   path_free(normPath);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return result;
</span> }
</pre><pre style='margin:0'>

</pre>