mirror of
https://github.com/gin-gonic/gin.git
synced 2026-06-07 12:48:16 +08:00
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:
parent
d3ffc99852
commit
fe12f4df29
17
context.go
17
context.go
@ -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)
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user