Hi,
Dann muss ich mir das wohl noch mal genauer anschauen...
Dann muss ich mir das wohl noch mal genauer anschauen...
09. November 2026, 18:28
F S - S U B System
=======================
F E . | P S . | D . \
A X . | R Y . | E . \ Implementiert
T T . | O S . | V . / CDI.FS
2 | G | /
=======================
Block | Kernel | Hard
device | infos | Ware
Lost hat im Kernel ein, Ich nene es mal FS - SUB system, das Dateisystem operationen aus dem Userspace entgegennimt ( durch bereitstellen entsprechender Funktionen ) die dann dort in den Kernelspace übertragen werden. Das FS-SUB greift dann auf die entsprechenden CDI.FS Treiber zurück um dann die Dateioperatioen schlussendlich durchzuführen.Jein. Das FS-Subsystem wie du es nennst (LostIO) sitzt nicht im Kernel, sondern in der libc der Userspace-Programme. Die Kommunikation läuft über die ganz normalen RPC-Funktionen.
Das CDI.FS bildet somit die schnittstelle für alle möglichen Dateisysteme. Nicht nur die echten wie z.B. FAT12/16/32 ext2/3 reiserfs, ... als auch die unechten / virtuellen wie z.B. prog / sys (sollten aus linux bekannt sein) sowie die Gerähtetreibercdi.fs deckt nur die echten Dateisysteme ab, wo es sinnvoll ist, eine OS-unabhängige Schnittstelle zu haben. Beim Rest wird direkt auf LostIO aufgesetzt.
#ifndef _CDI_FS_H_
#define _CDI_FS_H_
#include "types.h"
#include "cdi.h"
#include "cdi/lists.h"
struct cdi_fs_driver {
struct cdi_driver drv;
};
struct cdi_fs_device {
struct cdi_device dev;
};
struct cdi_fs_object;
/**
* Diese Struktur wird fuer jedes eingebundene Dateisystem einmal erstellt.
*/
struct cdi_fs_filesystem {
// Wurzelobjekt fuer die Baumstruktur
struct cdi_fs_object* root_object;
// Falls ein gravierender Fehler auftritt, wird diese Fehlernummer gesetzt.
// Wenn sie != 0 ist wird das Dateisystem fuer Schreibzugriffe gesperrt.
int error;
// Das Dateisystem darf nicht geschrieben werden. Damit schlaegt unter
// anderem cdi_fs_write_data fehl.
int read_only;
// Hier sollte man wohl noch ein paar allgemeine Mount-Optionen oder
// sonstige Flags die das ganze Dateisystem betreffen.
};
// XXX Bei den Fehlernummern weiss ich noch nicht wirklich, was da notwendig
// ist, deshalb lasse ich das mal so stehen.
typedef enum {
CDI_FS_ERROR_NONE = 0,
// Operation nicht unterstuetzt
CDI_FS_ERROR_ONS,
// Ressource nicht gefunden
CDI_FS_ERROR_RNF,
// Beim lesen einer Datei wurde das Ende erreicht
CDI_FS_ERROR_EOF,
// Interner Fehler
CDI_FS_ERROR_INTERNAL,
// Unbekannter Fehler
CDI_FS_ERROR_UNKNOWN,
} cdi_fs_error_t;
/**
* Der Stream stellt die Verbindung zwischen Aufrufer und Ressource dar.
*/
struct cdi_fs_stream {
// Betroffene Ressource
struct cdi_fs_resource* res;
// Fehlernummer
cdi_fs_error_t error;
};
/**
* Metaeigenschaften, die Ressourcen haben koennen
*/
typedef enum {
// R Groesse der Datei auslesen
CDI_FS_META_SIZE,
// R Anzahl der Benutzten Dateisystemblocks (Irgendwo muesste man dann
// auch auf diese Blockgroesse zurgreiffen koennen)
CDI_FS_META_USEDBLOCKS,
// R Optimale Blockgroesse mit der man auf die Datei zugreiffen sollte
CDI_FS_META_BESTBLOCKSZ,
// R Zeitpunkt an dem die Ressource erstellt wurde
CDI_FS_META_CREATETIME,
// RW Letzter Zugriff auf die Ressource, auch lesend
CDI_FS_META_ACCESSTIME,
// RW Letzte Veraenderung der Ressource
CDI_FS_META_CHANGETIME
} cdi_fs_meta_t;
/**
* Siese Struktur stellt die Moeglichkeiten, die an einer Ressource zur
* Verfuegung stehen, dar.
*/
struct cdi_fs_res_flags {
// Ressource loeschen
int remove;
// Ressource umbenennen
int rename;
// Ressource verschieben
int move;
// Lesender Zugriff gestattet
int read;
// Schreibender Zugriff gestattet
int write;
// Ausfuehren gestattet
int execute;
// Auflisten der Verzeichniseintraege gestattet
int browse;
// Aufloesen des Links
int read_link;
// Aendern des Links
int write_link;
// Anlegen eines Untereintrags
int create_child;
};
struct cdi_fs_res_file;
struct cdi_fs_res_dir;
struct cdi_fs_res_link;
struct cdi_fs_res_special;
/**
* Typ der eine Ressource, die zu der Klasse der Spezialdateien gehoert noch
* genauer beschreibt
*/
typedef enum {
CDI_FS_BLOCK,
CDI_FS_CHAR,
CDI_FS_FIFO,
CDI_FS_SOCKET
} cdi_fs_res_type_t;
/**
* Konstanten fuer die einzelnen Klassen, um sie beim Funktionsaufruf zum
* zuweisen einer Klasse, identifizieren zu koennen.
*/
typedef enum {
CDI_FS_CLASS_FILE,
CDI_FS_CLASS_DIR,
CDI_FS_CLASS_LINK,
CDI_FS_CLASS_SPECIAL
} cdi_fs_res_class_t;
/**
* Dieser Typ dient dazu Ressourcen ganz oder teilweise zu sperren
*/
typedef enum {
CDI_FS_LOCK_NONE,
CDI_FS_LOCK_WRITE,
CDI_FS_LOCK_ALL
} cdi_fs_lock_t;
/**
* Das Dateisystem wird hier nur mit abstrakten Strukturen vom Typ
* cdi_fs_resource dargestellt. Diese können beispielsweise sowohl regulaere
* Datei als auch Verzeichnis gleichzeitig darstellen.
*
* Weiter gilt, dass Ressourcen, die zu keiner Klasse gehoeren, nicht
* persistent sind.
*/
struct cdi_fs_resource {
// Name der Ressource
char* name;
// Lock fuer diese Ressource
cdi_fs_lock_t lock;
// Verweis auf das Elternobjekt
struct cdi_fs_object* parent;
// Liste mit allfaelligen Kindobjekten
cdi_list_t children;
// Link-Pfad
char* link_path;
// ACL; siehe Unten
cdi_list_t acl;
// Flags
struct cdi_fs_obj_flags flags;
// Einzelne Klassen, zu denen die Ressourcen gehoeren kann, oder Null falls
// es zu einer Bestimmten Klasse nicht gehoert.
struct cdi_fs_res_file* file;
struct cdi_fs_res_dir* dir;
struct cdi_fs_res_link* link;
struct cdi_fs_res_special* special;
// Falls die Ressource zu einer Spezialklasse gehoert, wird hier angegeben,
// um welchen Typ von Spezialressource sie gehoert.
cdi_fs_res_type_t type;
};
/**
* Diese Dateisystemobjekte werden in Klassen eingeteilt, die das eigentliche
* "Verhalten" der Ressourcen steuern. Diese Klassen beinhalten die moeglichen
* Operationen und auch die Eigenschaften, die fuer die Ressourcen gelten,
* denen diese Klassen zugeordnet sind.
* Das Definieren der einzelnen Klassen uebernehmen dann die einzelnen Treiber.
*
* Die Flags koennen von der Ressource ueberschrieben werden. Es koennen
* allerdings nur Flags deaktiviert werden, die in der Klasse gesetzt sind un
* nicht umgekehrt.
* Das Selbe gilt auch fuer Klassen bei denen NULL-Pointer fuer Operationen
* eingetragen sind. Wenn zum Beispiel fuer write NULL eingetragen wird, dann
* bringt ein gesetztes write-Flag nichts.
*/
/**
* Diese Klasse gilt unabhaengig von den andern, also egal welche anderen
* Klassen angegeben sind, diese muss angegeben werden.
*/
struct cdi_fs_obj_obj {
/**
* Ressource entfernen
*
* @param stream Stream
*
* @return Falls die Ressource erfolgreich geloescht wurde 1, sonst 0
*/
int (*remove)(struct cdi_fs_stream* stream);
/**
* Namen einer Ressource aendern. Der Parameter name ist nur der
* Resourcennamen ohne Pfad. Zum verschieben wird move() benutzt.
*
* @param stream Stream
* @param name Neuer Name
*
* @return Falls die Ressource erfolgreich umbenennt wurde 1, sonst 0
*/
int (*rename)(struct cdi_fs_stream* stream, const char* name);
/**
* Ressource innerhalb des Dateisystems verschieben. Das Verschieben ueber
* Dateisystemgrenzen hinweg wird per kopieren und loeschen durchgefuehrt.
*
* @param stream Stream
* @param dest Pointer auf die Ressource, in die die Ressource verschoben
* werden soll
*
* @return Falls die Ressource erfolgreich verschoben wurde 1, sonst 0
*/
int (*move)(struct cdi_fs_stream* stream, struct cdi_fs_resource* dest);
/**
* Neue Ressource in der Aktuellen erstellen. Diese wird erstmal noch
* keiner Klasse zugewiesen. Diese Funktion wird mit einem NULL-Pointer als
* Ressource im Stream aufgerufen. Dieser NULL-Pointer muss bei
* Erfolgreichem Beenden durch einen Pointer auf die neue Ressource ersetzt
* worden sein.
*
* @param stream Mit NULL-Pointer als Ressource
* @param parent Ressource, der die neue Ressource als Kindressource
* zugeordnet werden soll.
*
* @return Falls die Ressource erfolgreich erstellt wurde 1, sonst 0
*/
int (*create_child)(struct cdi_fs_stream* stream,
struct cdi_fs_resource* parent);
/**
* Diese Ressource einer neuen Klasse zuweisen. Dieser Aufruf schlaegt
* fehl, wenn die Ressource dieser Klasse schon zugewiesen ist.
*
* @param stream Stream
* @param class Konstante fuer den Typ der klasse, der die Ressource
* zugewiesen werden soll.
*
* @return 1 falls die Ressource erfolgreich der Klasse zugewiesen wurde, 0
* sonst
*/
int (*assign_class)(struct cdi_fs_stream* stream,
cdi_fs_res_class_t class);
/**
* Metaeigenschaft lesen
*
* @param stream Stream
* @param meta Konstante fuer die gewuenschte Metaeigenschaft
*
* @return Wert der Metaeigenschaft
*/
uint64_t (*meta_read)(struct cdi_fs_stream* stream, cdi_fs_meta_t meta);
/**
* Metaeigenschaft schreiben
*
* @param stream Stream
* @param meta Konstante fuer die gewuenschte Metaeigenschaft
* @param value Neuen Wert fuer die Metaeigenschaft
*
* @return Falls die Metaeigenschaft erfolgreich geaendert wurde 1, sonst 0
*/
uint64_t (*meta_write)(struct cdi_fs_stream* stream, cdi_fs_meta_t meta, uint64_t value);
};
struct cdi_fs_obj_file {
// XXX (Aber wie geht das, wenn eine Datei nicht lesbar, aber ausfuehrbar
// sein soll?)
int executable;
/**
* Daten aus dieser Datei lesen. Wird nur aufgerufen, wenn es durch die
* Flags oder Berechtigungen nicht verhindert wird.
*
* Im Fehlerfall wird je nach Fehler die Fehlernummer im Handle und die im
* Device gesetzt.
*
* @param stream Stream
* @param start Position von der an gelesen werden soll
* @param size Groesse der zu lesenden Daten
* @param buffer Puffer in den die Daten gelsen werden sollen
*
* @return Gelesene Bytes, oder 0 im Fehlerfall
*/
size_t (*read)(struct cdi_fs_stream* stream,uint64_t start, size_t size, void* buffer);
/**
* Daten in diese Datei schreiben. Wird nur aufgerufen, wenn es durch die
* Flags oder Berechtigungen nicht verhindert wird.
*
* Im Fehlerfall wird je nach Fehler die Fehlernummer im Handle und die im
* Device gesetzt.
*
* @param stream Stream
* @param start Position an die geschrieben werden soll
* @param size Groesse der zu schreibenden Daten
* @param buffer Puffer aus dem die Daten gelesen werden sollen
*
* @return Geschriebene Bytes oder 0 im Fehlerfall
*/
size_t (*write)(struct cdi_fs_stream* stream, uint64_t start, size_t size, void* buffer);
};
struct cdi_fs_obj_dir {
// XXX Ein browsable Flag koennen wir vermutlich hier eindeutig welgassen,
// waere ja irgenwie witzlos. ;-)
/**
* Diese Funktion gibt einen Pointer auf die Liste mit den Eintraegen
* zurueck. Hier wird nicht einfach fix der Pointer in fs_obj genommen,
* damit dort auch "versteckte" Eintraege vorhanden sein koennten. (Ich
* meine hier nicht irgend ein versteckt-Flag dass die Dateien vor dem
* Benutzer Verstecken soll, sondern eher von fuer den Internen gebrauch
* angelegten Eintraegen.
*
* @param stream Stream
*
* @return Pointer auf eine Liste mit den Untereintraegen.
*/
cdi_list_t* (*list)(struct cdi_fs_stream* stream);
};
struct cdi_fs_obj_link {
// XXX Ich glaube auch hier brauchen wir kein resolvable-Flag
/**
* Diese Funktion liest den Pfad aus, auf den der Link zeigt
*
* @param stream Stream
*
* @return Pointer auf einen Ouffer der den Pfad beinhaltet. Dieses Puffer
* darf vom Aufrufer nicht veraendert werden.
*/
const char* (*read_link)(struct cdi_fs_stream* stream);
/**
* Aendert den Pfad auf den der Link zeigt
*
* @param stream Stream
* @param path Neuer Pfad
*
* XXX Hm ist diese Funktion so vielleicht noch ein bisschen zu
* optimistisch?
*/
void (*write_link)(struct cdi_fs_stream* stream);
};
struct cdi_fs_res_special {
// XXX Reicht das so?
/**
* Geraeteadresse der Spezialdatei Lesen
*
* @param stream Stream
* @param dev Pointer auf die Variable in der die Geraeteadresse
* gespeichert werden soll.
*
* @return Falls die Geraeteadresse erfolgreich gelesen wurde 1, sonst 0
*/
int (*dev_read)(struct cdi_fs_stream* stream, dev_t* dev);
/**
* Geraeteadresse der Spezialdatei Aendern
*
* @param stream Stream
* @param dev Die neue Geraeteadresse
*
* @return Falls die Geraeteadresse erfolgreich geaendert wurde 1, sonst 0
*/
int (*dev_write)(struct cdi_fs_stream* stream, dev_t dev);
};
/**
* Der Basiseintrag in einer ACL, von dem die anderen Typen der Eintraege
* abgeleitet sind.
*/
struct cdi_fs_acl_entry {
// Typ des Eintrages, eine der obigen Konstanten
enum {
/**
* Die Berechtigunen werden mit Access controll lists, kurz ACLs verwaltet.
* Diese werden in Form von Listen gespeichert. Diese Listen enthalten
* eintraege von verschiedenen Typen.
*/
/// Eine UID
CDI_FS_ACL_USER_NUMERIC,
/// Ein Benutzername als String
CDI_FS_ACL_USER_STRING,
/// Eine GID
CDI_FS_ACL_GROUP_NUMERIC,
/// Ein Gruppenname als String
CDI_FS_ACL_GROUP_STRING
} type;
// Flags
struct cdi_fs_obj_flags flags;
};
/**
* Eintraege fuer die einzelnen Typen
*/
struct cdi_fs_acl_entry_usr_num {
struct cdi_fs_acl_entry entry;
// Benutzer-ID
uid_t user_id;
};
struct cdi_fs_acl_entry_usr_str {
struct cdi_fs_acl_entry entry;
// Benutzername
char* user_name;
};
struct cdi_fs_acl_entry_grp_num {
struct cdi_fs_acl_entry entry;
// Gruppen-ID
gid_t group_id;
};
struct cdi_fs_acl_entry_grp_str {
struct cdi_fs_acl_entry entry;
// Gruppenname
char* group_name;
};
void cdi_fs_driver_init(struct cdi_fs_driver* driver);
void cdi_fs_driver_destroy(struct cdi_fs_driver* driver);
void cdi_fs_driver_register(struct cdi_fs_driver* driver);
/**
* Quelldateien fuer ein Dateisystem lesen
* XXX Brauchen wir hier auch noch irgendwas errno-Maessiges?
*
* @param device Pointer auf die Device-Struktur des Dateisystems
* @param start Position von der an gelesen werden soll
* @param size Groesse des zu lesenden Datenblocks
* @param buffer Puffer in dem die Daten abgelegt werden sollen
*
* @return die Anzahl der gelesenen Bytes
*/
size_t cdi_fs_data_read(struct cdi_fs_device* device, uint64_t start, size_t size, void* buffer);
/**
* Quellmedium eines Dateisystems beschreiben
* XXX Brauchen wir hier auch noch irgendwas errno-Maessiges?
*
* @param device Pointer auf die Device-Struktur des Dateisystems
* @param start Position an die geschrieben werden soll
* @param size Groesse des zu schreibenden Datenblocks
* @param buffer Puffer aus dem die Daten gelesen werden sollen
*
* @return die Anzahl der geschriebenen Bytes
*/
size_t cdi_fs_data_write(struct cdi_fs_device* device, uint64_t start, size_t size, void* buffer);
#endif
Worin siehst du den Nutzen von sowas?
Ich habe das eigentlich so vorgesehen, dass die Implementation das selbst irgendwie Regelt. Bei LOST kann ich sowas beispielsweise direkt in LostIO unterbringen.

Das läuft eher anders rum: Die Implementation erhälrt über LostIO die Nachricht das Dateisystem einzubinden. Sie ruft dann die wohl noch nicht vorhandene cdi_fs_init_fs auf.
Nein. Der Treiber muss nur das Root-Verzeichnis laden und es als noch nicht geladen markieren. Dabei fällt mir noch auf, dass dafür auch noch ein Flag fehlt. Wenn dann darauf zugegriffen werden soll kann das Laden nachgeholt werden.