プログラミング言語を指定しませんでしたが、FUSE はネイティブ C++ ですが、ネイティブの Golang バインディングが bazil.org/fuse に実装されています。
回答の主要な部分には、次のものが含まれている必要があると思います。
- メモリ内のファイル システム ツリーを処理するためのデータ構造
- ノードの説明と iNode との関係
- cli コマンドを処理するための FUSE サーバー要求をキャプチャするためのフック
- FUSE サーバーでフォルダーをマウントする方法の説明。
私は最近、このアダプターを使用してメモリ内ファイル システムを作成しました: github.com/bbengfort/memfs。そのパフォーマンスに関する私の記事はこちら: In-Memory File System with FUSE . すぐに、私が行ったいくつかの選択:
インメモリ データ構造には、両方のノードである dir と file の 2 つの主要な構造体が含まれています。
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
}
Children
ご覧のとおり、これは単純なツリーで、 リンクとリンクを上下にたどることができParent
ます。FileのData
属性は、ファイルのすべての内容を保持します。したがって、ファイル システムは"\"
、マウント ポイントで呼び出される「ルート」ディレクトリを作成するだけで済みます。次に、mkdir
aDir
がその子に追加されcp
、aFile
が追加されます。Go では、これは次のように簡単です。
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
}
}
ここで、さまざまな FUSE リクエストと呼び出しを実装するためのフックが必要です。の例を次に示し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
}
最後に、サーバーをコンパイルして実行する方法、パスにマウントする方法、およびおそらく FUSE がカーネル呼び出しをインターセプトしてユーザー空間のプロセスに渡す方法について説明して、インタビューの質問を締めくくります。