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:
		
					parent
					
						
							
								83cdbd8e5c
							
						
					
				
			
			
				commit
				
					
						8614e73aa8
					
				
			
		
					 2 changed files with 74 additions and 7 deletions
				
			
		|  | @ -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; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Stillman
				Dan Stillman