Non è stato specificato un linguaggio di programmazione, sebbene FUSE sia nativo in C++, esistono binding nativi di Golang, implementati a bazil.org/fuse.
direi che le parti principali della risposta devono includere quanto segue:
- Una struttura di dati per gestire l'albero del file system in memoria
- Le descrizioni dei nodi e la loro relazione inode
- Ganci per catturare le richieste del server FUSE per gestire i comandi cli
- Una descrizione del montaggio di una cartella con il server FUSE.
Ho recentemente scritto un file system in memoria utilizzando questo adattatore: github.com/bbengfort/memfs. La mia recensione sulle sue prestazioni è qui: In-Memory File System with FUSE. Rapidamente, un paio di scelte che ho fatto:
La memoria struttura dati contiene 2 le strutture primarie, dir e di file che sono entrambi i nodi:
type Node struct {
ID uint64
Name string
Attrs fuse.Attr
Parent *Dir
}
type Dir struct {
Node
Children map[string]Node
}
type File struct {
Node
Data []byte
}
Come si può vedere, si tratta di un albero semplice che è percorribile su e giù attraverso i collegamenti Children
e Parent
. L'attributo Data
del file contiene tutti i contenuti dei file. Pertanto, il file system deve solo creare una directory "root" denominata "\"
nel punto di montaggio, quindi su mkdir
a Dir
viene aggiunto ai suoi figli e su cp
viene aggiunto uno File
. In Go, questo è il più semplice:
type FS struct {
root *Dir
}
func Mount(path string) error {
// Unmount the FS in case it was mounted with errors.
fuse.Unmount(path)
// Mount the FS with the specified options
conn, err := fuse.Mount(path)
if err != nil {
return err
}
// Ensure that the file system is shutdown
defer conn.Close()
// Create the root dir and file system
memfs := FS{
root: &Dir{
ID: 1,
Name: "\",
Parent: nil,
},
}
// Serve the file system
if err := fs.Serve(conn, memfs); err != nil {
return err
}
}
Ora è necessario ganci per implementare le varie richieste di FUSE e chiamate. Ecco un esempio per mkdir
:
func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
// Update the directory Atime
d.Attrs.Atime = time.Now()
// Create the child directory
c := new(Dir)
c.Init(req.Name, req.Mode, d)
// Set the directory's UID and GID to that of the caller
c.Attrs.Uid = req.Header.Uid
c.Attrs.Gid = req.Header.Gid
// Add the directory to the directory
d.Children[c.Name] = c
// Update the directory Mtime
d.Attrs.Mtime = time.Now()
return c, nil
}
Infine, chiudere la questione intervista con una discussione su come compilare ed eseguire il server, il montaggio di un percorso e, forse, come le chiamate del kernel intercetta fusibile e li passa al vostro processo in spazio utente.
Capisco che questo potrebbe aggirare la domanda, ma perché non usare [tmpfs] (http://en.wikipedia.org/wiki/Tmpfs) invece di far ruotare il proprio file system tramite FUSE? –
@ FrédéricHamidi: tmpfs è una buona alternativa, grazie. Ma purtroppo questo non risponde alla domanda come hai detto tu. – Gautam
Immagino che _stored in memory_ significhi che devi allocare qualche tipo di buffer e usare quel buffer come back-end fs? –