[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