[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [RFC PATCH 3/5] kernel2: Ressourcen und Verzeichnisbäume



+ kernel2: Funktionen zur Verwaltung von Services, Verzeichnisbäumen
  und Ressourcen

Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
 src/kernel2/src/lostio/client.c             |  105 ++++++++-
 src/kernel2/src/lostio/include/lostio_int.h |   74 ++++++
 src/kernel2/src/lostio/lostio.c             |    1 +
 src/kernel2/src/lostio/tree.c               |  365 +++++++++++++++++++++++++++
 4 files changed, 543 insertions(+), 2 deletions(-)
 create mode 100644 src/kernel2/src/lostio/tree.c

diff --git a/src/kernel2/src/lostio/client.c b/src/kernel2/src/lostio/client.c
index f87c6fa..43baadf 100644
--- a/src/kernel2/src/lostio/client.c
+++ b/src/kernel2/src/lostio/client.c
@@ -44,6 +44,35 @@
 #include "lostio_int.h"
 
 /**
+ * Versucht den uebergebenen Symlink aufzuloesen. Wenn die Resource, auf die er
+ * Zeigt, existiert wird ein Zeiger darauf zurueckgegeben, NULL sonst.
+ *
+ * @return Zeiger auf das Ziel, oder NULL falls der Link nicht aufgeloest werden
+ *         konnte.
+ */
+static struct lio_resource* resolve_symlink(struct lio_resource* link)
+{
+    char buf[link->size + 1];
+    struct lio_stream* stream;
+    ssize_t len;
+
+    if (!(stream = lio_open(link, LIO_READ | LIO_SYMLINK))) {
+        return NULL;
+    }
+
+    len = lio_read(stream, link->size, buf);
+    lio_close(stream);
+
+    if (len < 0) {
+        return NULL;
+    }
+    buf[len] = 0;
+
+    // TODO: Relative Symlinks
+    return lio_get_resource(buf, 1);
+}
+
+/**
  * Loest einen Pfad zu einer Ressource auf
  *
  * @return Die zum Pfad gehoerende Ressource oder NULL, wenn der Pfad keine
@@ -51,8 +80,80 @@
  */
 struct lio_resource* lio_get_resource(const char* path, int follow_symlinks)
 {
-    /* TODO */
-    return NULL;
+    struct lio_tree* tree;
+    struct lio_resource* res;
+    struct lio_node* node;
+    const char* rel_path;
+    char* tokenize_path;
+    char* name;
+    int i;
+
+    // Passenden Baum raussuchen
+    tree = lio_get_tree(path, &rel_path);
+    if (tree == NULL) {
+        return NULL;
+    }
+
+    node = tree->root;
+
+    // Von der Wurzel aus durchhangeln
+    char* saveptr;
+    tokenize_path = strdup(rel_path);
+    name = strtok_r(tokenize_path, "/", &saveptr);
+    while (name != NULL) {
+        res = node->res;
+
+        // Falls wir es mit einem Symlink zu tun haben, versuchen wir doch mal
+        // dem zu folgen.
+        if (res->resolvable) {
+            res = resolve_symlink(res);
+
+            // War wohl nix
+            if (!res) {
+                goto out;
+            }
+        }
+
+        tree = res->tree;
+
+        // Wir suchen noch ein Kind, aber diese Ressource hat keine
+        if (!res->browsable) {
+            res = NULL;
+            goto out;
+        }
+
+        // Falls die Liste der Kinder nicht geladen ist, nachholen
+        if (res->children == NULL) {
+            if (tree->service->lio_ops.load_children(res)) {
+                res = NULL;
+                goto out;
+            }
+        }
+
+        // Passendes Kind raussuchen
+        for (i = 0; (node = list_get_element_at(res->children, i)); i++) {
+            if (strcmp(node->name, name) == 0) {
+                goto found;
+            }
+        }
+        res = NULL;
+        goto out;
+
+found:
+        // Passender Kindknoten wurde gefunden, weiter im Pfad
+        name = strtok_r(NULL, "/", &saveptr);
+    }
+
+    res = node->res;
+
+    // Auch das koennte noch mal ein Symlink sein, den wir aufloesen muessen
+    if (res && follow_symlinks && res->resolvable) {
+        res = resolve_symlink(res);
+    }
+
+out:
+    free(tokenize_path);
+    return res;
 }
 
 /**
diff --git a/src/kernel2/src/lostio/include/lostio_int.h b/src/kernel2/src/lostio/include/lostio_int.h
index c7a511f..67343b1 100644
--- a/src/kernel2/src/lostio/include/lostio_int.h
+++ b/src/kernel2/src/lostio/include/lostio_int.h
@@ -50,6 +50,12 @@
 struct lio_service;
 struct lio_driver {
     /**
+     * Root-Ressource eines Dateisystems laden, das root-Feld in tree ist also
+     * noch NULL.
+     */
+    struct lio_resource* (*load_root)(struct lio_tree* tree);
+
+    /**
      * Laedt alle Kindknoten nach res->children
      */
     int (*load_children)(struct lio_resource* res);
@@ -202,10 +208,78 @@ struct lio_tree {
 
 
 /**
+ * Initialisiert die statischen Variablen von tree.c
+ */
+int lio_init_tree(void);
+
+/**
  * Initialisiert die Verwaltung der Userspace-Deskriptoren für Kernelobjekte
  */
 int lio_init_userspace(void);
 
+/**
+ * Neue Ressource initialisieren.
+ * Vom Aufrufer initialisiert werden muessen (werden alle auf 0 initialisiert):
+ *   - blocksize
+ *   - tree
+ *   - Flags
+ *
+ * @return Zeiger auf die neue Ressource
+ */
+struct lio_resource* lio_create_resource(void);
+
+/**
+ * Interne Daten einer Ressource initialisieren. Dabei werden nur die internen
+ * Felder veraendert, der Rest muss vom Aufrufer gesetzt werden. Diese Funktion
+ * kann verwendet werden, wenn der Speicher fuer eine Resource bereits
+ * verfuegbar ist (beispielsweise bei statischem Speicher).
+ *
+ * @param res Zu initialisierende Ressource
+ */
+void lio_init_resource(struct lio_resource* res);
+
+/**
+ * Ressource zerstören und Speicher freigeben. Der Aufrufer ist dafür
+ * zuständig, allenfalls Caches zu syncen.
+ *
+ * @param res Zu zerstoerende Ressource
+ */
+void lio_destroy_resource(struct lio_resource* res);
+
+/**
+ * Loest einen gegebenen Pfad in einen Verzeichnisbaum und einen
+ * servicerelativen Pfad auf.
+ *
+ * @param path Aufzulosender Pfad
+ * @param rel_path Wenn rel_path != NULL ist, wird darin ein Pointer auf den
+ * servicerelativen Teil des Pfads zurueckgegeben
+ *
+ * @return Den zum Pfad gehoerenden Verzeichnisbaum oder NULL im Fehlerfall
+ */
+struct lio_tree* lio_get_tree(const char* path, const char** rel_path);
+
+/**
+ * Registriert einen neuen LIO-Service
+ */
+void lio_add_service(struct lio_service* service);
+
+/** Kindknoten einer Ressource suchen */
+struct lio_node* lio_resource_get_child(struct lio_resource* parent,
+    const char* name);
+
+/** Einer Resource einen Kindknoten anfuegen */
+void lio_resource_add_child(struct lio_resource* parent,
+    struct lio_node* child);
+
+/** Kindknoten einer Ressource entfernen */
+void lio_resource_remove_child(struct lio_resource* parent,
+    struct lio_node* child);
+
+/** Neuen Knoten anlegen und bei Elternressource als Kind eintragen */
+struct lio_node* lio_create_node(struct lio_resource* parent,
+    struct lio_resource* res, const char* name);
+
+
 void lio_usp_add_resource(struct lio_resource* res);
 struct lio_resource* lio_usp_get_resource(lio_usp_resource_t id);
 void lio_usp_remove_resource(struct lio_resource* res);
diff --git a/src/kernel2/src/lostio/lostio.c b/src/kernel2/src/lostio/lostio.c
index 3843f4e..9a08d58 100644
--- a/src/kernel2/src/lostio/lostio.c
+++ b/src/kernel2/src/lostio/lostio.c
@@ -40,6 +40,7 @@
 
 void lio_init(void)
 {
+    lio_init_tree();
     lio_init_userspace();
 
     return;
diff --git a/src/kernel2/src/lostio/tree.c b/src/kernel2/src/lostio/tree.c
new file mode 100644
index 0000000..4078d52
--- /dev/null
+++ b/src/kernel2/src/lostio/tree.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2009 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the tyndur Project
+ *     and its contributors.
+ * 4. Neither the name of the tyndur Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "kernel.h"
+#include "kprintf.h"
+
+#include "lostio/core.h"
+#include "lostio/client.h"
+#include "lostio_int.h"
+
+static list_t* lio_trees;
+static list_t* lio_services;
+
+/**
+ * Initialisiert die statischen Variablen dieser Datei
+ */
+int lio_init_tree(void)
+{
+    lio_trees = list_create();
+    lio_services = list_create();
+
+    return 0;
+}
+
+/**
+ * Erzeugt einen neuen Verzeichnisbaum. Das root-Feld im der Baum-Struktur muss
+ * vom Aufrufer eingefuellt werden.
+ *
+ * @param serv LIO-Service, der den Baum verwaltet
+ * @param source LIO-Stream der Datenquelle
+ *
+ * @return Den neu angelegten Baum oder NULL im Fehlerfall
+ */
+static struct lio_tree* lio_add_tree(struct lio_service* serv,
+    struct lio_stream* source)
+{
+    struct lio_tree* tree;
+
+    // TODO Der Service sollte auch wirklich fuer den Pfad zustaendig sein
+
+    // Neuen Baum anlegen und in die Liste pushen
+    tree = calloc(1, sizeof(*tree));
+    tree->service = serv;
+    tree->source = source;
+
+    lio_usp_add_tree(tree);
+
+    return tree;
+}
+
+/**
+ * Zerlegt einen Pfad. Die zwei uebergebenen Zeiger zeigen anschliessend auf
+ * den Namen des zustaendigen Services bzw. den Anfang des servicerelativen
+ * Pfads im Originalpfad.
+ *
+ * Im Fehlerfall (der Pfad enthaelt kein ":/") wird rel_path auf NULL gesetzt.
+ */
+static void split_path(const char* path, const char** service,
+    const char** rel_path)
+{
+    const char* service_name;
+    const char* tmp_rel_path;
+
+    service_name = strrchr(path, '|');
+    if (service_name == NULL) {
+        service_name = path;
+    } else {
+        service_name++;
+    }
+
+    tmp_rel_path = strstr(service_name, ":/");
+    if (tmp_rel_path != NULL) {
+        tmp_rel_path += 2;
+    }
+
+    *service = service_name;
+    *rel_path = tmp_rel_path;
+}
+
+/**
+ * Sucht den richtigen Service zur Verarbeitung eines Pfads und erzeugt einen
+ * neuen Verzeichnisbaum fuer diesen.
+ *
+ * @param path Pfad der zu oeffnenden Datei
+ * @param rel_path Wenn rel_path != NULL ist, wird darin ein Pointer auf den
+ * servicerelativen Teil des Pfads zurueckgegeben.
+ *
+ * @return Den neu angelegten Verzeichnisbaum oder NULL im Fehlerfall
+ */
+static struct lio_tree* mount(const char* path, const char** rel_path)
+{
+    struct lio_stream* source_stream;
+    struct lio_resource* source_res;
+    struct lio_service* service;
+    struct lio_resource* root_res;
+    struct lio_node* root_node;
+    struct lio_tree* tree;
+    const char* service_name;
+    const char* tmp_rel_path;
+    int i;
+
+    // Pfad aufsplitten
+    split_path(path, &service_name, &tmp_rel_path);
+
+    // Passenden Service suchen
+    for (i = 0; (service = list_get_element_at(lio_services, i)); i++) {
+
+        size_t len = strlen(service->name);
+
+        if (len != tmp_rel_path - 2 - service_name) {
+            continue;
+        }
+
+        if (!strncmp(service->name, service_name, len)) {
+            goto found;
+        }
+    }
+    return NULL;
+
+found:
+
+    // Quelle oeffnen
+    source_stream = NULL;
+    if (path == service_name) {
+        source_stream = NULL;
+    } else {
+        char* source;
+        source = malloc(service_name - path);
+        strncpy(source, path, service_name - path - 1);
+        source[service_name - path - 1] = '\0';
+
+        if (!(source_res = lio_get_resource(source, 1))) {
+            return NULL;
+        }
+
+        // TODO: Was machen wir hier mit den Flags fuer fopen genau?
+        source_stream = lio_open(source_res, LIO_READ | LIO_WRITE);
+        free(source);
+
+        if (source_stream == NULL) {
+            return NULL;
+        }
+    }
+
+    tree = lio_add_tree(service, source_stream);
+
+    // Wurzelressource laden
+    root_res = service->lio_ops.load_root(tree);
+    if (root_res == NULL) {
+        if (source_stream) {
+            lio_close(source_stream);
+        }
+        goto out_err;
+    }
+
+    // Wurzelknoten fuer neuen Baum anlegen
+    root_node = calloc(1, sizeof(*root_node));
+    root_node->res = root_res;
+    root_node->name = malloc(tmp_rel_path - path + 1);
+    strncpy(root_node->name, path, tmp_rel_path - path);
+    root_node->name[tmp_rel_path - path] = '\0';
+
+    tree->root = root_node;
+    root_node->res->tree = tree;
+
+    // Neuen Baum registrieren
+    list_push(lio_trees, tree);
+    if (rel_path) {
+        *rel_path = tmp_rel_path;
+    }
+
+    return tree;
+
+out_err:
+    lio_usp_remove_tree(tree);
+    free(tree);
+    return NULL;
+}
+
+/**
+ * Loest einen gegebenen Pfad in einen Verzeichnisbaum und einen
+ * servicerelativen Pfad auf.
+ *
+ * @param path Aufzulosender Pfad
+ * @param rel_path Wenn rel_path != NULL ist, wird darin ein Pointer auf den
+ * servicerelativen Teil des Pfads zurueckgegeben
+ *
+ * @return Den zum Pfad gehoerenden Verzeichnisbaum oder NULL im Fehlerfall
+ */
+struct lio_tree* lio_get_tree(const char* path, const char** rel_path)
+{
+    int i;
+    struct lio_tree* tree;
+    const char* service_name;
+    const char* tmp_rel_path;
+
+    // Pfad fuer den Baum heraussucen
+    split_path(path, &service_name, &tmp_rel_path);
+    if (rel_path) {
+        *rel_path = tmp_rel_path;
+    }
+
+    // Suchen, ob es schon einen Baum fuer den Pfad gibt
+    for (i = 0; (tree = list_get_element_at(lio_trees, i)); i++) {
+        if (!tree->root) {
+            panic("BUG: lio_tree ohne Wurzel");
+        }
+
+        if (strlen(tree->root->name) != (tmp_rel_path - path)) {
+            continue;
+        }
+
+        if (!strncmp(tree->root->name, path, tmp_rel_path - path)) {
+            return tree;
+        }
+    }
+
+    // Neuen Baum anlegen
+    tree = mount(path, rel_path);
+
+    return tree;
+}
+
+/**
+ * Registriert einen neuen LIO-Service
+ */
+void lio_add_service(struct lio_service* service)
+{
+    list_push(lio_services, service);
+}
+
+/**
+ * Neue Ressource initialisieren.
+ * Vom Aufrufer initialisiert werden muessen (werden alle auf 0 initialisiert):
+ *   - blocksize
+ *   - tree
+ *   - Flags
+ *
+ * @return Zeiger auf die neue Ressource
+ */
+struct lio_resource* lio_create_resource(void)
+{
+    struct lio_resource* res = calloc(sizeof(*res), 1);
+
+    lio_init_resource(res);
+
+    return res;
+}
+
+/**
+ * Interne Daten einer Ressource initialisieren. Dabei werden nur die internen
+ * Felder veraendert, der Rest muss vom Aufrufer gesetzt werden. Diese Funktion
+ * kann verwendet werden, wenn der Speicher fuer eine Resource bereits
+ * verfuegbar ist (beispielsweise bei statischem Speicher).
+ *
+ * @param res Zu initialisierende Ressource
+ */
+void lio_init_resource(struct lio_resource* res)
+{
+    lio_usp_add_resource(res);
+}
+
+/**
+ * Ressource zerstoeren und Speicher freigeben. Der Aufrufer ist dafuer
+ * allenfalls Caches zu syncen.
+ *
+ * @param res Zu zerstoerende Ressource
+ */
+void lio_destroy_resource(struct lio_resource* res)
+{
+    lio_usp_remove_resource(res);
+    free(res);
+}
+
+/** Kindknoten einer Ressource suchen */
+struct lio_node* lio_resource_get_child(struct lio_resource* parent,
+    const char* name)
+{
+    struct lio_node* n;
+    size_t i;
+
+    for (i = 0; (n = list_get_element_at(parent->children, i)); i++) {
+        if (!strcmp(name, n->name)) {
+            return n;
+        }
+    }
+
+    return NULL;
+}
+
+/** Einer Resource einen Kindknoten anfuegen */
+void lio_resource_add_child(struct lio_resource* parent,
+    struct lio_node* child)
+{
+    if (!parent->children) {
+        parent->children = list_create();
+    }
+
+    list_push(parent->children, child);
+}
+
+/** Kindknoten einer Ressource entfernen */
+void lio_resource_remove_child(struct lio_resource* parent,
+    struct lio_node* child)
+{
+    struct lio_node* n;
+    size_t i;
+
+    // FIXME: Hier brauchen wir irgendwann noch gescheite Locks
+    for (i = 0; (n = list_get_element_at(parent->children, i)); i++) {
+        if (n == child) {
+            list_remove(parent->children, i);
+            break;
+        }
+    }
+}
+
+/** Neuen Knoten anlegen und bei Elternressource als Kind eintragen */
+struct lio_node* lio_create_node(struct lio_resource* parent,
+    struct lio_resource* res, const char* name)
+{
+    struct lio_node* n = calloc(sizeof(*n), 1);
+
+    n->res = res;
+    n->name = strdup(name);
+    lio_resource_add_child(parent, n);
+
+    return n;
+}
+
-- 
1.6.0.2