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) { | 	this.createDirectoryIfMissing = function (dir) { | ||||||
| 		dir = this.pathToFile(dir); | 		dir = this.pathToFile(dir); | ||||||
| 		if (!dir.exists() || !dir.isDirectory()) { | 		if (!dir.exists() || !dir.isDirectory()) { | ||||||
| 			if (dir.exists() && !dir.isDirectory()) { | 			if (dir.exists()) { | ||||||
|  | 				if (!dir.isDirectory()) { | ||||||
| 					dir.remove(null); | 					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); | 			dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o755); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	 | 	 | ||||||
| 	this.createDirectoryIfMissingAsync = function (path) { | 	this.createDirectoryIfMissingAsync = async function (path) { | ||||||
| 		return Zotero.Promise.resolve( | 		try { | ||||||
| 			OS.File.makeDir( | 			await OS.File.makeDir( | ||||||
| 				path, | 				path, | ||||||
| 				{ | 				{ | ||||||
| 					ignoreExisting: true, | 					ignoreExisting: false, | ||||||
| 					unixMode: 0o755 | 					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 () { | 	describe("#zipDirectory()", function () { | ||||||
| 		it("should compress a directory recursively", function* () { | 		it("should compress a directory recursively", function* () { | ||||||
| 			var tmpPath = Zotero.getTempDirectory().path; | 			var tmpPath = Zotero.getTempDirectory().path; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Stillman
				Dan Stillman