Bug 335545 - Use nsAnonymousTemporaryFile for clipboard cache r=mstange

The cache file is never directly exposed to consumers of DataStruct,
so it does not make sense to keep the clipboardcache file around
forever.

The only change in this commit is to switch from using a filename to
using a file descriptor. In the destructor, the FD is explicitly closed
(which releases the file data).  nsAnonymousTemporaryFile takes care
of removing the file when the destructor is not called (e.g. crashes).

Previously, the clipboard cache was stored in a file called:
TmpD/clipboardcache-N

As of this commit, the clipboard cache is stored at:
TmpD/mozilla-temp-randomN (macOS and Linux)
TmpD/mozilla-temp-files/mozilla-temp-randomN (Windows)
(see xpcom/io/nsAnonymousTemporaryFile.{h,cpp} for more details)

To verify that these files are really gone:
1. Create a document with 500k+ characters, open it in Firefox.
2. Copy its content - this will trigger the clipboard cache.
3. Look for the open file descriptor of the deleted file:
   ( macOS and Linux: )
   lsof +L1 | grep mozilla-temp
4. Copy anything (under the 500k threshold), or quit/kill Firefox.
5. Repeat step 3 and observe that the number of file descriptors
   has decreased.

MozReview-Commit-ID: 85GlKQrNUl5

--HG--
extra : rebase_source : eb05c1d4600f62373aa1b7e472154b57b99e6bf8
This commit is contained in:
Rob Wu 2017-09-03 02:29:10 +02:00
Родитель c1ce54a82a
Коммит ecc04a9245
2 изменённых файлов: 42 добавлений и 97 удалений

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

@ -14,6 +14,7 @@ Notes to self:
#include "nsTransferable.h"
#include "nsAnonymousTemporaryFile.h"
#include "nsArray.h"
#include "nsArrayUtils.h"
#include "nsString.h"
@ -35,7 +36,6 @@ Notes to self:
#include "nsIOutputStream.h"
#include "nsIInputStream.h"
#include "nsIWeakReferenceUtils.h"
#include "nsIFile.h"
#include "nsILoadContext.h"
#include "mozilla/UniquePtr.h"
@ -55,7 +55,9 @@ size_t GetDataForFlavor (const nsTArray<DataStruct>& aArray,
//-------------------------------------------------------------------------
DataStruct::~DataStruct()
{
if (mCacheFileName) free(mCacheFileName);
if (mCacheFD) {
PR_Close(mCacheFD);
}
}
//-------------------------------------------------------------------------
@ -82,7 +84,7 @@ void
DataStruct::GetData ( nsISupports** aData, uint32_t *aDataLen )
{
// check here to see if the data is cached on disk
if ( !mData && mCacheFileName ) {
if ( !mData && mCacheFD ) {
// if so, read it in and pass it back
// ReadCache creates memory and copies the data into it.
if ( NS_SUCCEEDED(ReadCache(aData, aDataLen)) )
@ -103,62 +105,25 @@ DataStruct::GetData ( nsISupports** aData, uint32_t *aDataLen )
}
//-------------------------------------------------------------------------
already_AddRefed<nsIFile>
DataStruct::GetFileSpec(const char* aFileName)
{
nsCOMPtr<nsIFile> cacheFile;
NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(cacheFile));
if (!cacheFile)
return nullptr;
// if the param aFileName contains a name we should use that
// because the file probably already exists
// otherwise create a unique name
if (!aFileName) {
cacheFile->AppendNative(NS_LITERAL_CSTRING("clipboardcache"));
nsresult rv = cacheFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv))
return nullptr;
} else {
cacheFile->AppendNative(nsDependentCString(aFileName));
}
return cacheFile.forget();
}
//-------------------------------------------------------------------------
nsresult
DataStruct::WriteCache(nsISupports* aData, uint32_t aDataLen)
{
// Get a new path and file to the temp directory
nsCOMPtr<nsIFile> cacheFile = GetFileSpec(mCacheFileName);
if (cacheFile) {
// remember the file name
if (!mCacheFileName) {
nsCString fName;
cacheFile->GetNativeLeafName(fName);
mCacheFileName = strdup(fName.get());
nsresult rv;
if (!mCacheFD) {
rv = NS_OpenAnonymousTemporaryFile(&mCacheFD);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
}
// write out the contents of the clipboard
// to the file
//uint32_t bytes;
nsCOMPtr<nsIOutputStream> outStr;
NS_NewLocalFileOutputStream(getter_AddRefs(outStr),
cacheFile);
if (!outStr) return NS_ERROR_FAILURE;
void* buff = nullptr;
nsPrimitiveHelpers::CreateDataFromPrimitive ( mFlavor, aData, &buff, aDataLen );
if ( buff ) {
uint32_t ignored;
outStr->Write(reinterpret_cast<char*>(buff), aDataLen, &ignored);
free(buff);
// write out the contents of the clipboard to the file
void* buff = nullptr;
nsPrimitiveHelpers::CreateDataFromPrimitive(mFlavor, aData, &buff, aDataLen);
if (buff) {
int32_t written = PR_Write(mCacheFD, buff, aDataLen);
free(buff);
if (written) {
return NS_OK;
}
}
@ -170,49 +135,29 @@ DataStruct::WriteCache(nsISupports* aData, uint32_t aDataLen)
nsresult
DataStruct::ReadCache(nsISupports** aData, uint32_t* aDataLen)
{
// if we don't have a cache filename we are out of luck
if (!mCacheFileName)
if (!mCacheFD) {
return NS_ERROR_FAILURE;
// get the path and file name
nsCOMPtr<nsIFile> cacheFile = GetFileSpec(mCacheFileName);
bool exists;
if ( cacheFile && NS_SUCCEEDED(cacheFile->Exists(&exists)) && exists ) {
// get the size of the file
int64_t fileSize;
int64_t max32 = 0xFFFFFFFF;
cacheFile->GetFileSize(&fileSize);
if (fileSize > max32)
return NS_ERROR_OUT_OF_MEMORY;
uint32_t size = uint32_t(fileSize);
// create new memory for the large clipboard data
auto data = mozilla::MakeUnique<char[]>(size);
if ( !data )
return NS_ERROR_OUT_OF_MEMORY;
// now read it all in
nsCOMPtr<nsIInputStream> inStr;
NS_NewLocalFileInputStream( getter_AddRefs(inStr),
cacheFile);
if (!cacheFile) return NS_ERROR_FAILURE;
nsresult rv = inStr->Read(data.get(), fileSize, aDataLen);
// make sure we got all the data ok
if (NS_SUCCEEDED(rv) && *aDataLen == size) {
nsPrimitiveHelpers::CreatePrimitiveForData(mFlavor, data.get(),
fileSize, aData);
return *aData ? NS_OK : NS_ERROR_FAILURE;
}
// zero the return params
*aData = nullptr;
*aDataLen = 0;
}
return NS_ERROR_FAILURE;
PRFileInfo fileInfo;
if (PR_GetOpenFileInfo(mCacheFD, &fileInfo) != PR_SUCCESS) {
return NS_ERROR_FAILURE;
}
uint32_t fileSize = fileInfo.size;
auto data = mozilla::MakeUnique<char[]>(fileSize);
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t actual = PR_Read(mCacheFD, data.get(), fileSize);
// actual = 0 means end of file.
if (actual != 0 && actual != fileSize) {
return NS_ERROR_FAILURE;
}
nsPrimitiveHelpers::CreatePrimitiveForData(mFlavor, data.get(), fileSize, aData);
return NS_OK;
}

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

@ -12,6 +12,7 @@
#include "nsString.h"
#include "nsTArray.h"
#include "nsIPrincipal.h"
#include "prio.h"
class nsIMutableArray;
@ -23,14 +24,13 @@ class nsIMutableArray;
struct DataStruct
{
explicit DataStruct ( const char* aFlavor )
: mDataLen(0), mFlavor(aFlavor), mCacheFileName(nullptr) { }
: mDataLen(0), mCacheFD(nullptr), mFlavor(aFlavor) { }
~DataStruct();
const nsCString& GetFlavor() const { return mFlavor; }
void SetData( nsISupports* inData, uint32_t inDataLen, bool aIsPrivateData );
void GetData( nsISupports** outData, uint32_t *outDataLen );
already_AddRefed<nsIFile> GetFileSpec(const char* aFileName);
bool IsDataAvailable() const { return (mData && mDataLen > 0) || (!mData && mCacheFileName); }
bool IsDataAvailable() const { return mData ? mDataLen > 0 : mCacheFD != nullptr; }
protected:
@ -45,8 +45,8 @@ protected:
nsCOMPtr<nsISupports> mData; // OWNER - some varient of primitive wrapper
uint32_t mDataLen;
PRFileDesc* mCacheFD;
const nsCString mFlavor;
char * mCacheFileName;
};