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

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



On Sun, Sep 25 18:02, Kevin Wolf wrote:
> + 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        |   45 ++++++++++++++
>  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 |  103 +++++++++++++++++++++++++++++++-
>  src/modules/lib/lostio/client/seek.c |   19 ++++++
>  src/modules/lib/stdlibc/directory.c  |  112 +++++++++++++++++++++++++++++++++-
>  src/modules/lib/stdlibc/file.c       |   36 +++++++++--
>  8 files changed, 323 insertions(+), 10 deletions(-)
> 
> diff --git a/src/include/syscall_structs.h b/src/include/syscall_structs.h
> index c23d39e..3b129dc 100644
> --- a/src/include/syscall_structs.h
> +++ b/src/include/syscall_structs.h
> @@ -83,6 +83,51 @@ 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, */
> +
> +    /** Symlinks nicht folgen, sondern den Link selbst öffnen */

Mit folgen hat das nichts mehr zu tun, soweit ich das sehe. Wird nur
noch benutzt, dass ein Symlink nur explizit als solcher geöffnet werden
kann.

> +    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 5aa580c..9e5a73c 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..5b3e68b 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,85 @@ 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; sonst wird full_path geleakt.

> +        return NULL;
> +    }
> +
> +    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);
> +

Wenn du schon dabei bist, mich stört die Leerzeile hier, lieber nach
dem }

> +        }
> +        free(dirname);
> +        free(filename);
> +    }
> +
> +    if (r < 0) {
> +        goto out_err;
> +    }
> +
> +    /* Datei öffnen */
> +    if ((s = lio_open(r, lio2_attr)) < 0) {
> +        goto out_err;
> +    }
> +
> +    if (m_append) {
> +        // FIXME lio_seek();

Müsste jetzt eigentlich ein einzeiler sein, oder? Oder sonst wäre da
vielelicht ein lio_close(s); goto out_err; nicht schlecht.

> +    }
> +
> +    /* Datenstruktur anlegen */
> +    result = malloc(sizeof(*result));

Vielleicht lieber calloc, oder werden die felder unten eh alle mit 0
überschrieben?

> +    *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 +163,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 +207,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 +267,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;

Hier kommt ja irgendwo noch lio_compat_eof(). Dort wäre es vielleicht
auch nicht schlecht, wenn da der lio2-Fall noch irgendwie abgefangen
wird, wobei ich gerade unsicher bin was da als rückgabe sinnvoll ist.

> 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..f2156d4 100644
> --- a/src/modules/lib/stdlibc/directory.c
> +++ b/src/modules/lib/stdlibc/directory.c
> @@ -32,27 +32,67 @@
>  #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;
> +    lio_resource_t res;
> +    char* abspath = io_get_absolute_path(path);
> +
> +    res = lio_resource(abspath, 1);

free(abspath)

> +    if (res < 0) {
> +        return NULL;
> +    }
> +
> +    /* Prüfen, ob es auch wirklich ein Verzeicnis ist */
> +    if (lio_read_dir(res, 0, 0, NULL) != 0) {
> +        return NULL;
> +    }
> +
> +    handle = malloc(sizeof(*handle));
> +    handle->old = false;
> +    handle->new_res = res;
> +    handle->offset = 0;
> +
> +    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 +101,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 +147,29 @@ io_direntry_t* directory_read(struct dir_handle* io_res)
>  
>  int directory_seek(struct dir_handle* handle, long int offset, int origin)
>  {
> +    /* TODO LIOv2-Variante */

Sollten wir hier im LIOv2-Fall nicht wenigstens ein -1 zurückgeben oder
sowas?

>      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;
> +
> +    printf("new_directory(%s) dir='%s' file='%s'\n", path, dir, file);

Hm wollen wir das printf() wirklich in master haben?

> +    if ((parent = lio_resource(dir, 1)) >= 0) {
> +        result = (lio_mkdir(parent, file) >= 0);
> +    }
> +
> +    free(dir);
> +    free(file);

free(abs) fehlt hier, oder?

> +    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 +183,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 +209,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 f540bc7..3c3a09c 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;
>  }

-- 
Antoine Kaufmann
<toni@xxxxxxxxxxxxxxxx>

Attachment: signature.asc
Description: Digital signature