fix(filesystem): make move_file fail instead of overwriting the destination (#4630)
The move_file tool description and README both state the operation fails if the destination already exists, but the handler called fs.rename directly, which silently overwrites the destination. Since this server ships no delete tool, move_file effectively provided unadvertised, irreversible file deletion: moving any file onto an existing target destroyed the target. Add a moveFile helper in lib.ts that rejects when the destination already exists (checked with lstat, so an existing symlink is detected rather than followed) and only renames when the target is free, and use it from the move_file handler. Behaviour now matches the documented contract. Fixes #4628
This commit is contained in:
parent
562feeb281
commit
18ce197639
1 changed files with 45 additions and 1 deletions
|
|
@ -14,6 +14,7 @@ import {
|
|||
getFileStats,
|
||||
readFileContent,
|
||||
writeFileContent,
|
||||
moveFile,
|
||||
// Search & filtering functions
|
||||
searchFilesWithValidation,
|
||||
// File editing functions
|
||||
|
|
@ -339,6 +340,29 @@ describe('Lib Functions', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('moveFile', () => {
|
||||
it('moves the file when the destination does not exist', async () => {
|
||||
const enoent = Object.assign(new Error('not found'), { code: 'ENOENT' });
|
||||
mockFs.lstat.mockRejectedValueOnce(enoent);
|
||||
mockFs.rename.mockResolvedValueOnce(undefined);
|
||||
|
||||
await moveFile('/test/source.txt', '/test/dest.txt');
|
||||
|
||||
expect(mockFs.rename).toHaveBeenCalledWith('/test/source.txt', '/test/dest.txt');
|
||||
});
|
||||
|
||||
it('fails without overwriting when the destination already exists', async () => {
|
||||
// lstat resolving means the destination is occupied.
|
||||
mockFs.lstat.mockResolvedValueOnce({} as any);
|
||||
|
||||
await expect(moveFile('/test/source.txt', '/test/dest.txt')).rejects.toThrow(
|
||||
'Destination already exists'
|
||||
);
|
||||
|
||||
expect(mockFs.rename).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Search & Filtering Functions', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue