Skip to content

Commit

Permalink
server(filesystem): fix archives in subdirectories
Browse files Browse the repository at this point in the history
When creating an archive starting from a subdirectory instead of the
root of a server's filesystem, the walker would treat the paths as if
they where relative to the parent of the subdirectory, instead of as
descendants of the subdirectory.

Fixes pterodactyl/panel#5030
  • Loading branch information
matthewpi committed Mar 14, 2024
1 parent 979df34 commit ac9bd1d
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 0 deletions.
7 changes: 7 additions & 0 deletions internal/ufs/walk_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func (fs *UnixFS) walkDir(b []byte, parentfd int, name, relative string, d DirEn
}

for _, d1 := range dirs {
// TODO: the path.Join on this line may actually be partially incorrect.
// If we are not walking starting at the root, relative will contain the
// name of the directory we are starting the walk from, which will be
// relative to the root of the filesystem instead of from where the walk
// was initiated from.
//
// ref; https://github.com/pterodactyl/panel/issues/5030
if err := fs.walkDir(b, dirfd, d1.Name(), path.Join(relative, d1.Name()), d1, walkDirFn); err != nil {
if err == SkipDir {
break
Expand Down
23 changes: 23 additions & 0 deletions server/filesystem/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ func (a *Archive) Stream(ctx context.Context, w io.Writer) error {
return errors.New("filesystem: archive.Filesystem is unset")
}

// The base directory may come with a prefixed `/`, strip it to prevent
// problems.
a.BaseDirectory = strings.TrimPrefix(a.BaseDirectory, "/")

if filesLen := len(a.Files); filesLen > 0 {
files := make([]string, filesLen)
for i, f := range a.Files {
Expand Down Expand Up @@ -167,11 +171,14 @@ func (a *Archive) Stream(ctx context.Context, w io.Writer) error {
callback = a.callback()
}

// Open the base directory we were provided.
dirfd, name, closeFd, err := fs.SafePath(a.BaseDirectory)
defer closeFd()
if err != nil {
return err
}

// Recursively walk the base directory.
return fs.WalkDirat(dirfd, name, func(dirfd int, name, relative string, d ufs.DirEntry, err error) error {
if err != nil {
return err
Expand All @@ -188,12 +195,28 @@ func (a *Archive) Stream(ctx context.Context, w io.Writer) error {
// Callback function used to determine if a given file should be included in the archive
// being generated.
func (a *Archive) callback(opts ...walkFunc) walkFunc {
// Get the base directory we need to strip when walking.
//
// This is important as when we are walking, the last part of the base directory
// is present on all the paths we walk.
var base string
if a.BaseDirectory != "" {
base = filepath.Base(a.BaseDirectory) + "/"
}
return func(dirfd int, name, relative string, d ufs.DirEntry) error {
// Skip directories because we are walking them recursively.
if d.IsDir() {
return nil
}

// If base isn't empty, strip it from the relative path. This fixes an
// issue when creating an archive starting from a nested directory.
//
// See https://github.com/pterodactyl/panel/issues/5030 for more details.
if base != "" {
relative = strings.TrimPrefix(relative, base)
}

// Call the additional options passed to this callback function. If any of them return
// a non-nil error we will exit immediately.
for _, opt := range opts {
Expand Down

0 comments on commit ac9bd1d

Please sign in to comment.