From e85b1cecb7a8737e1b0a0e25bfcb31af7d964d56 Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Fri, 31 Jul 2020 16:01:32 -0600 Subject: [PATCH] Fix 500 errors on file routes when accessing a file that doesn't exist --- router/router_server_files.go | 29 +++++++++++++++++++++++++++-- server/filesystem.go | 8 ++++---- server/filesystem_unarchive.go | 5 +++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/router/router_server_files.go b/router/router_server_files.go index 4559e0c..da3d996 100644 --- a/router/router_server_files.go +++ b/router/router_server_files.go @@ -3,6 +3,7 @@ package router import ( "bufio" "context" + "errors" "github.com/gin-gonic/gin" "github.com/pterodactyl/wings/server" "golang.org/x/sync/errgroup" @@ -129,7 +130,17 @@ func putServerRenameFiles(c *gin.Context) { case <-ctx.Done(): return ctx.Err() default: - return s.Filesystem.Rename(pf, pt) + if err := s.Filesystem.Rename(pf, pt); err != nil { + // Return nil if the error is an is not exists. + // NOTE: os.IsNotExist() does not work if the error is wrapped. + if errors.Is(err, os.ErrNotExist) { + return nil + } + + return err + } + + return nil } }) } @@ -155,6 +166,13 @@ func postServerCopyFile(c *gin.Context) { } if err := s.Filesystem.Copy(data.Location); err != nil { + // Check if the file does not exist. + // NOTE: os.IsNotExist() does not work if the error is wrapped. + if errors.Is(err, os.ErrNotExist) { + c.Status(http.StatusNotFound) + return + } + TrackedServerError(err, s).AbortWithServerError(c) return } @@ -177,7 +195,7 @@ func postServerDeleteFiles(c *gin.Context) { if len(data.Files) == 0 { c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{ - "error": "No files were specififed for deletion.", + "error": "No files were specified for deletion.", }) return } @@ -311,6 +329,13 @@ func postServerDecompressFiles(c *gin.Context) { } if err := s.Filesystem.DecompressFile(data.RootPath, data.File); err != nil { + // Check if the file does not exist. + // NOTE: os.IsNotExist() does not work if the error is wrapped. + if errors.Is(err, os.ErrNotExist) { + c.Status(http.StatusNotFound) + return + } + TrackedServerError(err, s).AbortWithServerError(c) return } diff --git a/server/filesystem.go b/server/filesystem.go index 4c1ea69..4f26684 100644 --- a/server/filesystem.go +++ b/server/filesystem.go @@ -40,8 +40,8 @@ func IsPathResolutionError(err error) bool { } type Filesystem struct { - Server *Server - cacheDiskMu sync.Mutex + Server *Server + cacheDiskMu sync.Mutex } // Returns the root path that contains all of a server's data. @@ -424,7 +424,7 @@ func (fs *Filesystem) unsafeStat(p string) (*Stat, error) { return st, nil } -// Creates a new directory (name) at a specificied path (p) for the server. +// Creates a new directory (name) at a specified path (p) for the server. func (fs *Filesystem) CreateDirectory(name string, p string) error { cleaned, err := fs.SafePath(path.Join(p, name)) if err != nil { @@ -540,7 +540,7 @@ func (fs *Filesystem) Copy(p string) error { } if s, err := os.Stat(cleaned); err != nil { - return err + return errors.WithStack(err) } else if s.IsDir() || !s.Mode().IsRegular() { // If this is a directory or not a regular file, just throw a not-exist error // since anything calling this function should understand what that means. diff --git a/server/filesystem_unarchive.go b/server/filesystem_unarchive.go index 9e40c28..bea2c76 100644 --- a/server/filesystem_unarchive.go +++ b/server/filesystem_unarchive.go @@ -73,6 +73,11 @@ func (fs *Filesystem) DecompressFile(dir string, file string) error { return errors.WithStack(err) } + // Make sure the file exists basically. + if _, err := os.Stat(source); err != nil { + return errors.WithStack(err) + } + // Walk over all of the files spinning up an additional go-routine for each file we've encountered // and then extract that file from the archive and write it to the disk. If any part of this process // encounters an error the entire process will be stopped.