Initial Contribution
diff --git a/amend/permissions.c b/amend/permissions.c
new file mode 100644
index 0000000..a642d0b
--- /dev/null
+++ b/amend/permissions.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "permissions.h"
+
+int
+initPermissionRequestList(PermissionRequestList *list)
+{
+    if (list != NULL) {
+        list->requests = NULL;
+        list->numRequests = 0;
+        list->requestsAllocated = 0;
+        return 0;
+    }
+    return -1;
+}
+
+int
+addPermissionRequestToList(PermissionRequestList *list,
+        const char *path, bool recursive, unsigned int permissions)
+{
+    if (list == NULL || list->numRequests < 0 ||
+            list->requestsAllocated < list->numRequests || path == NULL)
+    {
+        return -1;
+    }
+
+    if (list->numRequests == list->requestsAllocated) {
+        int newSize;
+        PermissionRequest *newRequests;
+
+        newSize = list->requestsAllocated * 2;
+        if (newSize < 16) {
+            newSize = 16;
+        }
+        newRequests = (PermissionRequest *)realloc(list->requests,
+                newSize * sizeof(PermissionRequest));
+        if (newRequests == NULL) {
+            return -2;
+        }
+        list->requests = newRequests;
+        list->requestsAllocated = newSize;
+    }
+
+    PermissionRequest *req;
+    req = &list->requests[list->numRequests++];
+    req->path = strdup(path);
+    if (req->path == NULL) {
+        list->numRequests--;
+        return -3;
+    }
+    req->recursive = recursive;
+    req->requested = permissions;
+    req->allowed = 0;
+
+    return 0;
+}
+
+void
+freePermissionRequestListElements(PermissionRequestList *list)
+{
+    if (list != NULL && list->numRequests >= 0 &&
+            list->requestsAllocated >= list->numRequests)
+    {
+        int i;
+        for (i = 0; i < list->numRequests; i++) {
+            free((void *)list->requests[i].path);
+        }
+        free(list->requests);
+        initPermissionRequestList(list);
+    }
+}
+
+/*
+ * Global permission table
+ */
+
+static struct {
+    Permission *permissions;
+    int numPermissionEntries;
+    int allocatedPermissionEntries;
+    bool permissionStateInitialized;
+} gPermissionState = {
+#if 1
+    NULL, 0, 0, false
+#else
+    .permissions = NULL,
+    .numPermissionEntries = 0,
+    .allocatedPermissionEntries = 0,
+    .permissionStateInitialized = false
+#endif
+};
+
+int
+permissionInit()
+{
+    if (gPermissionState.permissionStateInitialized) {
+        return -1;
+    }
+    gPermissionState.permissions = NULL;
+    gPermissionState.numPermissionEntries = 0;
+    gPermissionState.allocatedPermissionEntries = 0;
+    gPermissionState.permissionStateInitialized = true;
+//xxx maybe add an "namespace root gets no permissions" fallback by default
+    return 0;
+}
+
+void
+permissionCleanup()
+{
+    if (gPermissionState.permissionStateInitialized) {
+        gPermissionState.permissionStateInitialized = false;
+        if (gPermissionState.permissions != NULL) {
+            int i;
+            for (i = 0; i < gPermissionState.numPermissionEntries; i++) {
+                free((void *)gPermissionState.permissions[i].path);
+            }
+            free(gPermissionState.permissions);
+        }
+    }
+}
+
+int
+getPermissionCount()
+{
+    if (gPermissionState.permissionStateInitialized) {
+        return gPermissionState.numPermissionEntries;
+    }
+    return -1;
+}
+
+const Permission *
+getPermissionAt(int index)
+{
+    if (!gPermissionState.permissionStateInitialized) {
+        return NULL;
+    }
+    if (index < 0 || index >= gPermissionState.numPermissionEntries) {
+        return NULL;
+    }
+    return &gPermissionState.permissions[index];
+}
+
+int
+getAllowedPermissions(const char *path, bool recursive,
+        unsigned int *outAllowed)
+{
+    if (!gPermissionState.permissionStateInitialized) {
+        return -2;
+    }
+    if (outAllowed == NULL) {
+        return -1;
+    }
+    *outAllowed = 0;
+    if (path == NULL) {
+        return -1;
+    }
+    //TODO: implement this for real.
+    recursive = false;
+    *outAllowed = PERMSET_ALL;
+    return 0;
+}
+
+int
+countPermissionConflicts(PermissionRequestList *requests, bool updateAllowed)
+{
+    if (!gPermissionState.permissionStateInitialized) {
+        return -2;
+    }
+    if (requests == NULL || requests->requests == NULL ||
+            requests->numRequests < 0 ||
+            requests->requestsAllocated < requests->numRequests)
+    {
+        return -1;
+    }
+    int conflicts = 0;
+    int i;
+    for (i = 0; i < requests->numRequests; i++) {
+        PermissionRequest *req;
+        unsigned int allowed;
+        int ret;
+
+        req = &requests->requests[i];
+        ret = getAllowedPermissions(req->path, req->recursive, &allowed);
+        if (ret < 0) {
+            return ret;
+        }
+        if ((req->requested & ~allowed) != 0) {
+            conflicts++;
+        }
+        if (updateAllowed) {
+            req->allowed = allowed;
+        }
+    }
+    return conflicts;
+}
+
+int
+registerPermissionSet(int count, Permission *set)
+{
+    if (!gPermissionState.permissionStateInitialized) {
+        return -2;
+    }
+    if (count < 0 || (count > 0 && set == NULL)) {
+        return -1;
+    }
+    if (count == 0) {
+        return 0;
+    }
+
+    if (gPermissionState.numPermissionEntries + count >=
+            gPermissionState.allocatedPermissionEntries)
+    {
+        Permission *newList;
+        int newSize;
+
+        newSize = (gPermissionState.allocatedPermissionEntries + count) * 2;
+        if (newSize < 16) {
+            newSize = 16;
+        }
+        newList = (Permission *)realloc(gPermissionState.permissions,
+                newSize * sizeof(Permission));
+        if (newList == NULL) {
+            return -3;
+        }
+        gPermissionState.permissions = newList;
+        gPermissionState.allocatedPermissionEntries = newSize;
+    }
+
+    Permission *p = &gPermissionState.permissions[
+                        gPermissionState.numPermissionEntries];
+    int i;
+    for (i = 0; i < count; i++) {
+        *p = set[i];
+        //TODO: cache the strlen of the path
+        //TODO: normalize; strip off trailing /
+        p->path = strdup(p->path);
+        if (p->path == NULL) {
+            /* If we can't add all of the entries, we don't
+             * add any of them.
+             */
+            Permission *pp = &gPermissionState.permissions[
+                                gPermissionState.numPermissionEntries];
+            while (pp != p) {
+                free((void *)pp->path);
+                pp++;
+            }
+            return -4;
+        }
+        p++;
+    }
+    gPermissionState.numPermissionEntries += count;
+
+    return 0;
+}