Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions components/execd/pkg/web/controller/filesystem_upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (c *FilesystemController) processUploadPair(metadataHeader, fileHeader *mul
return uerr
}

resolvedPath, uerr := resolveUploadTarget(meta.Path)
resolvedPath, uerr := resolveUploadTarget(meta.Path, meta.Permission)
if uerr != nil {
return uerr
}
Expand Down Expand Up @@ -137,7 +137,7 @@ func parseUploadMetadata(header *multipart.FileHeader) (*model.FileMetadata, *up
return &meta, nil
}

func resolveUploadTarget(targetPath string) (string, *uploadError) {
func resolveUploadTarget(targetPath string, perm model.Permission) (string, *uploadError) {
resolvedPath, err := pathutil.ExpandPath(targetPath)
if err != nil {
return "", newUploadError(
Expand All @@ -147,7 +147,7 @@ func resolveUploadTarget(targetPath string) (string, *uploadError) {
)
}
targetDir := filepath.Dir(resolvedPath)
if err := os.MkdirAll(targetDir, os.ModePerm); err != nil {
if err := MkdirAllWithOwnership(targetDir, os.ModePerm, perm.Owner, perm.Group); err != nil {
Comment thread
Pangjiping marked this conversation as resolved.
return "", newUploadError(
http.StatusInternalServerError,
model.ErrorCodeRuntimeError,
Expand Down
59 changes: 55 additions & 4 deletions components/execd/pkg/web/controller/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,54 @@ func RenameFile(item model.RenameFileItem) error {
return nil
}

// MkdirAllWithOwnership creates targetDir and any missing parents, then applies
// owner/group only to the directories that were actually created (not pre-existing ones).
func MkdirAllWithOwnership(targetDir string, dirPerm os.FileMode, owner, group string) error {
// Walk up to find the first directory that needs to be created.
firstNew := ""
cur := targetDir
for {
if _, err := os.Stat(cur); err == nil {
break
}
firstNew = cur
parent := filepath.Dir(cur)
if parent == cur {
break
}
cur = parent
}

if err := os.MkdirAll(targetDir, dirPerm); err != nil {
return err
}

if firstNew == "" || (owner == "" && group == "") {
return nil
}

// Apply ownership to every newly created directory from firstNew down to targetDir.
rel, err := filepath.Rel(firstNew, targetDir)
if err != nil {
return err
}
parts := strings.Split(rel, string(filepath.Separator))
cur = firstNew
if err := SetFileOwnership(cur, owner, group); err != nil {
return err
}
for _, p := range parts {
if p == "." {
continue
}
cur = filepath.Join(cur, p)
if err := SetFileOwnership(cur, owner, group); err != nil {
return err
}
}
return nil
}

func MakeDir(dir string, perm model.Permission) error {
abs, err := pathutil.ExpandAbsPath(dir)
if err != nil {
Expand All @@ -153,13 +201,16 @@ func MakeDir(dir string, perm model.Permission) error {
_, statErr := os.Stat(abs)
existed := statErr == nil

err = os.MkdirAll(abs, os.ModePerm)
if err != nil {
if err := MkdirAllWithOwnership(abs, os.ModePerm, perm.Owner, perm.Group); err != nil {
return err
}

if !existed {
return ChmodFile(abs, perm)
if !existed && perm.Mode != 0 {
mode, err := strconv.ParseUint(strconv.Itoa(perm.Mode), 8, 32)
if err != nil {
return err
}
return os.Chmod(abs, os.FileMode(mode))
}
return nil
}
Expand Down
45 changes: 45 additions & 0 deletions components/execd/pkg/web/controller/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,51 @@ func TestMakeDir_NewDir(t *testing.T) {
}
}

func TestMkdirAllWithOwnership_NewNestedDirs(t *testing.T) {
tmp := t.TempDir()
nested := filepath.Join(tmp, "a", "b", "c")

err := MkdirAllWithOwnership(nested, 0o755, "", "")
require.NoError(t, err)

for _, seg := range []string{"a", "a/b", "a/b/c"} {
info, err := os.Stat(filepath.Join(tmp, seg))
require.NoError(t, err)
require.True(t, info.IsDir())
}
}

func TestMkdirAllWithOwnership_PreExistingParent(t *testing.T) {
tmp := t.TempDir()
existing := filepath.Join(tmp, "existing")
require.NoError(t, os.Mkdir(existing, 0o755))

origInfo, err := os.Stat(existing)
require.NoError(t, err)
origMode := origInfo.Mode().Perm()

nested := filepath.Join(existing, "new-child", "deep")
err = MkdirAllWithOwnership(nested, 0o755, "", "")
require.NoError(t, err)

afterInfo, err := os.Stat(existing)
require.NoError(t, err)
require.Equal(t, origMode, afterInfo.Mode().Perm(), "pre-existing dir should be unchanged")

info, err := os.Stat(nested)
require.NoError(t, err)
require.True(t, info.IsDir())
}

func TestMkdirAllWithOwnership_AllExist(t *testing.T) {
tmp := t.TempDir()
existing := filepath.Join(tmp, "already")
require.NoError(t, os.MkdirAll(existing, 0o755))

err := MkdirAllWithOwnership(existing, 0o755, "", "")
require.NoError(t, err, "all dirs exist — should be no-op")
}

func TestSetFileOwnership_EmptyOwnerGroup(t *testing.T) {
tmp := t.TempDir()
file := filepath.Join(tmp, "test.txt")
Expand Down
57 changes: 53 additions & 4 deletions components/execd/pkg/web/controller/utils_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,52 @@ func RenameFile(item model.RenameFileItem) error {
return nil
}

// MkdirAllWithOwnership creates targetDir and any missing parents, then applies
// owner/group only to the directories that were actually created (not pre-existing ones).
func MkdirAllWithOwnership(targetDir string, dirPerm os.FileMode, owner, group string) error {
firstNew := ""
cur := targetDir
for {
if _, err := os.Stat(cur); err == nil {
break
}
firstNew = cur
parent := filepath.Dir(cur)
if parent == cur {
break
}
cur = parent
}

if err := os.MkdirAll(targetDir, dirPerm); err != nil {
return err
}

if firstNew == "" || (owner == "" && group == "") {
return nil
}

rel, err := filepath.Rel(firstNew, targetDir)
if err != nil {
return err
}
parts := strings.Split(rel, string(filepath.Separator))
cur = firstNew
if err := SetFileOwnership(cur, owner, group); err != nil {
return err
}
for _, p := range parts {
if p == "." {
continue
}
cur = filepath.Join(cur, p)
if err := SetFileOwnership(cur, owner, group); err != nil {
return err
}
}
return nil
}

func MakeDir(dir string, perm model.Permission) error {
abs, err := pathutil.ExpandAbsPath(dir)
if err != nil {
Expand All @@ -123,13 +169,16 @@ func MakeDir(dir string, perm model.Permission) error {
_, statErr := os.Stat(abs)
existed := statErr == nil

err = os.MkdirAll(abs, os.ModePerm)
if err != nil {
if err := MkdirAllWithOwnership(abs, os.ModePerm, perm.Owner, perm.Group); err != nil {
return err
}

if !existed {
return ChmodFile(abs, perm)
if !existed && perm.Mode != 0 {
mode, err := strconv.ParseUint(strconv.Itoa(perm.Mode), 8, 32)
if err != nil {
return err
}
return os.Chmod(abs, os.FileMode(mode))
}
return nil
}
Expand Down
Loading