return 0;
}
+static void parse_perm(const char *perm, char *letter, unsigned int *dom_id)
+{
+ unsigned int n = sscanf(perm, "%c%u", letter, dom_id);
+
+ assert(n == 2);
+}
+
+static bool can_access(unsigned int dom_id, GList *perms, const char *letters)
+{
+ unsigned int i, n;
+ char perm_letter;
+ unsigned int perm_dom_id;
+ bool access;
+
+ if (dom_id == 0)
+ return true;
+
+ n = g_list_length(perms);
+ assert(n >= 1);
+
+ /*
+ * The dom_id of the first perm is the owner, and the owner always has
+ * read-write access.
+ */
+ parse_perm(g_list_nth_data(perms, 0), &perm_letter, &perm_dom_id);
+ if (dom_id == perm_dom_id)
+ return true;
+
+ /*
+ * The letter of the first perm specified the default access for all other
+ * domains.
+ */
+ access = !!strchr(letters, perm_letter);
+ for (i = 1; i < n; i++) {
+ parse_perm(g_list_nth_data(perms, i), &perm_letter, &perm_dom_id);
+ if (dom_id != perm_dom_id)
+ continue;
+ access = !!strchr(letters, perm_letter);
+ }
+
+ return access;
+}
+
/*
* Passed a full reference in *n which it may free if it needs to COW.
*
}
if (!child_name) {
+ const char *letters = op->mutating ? "wb" : "rb";
+
+ if (!can_access(op->dom_id, old->perms, letters))
+ return EACCES;
+
/* This is the actual node on which the operation shall be performed */
err = op->op_fn(n, op);
if (!err) {
stole_child = true;
}
} else if (op->create_dirs) {
+ assert(op->mutating);
+
+ if (!can_access(op->dom_id, old->perms, "wb"))
+ return EACCES;
+
child = xs_node_create(child_name, old->perms);
/* If we're creating a new child, we can clearly modify it (and its
* children) in place from here on down. */