Throw clearer error when 'storage' is a broken symlink

Instead of '(NS_ERROR_FILE_ALREADY_EXISTS) [nsIFile.create]', throw
"Broken symlink at <path>".

Closes #1834
This commit is contained in:
Dan Stillman 2020-08-07 18:18:31 -04:00
parent 83cdbd8e5c
commit 8614e73aa8
2 changed files with 74 additions and 7 deletions

View file

@ -984,24 +984,59 @@ Zotero.File = new function(){
this.createDirectoryIfMissing = function (dir) {
dir = this.pathToFile(dir);
if (!dir.exists() || !dir.isDirectory()) {
if (dir.exists() && !dir.isDirectory()) {
dir.remove(null);
if (dir.exists()) {
if (!dir.isDirectory()) {
dir.remove(null);
}
}
else {
let isSymlink = false;
// isSymlink() fails if the directory doesn't exist, but is true if it's a broken
// symlink, in which case exists() returns false
try {
isSymlink = dir.isSymlink();
}
catch (e) {}
if (isSymlink) {
throw new Error(`Broken symlink at ${dir.path}`);
}
}
dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o755);
}
}
this.createDirectoryIfMissingAsync = function (path) {
return Zotero.Promise.resolve(
OS.File.makeDir(
this.createDirectoryIfMissingAsync = async function (path) {
try {
await OS.File.makeDir(
path,
{
ignoreExisting: true,
ignoreExisting: false,
unixMode: 0o755
}
)
);
}
catch (e) {
// If there's a broken symlink at the given path, makeDir() will throw becauseExists,
// but exists() will return false
if (e.becauseExists) {
if (await OS.File.exists(path)) {
return;
}
let isSymlink = false;
// Confirm with nsIFile that it's a symlink
try {
isSymlink = this.pathToFile(path).isSymlink();
}
catch (e) {
Zotero.logError(e);
}
if (isSymlink) {
throw new Error(`Broken symlink at ${path}`);
}
}
throw e;
}
}

View file

@ -239,6 +239,38 @@ describe("Zotero.File", function () {
})
})
describe("#createDirectoryIfMissing()", function () {
it("should throw error on broken symlink", async function () {
if (Zotero.isWin) {
this.skip();
};
var tmpPath = await getTempDirectory();
var destPath = OS.Path.join(tmpPath, 'missing');
var linkPath = OS.Path.join(tmpPath, 'link');
await OS.File.unixSymLink(destPath, linkPath);
assert.throws(() => Zotero.File.createDirectoryIfMissing(linkPath), /^Broken symlink/);
});
});
describe("#createDirectoryIfMissingAsync()", function () {
it("should throw error on broken symlink", async function () {
if (Zotero.isWin) {
this.skip();
};
var tmpPath = await getTempDirectory();
var destPath = OS.Path.join(tmpPath, 'missing');
var linkPath = OS.Path.join(tmpPath, 'link');
await OS.File.unixSymLink(destPath, linkPath);
var e = await getPromiseError(Zotero.File.createDirectoryIfMissingAsync(linkPath));
assert.ok(e);
assert.match(e.message, /^Broken symlink/);
});
});
describe("#zipDirectory()", function () {
it("should compress a directory recursively", function* () {
var tmpPath = Zotero.getTempDirectory().path;