#include #define NAMESPACE_CAST(p) OBJECT_C_CAST(struct object_namespace, ns_base, &ns_type, p) static struct object_type ns_type; static struct object_namespace *global_ns; struct object_namespace { /* root directory set object */ struct object ns_base; struct object *ns_root; }; static kern_status_t ns_query_name(struct object *obj, char out[OBJECT_NAME_MAX]) { out[0] = '/'; out[1] = 0; return KERN_OK; } static kern_status_t ns_get_child_at(struct object *obj, size_t at, struct object **out) { struct object_namespace *ns = NAMESPACE_CAST(obj); return object_get_child_at(ns->ns_root, at, out); } static kern_status_t ns_get_child_named(struct object *obj, const char *name, struct object **out) { struct object_namespace *ns = NAMESPACE_CAST(obj); return object_get_child_named(ns->ns_root, name, out); } static struct object_type ns_type = { .ob_name = "namespace", .ob_size = sizeof(struct object_namespace), .ob_header_offset = offsetof(struct object_namespace, ns_base), .ob_ops = { .query_name = ns_query_name, .get_named = ns_get_child_named, .get_at = ns_get_child_at, }, }; void init_global_namespace(void) { object_type_register(&ns_type); global_ns = object_namespace_create(); } struct object_namespace *global_namespace(void) { return global_ns; } struct object_namespace *object_namespace_create(void) { struct object *ns_object = object_create(&ns_type); struct object_namespace *ns = NAMESPACE_CAST(ns_object); ns->ns_root = set_create("/"); return ns; } static void cleanup_object_path(char *path, size_t len, size_t *parts) { while (path[len - 1] == '/') { path[--len] = 0; } size_t final_len = len; *parts = 0; int slashes = 0; for (int i = 0; path[i]; i++) { if (path[i] == '/') { slashes++; continue; } if (slashes < 1) { continue; } char *from = path + i; char *to = path + i - slashes + 1; int count = len - i; memmove(to, from, count); final_len -= (slashes - 1); slashes = 0; (*parts)++; } path[final_len] = 0; } struct object *ns_header(struct object_namespace *ns) { return &ns->ns_base; } kern_status_t object_namespace_get_object(struct object_namespace *ns, const char *path, struct object **out) { if (*path != '/') { return KERN_INVALID_ARGUMENT; } while (*path == '/') { path++; } size_t path_len = strlen(path); if (path_len == 0) { *out = object_ref(ns->ns_root); return KERN_OK; } size_t parts = 0; char *rpath = kmalloc(path_len, 0); if (!rpath) { return KERN_NO_MEMORY; } memcpy(rpath, path, path_len); cleanup_object_path(rpath, path_len, &parts); char *sp; char *tok = strtok_r(rpath, "/", &sp); struct object *cur = ns->ns_root; unsigned long flags; while (tok) { object_lock_irqsave(cur, &flags); struct object *next; kern_status_t status = object_get_child_named(cur, tok, &next); if (status != KERN_OK) { object_unlock_irqrestore(cur, flags); kfree(rpath); return status; } object_unlock_irqrestore(cur, flags); cur = next; tok = strtok_r(NULL, "/", &sp); object_lock_irqsave(cur, &flags); if (!object_is_link(cur)) { object_unlock_irqrestore(cur, flags); continue; } struct object *dest_obj; dest_obj = link_read_ptr(cur); object_unlock_irqrestore(cur, flags); if (!dest_obj) { kfree(rpath); /* TODO better error code for broken links */ return KERN_INVALID_ARGUMENT; } object_deref(cur); cur = dest_obj; } kfree(rpath); if (object_is_link(cur)) { struct object *link_dest = link_read_ptr(cur); object_deref(cur); cur = object_ref(link_dest); } *out = cur; return KERN_OK; } kern_status_t object_namespace_create_link(struct object_namespace *ns, const char *linkpath, struct object *dest) { if (*linkpath != '/') { return KERN_INVALID_ARGUMENT; } while (*linkpath == '/') { linkpath++; } size_t path_len = strlen(linkpath); if (path_len == 0) { return KERN_INVALID_ARGUMENT; } size_t parts = 0; char *rpath = kmalloc(path_len, 0); if (!rpath) { return KERN_NO_MEMORY; } memcpy(rpath, linkpath, path_len); cleanup_object_path(rpath, path_len, &parts); char *p = rpath + strlen(rpath) - 1; while (*p != '/' && p >= rpath) { p--; } if (p == rpath) { kfree(rpath); return KERN_INVALID_ARGUMENT; } *p = '\0'; const char *linkname = p + 1; char *sp; char *tok = strtok_r(rpath, "/", &sp); struct object *cur = object_ref(ns->ns_root); unsigned long flags; while (tok) { object_lock_irqsave(cur, &flags); struct object *next; kern_status_t status = object_get_child_named(cur, tok, &next); if (status == KERN_NO_ENTRY) { next = set_create(tok); if (!next) { object_unlock_irqrestore(cur, flags); object_deref(cur); kfree(rpath); return KERN_NO_MEMORY; } status = set_add_object(cur, next); object_unlock_irqrestore(cur, flags); object_deref(cur); } else { object_unlock_irqrestore(cur, flags); } if (status != KERN_OK) { kfree(rpath); return status; } cur = next; tok = strtok_r(NULL, "/", &sp); } struct object *link = link_create(linkname, dest); kfree(rpath); if (!link) { object_deref(cur); return KERN_NO_MEMORY; } object_lock_irqsave(cur, &flags); kern_status_t status = set_add_object(cur, link); object_unlock_irqrestore(cur, flags); object_deref(cur); object_deref(link); return status; } kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj) { if (*path != '/') { return KERN_INVALID_ARGUMENT; } while (*path == '/') { path++; } size_t path_len = strlen(path); if (path_len == 0) { return set_add_object(ns->ns_root, obj); } size_t parts = 0; char *rpath = kmalloc(path_len, 0); if (!rpath) { return KERN_NO_MEMORY; } memcpy(rpath, path, path_len); cleanup_object_path(rpath, path_len, &parts); char *sp; char *tok = strtok_r(rpath, "/", &sp); struct object *cur = ns->ns_root; unsigned long flags; while (tok) { object_lock_irqsave(cur, &flags); struct object *next; kern_status_t status = object_get_child_named(cur, tok, &next); if (status == KERN_NO_ENTRY) { next = set_create(tok); if (!next) { object_unlock_irqrestore(cur, flags); kfree(rpath); return KERN_NO_MEMORY; } status = set_add_object(cur, next); } if (status != KERN_OK) { object_unlock_irqrestore(cur, flags); kfree(rpath); return status; } object_unlock_irqrestore(cur, flags); cur = next; tok = strtok_r(NULL, "/", &sp); } kfree(rpath); return set_add_object(cur, obj); } kern_status_t object_unpublish(struct object_namespace *ns, struct object *obj) { return KERN_OK; }