mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 06:40:54 +03:00
zip creation: avoid stat if not strictly required
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -999,7 +999,7 @@ func getFileWriter(conn *BaseConnection, virtualPath string, expectedSize int64)
|
||||
return w, numFiles, truncatedSize, cancelFn, nil
|
||||
}
|
||||
|
||||
func addZipEntry(wr *zipWriterWrapper, conn *BaseConnection, entryPath, baseDir string, recursion int) error {
|
||||
func addZipEntry(wr *zipWriterWrapper, conn *BaseConnection, entryPath, baseDir string, info os.FileInfo, recursion int) error { //nolint:gocyclo
|
||||
if entryPath == wr.Name {
|
||||
// skip the archive itself
|
||||
return nil
|
||||
@@ -1009,11 +1009,14 @@ func addZipEntry(wr *zipWriterWrapper, conn *BaseConnection, entryPath, baseDir
|
||||
return util.ErrRecursionTooDeep
|
||||
}
|
||||
recursion++
|
||||
info, err := conn.DoStat(entryPath, 1, false)
|
||||
var err error
|
||||
if info == nil {
|
||||
info, err = conn.DoStat(entryPath, 1, false)
|
||||
if err != nil {
|
||||
eventManagerLog(logger.LevelError, "unable to add zip entry %q, stat error: %v", entryPath, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
entryName, err := getZipEntryName(entryPath, baseDir)
|
||||
if err != nil {
|
||||
eventManagerLog(logger.LevelError, "unable to get zip entry name: %v", err)
|
||||
@@ -1050,7 +1053,7 @@ func addZipEntry(wr *zipWriterWrapper, conn *BaseConnection, entryPath, baseDir
|
||||
}
|
||||
for _, info := range contents {
|
||||
fullPath := util.CleanPath(path.Join(entryPath, info.Name()))
|
||||
if err := addZipEntry(wr, conn, fullPath, baseDir, recursion); err != nil {
|
||||
if err := addZipEntry(wr, conn, fullPath, baseDir, info, recursion); err != nil {
|
||||
eventManagerLog(logger.LevelError, "unable to add zip entry: %v", err)
|
||||
return err
|
||||
}
|
||||
@@ -2042,7 +2045,7 @@ func executeCompressFsActionForUser(c dataprovider.EventActionFsCompress, replac
|
||||
}
|
||||
startTime := time.Now()
|
||||
for _, item := range paths {
|
||||
if err := addZipEntry(zipWriter, conn, item, baseDir, 0); err != nil {
|
||||
if err := addZipEntry(zipWriter, conn, item, baseDir, nil, 0); err != nil {
|
||||
closeWriterAndUpdateQuota(writer, conn, name, "", numFiles, truncatedSize, err, operationUpload, startTime) //nolint:errcheck
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1823,7 +1823,7 @@ func TestFilesystemActionErrors(t *testing.T) {
|
||||
Writer: zip.NewWriter(bytes.NewBuffer(nil)),
|
||||
Entries: map[string]bool{},
|
||||
}
|
||||
err = addZipEntry(wr, conn, "/adir/sub/f.dat", "/adir/sub/sub", 0)
|
||||
err = addZipEntry(wr, conn, "/adir/sub/f.dat", "/adir/sub/sub", nil, 0)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, getErrorString(err), "is outside base dir")
|
||||
}
|
||||
@@ -1833,7 +1833,7 @@ func TestFilesystemActionErrors(t *testing.T) {
|
||||
Writer: zip.NewWriter(bytes.NewBuffer(nil)),
|
||||
Entries: map[string]bool{},
|
||||
}
|
||||
err = addZipEntry(wr, conn, "/p1", "/", 2000)
|
||||
err = addZipEntry(wr, conn, "/p1", "/", nil, 2000)
|
||||
assert.ErrorIs(t, err, util.ErrRecursionTooDeep)
|
||||
|
||||
err = dataprovider.DeleteUser(username, "", "", "")
|
||||
|
||||
@@ -384,7 +384,7 @@ func renderCompressedFiles(w http.ResponseWriter, conn *Connection, baseDir stri
|
||||
|
||||
for _, file := range files {
|
||||
fullPath := util.CleanPath(path.Join(baseDir, file))
|
||||
if err := addZipEntry(wr, conn, fullPath, baseDir, 0); err != nil {
|
||||
if err := addZipEntry(wr, conn, fullPath, baseDir, nil, 0); err != nil {
|
||||
if share != nil {
|
||||
dataprovider.UpdateShareLastUse(share, -1) //nolint:errcheck
|
||||
}
|
||||
@@ -400,17 +400,20 @@ func renderCompressedFiles(w http.ResponseWriter, conn *Connection, baseDir stri
|
||||
}
|
||||
}
|
||||
|
||||
func addZipEntry(wr *zip.Writer, conn *Connection, entryPath, baseDir string, recursion int) error {
|
||||
func addZipEntry(wr *zip.Writer, conn *Connection, entryPath, baseDir string, info os.FileInfo, recursion int) error {
|
||||
if recursion >= util.MaxRecursion {
|
||||
conn.Log(logger.LevelDebug, "unable to add zip entry %q, recursion too depth: %d", entryPath, recursion)
|
||||
return util.ErrRecursionTooDeep
|
||||
}
|
||||
recursion++
|
||||
info, err := conn.Stat(entryPath, 1)
|
||||
var err error
|
||||
if info == nil {
|
||||
info, err = conn.Stat(entryPath, 1)
|
||||
if err != nil {
|
||||
conn.Log(logger.LevelDebug, "unable to add zip entry %q, stat error: %v", entryPath, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
entryName, err := getZipEntryName(entryPath, baseDir)
|
||||
if err != nil {
|
||||
conn.Log(logger.LevelError, "unable to get zip entry name: %v", err)
|
||||
@@ -441,7 +444,7 @@ func addZipEntry(wr *zip.Writer, conn *Connection, entryPath, baseDir string, re
|
||||
}
|
||||
for _, info := range contents {
|
||||
fullPath := util.CleanPath(path.Join(entryPath, info.Name()))
|
||||
if err := addZipEntry(wr, conn, fullPath, baseDir, recursion); err != nil {
|
||||
if err := addZipEntry(wr, conn, fullPath, baseDir, info, recursion); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2291,14 +2291,14 @@ func TestZipErrors(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "write error")
|
||||
}
|
||||
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/", 0)
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/", nil, 0)
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "write error")
|
||||
}
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/", 2000)
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/", nil, 2000)
|
||||
assert.ErrorIs(t, err, util.ErrRecursionTooDeep)
|
||||
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), path.Join("/", filepath.Base(testDir), "dir"), 0)
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), path.Join("/", filepath.Base(testDir), "dir"), nil, 0)
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "is outside base dir")
|
||||
}
|
||||
@@ -2307,14 +2307,14 @@ func TestZipErrors(t *testing.T) {
|
||||
err = os.WriteFile(testFilePath, util.GenerateRandomBytes(65535), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
err = addZipEntry(wr, connection, path.Join("/", filepath.Base(testDir), filepath.Base(testFilePath)),
|
||||
"/"+filepath.Base(testDir), 0)
|
||||
"/"+filepath.Base(testDir), nil, 0)
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "write error")
|
||||
}
|
||||
|
||||
connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
|
||||
err = addZipEntry(wr, connection, path.Join("/", filepath.Base(testDir), filepath.Base(testFilePath)),
|
||||
"/"+filepath.Base(testDir), 0)
|
||||
"/"+filepath.Base(testDir), nil, 0)
|
||||
assert.ErrorIs(t, err, os.ErrPermission)
|
||||
|
||||
// creating a virtual folder to a missing path stat is ok but readdir fails
|
||||
@@ -2326,14 +2326,14 @@ func TestZipErrors(t *testing.T) {
|
||||
})
|
||||
connection.User = user
|
||||
wr = zip.NewWriter(bytes.NewBuffer(make([]byte, 0)))
|
||||
err = addZipEntry(wr, connection, user.VirtualFolders[0].VirtualPath, "/", 0)
|
||||
err = addZipEntry(wr, connection, user.VirtualFolders[0].VirtualPath, "/", nil, 0)
|
||||
assert.Error(t, err)
|
||||
|
||||
user.Filters.FilePatterns = append(user.Filters.FilePatterns, sdk.PatternsFilter{
|
||||
Path: "/",
|
||||
DeniedPatterns: []string{"*.zip"},
|
||||
})
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/", 0)
|
||||
err = addZipEntry(wr, connection, "/"+filepath.Base(testDir), "/", nil, 0)
|
||||
assert.ErrorIs(t, err, os.ErrPermission)
|
||||
|
||||
err = os.RemoveAll(testDir)
|
||||
|
||||
Reference in New Issue
Block a user