1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Windows: Fixes #10525: Prevent notes with titles that differ only in case from being overwritten when exporting (#10541)

This commit is contained in:
Henry Heino 2024-06-10 23:41:23 -07:00 committed by GitHub
parent 47a924ff4e
commit 629e968878
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 3 deletions

View File

@ -152,13 +152,21 @@ export default class FsDriverBase {
} }
let counter = 1; let counter = 1;
// On Windows, ./FiLe.md and ./file.md are equivalent file paths.
// As such, to avoid overwriting reserved names, comparisons need to be
// case-insensitive.
reservedNames = reservedNames.map(name => name.toLowerCase());
const isReserved = (testName: string) => {
return reservedNames.includes(testName.toLowerCase());
};
const nameNoExt = filename(name, true); const nameNoExt = filename(name, true);
let extension = fileExtension(name); let extension = fileExtension(name);
if (extension) extension = `.${extension}`; if (extension) extension = `.${extension}`;
let nameToTry = nameNoExt + extension; let nameToTry = nameNoExt + extension;
while (true) { while (true) {
// Check if the filename does not exist in the filesystem and is not reserved // Check if the filename does not exist in the filesystem and is not reserved
const exists = await this.exists(nameToTry) || reservedNames.includes(nameToTry); const exists = await this.exists(nameToTry) || isReserved(nameToTry);
if (!exists) return nameToTry; if (!exists) return nameToTry;
if (!markdownSafe) { if (!markdownSafe) {
nameToTry = `${nameNoExt} (${counter})${extension}`; nameToTry = `${nameNoExt} (${counter})${extension}`;

View File

@ -1,6 +1,7 @@
import { join } from 'path';
import FsDriverNode from './fs-driver-node'; import FsDriverNode from './fs-driver-node';
import shim from './shim'; import shim from './shim';
import { expectThrow } from './testing/test-utils'; import { expectThrow, supportDir } from './testing/test-utils';
const windowsPartitionLetter = __filename[0]; const windowsPartitionLetter = __filename[0];
@ -15,7 +16,6 @@ function platformPath(path: string) {
} }
describe('fsDriver', () => { describe('fsDriver', () => {
it('should resolveRelativePathWithinDir', async () => { it('should resolveRelativePathWithinDir', async () => {
const fsDriver = new FsDriverNode(); const fsDriver = new FsDriverNode();
expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './my/file.txt').toLowerCase()).toBe(platformPath('/test/temp/my/file.txt')); expect(fsDriver.resolveRelativePathWithinDir('/test/temp', './my/file.txt').toLowerCase()).toBe(platformPath('/test/temp/my/file.txt'));
@ -28,4 +28,18 @@ describe('fsDriver', () => {
await expectThrow(() => fsDriver.resolveRelativePathWithinDir('/test/temp', '/var/local/no.txt')); await expectThrow(() => fsDriver.resolveRelativePathWithinDir('/test/temp', '/var/local/no.txt'));
}); });
it('should compare reserved names in a case-insensitive way in findUniqueFilename', async () => {
// Compare with filenames in the reserved list should be case insensitive
expect(
await shim.fsDriver().findUniqueFilename(
join(supportDir, 'this-file-does-not-exist.txt'),
[join(supportDir, 'THIS-file-does-not-exist.txt'), join(supportDir, 'THIS-file-DOES-not-exist (1).txt')],
),
).toBe(join(supportDir, 'this-file-does-not-exist (2).txt'));
// Should still not match reserved names that aren't equivalent.
expect(
await shim.fsDriver().findUniqueFilename(join(supportDir, 'this-file-does-not-exist.txt'), [join(supportDir, 'some-other-file.txt')]),
).toBe(join(supportDir, 'this-file-does-not-exist.txt'));
});
}); });