fix(drivers/strm): respect deployment umask for local directories (#2931)

* feat(strm): add local save permission mode

- add private and shared permission modes for local STRM files
- repair shared-mode directory and file permissions during generation
- add permission handling tests

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>

* fix(strm): respect deployment umask for local directories

- remove application-level permission modes and chmod operations
- create local STRM directories with umask-controlled permissions
- preserve existing permissions and test the behavior

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>

---------

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
This commit is contained in:
Strom
2026-08-29 01:20:44 +08:00
committed by GitHub
parent e0e4de5e82
commit 0d277b8550
3 changed files with 138 additions and 47 deletions
+21 -3
View File
@@ -8,6 +8,7 @@ import (
"io"
"os"
stdpath "path"
"path/filepath"
"strings"
"github.com/OpenListTeam/OpenList/v4/internal/model"
@@ -26,6 +27,10 @@ func UpdateLocalStrm(ctx context.Context, path string, objs []model.Obj) {
updateLocal := func(driver *Strm, basePath string, objs []model.Obj) {
relParent := strings.TrimPrefix(basePath, utils.GetActualMountPath(driver.MountPath))
localParentPath := stdpath.Join(driver.SaveStrmLocalPath, relParent)
if err := createLocalDirectory(localParentPath); err != nil {
log.Warnf("failed to create local strm directory %s: %v", localParentPath, err)
return
}
for _, obj := range objs {
localPath := stdpath.Join(localParentPath, obj.GetName())
generateStrm(ctx, driver, obj, localPath)
@@ -92,7 +97,13 @@ func RemoveStrm(dstPath string, d *Strm) {
}
func generateStrm(ctx context.Context, driver *Strm, obj model.Obj, localPath string) {
if !obj.IsDir() {
if obj.IsDir() {
if err := createLocalDirectory(localPath); err != nil {
log.Warnf("failed to create local strm directory %s: %v", localPath, err)
}
return
}
if utils.Exists(localPath) && driver.SaveLocalMode == SaveLocalInsertMode {
return
}
@@ -131,7 +142,11 @@ func generateStrm(ctx context.Context, driver *Strm, obj model.Obj, localPath st
return
}
defer rc.Close()
file, err := utils.CreateNestedFile(localPath)
if err := createLocalDirectory(filepath.Dir(localPath)); err != nil {
log.Warnf("failed to generate strm of obj %s: failed to create parent directory: %v", localPath, err)
return
}
file, err := os.Create(localPath)
if err != nil {
log.Warnf("failed to generate strm of obj %s: failed to create local file: %v", localPath, err)
return
@@ -140,7 +155,10 @@ func generateStrm(ctx context.Context, driver *Strm, obj model.Obj, localPath st
if _, err := utils.CopyWithBuffer(file, rc); err != nil {
log.Warnf("failed to generate strm of obj %s: copy failed: %v", localPath, err)
}
}
}
func createLocalDirectory(path string) error {
return os.MkdirAll(path, 0o777)
}
func isSameContent(localPath string, size int64, rc io.Reader) (bool, error) {
+43
View File
@@ -0,0 +1,43 @@
package strm
import (
"os"
"path/filepath"
"runtime"
"testing"
)
func TestCreateLocalDirectory(t *testing.T) {
root := t.TempDir()
nested := filepath.Join(root, "library", "movie")
if err := createLocalDirectory(nested); err != nil {
t.Fatalf("createLocalDirectory() error = %v", err)
}
if _, err := os.Stat(nested); err != nil {
t.Fatalf("stat created directory: %v", err)
}
}
func TestCreateLocalDirectoryPreservesExistingPermissions(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("directory permission bits are not supported on Windows")
}
root := t.TempDir()
nested := filepath.Join(root, "library", "movie")
if err := os.MkdirAll(nested, 0o700); err != nil {
t.Fatalf("create existing directory: %v", err)
}
if err := createLocalDirectory(nested); err != nil {
t.Fatalf("createLocalDirectory() error = %v", err)
}
info, err := os.Stat(nested)
if err != nil {
t.Fatalf("stat existing directory: %v", err)
}
if got := info.Mode().Perm(); got != 0o700 {
t.Errorf("existing directory permissions = %#o, want %#o", got, 0o700)
}
}
+30
View File
@@ -0,0 +1,30 @@
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
package strm
import (
"os"
"path/filepath"
"syscall"
"testing"
)
func TestCreateLocalDirectoryRespectsUmask(t *testing.T) {
root := t.TempDir()
nested := filepath.Join(root, "library", "movie")
originalUmask := syscall.Umask(0o027)
defer syscall.Umask(originalUmask)
if err := createLocalDirectory(nested); err != nil {
t.Fatalf("createLocalDirectory() error = %v", err)
}
info, err := os.Stat(nested)
if err != nil {
t.Fatalf("stat created directory: %v", err)
}
if got := info.Mode().Perm(); got != 0o750 {
t.Errorf("created directory permissions = %#o, want %#o", got, 0o750)
}
}