Hier die überarbeitete Version. Die besprochenen Änderungen sind gemacht und ein paar kleine Dinge die mir noch so eingefallen sind, habe ich auch noch ergänzt:
#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_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
*/
int64_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
*/
int64_t (*meta_write)(struct cdi_fs_stream* stream, cdi_fs_meta_t meta,
int64_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);
}
/**
* 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
#define CDI_FS_ACL_USER_NUMERIC,
/// Ein Benutzername als String
#define CDI_FS_ACL_USER_STRING,
/// Eine GID
#define CDI_FS_ACL_GROUP_NUMERIC,
/// Ein Gruppenname als String
#define CDI_FS_ACL_GROUP_STRING
/**
* 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
int 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_usr_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