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

Re: [Lost] Neue io_get_absolute_path



So hier nun der 2. Versuch, mit den vorgeschlagenen Änderungen.
Hoffentlich fällt das diesmal nicht wieder so schlimm aus ;-)
Index: src/modules/lib/lost_path.c
===================================================================
--- src/modules/lib/lost_path.c	(Revision 0)
+++ src/modules/lib/lost_path.c	(Revision 0)
@@ -0,0 +1,451 @@
+/*  
+ * Copyright (c) 2007 The LOST Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the LOST Project
+ * by Antoine Kaufmann.
+ *
+ * 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 LOST Project
+ *     and its contributors.
+ * 4. Neither the name of the LOST 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <collections.h>
+
+typedef enum {
+    // Kein Seperator (nur am Anfang und am Ende moeglich)
+    NO_SEP,
+    // Service Seperator ":/"
+    SERVICE_SEP,
+    // Normaler Pfad-Seperator "/"
+    PATH_SEP,
+    // Seperator fuer gepipte Pfade "|"
+    PIPE_SEP
+} path_sep_t;
+
+struct path_element {
+    path_sep_t left_sep;
+    path_sep_t right_sep;
+
+    char text[256];
+};
+
+
+/**
+ * Alloziert Speicher fuer eine Element-Struktur, fuellt sie, und gibt einen
+ * Pointer darauf zurueck
+ *
+ * @param text Pointer auf den Anfang der Element-Textes
+ * @param len Laenge des Element-Textes
+ * @param left_sep Linker Seperator
+ * @param right_sep Rechter Seperator
+ *
+ * @return Pointer auf neues Element
+ */
+static inline struct path_element* create_path_element(const char* text,
+    size_t len, path_sep_t left_sep, path_sep_t right_sep)
+{
+    struct path_element* element = malloc(sizeof(struct path_element));
+    
+    // Text auf die maximal 255 Zeichen zurechtstutzen. Dabei wird einfach
+    // alles knallhart abgeschnitten. Aber so lange Verzeichnis- und Dateinamen
+    // benutzt man einfach nicht.
+    if (len > 255) {
+        len = 255;
+    }
+    memcpy(element->text, text, len);
+    element->text[len] = '\0';
+
+    element->left_sep = left_sep;
+    element->right_sep = right_sep;
+
+    return element;
+}
+
+/**
+ * Zerstueckelt einen Pfad in die einzelnen Elemente. Dies laesst sich am
+ * besten ahnhand eines Beispiels zeigen:
+ * ide:/hd1a|fat:/
+ *  Element 0: ide
+ *  Element 1: hd1a
+ *  Element 2: fat
+ *
+ * Dabei wird zu jedem Element abgespeichert, welche Seperatoren es links und
+ * rechts von den anderen trennen. Die Elemente werden in die uebergebene Liste
+ * ab {position} in umgekehrter Reihenfolge eingefuellt.
+ *
+ * @param path Der Pfad als String
+ * @param lost Pointer auf die Liste, in die eingefuellt werden soll
+ * @param position Position an die die Elemente in die Liste sollen
+ * 
+ * @return Anzahl der Elemente
+ */
+static int get_path_elements(const char* path, list_t* list, int position)
+{
+    bool escaped = FALSE;
+    const char* pos = path;
+    const char* last_element = path;
+    path_sep_t left_sep = NO_SEP;
+    struct path_element* element = NULL;
+    int element_count = 0;
+
+    // Pfad Zeichenweise durchgehen
+    while (TRUE) {
+        // Wenn das letzte Zeichen ein Escape-Zeichen war, muss das aktuelle
+        // nicht beruecksichtigt werden
+        if (escaped == TRUE) {
+            escaped = FALSE;
+        } else {
+            size_t cur_size = (uintptr_t) pos - (uintptr_t) last_element;
+            
+            switch(*pos) {
+                // Wenn das aktuelle Zeichen ein Escape ist, wird escaped auf TRUE
+                // gesetzt, damit das naechste Zeichen nicht beachtet wird
+                case '\\':
+                    // Das abschliessende Null-Byte darf natuerlich nicht
+                    // ignoriert werden, da wir sonst ueber den String
+                    // rausrasseln ohne es zu merken.
+                    if (*(pos + 1) != '\0') {
+                        escaped = TRUE;
+                    }
+                    break;
+                
+                // Auf Service-Seperator :/ Pruefen
+                case ':':
+                    if (*(pos + 1) == '/') {
+                        element = create_path_element(last_element, cur_size,
+                            left_sep, SERVICE_SEP);
+
+                        // Da dieser Seperator 2 Zeichen lang ist, muss pos
+                        // manuell schon einmal inkrementiert werden;
+                        pos++;
+                    }
+                    break;
+
+                case '/':
+                    element = create_path_element(last_element, cur_size,
+                        left_sep, PATH_SEP);
+                    break;
+
+                case '|':
+                    element = create_path_element(last_element, cur_size,
+                        left_sep, PIPE_SEP);
+                    break;
+
+                // String-Ende
+                case '\0':
+                    element = create_path_element(last_element, cur_size,
+                        left_sep, NO_SEP);
+                    break;
+            }
+        }
+
+        // Wenn im aktuellen durchlauf ein Element gefunden wurde, werden die
+        // Pointer fuer den Anfang des naechhsten Elements und dessen linker
+        // Seperator gesetzt
+        if (element != NULL) {
+            left_sep = element->right_sep;
+            last_element = pos + 1;
+            
+            // Das Element in die Liste einfuegen
+            list_insert(list, position, element);
+            element_count++;
+
+            // Pointer wieder auf NULL setzen, damit wir im naechsten Durchlauf
+            // nicht wieder hier landen, obwohl gar kein Element zu Ende war.
+            element = NULL;
+        }
+        
+        // Am Ende angekommen?
+        if (*pos == '\0') {
+            break;
+        }
+
+        // Pointer auf das naechste Zeichen zeigen lassen
+        pos++;
+    }
+    
+    return element_count;
+}
+
+/**
+ * Ueberarbeitet einen Pfad, der in die einzelnen Elemente zerlegt als liste
+ * uebergeben wird, so dass keine Dot und Dotdot-Elemente mehr vorkommen
+ *
+ * @param list Liste mit den Elementen
+ */
+static void eliminate_dot_elements(list_t* list)
+{
+    int i = 0;
+    int dotdot = 0;
+    struct path_element* element;
+    while ((element = list_get_element_at(list, i))) {
+        // Bei Dotdot wird das aktuelle geloescht und dotdot inkrementiert,
+        // damit die naechsten Elemente entsprechend geloescht werden
+        if (strcmp(element->text, "..") == 0) {
+            list_remove(list, i);
+            free(element);
+            dotdot++;
+        }
+        // Dot-Elemente und leere werden einfach verworfen
+        else if ((strcmp(element->text, ".") == 0) || (strlen(element->text)
+            == 0))
+        {
+            list_remove(list, i);
+            free(element);
+        }
+        // Alles andere bleibt gleich
+        else {
+            // Wenn Dotdot-Elemente da waren, muss das Element geloescht werden
+            // und dotdot dekrementiert
+            if (dotdot != 0) {
+                list_remove(list, i);
+                free(element);
+                dotdot--;
+            } else {
+                i++;
+            }
+        }
+    }
+}
+
+/**
+ * Verarbeitet einen Pfad relativ zum aktuellen Verzeichnis
+ *
+ * @param list Pfad als Liste
+ */
+static inline void resolve_relative_path(list_t* list)
+{
+    char* cwd = getcwd(NULL, 0);
+    struct path_element* element;
+    int last_element = list_size(list);
+
+    // CWD-Elemente holen und an Liste anhaengen
+    get_path_elements(cwd, list, last_element);
+
+    // Beim letzten Element muss noch der Seperator angepasst werden
+    // TODO: Stimmt das?
+    element = list_get_element_at(list, last_element);
+    element->right_sep = PATH_SEP;
+
+    free(cwd);
+}
+
+/**
+ * Verarbeitet einen Pfad relativ zum aktuellen Service verarbeiten. Dabei
+ * werden von CWD erst alle verzeichnisse bis zum hintersten Service abgetrennt
+ * werden, und danach wird das was uebrig bleibt vor den anderen Pfad
+ * geschrieben (Achtung: Auch hier wieder ist die Liste in der umgekehrten
+ * Reihenfolge).
+ *
+ * @param list Pfad als Liste
+ */
+static inline void resolve_relative_serv_path(list_t* list)
+{
+
+    // Temporaere Liste fuer die CWD-Elemente erstellen
+    list_t* cwd_list = list_create();
+
+    // CWD-Elemente holen und an Liste anhaengen
+    char* cwd = getcwd(NULL, 0);
+    get_path_elements(cwd, cwd_list, 0);
+    free(cwd);
+    struct path_element* element;
+    
+    
+    // Jetzt werden alle Elemente bis zum Service-Element verworfen
+    int i = 0;
+    while ((element = list_get_element_at(cwd_list, i)) && (element->
+        right_sep != SERVICE_SEP))
+    {
+        list_remove(cwd_list, i);
+        free(element);
+
+        i++;
+    }
+
+    // Die uebrig gebliebenen Elemente werden an die Pfad-Liste angehaengt
+    int last_element = list_size(list);
+    i = list_size(cwd_list);
+    while ((element = list_get_element_at(cwd_list, --i))) {
+        list_insert(list, last_element, element);
+    }
+    
+    list_destroy(cwd_list);
+}
+
+/**
+ * Berechnet wieviel Speicher ein Pfad in Listenform benoetigt, wenn er in
+ * einen String umgewandelt wird
+ *
+ * @param list Liste mit den Elementen
+ *
+ * @return Anzahl der notwendigen Bytes (ohne abschliessendes Nullbyte)
+ */
+static inline size_t calc_path_length(list_t* list)
+{
+    size_t size = 0;
+    int i = 0;
+    struct path_element* element;
+    while ((element = list_get_element_at(list, i++))) {
+        size += strlen(element->text);
+        // Berechnen, wieviel Speicher der Seperator belegen wird
+        switch (element->right_sep) {
+            case SERVICE_SEP:
+                size += strlen(":/");
+                break;
+
+            case PATH_SEP:
+            case PIPE_SEP:
+                // strlen("/") resp. strlen("|");
+                size += 1;
+                break;
+
+            case NO_SEP:
+                // Der brauch garnichts, aber sonst warnt gcc
+                break;
+        }
+    }
+    
+    return size;
+}
+
+/**
+ * Wandelt den Pfad von der Listen-Form in einen String um, und gibt alle
+ * Elemente Frei. 
+ *
+ * @param list Pfad als Liste
+ * @param buffer Puffer in dem der String gespeichert werden soll
+ * @param free_element TRUE, falls die elemente gefreet werden sollen
+ */
+static inline void create_path_string(list_t* list, char* buffer,
+    bool free_element)
+{
+    // Jetzt muss der Pfad rueckwaerts abgearbeitet werden, damit er im String
+    // in der richtigen reihenfolge ist
+    int i = list_size(list);
+    size_t size;
+    struct path_element* element;
+    while ((element = list_get_element_at(list, --i))) {
+        // Element-Text kopieren
+        size = strlen(element->text);
+        memcpy(buffer, element->text, size);
+        buffer += size;
+        
+        // Seperator einfuegen
+        switch (element->right_sep) {
+            case SERVICE_SEP:
+                *(buffer++) = ':';
+                *(buffer++) = '/';
+                break;
+
+            case PATH_SEP:
+                *(buffer++) = '/';
+                break;
+
+            case PIPE_SEP:
+                *(buffer++) = '|';
+                break;
+
+            case NO_SEP:
+                // Nur um Warnungen zu verhindern
+                break;
+        }
+        
+        if (free_element == TRUE) {
+            free(element);
+        }
+    }
+    *buffer = '\0';
+}
+
+/**
+ * Erstellt aus einem Beliebigen Pfad einen absoluten
+ *
+ * @param path Pointer auf dem Pfad
+ *
+ * @return Pointer auf ein neu alloziertes Stueck Speicher in dem der neue Pfad
+ *          liegt. Also free() nicht vergessen ;-)
+ */
+char* io_get_absolute_path(const char* path)
+{
+    struct path_element* element;
+    // Liste fuer die Elemente des Pfades
+    list_t* element_stack = list_create();
+    // Elemente holen, und an Liste anhaengen
+    get_path_elements(path, element_stack, 0);
+
+    
+    // Jetzt werden relative Pfade aufgeloest
+    // Dafuer gibt es 2 verschiedene Moeglichkeiten. Die eine sind die Pfade
+    // relativ zum aktuellen Verzeichnis, wie man sie zum Beispiel von Linux
+    // kennt, die anderen beginnen mit einem / und sind dadurch relativ zum
+    // aktuellen Service.
+    //
+    // Beispiel:
+    // CWD sei ide:/hda1|fat:/data
+    // Dann wird ein "foo/bar" zu "ide:/hda1|fat:/data/foo/bar"
+    // Und ein "/test" zu "ide:/hda1|fat:/test"
+    //
+    // Entschieden wird das anhand des ersten Elements des Pfades. Wenn kein
+    // Serperator links ist, handelt es sich um einen Pfad relativ zum
+    // aktuellen Verzeichnis oder um einen absoluten, wenn der Seperator rechts
+    // kein Service-Seperator ist, denn dann ist er relativ zum Verzeichnis,
+    // sonst absolut. Die Pfade relativ zum aktuellen Service werden einfach
+    // anhand des Pfad-Seperators Links erkannt.
+    
+    // Das erste Element ist aufgrund der Reihenfolge in der Liste das letzte,
+    // also das mit dem höchsten Index.
+    int last_element = list_size(element_stack) - 1;
+    element = list_get_element_at(element_stack, last_element);
+    
+    if ((element->left_sep == NO_SEP) && (element->right_sep != SERVICE_SEP)) {
+        // Pfad relativ zum aktuellen Verzeichnis
+        resolve_relative_path(element_stack);
+    } else if (element->left_sep == PATH_SEP) {
+        // Pfad relativ zum aktuellen Serivice
+        resolve_relative_serv_path(element_stack);
+    } 
+    
+    // Dot und Dotdot Elemente eliminieren
+    eliminate_dot_elements(element_stack);
+    
+    // Berechnen, wieviel Speicher der fertige Pfad belegt
+    size_t size = calc_path_length(element_stack);
+    
+    // Jezt ist es soweit, der neue Pfad kann kopiert werden
+    char* new_path = malloc(size + 1);
+    create_path_string(element_stack, new_path, TRUE);
+
+    list_destroy(element_stack);
+    return new_path;
+}
+
Index: src/modules/lib/stdlibc/file.c
===================================================================
--- src/modules/lib/stdlibc/file.c	(Revision 590)
+++ src/modules/lib/stdlibc/file.c	(Arbeitskopie)
@@ -45,69 +45,8 @@
 #define IO_BUFFER_MODE_FULL 1
 #define IO_BUFFER_MODE_LINE 2
 
+extern char* io_get_absolute_path(const char* path);
 
-char* io_get_absolute_path(const char* path)
-{
-    const char* cwd = getcwd(NULL, 0);
-    if (cwd == NULL) {
-        cwd = path;
-    }
-    char* buffer = malloc(strlen(path) + strlen(cwd) + 2);
-    size_t cwd_len = strlen(cwd);
-    
-    //Ueberpruefen, ob ein relativer pfad vorliegt
-    if(strcmp(path, "..") == 0)
-    {
-        //CWD kopieren
-        memcpy(buffer, cwd, cwd_len + 1);
-
-        int i = strlen(buffer) - 2;
-        for(; i > 0; i--)
-        {
-            if(buffer[i] == '/')
-            {
-                if(buffer[i-1] == ':')
-                {
-                    i++;
-                }
-                buffer[i] = 0;
-                break;
-            }
-        }
-    }
-    else if((strcmp(path, ".") == 0) && (strlen(path) == 1))
-    {
-        memcpy(buffer, cwd, cwd_len);
-        buffer[cwd_len] = 0;
-    }
-    else if(strstr(path, ":/") == NULL)
-    {
-        //CWD kopieren
-        memcpy(buffer, cwd, cwd_len);
-
-
-        if(buffer[cwd_len-1] != '/')
-        {
-            buffer[cwd_len] = '/';
-            memcpy((void*)((dword)buffer + cwd_len + 1), path, strlen(path) + 1);
-        }
-        else
-        {
-            memcpy((void*)((dword)buffer + cwd_len), path, strlen(path) + 1);
-        }
-    }
-    else
-    {
-        memcpy(buffer, path, strlen(path) + 1);
-    }
-    
-    if (cwd != path) {
-        free((char*) cwd);
-    }
-    return buffer;
-}
-
-
 /**
  * Datei oeffnen
  *