Bug 1079649: Use a temporary (.part) file to store incoming file. (bluetooth2/bluez) r=btian

This commit is contained in:
Bruce Sun 2014-11-10 18:56:24 +08:00
Родитель b99f40c9ca
Коммит 0fb740de24
2 изменённых файлов: 65 добавлений и 13 удалений

Просмотреть файл

@ -553,6 +553,7 @@ BluetoothOppManager::AfterOppDisconnected()
mLastCommand = 0; mLastCommand = 0;
mPutPacketReceivedLength = 0; mPutPacketReceivedLength = 0;
mDsFile = nullptr; mDsFile = nullptr;
mDummyDsFile = nullptr;
// We can't reset mSuccessFlag here since this function may be called // We can't reset mSuccessFlag here since this function may be called
// before we send system message of transfer complete // before we send system message of transfer complete
@ -579,6 +580,34 @@ BluetoothOppManager::AfterOppDisconnected()
} }
} }
void
BluetoothOppManager::RecoverFileName()
{
// Remove the trailing ".part" file name from mDsFile by two steps
// 1. mDsFile->SetPath() so that the notification sent to Gaia will carry
// correct information of the file.
// 2. mDsFile->mFile->RenameTo() so that the file name would actually be
// changed in file system.
if (mDsFile && mDsFile->mFile) {
nsString path;
path.AssignLiteral(TARGET_SUBDIR);
path.Append(mFileName);
mDsFile->SetPath(path);
mDsFile->mFile->RenameTo(nullptr, mFileName);
}
}
void
BluetoothOppManager::DeleteDummyFile()
{
// Remove the empty temp file
if (mDummyDsFile && mDummyDsFile->mFile) {
mDummyDsFile->mFile->Remove(false);
mDummyDsFile = nullptr;
}
}
void void
BluetoothOppManager::DeleteReceivedFile() BluetoothOppManager::DeleteReceivedFile()
{ {
@ -591,6 +620,8 @@ BluetoothOppManager::DeleteReceivedFile()
mDsFile->mFile->Remove(false); mDsFile->mFile->Remove(false);
mDsFile = nullptr; mDsFile = nullptr;
} }
DeleteDummyFile();
} }
bool bool
@ -598,25 +629,39 @@ BluetoothOppManager::CreateFile()
{ {
MOZ_ASSERT(mPutPacketReceivedLength == mPacketLength); MOZ_ASSERT(mPutPacketReceivedLength == mPacketLength);
// Create one dummy file to be a placeholder for the target file name, and
// create another file with a meaningless file extension to write the received
// data. By doing this, we can prevent applications from parsing incomplete
// data in the middle of the receiving process.
nsString path; nsString path;
path.AssignLiteral(TARGET_SUBDIR); path.AssignLiteral(TARGET_SUBDIR);
path.Append(mFileName); path.Append(mFileName);
mDsFile = DeviceStorageFile::CreateUnique( // Use an empty dummy file object to occupy the file name, so that after the
path, nsIFile::NORMAL_FILE_TYPE, 0644); // whole file has been received successfully by using mDsFile, we could just
// remove mDummyDsFile and rename mDsFile to the file name of mDummyDsFile.
mDummyDsFile =
DeviceStorageFile::CreateUnique(path, nsIFile::NORMAL_FILE_TYPE, 0644);
NS_ENSURE_TRUE(mDummyDsFile, false);
// The function CreateUnique() may create a file with a different file
// name from the original mFileName. Therefore we have to retrieve
// the file name again.
mDummyDsFile->mFile->GetLeafName(mFileName);
BT_LOGR("mFileName: %s", NS_ConvertUTF16toUTF8(mFileName).get());
// Prepare the entire file path for the .part file
path.Truncate();
path.AssignLiteral(TARGET_SUBDIR);
path.Append(mFileName);
path.AppendLiteral(".part");
mDsFile =
DeviceStorageFile::CreateUnique(path, nsIFile::NORMAL_FILE_TYPE, 0644);
NS_ENSURE_TRUE(mDsFile, false); NS_ENSURE_TRUE(mDsFile, false);
nsCOMPtr<nsIFile> f; NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), mDsFile->mFile);
mDsFile->mFile->Clone(getter_AddRefs(f));
/*
* The function CreateUnique() may create a file with a different file
* name from the original mFileName. Therefore we have to retrieve
* the file name again.
*/
f->GetLeafName(mFileName);
NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
NS_ENSURE_TRUE(mOutputStream, false); NS_ENSURE_TRUE(mOutputStream, false);
return true; return true;
@ -932,6 +977,10 @@ BluetoothOppManager::ServerDataHandler(UnixSocketRawData* aMessage)
// Success to receive a file and notify completion // Success to receive a file and notify completion
if (mPutFinalFlag) { if (mPutFinalFlag) {
mSuccessFlag = true; mSuccessFlag = true;
DeleteDummyFile();
RecoverFileName();
FileTransferComplete(); FileTransferComplete();
NotifyAboutFileChange(); NotifyAboutFileChange();
} }

Просмотреть файл

@ -85,6 +85,8 @@ private:
void ReceivingFileConfirmation(); void ReceivingFileConfirmation();
bool CreateFile(); bool CreateFile();
bool WriteToFile(const uint8_t* aData, int aDataLength); bool WriteToFile(const uint8_t* aData, int aDataLength);
void RecoverFileName();
void DeleteDummyFile();
void DeleteReceivedFile(); void DeleteReceivedFile();
void ReplyToConnect(); void ReplyToConnect();
void ReplyToDisconnectOrAbort(); void ReplyToDisconnectOrAbort();
@ -209,6 +211,7 @@ private:
nsCOMPtr<nsIInputStream> mInputStream; nsCOMPtr<nsIInputStream> mInputStream;
nsCOMPtr<nsIVolumeMountLock> mMountLock; nsCOMPtr<nsIVolumeMountLock> mMountLock;
nsRefPtr<DeviceStorageFile> mDsFile; nsRefPtr<DeviceStorageFile> mDsFile;
nsRefPtr<DeviceStorageFile> mDummyDsFile;
// If a connection has been established, mSocket will be the socket // If a connection has been established, mSocket will be the socket
// communicating with the remote socket. We maintain the invariant that if // communicating with the remote socket. We maintain the invariant that if