mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-06-13 23:36:45 +03:00
Don't mangle filer paths with the OS separator on Windows (#9878)
fix: don't mangle filer paths with the OS separator on Windows filepath.Dir/Join use the platform separator, so on Windows they rewrite a forward-slash filer path like /buckets/x into \buckets\x. The mangled value then goes into a filer RPC and operates on the wrong key, so the op silently targets nothing. The admin file browser hit this in New Folder (the entry landed under \buckets\my-bucket and never showed up under /buckets/my-bucket), and the same way in delete, view and properties. MQ topic retention and consumer-offset listing, and the SFTP home dir plus create-permission parent lookup, had the same bug. Switch all of these to the path package, which always uses "/".
This commit is contained in:
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -325,7 +325,7 @@ func (s *AdminServer) GetConsumerGroupOffsets(namespace, topicName string) ([]Co
|
||||
|
||||
// Only process directories that are versions (start with "v")
|
||||
if versionResp.Entry != nil && versionResp.Entry.IsDirectory && strings.HasPrefix(versionResp.Entry.Name, "v") {
|
||||
versionDir := filepath.Join(topicDir, versionResp.Entry.Name)
|
||||
versionDir := path.Join(topicDir, versionResp.Entry.Name)
|
||||
|
||||
// List all partition directories under the version directory (e.g., 0315-0630)
|
||||
partitionStream, err := client.ListEntries(context.Background(), &filer_pb.ListEntriesRequest{
|
||||
@@ -360,7 +360,7 @@ func (s *AdminServer) GetConsumerGroupOffsets(namespace, topicName string) ([]Co
|
||||
continue
|
||||
}
|
||||
|
||||
partitionDir := filepath.Join(versionDir, partitionResp.Entry.Name)
|
||||
partitionDir := path.Join(versionDir, partitionResp.Entry.Name)
|
||||
|
||||
// List all .offset files in this partition directory
|
||||
offsetStream, err := client.ListEntries(context.Background(), &filer_pb.ListEntriesRequest{
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -187,7 +187,7 @@ func (p *TopicRetentionPurger) purgeTopicData(topicRetention TopicRetentionConfi
|
||||
|
||||
// Check if this version directory is expired
|
||||
if versionDir.VersionTime.Before(cutoffTime) {
|
||||
dirPath := filepath.Join(topicDir, versionDir.Name)
|
||||
dirPath := path.Join(topicDir, versionDir.Name)
|
||||
|
||||
// Delete the entire version directory
|
||||
err := p.deleteDirectoryRecursively(client, dirPath)
|
||||
@@ -267,7 +267,7 @@ func (p *TopicRetentionPurger) deleteDirectoryRecursively(client filer_pb.Seawee
|
||||
if resp.Entry == nil {
|
||||
continue
|
||||
}
|
||||
entryPath := filepath.Join(dirPath, resp.Entry.Name)
|
||||
entryPath := path.Join(dirPath, resp.Entry.Name)
|
||||
|
||||
if resp.Entry.IsDirectory {
|
||||
// Recursively delete subdirectory
|
||||
@@ -288,8 +288,8 @@ func (p *TopicRetentionPurger) deleteDirectoryRecursively(client filer_pb.Seawee
|
||||
}
|
||||
|
||||
// Delete the directory itself
|
||||
parentDir := filepath.Dir(dirPath)
|
||||
dirName := filepath.Base(dirPath)
|
||||
parentDir := path.Dir(dirPath)
|
||||
dirName := path.Base(dirPath)
|
||||
|
||||
_, err = client.DeleteEntry(context.Background(), &filer_pb.DeleteEntryRequest{
|
||||
Directory: parentDir,
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -111,8 +110,8 @@ func (h *FileBrowserHandlers) DeleteFile(w http.ResponseWriter, r *http.Request)
|
||||
// Delete file via filer
|
||||
err := h.adminServer.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||
_, err := client.DeleteEntry(context.Background(), &filer_pb.DeleteEntryRequest{
|
||||
Directory: filepath.Dir(request.Path),
|
||||
Name: filepath.Base(request.Path),
|
||||
Directory: path.Dir(request.Path),
|
||||
Name: path.Base(request.Path),
|
||||
IsDeleteData: true,
|
||||
IsRecursive: true,
|
||||
IgnoreRecursiveError: false,
|
||||
@@ -143,8 +142,8 @@ func (h *FileBrowserHandlers) DeleteMultipleFiles(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
|
||||
for _, path := range request.Paths {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
for _, p := range request.Paths {
|
||||
if strings.TrimSpace(p) == "" {
|
||||
writeJSONError(w, http.StatusBadRequest, "path is required")
|
||||
return
|
||||
}
|
||||
@@ -155,11 +154,11 @@ func (h *FileBrowserHandlers) DeleteMultipleFiles(w http.ResponseWriter, r *http
|
||||
var errors []string
|
||||
|
||||
// Delete each file/folder
|
||||
for _, path := range request.Paths {
|
||||
for _, p := range request.Paths {
|
||||
err := h.adminServer.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||
_, err := client.DeleteEntry(context.Background(), &filer_pb.DeleteEntryRequest{
|
||||
Directory: filepath.Dir(path),
|
||||
Name: filepath.Base(path),
|
||||
Directory: path.Dir(p),
|
||||
Name: path.Base(p),
|
||||
IsDeleteData: true,
|
||||
IsRecursive: true,
|
||||
IgnoreRecursiveError: false,
|
||||
@@ -169,7 +168,7 @@ func (h *FileBrowserHandlers) DeleteMultipleFiles(w http.ResponseWriter, r *http
|
||||
|
||||
if err != nil {
|
||||
failedCount++
|
||||
errors = append(errors, fmt.Sprintf("%s: %v", path, err))
|
||||
errors = append(errors, fmt.Sprintf("%s: %v", p, err))
|
||||
} else {
|
||||
deletedCount++
|
||||
}
|
||||
@@ -230,9 +229,9 @@ func (h *FileBrowserHandlers) CreateFolder(w http.ResponseWriter, r *http.Reques
|
||||
// Create folder via filer
|
||||
err := h.adminServer.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||
_, err := client.CreateEntry(context.Background(), &filer_pb.CreateEntryRequest{
|
||||
Directory: filepath.Dir(fullPath),
|
||||
Directory: path.Dir(fullPath),
|
||||
Entry: &filer_pb.Entry{
|
||||
Name: filepath.Base(fullPath),
|
||||
Name: path.Base(fullPath),
|
||||
IsDirectory: true,
|
||||
Attributes: &filer_pb.FuseAttributes{
|
||||
FileMode: uint32(0o755 | os.ModeDir), // Directory mode
|
||||
@@ -444,8 +443,8 @@ func (h *FileBrowserHandlers) ViewFile(w http.ResponseWriter, r *http.Request) {
|
||||
var fileEntry dash.FileEntry
|
||||
err := h.adminServer.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||
resp, err := client.LookupDirectoryEntry(context.Background(), &filer_pb.LookupDirectoryEntryRequest{
|
||||
Directory: filepath.Dir(filePath),
|
||||
Name: filepath.Base(filePath),
|
||||
Directory: path.Dir(filePath),
|
||||
Name: path.Base(filePath),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -549,8 +548,8 @@ func (h *FileBrowserHandlers) GetFileProperties(w http.ResponseWriter, r *http.R
|
||||
var properties map[string]interface{}
|
||||
err := h.adminServer.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||
resp, err := client.LookupDirectoryEntry(context.Background(), &filer_pb.LookupDirectoryEntryRequest{
|
||||
Directory: filepath.Dir(filePath),
|
||||
Name: filepath.Base(filePath),
|
||||
Directory: path.Dir(filePath),
|
||||
Name: path.Base(filePath),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,7 +3,7 @@ package sftpd
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
stdpath "path"
|
||||
"strings"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
@@ -66,7 +66,7 @@ func (fs *SftpServer) CheckFilePermission(path string, perm string) error {
|
||||
// If the path doesn't exist and we're checking for create/write/mkdir permission,
|
||||
// check permissions on the parent directory instead
|
||||
if err == os.ErrNotExist {
|
||||
parentPath := filepath.Dir(path)
|
||||
parentPath := stdpath.Dir(path)
|
||||
// Check if user can write to the parent directory
|
||||
return fs.CheckFilePermission(parentPath, perm)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package user
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
"path/filepath"
|
||||
"path"
|
||||
)
|
||||
|
||||
// User represents an SFTP user with authentication and permission details
|
||||
@@ -27,7 +27,7 @@ func NewUser(username string) *User {
|
||||
return &User{
|
||||
Username: username,
|
||||
Permissions: make(map[string][]string),
|
||||
HomeDir: filepath.Join("/home", username),
|
||||
HomeDir: path.Join("/home", username),
|
||||
Uid: uint32(randomId),
|
||||
Gid: uint32(randomId),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user