Avoid chmod on pre-existing upload destination directories

When SaveUploadedFile targets a path under an existing directory, applying
the optional permission mode to that existing directory can fail despite
the file creation itself being allowed. This change only creates and chmods
the destination directory when it does not already exist.

The permission tests now cover both newly created upload directories and
existing destination directories whose mode should be preserved.

Tested: docker run --rm --user "$(id -u):$(id -g)" -e GOMODCACHE=/tmp/gomodcache -e GOCACHE=/tmp/gocache -v "$PWD":/src -w /src golang:1.25.0 go test . -count=1
This commit is contained in:
Mike Ma 2026-05-06 22:01:51 -05:00
parent d3ffc99852
commit fe12f4df29
2 changed files with 44 additions and 11 deletions

View File

@ -728,11 +728,18 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string, perm
mode = perm[0]
}
dir := filepath.Dir(dst)
if err = os.MkdirAll(dir, mode); err != nil {
return err
}
if err = os.Chmod(dir, mode); err != nil {
return err
if dir != "." {
if _, err = os.Stat(dir); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return err
}
if err = os.MkdirAll(dir, mode); err != nil {
return err
}
if err = os.Chmod(dir, mode); err != nil {
return err
}
}
}
out, err := os.Create(dst)

View File

@ -246,16 +246,42 @@ func TestSaveUploadedFileWithPermission(t *testing.T) {
f, err := c.FormFile("file")
require.NoError(t, err)
assert.Equal(t, "permission_test", f.Filename)
dst := filepath.Join(t.TempDir(), "uploads", "permission_test")
var mode fs.FileMode = 0o755
require.NoError(t, c.SaveUploadedFile(f, "permission_test", mode))
t.Cleanup(func() {
assert.NoError(t, os.Remove("permission_test"))
})
info, err := os.Stat(filepath.Dir("permission_test"))
require.NoError(t, c.SaveUploadedFile(f, dst, mode))
info, err := os.Stat(filepath.Dir(dst))
require.NoError(t, err)
assert.Equal(t, info.Mode().Perm(), mode)
}
func TestSaveUploadedFileWithPermissionExistingDirectory(t *testing.T) {
buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf)
w, err := mw.CreateFormFile("file", "permission_test")
require.NoError(t, err)
_, err = w.Write([]byte("permission_test"))
require.NoError(t, err)
mw.Close()
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodPost, "/", buf)
c.Request.Header.Set("Content-Type", mw.FormDataContentType())
f, err := c.FormFile("file")
require.NoError(t, err)
assert.Equal(t, "permission_test", f.Filename)
dstDir := filepath.Join(t.TempDir(), "uploads")
const existingMode fs.FileMode = 0o700
require.NoError(t, os.Mkdir(dstDir, existingMode))
var mode fs.FileMode = 0o755
dst := filepath.Join(dstDir, "permission_test")
require.NoError(t, c.SaveUploadedFile(f, dst, mode))
info, err := os.Stat(dstDir)
require.NoError(t, err)
assert.Equal(t, existingMode, info.Mode().Perm())
}
func TestSaveUploadedFileWithPermissionFailed(t *testing.T) {
buf := new(bytes.Buffer)
mw := multipart.NewWriter(buf)
@ -271,7 +297,7 @@ func TestSaveUploadedFileWithPermissionFailed(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "permission_test", f.Filename)
var mode fs.FileMode = 0o644
require.Error(t, c.SaveUploadedFile(f, "test/permission_test", mode))
require.Error(t, c.SaveUploadedFile(f, filepath.Join(t.TempDir(), "test", "permission_test"), mode))
}
func TestContextReset(t *testing.T) {