feat: Add basic support for initializing empty archives in filesystem
This commit is contained in:
@@ -122,11 +122,6 @@ var serveFTPCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
root, err := metadataPersister.GetRootPath(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonLogger := logging.NewJSONLogger(viper.GetInt(verboseFlag))
|
||||
|
||||
readOps := operations.NewOperations(
|
||||
@@ -216,6 +211,20 @@ var serveFTPCmd = &cobra.Command{
|
||||
jsonLogger,
|
||||
)
|
||||
|
||||
root, err := metadataPersister.GetRootPath(context.Background())
|
||||
if err != nil {
|
||||
if err == config.ErrNoRootDirectory {
|
||||
// FIXME: Re-index first, and only `Mkdir` if it still fails after indexing, otherwise this would prevent usage of non-indexed, existing tar files
|
||||
|
||||
root = "/"
|
||||
if err := stfs.MkdirRoot(root, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fs, err := cache.NewCacheFilesystem(
|
||||
stfs,
|
||||
root,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/pojntfx/stfs/pkg/persisters"
|
||||
models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata"
|
||||
)
|
||||
|
||||
type DriveReaderConfig struct {
|
||||
@@ -34,8 +35,22 @@ type BackendConfig struct {
|
||||
CloseDrive func() error
|
||||
}
|
||||
|
||||
type MetadataPersister interface {
|
||||
UpsertHeader(ctx context.Context, dbhdr *models.Header) error
|
||||
UpdateHeaderMetadata(ctx context.Context, dbhdr *models.Header) error
|
||||
MoveHeader(ctx context.Context, oldName string, newName string, lastknownrecord, lastknownblock int64) error
|
||||
GetHeaders(ctx context.Context) (models.HeaderSlice, error)
|
||||
GetHeader(ctx context.Context, name string) (*models.Header, error)
|
||||
GetHeaderChildren(ctx context.Context, name string) (models.HeaderSlice, error)
|
||||
GetRootPath(ctx context.Context) (string, error)
|
||||
GetHeaderDirectChildren(ctx context.Context, name string, limit int) (models.HeaderSlice, error)
|
||||
DeleteHeader(ctx context.Context, name string, lastknownrecord, lastknownblock int64) (*models.Header, error)
|
||||
GetLastIndexedRecordAndBlock(ctx context.Context, recordSize int) (int64, int64, error)
|
||||
PurgeAllHeaders(ctx context.Context) error
|
||||
}
|
||||
|
||||
type MetadataConfig struct {
|
||||
Metadata *persisters.MetadataPersister
|
||||
Metadata MetadataPersister
|
||||
}
|
||||
|
||||
type PipeConfig struct {
|
||||
|
||||
@@ -41,4 +41,6 @@ var (
|
||||
|
||||
ErrWriteCacheTypeUnsupported = errors.New("write cache type unsupported")
|
||||
ErrWriteCacheTypeUnknown = errors.New("write cache type unknown")
|
||||
|
||||
ErrNoRootDirectory = errors.New("root directory could not be found")
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewSTFS(
|
||||
|
||||
onHeader func(hdr *models.Header),
|
||||
log *logging.JSONLogger,
|
||||
) afero.Fs {
|
||||
) *STFS {
|
||||
return &STFS{
|
||||
readOps: readOps,
|
||||
writeOps: writeOps,
|
||||
@@ -79,7 +79,7 @@ func (f *STFS) Create(name string) (afero.File, error) {
|
||||
return os.OpenFile(name, os.O_CREATE, 0666)
|
||||
}
|
||||
|
||||
func (f *STFS) mknode(dir bool, name string, perm os.FileMode) error {
|
||||
func (f *STFS) mknode(dir bool, name string, perm os.FileMode, overwrite bool) error {
|
||||
f.log.Trace("FileSystem.mknode", map[string]interface{}{
|
||||
"name": name,
|
||||
"perm": perm,
|
||||
@@ -148,7 +148,7 @@ func (f *STFS) mknode(dir bool, name string, perm os.FileMode) error {
|
||||
}, nil
|
||||
},
|
||||
f.compressionLevel,
|
||||
false,
|
||||
overwrite,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -156,13 +156,22 @@ func (f *STFS) mknode(dir bool, name string, perm os.FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *STFS) MkdirRoot(name string, perm os.FileMode) error {
|
||||
f.log.Debug("FileSystem.MkdirRoot", map[string]interface{}{
|
||||
"name": name,
|
||||
"perm": perm,
|
||||
})
|
||||
|
||||
return f.mknode(true, name, perm, true)
|
||||
}
|
||||
|
||||
func (f *STFS) Mkdir(name string, perm os.FileMode) error {
|
||||
f.log.Debug("FileSystem.Mkdir", map[string]interface{}{
|
||||
"name": name,
|
||||
"perm": perm,
|
||||
})
|
||||
|
||||
return f.mknode(true, name, perm)
|
||||
return f.mknode(true, name, perm, false)
|
||||
}
|
||||
|
||||
func (f *STFS) MkdirAll(path string, perm os.FileMode) error {
|
||||
@@ -181,7 +190,7 @@ func (f *STFS) MkdirAll(path string, perm os.FileMode) error {
|
||||
currentPath = filepath.Join(currentPath, part)
|
||||
}
|
||||
|
||||
if err := f.mknode(true, currentPath, perm); err != nil {
|
||||
if err := f.mknode(true, currentPath, perm, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -241,7 +250,7 @@ func (f *STFS) OpenFile(name string, flag int, perm os.FileMode) (afero.File, er
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
if flag&os.O_CREATE != 0 && flag&os.O_EXCL == 0 {
|
||||
if err := f.mknode(false, name, perm); err != nil {
|
||||
if err := f.mknode(false, name, perm, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
models "github.com/pojntfx/stfs/internal/db/sqlite/models/metadata"
|
||||
"github.com/pojntfx/stfs/internal/pathext"
|
||||
ipersisters "github.com/pojntfx/stfs/internal/persisters"
|
||||
"github.com/pojntfx/stfs/pkg/config"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
"github.com/volatiletech/sqlboiler/v4/boil"
|
||||
"github.com/volatiletech/sqlboiler/v4/queries"
|
||||
@@ -203,6 +204,10 @@ func (p *MetadataPersister) GetRootPath(ctx context.Context) (string, error) {
|
||||
models.HeaderColumns.Deleted,
|
||||
),
|
||||
).Bind(ctx, p.DB, &root); err != nil {
|
||||
if strings.Contains(err.Error(), "converting NULL to string is unsupported") {
|
||||
return "", config.ErrNoRootDirectory
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/pojntfx/stfs/internal/records"
|
||||
"github.com/pojntfx/stfs/internal/suffix"
|
||||
"github.com/pojntfx/stfs/pkg/config"
|
||||
"github.com/pojntfx/stfs/pkg/persisters"
|
||||
)
|
||||
|
||||
func Index(
|
||||
@@ -237,7 +236,7 @@ func Index(
|
||||
func indexHeader(
|
||||
record, block int64,
|
||||
hdr *tar.Header,
|
||||
metadataPersister *persisters.MetadataPersister,
|
||||
metadataPersister config.MetadataPersister,
|
||||
compressionFormat string,
|
||||
encryptionFormat string,
|
||||
onHeader func(hdr *models.Header),
|
||||
|
||||
Reference in New Issue
Block a user