- Fix "Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [nsIFile.create]" error during sync due to very long filenames causing file path to go past 260 characters, which is the Windows API limit -- filenames are now automatically shortened

- Display a clearer warning when attempting to rename a missing attachment via right pane
This commit is contained in:
Dan Stillman 2009-09-19 10:52:58 +00:00
parent ae52a05c3b
commit 7e544aecca
2 changed files with 122 additions and 13 deletions

View file

@ -418,10 +418,21 @@
// start again
continue;
}
else if (renamed == -2 || !renamed) {
alert(Zotero.getString('pane.item.attachments.rename.error'));
else if (renamed == -2) {
nsIPS.alert(
window,
Zotero.getString('general.error'),
Zotero.getString('pane.item.attachments.rename.error')
);
return;
}
else if (!renamed) {
nsIPS.alert(
window,
Zotero.getString('pane.item.attachments.fileNotFound.title'),
Zotero.getString('pane.item.attachments.fileNotFound.text')
);
}
}
break;

View file

@ -567,13 +567,25 @@ Zotero.Sync.Storage = new function () {
// TODO: Test file hash
if (data.compressed) {
_processZipDownload(item);
var newFile = _processZipDownload(item);
}
else {
_processDownload(item);
var newFile = _processDownload(item);
}
// If |updated| is a file, it was renamed, so set item filename to that
// and mark for updated
var file = item.getFile();
if (newFile && file.leafName != newFile.leafName) {
item.relinkAttachmentFile(newFile);
file = item.getFile();
// TODO: use an integer counter instead of mod time for change detection
var useCurrentModTime = true;
}
else {
var useCurrentModTime = false;
}
if (!file) {
// This can happen if an HTML snapshot filename was changed and synced
// elsewhere but the renamed file wasn't synced, so the ZIP doesn't
@ -583,7 +595,6 @@ Zotero.Sync.Storage = new function () {
+ item.libraryID + "/" + item.key + " in " + funcName);
return;
}
file.lastModifiedTime = syncModTime * 1000;
Zotero.DB.beginTransaction();
var syncState = Zotero.Sync.Storage.getSyncState(item.id);
@ -592,13 +603,25 @@ Zotero.Sync.Storage = new function () {
var updateItem = syncState != 1;
var updateItem = false;
if (useCurrentModTime) {
file.lastModifiedTime = new Date();
// Reset hash and sync state
Zotero.Sync.Storage.setSyncedHash(item.id, null);
Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD);
Zotero.Sync.Storage.resyncOnFinish = true;
}
else {
file.lastModifiedTime = syncModTime * 1000;
// Only save hash if file isn't compressed
if (!data.compressed) {
Zotero.Sync.Storage.setSyncedHash(item.id, syncHash, false);
}
Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
}
Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
Zotero.DB.commitTransaction();
_changesMade = true;
}
@ -738,10 +761,48 @@ Zotero.Sync.Storage = new function () {
throw ("Empty path for item " + item.key + " in " + funcName);
}
var newName = file.leafName;
var returnFile = null
Zotero.debug("Moving download file " + tempFile.leafName + " into attachment directory");
try {
tempFile.moveTo(parentDir, newName);
}
catch (e) {
var destFile = parentDir.clone();
destFile.append(newName);
// Windows API only allows paths of 260 characters
if (e.name == "NS_ERROR_FILE_NOT_FOUND" && destFile.path.length > 255) {
var pathLength = destFile.path.length - destFile.leafName.length;
var newLength = 255 - pathLength;
// Require 40 available characters in path -- this is arbitrary,
// but otherwise filenames are going to end up being cut off
if (newLength < 40) {
throw ("Storage directory path is too long in " + funcName);
}
// Shorten file if it's too long -- we don't relink it, but this should
// be pretty rare and probably only occurs on extraneous files with
// gibberish for filenames
var newName = destFile.leafName.substr(0, newLength);
var msg = "Shortening filename to '" + newName + "'";
Zotero.debug(msg, 2);
Components.utils.reportError(msg);
tempFile.moveTo(parentDir, newName);
destFile = parentDir.clone();
destFile.append(newName);
// processDownload() needs to know that we're renaming the file
returnFile = destFile;
}
else {
throw(e);
}
}
return returnFile;
}
function _processZipDownload(item) {
@ -767,7 +828,7 @@ Zotero.Sync.Storage = new function () {
if (zipFile.exists()) {
zipFile.remove(false);
}
return;
return false;
}
var parentDir = Zotero.Attachments.getStorageDirectory(item.id);
@ -777,6 +838,8 @@ Zotero.Sync.Storage = new function () {
_deleteExistingAttachmentFiles(item);
var returnFile = null;
var entries = zipReader.findEntries(null);
while (entries.hasMore()) {
var entryName = entries.getNext();
@ -811,7 +874,40 @@ Zotero.Sync.Storage = new function () {
Components.utils.reportError(msg + " in " + funcName);
continue;
}
try {
destFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
}
catch (e) {
// Windows API only allows paths of 260 characters
if (e.name == "NS_ERROR_FILE_NOT_FOUND" && destFile.path.length > 255) {
// Is this the main attachment file?
var primaryFile = item.getFile(null, true).leafName == destFile.leafName;
var pathLength = destFile.path.length - destFile.leafName.length;
var newLength = 255 - pathLength;
// Require 40 available characters in path -- this is arbitrary,
// but otherwise filenames are going to end up being cut off
if (newLength < 40) {
throw ("Storage directory path is too long in " + funcName);
}
// Shorten file if it's too long -- we don't relink it, but this should
// be pretty rare and probably only occurs on extraneous files with
// gibberish for filenames
var newName = destFile.leafName.substr(0, newLength);
Components.utils.reportError("Shortening filename to '" + newName + "'");
destFile.leafName = newName;
destFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
// If we're renaming the main file, processDownload() needs to know
if (primaryFile) {
returnFile = destFile;
}
}
else {
throw(e);
}
}
zipReader.extract(entryName, destFile);
var origPath = destFile.path;
@ -828,6 +924,8 @@ Zotero.Sync.Storage = new function () {
}
zipReader.close();
zipFile.remove(false);
return returnFile;
}