Initial commit
Proof-of-concept implementation. Bugs will occur.
This commit is contained in:
146
internal/domains/filesystem/music_file.go
Normal file
146
internal/domains/filesystem/music_file.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hanwen/go-fuse/v2/fs"
|
||||
"github.com/hanwen/go-fuse/v2/fuse"
|
||||
)
|
||||
|
||||
type MusicFile struct {
|
||||
fs.Inode
|
||||
|
||||
f *FS
|
||||
sourcePath string
|
||||
virtualName string
|
||||
isMetaFile bool
|
||||
}
|
||||
|
||||
var (
|
||||
_ = (fs.NodeGetattrer)((*MusicFile)(nil))
|
||||
_ = (fs.NodeOpener)((*MusicFile)(nil))
|
||||
_ = (fs.NodeSetattrer)((*MusicFile)(nil))
|
||||
)
|
||||
|
||||
func (f *MusicFile) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
||||
if f.isMetaFile {
|
||||
metaPath := filepath.Join(f.f.metadataDir, f.virtualName)
|
||||
|
||||
if info, err := os.Stat(metaPath); err == nil {
|
||||
out.Mode = fuse.S_IFREG | 0644
|
||||
out.Nlink = 1
|
||||
out.Ino = f.StableAttr().Ino
|
||||
out.Size = uint64(info.Size())
|
||||
out.Mtime = uint64(info.ModTime().Unix())
|
||||
out.Atime = out.Mtime
|
||||
out.Ctime = out.Mtime
|
||||
out.Blocks = (out.Size + 511) / 512
|
||||
} else {
|
||||
out.Mode = fuse.S_IFREG | 0644
|
||||
out.Nlink = 1
|
||||
out.Ino = f.StableAttr().Ino
|
||||
out.Size = 0
|
||||
out.Mtime = uint64(time.Now().Unix())
|
||||
out.Atime = out.Mtime
|
||||
out.Ctime = out.Mtime
|
||||
out.Blocks = 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
out.Mode = fuse.S_IFREG | 0444
|
||||
out.Nlink = 1
|
||||
out.Ino = f.StableAttr().Ino
|
||||
out.Blocks = 1
|
||||
|
||||
if size, err := f.f.cacher.GetStat(f.sourcePath); err == nil {
|
||||
out.Size = uint64(size)
|
||||
out.Blocks = (out.Size + 511) / 512
|
||||
} else {
|
||||
out.Size = 0
|
||||
}
|
||||
|
||||
out.Mtime = uint64(time.Now().Unix())
|
||||
out.Atime = out.Mtime
|
||||
out.Ctime = out.Mtime
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *MusicFile) Setattr(ctx context.Context, fh fs.FileHandle, in *fuse.SetAttrIn, out *fuse.AttrOut) syscall.Errno {
|
||||
if f.isMetaFile {
|
||||
metaPath := filepath.Join(f.f.metadataDir, f.virtualName)
|
||||
if info, err := os.Stat(metaPath); err == nil {
|
||||
out.Mode = fuse.S_IFREG | 0644
|
||||
out.Nlink = 1
|
||||
out.Ino = f.StableAttr().Ino
|
||||
out.Size = uint64(info.Size())
|
||||
out.Mtime = uint64(info.ModTime().Unix())
|
||||
out.Atime = out.Mtime
|
||||
out.Ctime = out.Mtime
|
||||
out.Blocks = (out.Size + 511) / 512
|
||||
} else {
|
||||
out.Mode = fuse.S_IFREG | 0644
|
||||
out.Nlink = 1
|
||||
out.Ino = f.StableAttr().Ino
|
||||
out.Size = 0
|
||||
out.Mtime = uint64(time.Now().Unix())
|
||||
out.Atime = out.Mtime
|
||||
out.Ctime = out.Mtime
|
||||
out.Blocks = 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
return syscall.EPERM
|
||||
}
|
||||
|
||||
func (f *MusicFile) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||
if f.isMetaFile {
|
||||
metaPath := filepath.Join(f.f.metadataDir, f.virtualName)
|
||||
|
||||
file, err := os.OpenFile(metaPath, int(flags), 0644)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
file, err = os.Create(metaPath)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, 0, syscall.EIO
|
||||
}
|
||||
|
||||
return &File{file: file}, fuse.FOPEN_DIRECT_IO, 0
|
||||
}
|
||||
|
||||
if flags&fuse.O_ANYWRITE != 0 {
|
||||
return nil, 0, syscall.EPERM
|
||||
}
|
||||
|
||||
entry, err := f.f.cacher.GetFileDTO(f.sourcePath)
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert %s to ALAC: %v", filepath.Base(f.sourcePath), err)
|
||||
|
||||
return nil, 0, syscall.EIO
|
||||
}
|
||||
|
||||
file, err := os.Open(entry.Path)
|
||||
if err != nil {
|
||||
return nil, 0, syscall.EIO
|
||||
}
|
||||
|
||||
return &File{file: file}, fuse.FOPEN_KEEP_CACHE, 0
|
||||
}
|
||||
|
||||
func (f *FS) NewMusicFile(sourcePath, virtualName string, isMetaFile bool) *MusicFile {
|
||||
return &MusicFile{
|
||||
f: f,
|
||||
sourcePath: sourcePath,
|
||||
virtualName: virtualName,
|
||||
isMetaFile: isMetaFile,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user