server(filesystem): fix file names when extracting archives (#165)

This commit is contained in:
Daniel Barton 2023-10-18 10:47:36 +08:00 committed by GitHub
parent 79eb8e1365
commit d1fd0465e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 3 additions and 54 deletions

View File

@ -100,7 +100,7 @@ func (b *LocalBackup) Restore(ctx context.Context, _ io.Reader, callback Restore
} }
defer r.Close() defer r.Close()
return callback(filesystem.ExtractNameFromArchive(f), f.FileInfo, r) return callback(f.NameInArchive, f.FileInfo, r)
}); err != nil { }); err != nil {
return err return err
} }

View File

@ -100,7 +100,7 @@ func (s *S3Backup) Restore(ctx context.Context, r io.Reader, callback RestoreCal
} }
defer r.Close() defer r.Close()
return callback(filesystem.ExtractNameFromArchive(f), f.FileInfo, r) return callback(f.NameInArchive, f.FileInfo, r)
}); err != nil { }); err != nil {
return err return err
} }

View File

@ -1,9 +1,6 @@
package filesystem package filesystem
import ( import (
"archive/tar"
"archive/zip"
"compress/gzip"
"context" "context"
"fmt" "fmt"
"io" "io"
@ -11,14 +8,11 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"reflect"
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
"emperror.dev/errors" "emperror.dev/errors"
gzip2 "github.com/klauspost/compress/gzip"
zip2 "github.com/klauspost/compress/zip"
"github.com/mholt/archiver/v4" "github.com/mholt/archiver/v4"
) )
@ -201,7 +195,7 @@ func (fs *Filesystem) extractStream(ctx context.Context, opts extractStreamOptio
if f.IsDir() { if f.IsDir() {
return nil return nil
} }
p := filepath.Join(opts.Directory, ExtractNameFromArchive(f)) p := filepath.Join(opts.Directory, f.NameInArchive)
// If it is ignored, just don't do anything with the file and skip over it. // If it is ignored, just don't do anything with the file and skip over it.
if err := fs.IsIgnored(p); err != nil { if err := fs.IsIgnored(p); err != nil {
return nil return nil
@ -227,48 +221,3 @@ func (fs *Filesystem) extractStream(ctx context.Context, opts extractStreamOptio
} }
return nil return nil
} }
// ExtractNameFromArchive looks at an archive file to try and determine the name
// for a given element in an archive. Because of... who knows why, each file type
// uses different methods to determine the file name.
//
// If there is a archiver.File#Sys() value present we will try to use the name
// present in there, otherwise falling back to archiver.File#Name() if all else
// fails. Without this logic present, some archive types such as zip/tars/etc.
// will write all of the files to the base directory, rather than the nested
// directory that is expected.
//
// For files like ".rar" types, there is no f.Sys() value present, and the value
// of archiver.File#Name() will be what you need.
func ExtractNameFromArchive(f archiver.File) string {
sys := f.Sys()
// Some archive types won't have a value returned when you call f.Sys() on them,
// such as ".rar" archives for example. In those cases the only thing you can do
// is hope that "f.Name()" is actually correct for them.
if sys == nil {
return f.Name()
}
switch s := sys.(type) {
case *zip.FileHeader:
return s.Name
case *zip2.FileHeader:
return s.Name
case *tar.Header:
return s.Name
case *gzip.Header:
return s.Name
case *gzip2.Header:
return s.Name
default:
// At this point we cannot figure out what type of archive this might be so
// just try to find the name field in the struct. If it is found return it.
field := reflect.Indirect(reflect.ValueOf(sys)).FieldByName("Name")
if field.IsValid() {
return field.String()
}
// Fallback to the basename of the file at this point. There is nothing we can really
// do to try and figure out what the underlying directory of the file is supposed to
// be since it didn't implement a name field.
return f.Name()
}
}