diff --git a/context.go b/context.go index 1e8c8e27..f926bd2e 100644 --- a/context.go +++ b/context.go @@ -7,6 +7,7 @@ package gin import ( "errors" "io" + "io/fs" "log" "math" "mime/multipart" @@ -677,14 +678,22 @@ func (c *Context) MultipartForm() (*multipart.Form, error) { } // SaveUploadedFile uploads the form file to specific dst. -func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error { +func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string, perm ...fs.FileMode) error { src, err := file.Open() if err != nil { return err } defer src.Close() - if err = os.MkdirAll(filepath.Dir(dst), 0o750); err != nil { + if len(perm) <= 0 { + perm = append(perm, 0o750) + } + + if err = os.MkdirAll(filepath.Dir(dst), perm[0]); err != nil { + return err + } + + if err = os.Chmod(filepath.Dir(dst), perm[0]); err != nil { return err } diff --git a/context_test.go b/context_test.go index 62a1e14f..6cb32e76 100644 --- a/context_test.go +++ b/context_test.go @@ -11,12 +11,14 @@ import ( "fmt" "html/template" "io" + "io/fs" "mime/multipart" "net" "net/http" "net/http/httptest" "net/url" "os" + "path/filepath" "reflect" "strings" "sync" @@ -154,6 +156,45 @@ func TestSaveUploadedCreateFailed(t *testing.T) { require.Error(t, c.SaveUploadedFile(f, "/")) } +func TestSaveUploadedFileWithPermission(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("POST", "/", 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) + var mode fs.FileMode = 0o755 + require.NoError(t, c.SaveUploadedFile(f, "permission_test", mode)) + info, err := os.Stat(filepath.Dir("permission_test")) + require.NoError(t, err) + assert.Equal(t, info.Mode().Perm(), mode) +} + +func TestSaveUploadedFileWithPermissionFailed(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("POST", "/", 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) + var mode fs.FileMode = 0o644 + require.Error(t, c.SaveUploadedFile(f, "test/permission_test", mode)) +} + func TestContextReset(t *testing.T) { router := New() c := router.allocateContext(0)