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

[tyndur-devel] [PATCH v2 6/6] libc: LIOv2-Clientunterstützung



+ libc: Die stdio-Funktionen können jetzt sowohl mit LIOv1- als auch
  LIOv2-Dateien umgehen. Ein gegen diese libc-Version gebautes Programm
  kann also unter einem LIOv2-fähigen Kernel auf alle Dateien zugreifen.
  Mit dem aktuellen Kernel bleibt die Erweiterung wirkungslos, auf
  älteren Kerneln wird das Programm mit einem unbekannten Syscall
  abstürzen.

Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
 src/include/syscall_structs.h        |   48 +++++++++++++
 src/modules/include/dir.h            |    4 +
 src/modules/include/io_struct.h      |    3 +
 src/modules/include/lostio.h         |   11 +++-
 src/modules/lib/lostio/client/file.c |  105 +++++++++++++++++++++++++++-
 src/modules/lib/lostio/client/seek.c |   19 +++++
 src/modules/lib/stdlibc/directory.c  |  129 +++++++++++++++++++++++++++++++++-
 src/modules/lib/stdlibc/file.c       |   36 ++++++++--
 8 files changed, 345 insertions(+), 10 deletions(-)

diff --git a/src/include/syscall_structs.h b/src/include/syscall_structs.h
index c23d39e..6ec63a0 100644
--- a/src/include/syscall_structs.h
+++ b/src/include/syscall_structs.h
@@ -83,6 +83,54 @@ typedef int64_t lio_usp_stream_t;
 typedef int64_t lio_usp_resource_t;
 
 /**
+ * Beschreibt als Bitmaske den Modus, in dem ein Stream arbeiten soll.
+ */
+enum lio_flags {
+    /**
+     * Die Ressource soll beim Öffnen auf Größe 0 gekürzt werden. Nur
+     * gültig, wenn die Datei auch zum Schreiben geöffnet wird.
+     */
+    LIO_TRUNC       =   1,
+
+    /** Die Ressource soll zum Lesen geöffnet werden */
+    LIO_READ        =   2,
+
+    /** Die Ressource soll zum Schreiben geöffnet werden */
+    LIO_WRITE       =   4,
+
+    /**
+     * Die Ressource soll im Writethrough-Modus geöffnet werden, d.h. alle
+     * Änderungen werden sofort persistent gemacht.
+     */
+    /* TODO LIO_WRTHROUGH   =  32, */
+
+    /** Der Cache soll nicht benutzt werden */
+    /* TODO LIO_NOCACHE     =  64, */
+
+    /**
+     * Wenn auf die Ressource geschrieben oder von ihr gelesen werden soll, sie
+     * aber nicht bereit ist, soll die Anfrage blockieren anstatt einen Fehler
+     * zurückzugeben.
+     *
+     * TODO Short Reads/Writes möglich?
+     */
+    /* TODO LIO_BLOCKING    = 128, */
+
+    /**
+     * Der Inhalt der Ressource ist nicht reproduzierbar (z.B. Netzwerk).
+     * Er muss im Cache behalten werden, solange er benutzt wird.
+     */
+    /* TODO LIO_VOLATILE    = 256, */
+
+    /**
+     * Muss zum Öffnen von Symlinks gesetzt sein, darf für andere Ressourcen
+     * nicht gesetzt sein.
+     */
+    LIO_SYMLINK     = 512,
+};
+
+
+/**
  * Gibt an, realtiv zu welcher Position in der Datei das lio_seek-Offset
  * zu interpretieren ist.
  */
diff --git a/src/modules/include/dir.h b/src/modules/include/dir.h
index 3056c0d..4fbf63a 100644
--- a/src/modules/include/dir.h
+++ b/src/modules/include/dir.h
@@ -31,9 +31,13 @@
 #include "types.h"
 #include "stdio.h"
 #include "io.h"
+#include <dirent.h>
 
 struct dir_handle {
+    bool old;
     io_resource_t* lio1_handle;
+    lio_resource_t new_res;
+    size_t offset;
 };
 
 struct dir_handle* directory_open(const char* dirname);
diff --git a/src/modules/include/io_struct.h b/src/modules/include/io_struct.h
index 665ab38..e2500a2 100644
--- a/src/modules/include/io_struct.h
+++ b/src/modules/include/io_struct.h
@@ -29,6 +29,7 @@
 #define _IO_STRUCT_H_
 #include <stdint.h>
 #include <sys/types.h>
+#include <syscall.h>
 
 #define MAX_FILENAME_LEN 255
 #define IO_DIRENTRY_FILE 1
@@ -52,6 +53,8 @@ typedef struct
     pid_t               pid;
     io_resource_id_t    resid;
 
+    lio_stream_t        lio2_stream;
+    lio_resource_t      lio2_res;
 } __attribute__ ((packed)) io_resource_t;
 #endif //ifndef _IO_STRUCT_H_
 
diff --git a/src/modules/include/lostio.h b/src/modules/include/lostio.h
index f70a7d1..8fc4e4d 100644
--- a/src/modules/include/lostio.h
+++ b/src/modules/include/lostio.h
@@ -130,8 +130,17 @@ struct lostio_internal_file {
     size_t          buffer_pos;
     uint8_t         buffer_mode;
     bool            free_buffer;
-};
 
+    /*
+     * Achtung: os_eof ist _nicht_ der EOF-Marker aus der C-Spezifikation, der
+     * erst gesetzt wird, wenn das Programm aus dem Puffer das letzte Byte
+     * einliest, sondern das EOF, auf das beim Einlesen des Puffers gestoßen
+     * wurde!
+     */
+    bool            os_eof;
+    bool            error;
+};
+#define IS_LIO2(h) (h->lio2_res > 0)
 
 ///LostIO-Schnittstelle initialisieren
 void lostio_init(void);
diff --git a/src/modules/lib/lostio/client/file.c b/src/modules/lib/lostio/client/file.c
index 142de7d..8fe5ebe 100644
--- a/src/modules/lib/lostio/client/file.c
+++ b/src/modules/lib/lostio/client/file.c
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <rpc.h>
 #include <syscall.h>
+#include <errno.h>
 
 static void* shm_ptr;
 static uint32_t shm_id;
@@ -54,11 +55,87 @@ static void* get_shm(size_t size)
     return shm_ptr;
 }
 
+static io_resource_t* lio2_open(const char* filename, uint8_t attr)
+{
+    char* full_path;
+    uint8_t lio2_attr = 0;
+    bool m_append = false;
+    bool m_create = false;
+
+    lio_stream_t s;
+    lio_resource_t r;
+    io_resource_t* result = NULL;
+
+    full_path = io_get_absolute_path(filename);
+    if (!full_path) {
+        return NULL;
+    }
+
+    /* Modus auswerten */
+    if (attr & ~(IO_OPEN_MODE_READ | IO_OPEN_MODE_WRITE | IO_OPEN_MODE_CREATE
+        | IO_OPEN_MODE_TRUNC | IO_OPEN_MODE_APPEND))
+    {
+        goto out_err;
+    }
+
+    if (attr & IO_OPEN_MODE_READ)   lio2_attr |= LIO_READ;
+    if (attr & IO_OPEN_MODE_WRITE)  lio2_attr |= LIO_WRITE;
+    if (attr & IO_OPEN_MODE_CREATE) m_create = true;
+    if (attr & IO_OPEN_MODE_TRUNC)  lio2_attr  |= LIO_TRUNC;
+    if (attr & IO_OPEN_MODE_APPEND) m_append = true;
+
+    /* Datei erzeugen, falls nötig */
+    r = lio_resource(full_path, 1);
+    if ((r < 0) && m_create) {
+        lio_resource_t parent;
+        char* dirname = io_split_dirname(full_path);
+        char* filename = io_split_filename(full_path);
+
+        if ((parent = lio_resource(dirname, 1)) > 0) {
+            r = lio_mkfile(parent, filename);
+        }
+
+        free(dirname);
+        free(filename);
+    }
+
+    if (r < 0) {
+        goto out_err;
+    }
+
+    /* Datei öffnen */
+    s = lio_open(r, lio2_attr);
+    if (s < 0) {
+        goto out_err;
+    }
+
+    if (m_append) {
+        lio_seek(s, 0, LIO_SEEK_END);
+    }
+
+    /* Datenstruktur anlegen */
+    result = malloc(sizeof(*result));
+    *result = (io_resource_t) {
+        .lio2_stream    =   s,
+        .lio2_res       =   r,
+    };
+
+out_err:
+    free(full_path);
+    return result;
+}
+
 io_resource_t* lio_compat_open(const char* filename, uint8_t attr)
 {
-    char* full_path = io_get_absolute_path(filename);
+    char* full_path;
     io_resource_t* result;
 
+    result = lio2_open(filename, attr);
+    if (result) {
+        return result;
+    }
+
+    full_path = io_get_absolute_path(filename);
     if (!full_path) {
         return NULL;
     }
@@ -88,9 +165,27 @@ out:
     return result;
 }
 
+static int lio2_fclose(io_resource_t* stream)
+{
+    int result = 0;
+
+    if (stream->lio2_stream > 0) {
+        result = lio_close(stream->lio2_stream);
+    }
+    free(stream);
+
+    return result;
+}
+
+
 int lio_compat_close(io_resource_t* io_res)
 {
     uint32_t result;
+
+    if (IS_LIO2(io_res)) {
+        return lio2_fclose(io_res);
+    }
+
     result = rpc_get_dword(io_res->pid, "IO_CLOSE",
         sizeof(io_resource_id_t), (char*) &(io_res->id));
     free(io_res);
@@ -114,6 +209,10 @@ ssize_t lio_compat_read(void* dest, size_t blocksize, size_t blockcount,
         .blockcount = blockcount,
     };
 
+    if (IS_LIO2(io_res)) {
+        return lio_read(io_res->lio2_stream, blocksize * blockcount, dest);
+    }
+
     // Wenn mehr als 256 Bytes gelesen werden sollen, wird SHM benutzt
     if ((blocksize * blockcount) > 256) {
 
@@ -170,6 +269,10 @@ ssize_t lio_compat_write(const void* src, size_t blocksize, size_t blockcount,
     size_t data_size = blockcount * blocksize;
     size_t request_size = sizeof(io_write_request_t);
 
+    if (IS_LIO2(io_res)) {
+        return lio_write(io_res->lio2_stream, blocksize * blockcount, src);
+    }
+
     // Bei mehr als einem Kilobyte wird shared memory fuer die Daten benutzt
     if (data_size < 1024) {
         request_size += data_size;
diff --git a/src/modules/lib/lostio/client/seek.c b/src/modules/lib/lostio/client/seek.c
index 8564486..2ad7a84 100644
--- a/src/modules/lib/lostio/client/seek.c
+++ b/src/modules/lib/lostio/client/seek.c
@@ -30,6 +30,20 @@
 #include <stdio.h>
 #include <rpc.h>
 #include <stdint.h>
+#include <stdio.h>
+static bool newlio_flseek(io_resource_t* io_res, uint64_t offset, int origin)
+{
+    int whence;
+
+    switch (origin) {
+        case SEEK_SET: whence = LIO_SEEK_SET; break;
+        case SEEK_CUR: whence = LIO_SEEK_CUR; break;
+        case SEEK_END: whence = LIO_SEEK_END; break;
+        default: return false;
+    }
+
+    return lio_seek(io_res->lio2_stream, offset, whence) >= 0;
+}
 
 /**
  * Cursorposition im Dateihandle setzen
@@ -47,6 +61,11 @@ bool lio_compat_seek(io_resource_t* io_res, uint64_t offset, int origin)
 {
     io_seek_request_t seek_request;
 
+
+    if (IS_LIO2(io_res)) {
+        return newlio_flseek(io_res, offset, origin);
+    }
+
     seek_request.id = io_res->id;
     seek_request.offset = offset;
     seek_request.origin = origin;
diff --git a/src/modules/lib/stdlibc/directory.c b/src/modules/lib/stdlibc/directory.c
index 216df40..fbfcf3a 100644
--- a/src/modules/lib/stdlibc/directory.c
+++ b/src/modules/lib/stdlibc/directory.c
@@ -32,27 +32,69 @@
 #include "stdlib.h"
 #include "dir.h"
 #include <string.h>
+#include <lostio.h>
+
+static struct dir_handle* new_opendir(const char* path)
+{
+    struct dir_handle* handle = NULL;
+    lio_resource_t res;
+    char* abspath = io_get_absolute_path(path);
+
+    res = lio_resource(abspath, 1);
+    if (res < 0) {
+        goto out;
+    }
+
+    /* Prüfen, ob es auch wirklich ein Verzeicnis ist */
+    if (lio_read_dir(res, 0, 0, NULL) != 0) {
+        goto out;
+    }
+
+    handle = malloc(sizeof(*handle));
+    handle->old = false;
+    handle->new_res = res;
+    handle->offset = 0;
+
+out:
+    free(abpath);
+    return handle;
+}
 
 struct dir_handle* directory_open(const char* path)
 {
     struct dir_handle* handle;
     io_resource_t* io_res;
 
+    handle = new_opendir(path);
+    if (handle) {
+        return handle;
+    }
+
     io_res = lio_compat_open(path, IO_OPEN_MODE_READ | IO_OPEN_MODE_DIRECTORY);
     if (io_res == NULL) {
         return NULL;
     }
 
     handle = malloc(sizeof(*handle));
+    handle->old = true;
     handle->lio1_handle = io_res;
 
     return handle;
 }
 
+static int new_closedir(struct dir_handle* handle)
+{
+    free(handle);
+    return 0;
+}
 int directory_close(struct dir_handle* handle)
 {
     int result = 0;
 
+    if (!handle->old) {
+        return new_closedir(handle);
+    }
+
     if (lio_compat_close(handle->lio1_handle)) {
         result = -1;
     }
@@ -61,10 +103,35 @@ int directory_close(struct dir_handle* handle)
     return result;
 }
 
+static io_direntry_t* new_directory_read(struct dir_handle* handle)
+{
+    io_direntry_t* ent = NULL;
+    struct lio_dir_entry lent;
+
+    if (lio_read_dir(handle->new_res, handle->offset, 1, &lent) == 1) {
+        ent = calloc(sizeof(*ent), 1);
+        strcpy(ent->name, lent.name);
+        ent->type =
+            (((lent.stat.flags & LIO_FLAG_READABLE) |
+                (lent.stat.flags & LIO_FLAG_WRITABLE)) ? IO_DIRENTRY_FILE : 0)|
+            ((lent.stat.flags & LIO_FLAG_BROWSABLE) ? IO_DIRENTRY_DIR : 0) |
+            ((lent.stat.flags & LIO_FLAG_RESOLVABLE) ? IO_DIRENTRY_LINK : 0);
+        ent->size = lent.stat.size;
+
+        handle->offset++;
+    }
+
+    return ent;
+}
+
 io_direntry_t* directory_read(struct dir_handle* io_res)
 {
     int ret;
 
+    if (!io_res->old) {
+        return new_directory_read(io_res);
+    }
+
     if ((io_res == NULL) || (lio_compat_eof(io_res->lio1_handle) != 0)) {
         return NULL;
     }
@@ -82,10 +149,44 @@ io_direntry_t* directory_read(struct dir_handle* io_res)
 
 int directory_seek(struct dir_handle* handle, long int offset, int origin)
 {
+    if (IS_LIO2(handle)) {
+        switch (origin) {
+            case SEEK_SET:
+                break;
+            case SEEK_CUR:
+                offset += (handle->offset * sizeof(io_direntry_t));
+                break;
+            case SEEK_END:
+            default:
+                return -1;
+        }
+        handle->offset = offset / sizeof(io_direntry_t);
+        return offset;
+    }
+
     return lio_compat_seek(handle->lio1_handle, offset, origin);
 }
 
-bool directory_create(const char* dirname)
+static bool new_directory_create(const char* path)
+{
+    char* abs = io_get_absolute_path(path);
+    char* dir = io_split_dirname(abs);
+    char* file = io_split_filename(abs);
+    bool result = false;
+    lio_resource_t parent;
+
+    if ((parent = lio_resource(dir, 1)) >= 0) {
+        result = (lio_mkdir(parent, file) >= 0);
+    }
+
+    free(dir);
+    free(file);
+    free(abs);
+
+    return result;
+}
+
+static bool old_directory_create(const char* dirname)
 {
     io_resource_t* io_res = lio_compat_open(dirname,
         IO_OPEN_MODE_WRITE | IO_OPEN_MODE_CREATE | IO_OPEN_MODE_TRUNC |
@@ -99,9 +200,25 @@ bool directory_create(const char* dirname)
     return true;
 }
 
-bool is_directory(const char* dirname)
+bool directory_create(const char* dirname)
+{
+    return new_directory_create(dirname) || old_directory_create(dirname);
+}
+
+static bool new_is_directory(const char* path)
 {
-    struct dir_handle* dir = directory_open(dirname);
+    lio_resource_t res = lio_resource(path, 1);
+
+    if (res < 0) {
+        return false;
+    }
+
+    return (lio_read_dir(res, 0, 0, NULL) == 0);
+}
+
+static bool old_is_directory(const char* path)
+{
+    struct dir_handle* dir = directory_open(path);
     if (dir != NULL) {
         directory_close(dir);
         return true;
@@ -109,3 +226,9 @@ bool is_directory(const char* dirname)
         return false;
     }
 }
+
+bool is_directory(const char* dirname)
+{
+    return new_is_directory(dirname) || old_is_directory(dirname);
+}
+
diff --git a/src/modules/lib/stdlibc/file.c b/src/modules/lib/stdlibc/file.c
index 759c73c..559920f 100644
--- a/src/modules/lib/stdlibc/file.c
+++ b/src/modules/lib/stdlibc/file.c
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <stdint.h>
 #include <syscall.h>
+#include <errno.h>
 
 #define IO_BUFFER_MODE_NONE 0
 #define IO_BUFFER_MODE_FULL 1
@@ -42,9 +43,11 @@
 
 extern char* io_get_absolute_path(const char* path);
 
+#define IS_LIO2_FILE(f) IS_LIO2(f->res)
+
 static bool is_valid_res(FILE* io_res)
 {
-    return (io_res != NULL) && (io_res->res->pid != 0);
+    return (io_res != NULL) && (IS_LIO2(io_res->res) || io_res->res->pid != 0);
 }
 
 /**
@@ -112,6 +115,9 @@ FILE* fopen (const char* filename, const char* mode)
     setvbuf(int_res, malloc(BUFSIZ), _IOFBF, BUFSIZ);
     int_res->free_buffer = true;
 
+    int_res->error = false;
+    int_res->os_eof = false;
+
     return int_res;
 }
 
@@ -222,8 +228,14 @@ size_t fread(void* dest, size_t blocksize, size_t blockcount, FILE* io_res)
 
     ret = lio_compat_read(dest + read_bytes,
         (blocksize * blockcount) - read_bytes, 1, io_res->res);
-    if (ret < 0) {
+
+    if (ret == -EAGAIN) {
+        return 0;
+    } else if (ret < 0) {
+        io_res->error = true;
         return 0;
+    } else if (!ret) {
+        io_res->os_eof = true;
     }
 
     return (read_bytes + ret) / blocksize;
@@ -367,6 +379,7 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
         case IO_BUFFER_MODE_NONE:
             ret = lio_compat_write(data, blocksize, blockcount, io_res->res);
             if (ret < 0) {
+                io_res->error = true;
                 return 0;
             } else {
                 return ret / blocksize;
@@ -389,6 +402,7 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
                 }
                 ret = lio_compat_write(data, blocksize, blockcount, io_res->res);
                 if (ret < 0) {
+                    io_res->error = true;
                     return 0;
                 } else {
                     return ret / blocksize;
@@ -409,6 +423,7 @@ size_t fwrite(const void* data, size_t blocksize, size_t blockcount,
                 }
                 ret = lio_compat_write(data, blocksize, blockcount, io_res->res);
                 if (ret < 0) {
+                    io_res->error = true;
                     return 0;
                 } else {
                     return ret / blocksize;
@@ -509,6 +524,11 @@ long ftell(FILE* io_res)
         return EOF;
     }
 
+    if (IS_LIO2_FILE(io_res)) {
+        int64_t pos = lio_seek(io_res->res->lio2_stream, 0, LIO_SEEK_CUR);
+        return (pos < 0 ? -1 : pos);
+    }
+
     io_tell_request_t tell_request;
     long result;
     tell_request.id = io_res->res->id;
@@ -549,6 +569,12 @@ int feof(FILE* io_res)
         return 0;
     }
 
+    if (IS_LIO2_FILE(io_res)) {
+        // FIXME: EOF ist hier eigentlich doof, aber irgend ein Idiot hat das
+        // mal so implementiert und das wird teilweise so geprüft... ;-)
+        return (io_res->os_eof ? EOF : 0);
+    }
+
     //Auch hier könnte mit Daten im Buffer ein falsches Ergebnis rauskommen
     fflush(io_res);
 
@@ -566,8 +592,7 @@ int feof(FILE* io_res)
  */
 int ferror(FILE* io_res)
 {
-    //FIXME
-    return 0;
+    return io_res->error;
 }
 
 
@@ -578,7 +603,8 @@ int ferror(FILE* io_res)
  */
 void clearerr(FILE* io_res)
 {
-    // TODO
+    io_res->error = false;
+    io_res->os_eof = false;
 }
 
 
-- 
1.6.0.2