correct modtime
All checks were successful
docker / build-docker (push) Successful in 3m22s

This commit is contained in:
royalcat 2024-12-17 12:51:10 +03:00
parent 92bb67959b
commit 0ae11aa283
15 changed files with 107 additions and 85 deletions

View file

@ -160,6 +160,11 @@ func (fs *Daemon) GetTorrentFS(ctx context.Context, sourcePath string, file vfs.
ctx, span := trace.Start(ctx, "GetTorrentFS") ctx, span := trace.Start(ctx, "GetTorrentFS")
defer span.End() defer span.End()
stat, err := file.Info()
if err != nil {
return nil, err
}
log := fs.log.With(slog.String("file", file.Name())) log := fs.log.With(slog.String("file", file.Name()))
ih, err := readInfoHash(ctx, file) ih, err := readInfoHash(ctx, file)
@ -185,7 +190,7 @@ func (fs *Daemon) GetTorrentFS(ctx context.Context, sourcePath string, file vfs.
fs.sourceFiles[sourcePath] = ih.HexString() fs.sourceFiles[sourcePath] = ih.HexString()
fs.sourceFilesMu.Unlock() fs.sourceFilesMu.Unlock()
return newTorrentFS(ctx, fs.ur, fs.client, file.Name(), ih.HexString(), torrentPath) return newTorrentFS(ctx, fs.client, file.Name(), ih.HexString(), stat.ModTime(), torrentPath)
} }
func (d *Daemon) syncTorrentState(ctx context.Context, file vfs.File, ih metainfo.Hash, torrentPath string) error { func (d *Daemon) syncTorrentState(ctx context.Context, file vfs.File, ih metainfo.Hash, torrentPath string) error {

View file

@ -15,7 +15,6 @@ import (
"git.kmsign.ru/royalcat/tstor/pkg/qbittorrent" "git.kmsign.ru/royalcat/tstor/pkg/qbittorrent"
"git.kmsign.ru/royalcat/tstor/pkg/rlog" "git.kmsign.ru/royalcat/tstor/pkg/rlog"
"git.kmsign.ru/royalcat/tstor/pkg/uring"
"git.kmsign.ru/royalcat/tstor/src/vfs" "git.kmsign.ru/royalcat/tstor/src/vfs"
"github.com/iceber/iouring-go" "github.com/iceber/iouring-go"
) )
@ -26,6 +25,7 @@ type FS struct {
name string name string
hash string hash string
dataDir string // directory where torrent files are stored dataDir string // directory where torrent files are stored
modTime time.Time
ur *iouring.IOURing ur *iouring.IOURing
@ -43,7 +43,7 @@ type fileEntry struct {
var _ vfs.Filesystem = (*FS)(nil) var _ vfs.Filesystem = (*FS)(nil)
func newTorrentFS(ctx context.Context, ur *iouring.IOURing, client *cacheClient, name string, hash string, dataDir string) (*FS, error) { func newTorrentFS(ctx context.Context, client *cacheClient, name string, hash string, modTime time.Time, dataDir string) (*FS, error) {
ctx, span := trace.Start(ctx, "newTorrentFS") ctx, span := trace.Start(ctx, "newTorrentFS")
defer span.End() defer span.End()
@ -60,21 +60,20 @@ func newTorrentFS(ctx context.Context, ur *iouring.IOURing, client *cacheClient,
entries[vfs.AbsPath(cnt.Name)] = fileEntry{ entries[vfs.AbsPath(cnt.Name)] = fileEntry{
Content: cnt, Content: cnt,
FileInfo: vfs.NewFileInfo(cnt.Name, cnt.Size), FileInfo: vfs.NewFileInfo(cnt.Name, cnt.Size, modTime),
} }
} }
return &FS{ return &FS{
client: client, client: client,
name: name, name: name,
hash: hash, hash: hash,
modTime: modTime,
dataDir: dataDir, dataDir: dataDir,
entries: entries, entries: entries,
ur: ur,
log: rlog.Component("qbittorrent", "fs"), log: rlog.Component("qbittorrent", "fs"),
FilesystemPrototype: vfs.FilesystemPrototype(name), FilesystemPrototype: vfs.FilesystemPrototype(name),
@ -115,7 +114,7 @@ func (f *FS) Stat(ctx context.Context, name string) (fs.FileInfo, error) {
name = vfs.AbsPath(path.Clean(name)) name = vfs.AbsPath(path.Clean(name))
if vfs.IsRoot(name) { if vfs.IsRoot(name) {
return vfs.NewDirInfo(f.name), nil return vfs.NewDirInfo(f.name, f.modTime), nil
} }
if entry, ok := f.entries[name]; ok { if entry, ok := f.entries[name]; ok {
@ -124,7 +123,7 @@ func (f *FS) Stat(ctx context.Context, name string) (fs.FileInfo, error) {
for p := range f.entries { for p := range f.entries {
if strings.HasPrefix(p, name) { if strings.HasPrefix(p, name) {
return vfs.NewDirInfo(name), nil return vfs.NewDirInfo(name, f.modTime), nil
} }
} }
@ -219,23 +218,24 @@ func openFile(ctx context.Context, ur *iouring.IOURing, client *cacheClient, tor
pieceSize: props.PieceSize, pieceSize: props.PieceSize,
fileSize: content.Size, fileSize: content.Size,
file: uring.NewFile(ur, file), file: file,
offset: 0, offset: 0,
}, nil }, nil
} }
type File struct { type File struct {
client *cacheClient client *cacheClient
hash string hash string
torrentDir string torrentModTime time.Time
filePath string // path inside a torrent directory torrentDir string
contentIndex int filePath string // path inside a torrent directory
pieceSize int contentIndex int
fileSize int64 pieceSize int
fileSize int64
mu sync.Mutex mu sync.Mutex
file *uring.File file *os.File
offset int64 offset int64
} }
@ -243,7 +243,7 @@ var _ vfs.File = (*File)(nil)
// Info implements vfs.File. // Info implements vfs.File.
func (f *File) Info() (fs.FileInfo, error) { func (f *File) Info() (fs.FileInfo, error) {
return &fileInfo{name: path.Base(f.filePath), size: f.fileSize}, nil return vfs.NewFileInfo(path.Base(f.filePath), f.fileSize, f.torrentModTime), nil
} }
// IsDir implements vfs.File. // IsDir implements vfs.File.
@ -345,7 +345,7 @@ func (f *File) Read(ctx context.Context, p []byte) (int, error) {
return 0, err return 0, err
} }
n, err := f.file.ReadAt(ctx, p, f.offset) n, err := f.file.ReadAt(p, f.offset)
f.offset += int64(n) f.offset += int64(n)
return n, err return n, err
} }
@ -356,7 +356,7 @@ func (f *File) ReadAt(ctx context.Context, p []byte, off int64) (int, error) {
return 0, err return 0, err
} }
return f.file.ReadAt(ctx, p, off) return f.file.ReadAt(p, off)
} }
// Size implements vfs.File. // Size implements vfs.File.
@ -371,42 +371,43 @@ func (f *File) Type() fs.FileMode {
// Close implements vfs.File. // Close implements vfs.File.
func (f *File) Close(ctx context.Context) error { func (f *File) Close(ctx context.Context) error {
return f.file.Close(ctx) return f.file.Close()
} }
type fileInfo struct { // type fileInfo struct {
name string // name string
size int64 // size int64
} // modTime time.Time
// }
var _ fs.FileInfo = (*fileInfo)(nil) // var _ fs.FileInfo = (*fileInfo)(nil)
// IsDir implements fs.FileInfo. // // IsDir implements fs.FileInfo.
func (f *fileInfo) IsDir() bool { // func (f *fileInfo) IsDir() bool {
return false // return false
} // }
// ModTime implements fs.FileInfo. // // ModTime implements fs.FileInfo.
func (f *fileInfo) ModTime() time.Time { // func (f *fileInfo) ModTime() time.Time {
return time.Time{} // return f.modTime
} // }
// Mode implements fs.FileInfo. // // Mode implements fs.FileInfo.
func (f *fileInfo) Mode() fs.FileMode { // func (f *fileInfo) Mode() fs.FileMode {
return vfs.ModeFileRO // return vfs.ModeFileRO
} // }
// Name implements fs.FileInfo. // // Name implements fs.FileInfo.
func (f *fileInfo) Name() string { // func (f *fileInfo) Name() string {
return f.name // return f.name
} // }
// Size implements fs.FileInfo. // // Size implements fs.FileInfo.
func (f *fileInfo) Size() int64 { // func (f *fileInfo) Size() int64 {
return f.size // return f.size
} // }
// Sys implements fs.FileInfo. // // Sys implements fs.FileInfo.
func (f *fileInfo) Sys() any { // func (f *fileInfo) Sys() any {
return nil // return nil
} // }

View file

@ -3,6 +3,7 @@ package rclone
import ( import (
"context" "context"
"io/fs" "io/fs"
"time"
"git.kmsign.ru/royalcat/tstor/src/vfs" "git.kmsign.ru/royalcat/tstor/src/vfs"
rclonefs "github.com/rclone/rclone/fs" rclonefs "github.com/rclone/rclone/fs"
@ -78,7 +79,7 @@ func (f *fileWrapper) Close(ctx context.Context) error {
// Info implements vfs.File. // Info implements vfs.File.
func (f *fileWrapper) Info() (fs.FileInfo, error) { func (f *fileWrapper) Info() (fs.FileInfo, error) {
return vfs.NewFileInfo(f.name, f.Size()), nil return vfs.NewFileInfo(f.name, f.Size(), time.Time{}), nil
} }
// IsDir implements vfs.File. // IsDir implements vfs.File.

View file

@ -450,7 +450,7 @@ func (tf *torrentFile) Type() fs.FileMode {
} }
func (tf *torrentFile) Info() (fs.FileInfo, error) { func (tf *torrentFile) Info() (fs.FileInfo, error) {
return vfs.NewFileInfo(tf.name, tf.file.Length()), nil return vfs.NewFileInfo(tf.name, tf.file.Length(), time.Time{}), nil
} }
func (tf *torrentFile) Size() int64 { func (tf *torrentFile) Size() int64 {

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"io/fs" "io/fs"
"os" "os"
"time"
"git.kmsign.ru/royalcat/tstor/pkg/ctxbilly" "git.kmsign.ru/royalcat/tstor/pkg/ctxbilly"
"git.kmsign.ru/royalcat/tstor/src/vfs" "git.kmsign.ru/royalcat/tstor/src/vfs"
@ -53,7 +54,7 @@ func (s *SourceFS) ReadDir(ctx context.Context, path string) ([]fs.DirEntry, err
entries := make([]fs.DirEntry, 0, len(infos)) entries := make([]fs.DirEntry, 0, len(infos))
for _, info := range infos { for _, info := range infos {
entries = append(entries, vfs.NewFileInfo(info.Name(), info.Size())) entries = append(entries, vfs.NewFileInfo(info.Name(), info.Size(), time.Time{}))
} }
return entries, nil return entries, nil

View file

@ -94,10 +94,15 @@ type webDAVFile struct {
} }
func newFile(ctx context.Context, name string, f vfs.File, df func() ([]os.FileInfo, error)) *webDAVFile { func newFile(ctx context.Context, name string, f vfs.File, df func() ([]os.FileInfo, error)) *webDAVFile {
info, err := f.Info()
if err != nil {
info = newFileInfo(name, f.Size(), f.IsDir())
}
return &webDAVFile{ return &webDAVFile{
ctx: ctx, ctx: ctx,
f: f, f: f,
fi: NewFileInfo(name, f.Size(), f.IsDir()), fi: info,
dirFunc: df, dirFunc: df,
} }
} }
@ -185,7 +190,7 @@ type webDAVFileInfo struct {
isDir bool isDir bool
} }
func NewFileInfo(name string, size int64, isDir bool) *webDAVFileInfo { func newFileInfo(name string, size int64, isDir bool) *webDAVFileInfo {
return &webDAVFileInfo{ return &webDAVFileInfo{
name: name, name: name,
size: size, size: size,
@ -210,8 +215,7 @@ func (wdfi *webDAVFileInfo) Mode() os.FileMode {
} }
func (wdfi *webDAVFileInfo) ModTime() time.Time { func (wdfi *webDAVFileInfo) ModTime() time.Time {
// TODO fix it return time.Time{}
return time.Now()
} }
func (wdfi *webDAVFileInfo) IsDir() bool { func (wdfi *webDAVFileInfo) IsDir() bool {

View file

@ -119,7 +119,7 @@ func NewArchive(ctx context.Context, archivePath, name string, f File, size int6
// FIXME configurable // FIXME configurable
files["/.forcegallery"] = fileEntry{ files["/.forcegallery"] = fileEntry{
FileInfo: NewFileInfo("/.forcegallery", 0), FileInfo: NewFileInfo("/.forcegallery", 0, time.Time{}),
open: func(ctx context.Context) (File, error) { open: func(ctx context.Context) (File, error) {
return NewMemoryFile(".forcegallery", []byte{}), nil return NewMemoryFile(".forcegallery", []byte{}), nil
}, },
@ -173,7 +173,7 @@ func (afs *ArchiveFS) Stat(ctx context.Context, filename string) (fs.FileInfo, e
for p, _ := range afs.files { for p, _ := range afs.files {
if strings.HasPrefix(p, filename) { if strings.HasPrefix(p, filename) {
return NewDirInfo(path.Base(filename)), nil return NewDirInfo(path.Base(filename), time.Time{}), nil
} }
} }
@ -245,7 +245,7 @@ func (d *archiveFile) Type() fs.FileMode {
} }
func (d *archiveFile) Info() (fs.FileInfo, error) { func (d *archiveFile) Info() (fs.FileInfo, error) {
return NewFileInfo(d.name, d.size), nil return NewFileInfo(d.name, d.size, time.Time{}), nil
} }
func (d *archiveFile) Size() int64 { func (d *archiveFile) Size() int64 {
@ -431,7 +431,7 @@ func RarLoader(ctx context.Context, archivePath string, f File, size int64) (map
rr := newRandomReaderFromLinear(archiveFileIndex{archiveHash: hash, filename: header.Name}, header.UnPackedSize, af) rr := newRandomReaderFromLinear(archiveFileIndex{archiveHash: hash, filename: header.Name}, header.UnPackedSize, af)
out[AbsPath(header.Name)] = fileEntry{ out[AbsPath(header.Name)] = fileEntry{
FileInfo: NewFileInfo(header.Name, header.UnPackedSize), FileInfo: NewFileInfo(header.Name, header.UnPackedSize, header.ModificationTime),
open: func(ctx context.Context) (File, error) { open: func(ctx context.Context) (File, error) {
return newArchiveFile(header.Name, header.UnPackedSize, rr), nil return newArchiveFile(header.Name, header.UnPackedSize, rr), nil
}, },

View file

@ -2,13 +2,14 @@ package vfs
import ( import (
"io/fs" "io/fs"
"time"
) )
type DefaultFS string type DefaultFS string
// Info implements Filesystem. // Info implements Filesystem.
func (d DefaultFS) Info() (fs.FileInfo, error) { func (d DefaultFS) Info() (fs.FileInfo, error) {
return NewDirInfo(string(d)), nil return NewDirInfo(string(d), time.Time{}), nil
} }
// IsDir implements Filesystem. // IsDir implements Filesystem.

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"io/fs" "io/fs"
"path" "path"
"time"
) )
var _ File = &dirFile{} var _ File = &dirFile{}
@ -25,7 +26,7 @@ func (d *dirFile) Close(ctx context.Context) error {
// Info implements File. // Info implements File.
func (d *dirFile) Info() (fs.FileInfo, error) { func (d *dirFile) Info() (fs.FileInfo, error) {
return NewDirInfo(d.name), nil return NewDirInfo(d.name, time.Time{}), nil
} }
// IsDir implements File. // IsDir implements File.

View file

@ -36,7 +36,7 @@ func (d *DummyFs) FsName() string {
// Stat implements Filesystem. // Stat implements Filesystem.
func (*DummyFs) Stat(ctx context.Context, filename string) (fs.FileInfo, error) { func (*DummyFs) Stat(ctx context.Context, filename string) (fs.FileInfo, error) {
return NewFileInfo(path.Base(filename), 0), nil // TODO return NewFileInfo(path.Base(filename), 0, time.Time{}), nil // TODO
} }
func (d *DummyFs) Open(ctx context.Context, filename string) (File, error) { func (d *DummyFs) Open(ctx context.Context, filename string) (File, error) {
@ -50,8 +50,8 @@ func (d *DummyFs) Unlink(ctx context.Context, filename string) error {
func (d *DummyFs) ReadDir(ctx context.Context, path string) ([]fs.DirEntry, error) { func (d *DummyFs) ReadDir(ctx context.Context, path string) ([]fs.DirEntry, error) {
if path == "/dir/here" { if path == "/dir/here" {
return []fs.DirEntry{ return []fs.DirEntry{
NewFileInfo("file1.txt", 0), NewFileInfo("file1.txt", 0, time.Time{}),
NewFileInfo("file2.txt", 0), NewFileInfo("file2.txt", 0, time.Time{}),
}, nil }, nil
} }
@ -60,7 +60,7 @@ func (d *DummyFs) ReadDir(ctx context.Context, path string) ([]fs.DirEntry, erro
// Info implements Filesystem. // Info implements Filesystem.
func (d *DummyFs) Info() (fs.FileInfo, error) { func (d *DummyFs) Info() (fs.FileInfo, error) {
return NewDirInfo(d.name), nil return NewDirInfo(d.name, time.Time{}), nil
} }
// IsDir implements Filesystem. // IsDir implements Filesystem.
@ -101,7 +101,7 @@ func (d *DummyFile) Type() fs.FileMode {
// Stat implements File. // Stat implements File.
func (d *DummyFile) Info() (fs.FileInfo, error) { func (d *DummyFile) Info() (fs.FileInfo, error) {
return NewFileInfo(d.name, 0), nil return NewFileInfo(d.name, 0, time.Time{}), nil
} }
func (d *DummyFile) Size() int64 { func (d *DummyFile) Size() int64 {

View file

@ -55,7 +55,7 @@ type fileInfo struct {
var _ fs.FileInfo = &fileInfo{} var _ fs.FileInfo = &fileInfo{}
var _ fs.DirEntry = &fileInfo{} var _ fs.DirEntry = &fileInfo{}
func NewDirInfo(name string) *fileInfo { func NewDirInfo(name string, modTime time.Time) *fileInfo {
return &fileInfo{ return &fileInfo{
name: path.Base(name), name: path.Base(name),
size: 0, size: 0,
@ -63,7 +63,7 @@ func NewDirInfo(name string) *fileInfo {
} }
} }
func NewFileInfo(name string, size int64) *fileInfo { func NewFileInfo(name string, size int64, modTime time.Time) *fileInfo {
return &fileInfo{ return &fileInfo{
name: path.Base(name), name: path.Base(name),
size: size, size: size,
@ -116,7 +116,7 @@ type FilesystemPrototype string
// Info implements Filesystem. // Info implements Filesystem.
func (p FilesystemPrototype) Info() (fs.FileInfo, error) { func (p FilesystemPrototype) Info() (fs.FileInfo, error) {
return NewDirInfo(string(p)), nil return NewDirInfo(string(p), time.Time{}), nil
} }
// IsDir implements Filesystem. // IsDir implements Filesystem.

View file

@ -3,6 +3,7 @@ package vfs
import ( import (
"io/fs" "io/fs"
"testing" "testing"
"time"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -12,7 +13,7 @@ func TestFileinfo(t *testing.T) {
require := require.New(t) require := require.New(t)
fi := NewFileInfo("abc/name", 42) fi := NewFileInfo("abc/name", 42, time.Time{})
require.Equal("name", fi.Name()) require.Equal("name", fi.Name())
require.False(fi.IsDir()) require.False(fi.IsDir())
@ -29,7 +30,7 @@ func TestDirInfo(t *testing.T) {
require := require.New(t) require := require.New(t)
fi := NewDirInfo("abc/name") fi := NewDirInfo("abc/name", time.Time{})
require.True(fi.IsDir()) require.True(fi.IsDir())
require.Equal("name", fi.Name()) require.Equal("name", fi.Name())

View file

@ -42,7 +42,7 @@ func (fs *MemoryFs) FsName() string {
// Info implements Filesystem. // Info implements Filesystem.
func (fs *MemoryFs) Info() (fs.FileInfo, error) { func (fs *MemoryFs) Info() (fs.FileInfo, error) {
return NewDirInfo(fs.name), nil return NewDirInfo(fs.name, time.Time{}), nil
} }
// IsDir implements Filesystem. // IsDir implements Filesystem.
@ -86,7 +86,7 @@ func (mfs *MemoryFs) Stat(ctx context.Context, filename string) (fs.FileInfo, er
if !ok { if !ok {
return nil, ErrNotExist return nil, ErrNotExist
} }
return NewFileInfo(path.Base(filename), file.Size()), nil return NewFileInfo(path.Base(filename), file.Size(), time.Time{}), nil
} }
// Unlink implements Filesystem. // Unlink implements Filesystem.
@ -124,7 +124,7 @@ func (d *MemoryFile) Type() fs.FileMode {
} }
func (d *MemoryFile) Info() (fs.FileInfo, error) { func (d *MemoryFile) Info() (fs.FileInfo, error) {
return NewFileInfo(d.name, int64(d.data.Len())), nil return NewFileInfo(d.name, int64(d.data.Len()), time.Time{}), nil
} }
func (d *MemoryFile) Size() int64 { func (d *MemoryFile) Size() int64 {

View file

@ -7,6 +7,7 @@ import (
"os" "os"
"path" "path"
"sync" "sync"
"time"
) )
type OsFS struct { type OsFS struct {
@ -18,7 +19,7 @@ var _ Filesystem = (*OsFS)(nil)
// Stat implements Filesystem. // Stat implements Filesystem.
func (fs *OsFS) Stat(ctx context.Context, filename string) (fs.FileInfo, error) { func (fs *OsFS) Stat(ctx context.Context, filename string) (fs.FileInfo, error) {
if path.Clean(filename) == Separator { if path.Clean(filename) == Separator {
return NewDirInfo(Separator), nil return NewDirInfo(Separator, time.Time{}), nil
} }
info, err := os.Stat(path.Join(fs.hostDir, filename)) info, err := os.Stat(path.Join(fs.hostDir, filename))
@ -58,7 +59,7 @@ func (o *OsFS) ReadDir(ctx context.Context, dir string) ([]fs.DirEntry, error) {
// Info implements Filesystem. // Info implements Filesystem.
func (fs *OsFS) Info() (fs.FileInfo, error) { func (fs *OsFS) Info() (fs.FileInfo, error) {
return NewDirInfo(fs.Name()), nil return NewDirInfo(fs.Name(), time.Time{}), nil
} }
// IsDir implements Filesystem. // IsDir implements Filesystem.

View file

@ -389,11 +389,16 @@ func ListDirFromFiles[F File](m map[string]F, name string) ([]fs.DirEntry, error
name = AddTrailSlash(path.Clean(name)) name = AddTrailSlash(path.Clean(name))
for p, f := range m { for p, f := range m {
if strings.HasPrefix(p, name) { if strings.HasPrefix(p, name) {
stat, err := f.Info()
if err != nil {
return nil, err
}
parts := strings.Split(trimRelPath(p, name), Separator) parts := strings.Split(trimRelPath(p, name), Separator)
if len(parts) == 1 { if len(parts) == 1 {
out = append(out, NewFileInfo(parts[0], f.Size())) out = append(out, NewFileInfo(parts[0], f.Size(), stat.ModTime()))
} else { } else {
out = append(out, NewDirInfo(parts[0])) out = append(out, NewDirInfo(parts[0], stat.ModTime()))
} }
} }
@ -413,11 +418,12 @@ func ListDirFromInfo(m map[string]fs.FileInfo, name string) ([]fs.DirEntry, erro
name = AddTrailSlash(path.Clean(name)) name = AddTrailSlash(path.Clean(name))
for p, f := range m { for p, f := range m {
if strings.HasPrefix(p, name) { if strings.HasPrefix(p, name) {
parts := strings.Split(trimRelPath(p, name), Separator) parts := strings.Split(trimRelPath(p, name), Separator)
if len(parts) == 1 { if len(parts) == 1 {
out = append(out, NewFileInfo(parts[0], f.Size())) out = append(out, NewFileInfo(parts[0], f.Size(), f.ModTime()))
} else { } else {
out = append(out, NewDirInfo(parts[0])) out = append(out, NewDirInfo(parts[0], f.ModTime()))
} }
} }