mirror of
https://github.com/filebrowser/filebrowser.git
synced 2026-07-18 00:45:47 +00:00
fix: normalize recursive listing paths to forward slashes (#6003)
This commit is contained in:
parent
43a404ca69
commit
2472fbcd30
3 changed files with 56 additions and 4 deletions
|
|
@ -220,4 +220,52 @@ describe("checkConflict", () => {
|
|||
|
||||
expect(conflicts).toHaveLength(0);
|
||||
});
|
||||
|
||||
// Regression for #5980: a FileBrowser server running on Windows returns
|
||||
// backslash-separated paths from the recursive listing. Without normalizing
|
||||
// them, the prefix strip and key lookup never match, so the conflict modal is
|
||||
// skipped and the backend returns a bare 409.
|
||||
it("detects a conflict for backslash-separated server paths (Windows)", async () => {
|
||||
vi.mocked(api.fetchAll).mockResolvedValue([
|
||||
{
|
||||
path: "\\target\\file.txt",
|
||||
name: "file.txt",
|
||||
size: 10,
|
||||
modified: "2026-06-04T00:00:00Z",
|
||||
isDir: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const conflicts = await checkConflict(
|
||||
[moveItem("file.txt", "/files/target/")],
|
||||
"/files/target/"
|
||||
);
|
||||
|
||||
expect(conflicts).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("detects nested conflicts for backslash-separated server paths (Windows)", async () => {
|
||||
vi.mocked(api.fetchAll).mockResolvedValue([
|
||||
{
|
||||
path: "\\target\\folder\\nested file.txt",
|
||||
name: "nested file.txt",
|
||||
size: 10,
|
||||
modified: "2026-06-04T00:00:00Z",
|
||||
isDir: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const files = [
|
||||
{
|
||||
name: "nested file.txt",
|
||||
size: 12,
|
||||
isDir: false,
|
||||
fullPath: "folder/nested file.txt",
|
||||
},
|
||||
];
|
||||
|
||||
const conflicts = await checkConflict(files, "/files/target/");
|
||||
|
||||
expect(conflicts).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -62,9 +62,10 @@ export async function checkConflict(
|
|||
const normBase = removePrefix(basePath).replace(/\/+$/, "");
|
||||
const serverMap = new Map<string, RecursiveEntry>();
|
||||
for (const entry of serverEntries) {
|
||||
const rel = entry.path.startsWith(normBase)
|
||||
? entry.path.slice(normBase.length)
|
||||
: entry.path;
|
||||
// A Windows server may return OS-native backslash separators; normalize to
|
||||
// forward slashes so the prefix strip and key lookup line up.
|
||||
const path = entry.path.replace(/\\/g, "/");
|
||||
const rel = path.startsWith(normBase) ? path.slice(normBase.length) : path;
|
||||
serverMap.set(rel.replace(/^\/+/, ""), entry);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -424,7 +424,10 @@ var resourceGetRecursiveHandler = withUser(func(w http.ResponseWriter, r *http.R
|
|||
}
|
||||
|
||||
entries = append(entries, RecursiveEntry{
|
||||
Path: fPath,
|
||||
// afero.Walk joins paths with the OS separator, so on Windows fPath
|
||||
// uses backslashes. The web API contract is forward slashes, so
|
||||
// normalize it here (mirrors search/search.go).
|
||||
Path: filepath.ToSlash(fPath),
|
||||
Name: info.Name(),
|
||||
Size: info.Size(),
|
||||
ModTime: info.ModTime(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue