server(filesystem): fix inaccurate archive progress (#145)
This commit is contained in:
@@ -8,16 +8,21 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"emperror.dev/errors"
|
||||
"github.com/apex/log"
|
||||
"github.com/mholt/archiver/v4"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/pterodactyl/wings/config"
|
||||
"github.com/pterodactyl/wings/remote"
|
||||
)
|
||||
|
||||
var format = archiver.CompressedArchive{
|
||||
Compression: archiver.Gz{},
|
||||
Archival: archiver.Tar{},
|
||||
}
|
||||
|
||||
type AdapterType string
|
||||
|
||||
const (
|
||||
@@ -27,7 +32,7 @@ const (
|
||||
|
||||
// RestoreCallback is a generic restoration callback that exists for both local
|
||||
// and remote backups allowing the files to be restored.
|
||||
type RestoreCallback func(file string, r io.Reader, mode fs.FileMode, atime, mtime time.Time) error
|
||||
type RestoreCallback func(file string, info fs.FileInfo, r io.ReadCloser) error
|
||||
|
||||
// noinspection GoNameStartsWithPackageName
|
||||
type BackupInterface interface {
|
||||
|
||||
@@ -6,8 +6,10 @@ import (
|
||||
"os"
|
||||
|
||||
"emperror.dev/errors"
|
||||
"github.com/mholt/archiver/v3"
|
||||
"github.com/juju/ratelimit"
|
||||
"github.com/mholt/archiver/v4"
|
||||
|
||||
"github.com/pterodactyl/wings/config"
|
||||
"github.com/pterodactyl/wings/remote"
|
||||
"github.com/pterodactyl/wings/server/filesystem"
|
||||
)
|
||||
@@ -79,16 +81,27 @@ func (b *LocalBackup) Generate(ctx context.Context, basePath, ignore string) (*A
|
||||
// Restore will walk over the archive and call the callback function for each
|
||||
// file encountered.
|
||||
func (b *LocalBackup) Restore(ctx context.Context, _ io.Reader, callback RestoreCallback) error {
|
||||
return archiver.Walk(b.Path(), func(f archiver.File) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Stop walking if the context is canceled.
|
||||
return archiver.ErrStopWalk
|
||||
default:
|
||||
if f.IsDir() {
|
||||
return nil
|
||||
}
|
||||
return callback(filesystem.ExtractNameFromArchive(f), f, f.Mode(), f.ModTime(), f.ModTime())
|
||||
f, err := os.Open(b.Path())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var reader io.Reader = f
|
||||
// Steal the logic we use for making backups which will be applied when restoring
|
||||
// this specific backup. This allows us to prevent overloading the disk unintentionally.
|
||||
if writeLimit := int64(config.Get().System.Backups.WriteLimit * 1024 * 1024); writeLimit > 0 {
|
||||
reader = ratelimit.Reader(f, ratelimit.NewBucketWithRate(float64(writeLimit), writeLimit))
|
||||
}
|
||||
if err := format.Extract(ctx, reader, nil, func(ctx context.Context, f archiver.File) error {
|
||||
r, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
})
|
||||
defer r.Close()
|
||||
|
||||
return callback(filesystem.ExtractNameFromArchive(f), f.FileInfo, r)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -13,13 +11,12 @@ import (
|
||||
|
||||
"emperror.dev/errors"
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
|
||||
"github.com/pterodactyl/wings/server/filesystem"
|
||||
|
||||
"github.com/juju/ratelimit"
|
||||
"github.com/mholt/archiver/v4"
|
||||
|
||||
"github.com/pterodactyl/wings/config"
|
||||
"github.com/pterodactyl/wings/remote"
|
||||
"github.com/pterodactyl/wings/server/filesystem"
|
||||
)
|
||||
|
||||
type S3Backup struct {
|
||||
@@ -96,31 +93,16 @@ func (s *S3Backup) Restore(ctx context.Context, r io.Reader, callback RestoreCal
|
||||
if writeLimit := int64(config.Get().System.Backups.WriteLimit * 1024 * 1024); writeLimit > 0 {
|
||||
reader = ratelimit.Reader(r, ratelimit.NewBucketWithRate(float64(writeLimit), writeLimit))
|
||||
}
|
||||
gr, err := gzip.NewReader(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gr.Close()
|
||||
tr := tar.NewReader(gr)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
default:
|
||||
// Do nothing, fall through to the next block of code in this loop.
|
||||
}
|
||||
header, err := tr.Next()
|
||||
if err := format.Extract(ctx, reader, nil, func(ctx context.Context, f archiver.File) error {
|
||||
r, err := f.Open()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
if header.Typeflag == tar.TypeReg {
|
||||
if err := callback(header.Name, tr, header.FileInfo().Mode(), header.AccessTime, header.ModTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
return callback(filesystem.ExtractNameFromArchive(f), f.FileInfo, r)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user