feat: Add basic support for initializing empty archives in filesystem

This commit is contained in:
Felicitas Pojtinger
2022-01-01 18:08:47 +01:00
parent 5089333d13
commit d71421e14e
6 changed files with 54 additions and 15 deletions

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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")
)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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),