Bug 982006 - Make GetDownloadDirectory return error for both SD card missing and SD card busy. r=bz

This commit is contained in:
Ghislain 'Aus' Lacroix 2014-03-31 12:10:44 -07:00
parent eb43826f40
commit 4574a13528
5 changed files with 111 additions and 15 deletions

View File

@ -319,7 +319,8 @@ DOMDownloadImpl.prototype = {
});
if (aDownload.error) {
this.error = new this._window.DOMError("DownloadError", aDownload.error);
this.error =
new this._window.DOMError("DownloadError", aDownload.error.result);
} else {
this.error = null;
}

View File

@ -96,7 +96,7 @@ let DownloadsAPI = {
};
if (aDownload.error) {
res.error = aDownload.error.name;
res.error = aDownload.error;
}
res.id = this.downloadId(aDownload);

View File

@ -8,7 +8,8 @@ launchError=%S could not be opened, because an unknown error occurred.\n\nTry sa
diskFull=There is not enough room on the disk to save %S.\n\nRemove unnecessary files from the disk and try again, or try saving in a different location.
readOnly=%S could not be saved, because the disk, folder, or file is write-protected.\n\nWrite-enable the disk and try again, or try saving in a different location.
accessError=%S could not be saved, because you cannot change the contents of that folder.\n\nChange the folder properties and try again, or try saving in a different location.
accessErrorSD=No SD card.\n\nAn SD card is required to download %S.
SDAccessErrorCardReadOnly=Cannot download file because the SD card is in use.
SDAccessErrorCardMissing=Cannot download file because the SD card is missing.
helperAppNotFound=%S could not be opened, because the associated helper application does not exist. Change the association in your preferences.
noMemory=There is not sufficient memory to complete the action you requested.\n\nQuit some applications and try again.
title=Downloading %S

View File

@ -87,11 +87,7 @@
#include "nsIDownloadHistory.h" // to mark downloads as visited
#include "nsDocShellCID.h"
#include "nsIDOMWindow.h"
#include "nsIDocShell.h"
#include "nsCRT.h"
#include "nsLocalHandlerApp.h"
#include "nsIRandomGenerator.h"
@ -292,8 +288,11 @@ static bool GetFilenameAndExtensionFromChannel(nsIChannel* aChannel,
* needs to be consistent throughout our codepaths. For platforms where
* helper apps use the downloads directory, this should be kept in
* sync with nsDownloadManager.cpp
*
* Optionally skip availability of the directory and storage.
*/
static nsresult GetDownloadDirectory(nsIFile **_directory)
static nsresult GetDownloadDirectory(nsIFile **_directory,
bool aSkipChecks = false)
{
nsCOMPtr<nsIFile> dir;
#ifdef XP_MACOSX
@ -309,6 +308,12 @@ static nsresult GetDownloadDirectory(nsIFile **_directory)
getter_AddRefs(dir));
if (!dir) break;
// If we're not checking for availability we're done.
if (aSkipChecks) {
dir.forget(_directory);
return NS_OK;
}
// We have the directory, and now we need to make sure it exists
bool dirExists = false;
(void) dir->Exists(&dirExists);
@ -342,13 +347,35 @@ static nsresult GetDownloadDirectory(nsIFile **_directory)
nsString storageName;
nsDOMDeviceStorage::GetDefaultStorageName(NS_LITERAL_STRING("sdcard"),
storageName);
NS_ENSURE_TRUE(!storageName.IsEmpty(), NS_ERROR_FAILURE);
DeviceStorageFile dsf(NS_LITERAL_STRING("sdcard"),
storageName,
NS_LITERAL_STRING("downloads"));
NS_ENSURE_TRUE(dsf.mFile, NS_ERROR_FILE_ACCESS_DENIED);
NS_ENSURE_TRUE(dsf.IsAvailable(), NS_ERROR_FILE_ACCESS_DENIED);
// If we're not checking for availability we're done.
if (aSkipChecks) {
dsf.mFile.forget(_directory);
return NS_OK;
}
// Check device storage status before continuing.
nsString storageStatus;
dsf.GetStatus(storageStatus);
// If we get an "unavailable" status, it means the sd card is not present.
// We'll also catch internal errors by looking for an empty string and assume
// the SD card isn't present when this occurs.
if (storageStatus.EqualsLiteral("unavailable") ||
storageStatus.IsEmpty()) {
return NS_ERROR_FILE_NOT_FOUND;
}
// If we get a status other than 'available' here it means the card is busy
// because it's mounted via USB or it is being formatted.
if (!storageStatus.EqualsLiteral("available")) {
return NS_ERROR_FILE_ACCESS_DENIED;
}
bool alreadyThere;
nsresult rv = dsf.mFile->Exists(&alreadyThere);
@ -366,11 +393,17 @@ static nsresult GetDownloadDirectory(nsIFile **_directory)
char* downloadDir = getenv("DOWNLOADS_DIRECTORY");
nsresult rv;
if (downloadDir) {
nsCOMPtr<nsIFile> ldir;
nsCOMPtr<nsIFile> ldir;
rv = NS_NewNativeLocalFile(nsDependentCString(downloadDir),
true, getter_AddRefs(ldir));
NS_ENSURE_SUCCESS(rv, rv);
dir = do_QueryInterface(ldir);
// If we're not checking for availability we're done.
if (aSkipChecks) {
dir.forget(_directory);
return NS_OK;
}
}
else {
return NS_ERROR_FAILURE;
@ -1621,12 +1654,25 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIRequest *request, nsISuppo
rv = SetUpTempFile(aChannel);
if (NS_FAILED(rv)) {
nsresult transferError = rv;
rv = CreateFailedTransfer(aChannel && NS_UsePrivateBrowsing(aChannel));
#ifdef PR_LOGGING
if (NS_FAILED(rv)) {
LOG(("Failed to create transfer to report failure."
"Will fallback to prompter!"));
}
#endif
mCanceled = true;
request->Cancel(rv);
request->Cancel(transferError);
nsAutoString path;
if (mTempFile)
mTempFile->GetPath(path);
SendStatusChange(kWriteError, rv, request, path);
SendStatusChange(kWriteError, transferError, request, path);
return NS_OK;
}
@ -1786,8 +1832,9 @@ void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, nsIRequ
if (type == kWriteError) {
// Attempt to write without sufficient permissions.
#if defined(ANDROID)
// On Android, assume the SD card is missing or read-only
msgId.AssignLiteral("accessErrorSD");
// On Android (and Gonk), this means the SD card is present but
// unavailable (read-only).
msgId.AssignLiteral("SDAccessErrorCardReadOnly");
#else
msgId.AssignLiteral("accessError");
#endif
@ -1806,6 +1853,14 @@ void nsExternalAppHandler::SendStatusChange(ErrorType type, nsresult rv, nsIRequ
msgId.AssignLiteral("helperAppNotFound");
break;
}
#if defined(ANDROID)
else if (type == kWriteError) {
// On Android (and Gonk), this means the SD card is missing (not in
// SD slot).
msgId.AssignLiteral("SDAccessErrorCardMissing");
break;
}
#endif
// fall through
default:
@ -2137,6 +2192,39 @@ nsresult nsExternalAppHandler::CreateTransfer()
return rv;
}
nsresult nsExternalAppHandler::CreateFailedTransfer(bool aIsPrivateBrowsing)
{
nsresult rv;
nsCOMPtr<nsITransfer> transfer =
do_CreateInstance(NS_TRANSFER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// If we don't have a download directory we're kinda screwed but it's OK
// we'll still report the error via the prompter.
nsCOMPtr<nsIFile> pseudoFile;
rv = GetDownloadDirectory(getter_AddRefs(pseudoFile), true);
NS_ENSURE_SUCCESS(rv, rv);
// Append the default suggested filename. If the user restarts the transfer
// we will re-trigger a filename check anyway to ensure that it is unique.
rv = pseudoFile->Append(mSuggestedFileName);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> pseudoTarget;
rv = NS_NewFileURI(getter_AddRefs(pseudoTarget), pseudoFile);
NS_ENSURE_SUCCESS(rv, rv);
rv = transfer->Init(mSourceUrl, pseudoTarget, EmptyString(),
mMimeInfo, mTimeDownloadStarted, nullptr, this,
aIsPrivateBrowsing);
NS_ENSURE_SUCCESS(rv, rv);
// Our failed transfer is ready.
mTransfer = transfer.forget();
return NS_OK;
}
nsresult nsExternalAppHandler::SaveDestinationAvailable(nsIFile * aFile)
{
if (aFile)

View File

@ -356,6 +356,12 @@ protected:
*/
nsresult CreateTransfer();
/**
* If we fail to create the necessary temporary file to initiate a transfer
* we will report the failure by creating a failed nsITransfer.
*/
nsresult CreateFailedTransfer(bool aIsPrivateBrowsing);
/*
* The following two functions are part of the split of SaveToDisk
* to make it async, and works as following: