diff --git a/dom/devicestorage/DeviceStorage.h b/dom/devicestorage/DeviceStorage.h index 28958e80812..0bce26ba5e2 100644 --- a/dom/devicestorage/DeviceStorage.h +++ b/dom/devicestorage/DeviceStorage.h @@ -31,6 +31,9 @@ public: nsString mRootDir; nsString mPath; bool mEditable; + nsString mMimeType; + uint64_t mLength; + uint64_t mLastModifiedDate; // Used when the path will be set later via SetPath. DeviceStorageFile(const nsAString& aStorageType, @@ -83,6 +86,10 @@ public: static void GetRootDirectoryForType(const nsAString& aStorageType, const nsAString& aStorageName, nsIFile** aFile); + + nsresult CalculateSizeAndModifiedDate(); + nsresult CalculateMimeType(); + private: void Init(); void NormalizeFilePath(); diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index a0d70e7e9f8..ab089a69000 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -487,6 +487,8 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, , mRootDir(aRootDir) , mPath(aPath) , mEditable(false) + , mLength(UINT64_MAX) + , mLastModifiedDate(UINT64_MAX) { Init(); AppendRelativePath(mRootDir); @@ -503,6 +505,8 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, , mStorageName(aStorageName) , mPath(aPath) , mEditable(false) + , mLength(UINT64_MAX) + , mLastModifiedDate(UINT64_MAX) { Init(); AppendRelativePath(aPath); @@ -514,6 +518,8 @@ DeviceStorageFile::DeviceStorageFile(const nsAString& aStorageType, : mStorageType(aStorageType) , mStorageName(aStorageName) , mEditable(false) + , mLength(UINT64_MAX) + , mLastModifiedDate(UINT64_MAX) { Init(); } @@ -958,6 +964,45 @@ DeviceStorageFile::Remove() return NS_OK; } +nsresult +DeviceStorageFile::CalculateMimeType() +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + nsAutoCString mimeType; + nsCOMPtr mimeService = + do_GetService(NS_MIMESERVICE_CONTRACTID); + if (mimeService) { + nsresult rv = mimeService->GetTypeFromFile(mFile, mimeType); + if (NS_FAILED(rv)) { + mimeType.Truncate(); + return rv; + } + } + + mMimeType = NS_ConvertUTF8toUTF16(mimeType); + return NS_OK; +} + +nsresult +DeviceStorageFile::CalculateSizeAndModifiedDate() +{ + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); + + int64_t fileSize; + nsresult rv = mFile->GetFileSize(&fileSize); + NS_ENSURE_SUCCESS(rv, rv); + + mLength = fileSize; + + PRTime modDate; + rv = mFile->GetLastModifiedTime(&modDate); + NS_ENSURE_SUCCESS(rv, rv); + + mLastModifiedDate = modDate; + return NS_OK; +} + void DeviceStorageFile::CollectFiles(nsTArray > &aFiles, PRTime aSince) @@ -1034,6 +1079,7 @@ DeviceStorageFile::collectFilesInternal(nsTArray > & } else if (isFile) { nsRefPtr dsf = new DeviceStorageFile(mStorageType, mStorageName, mRootDir, newPath); + dsf->CalculateSizeAndModifiedDate(); aFiles.AppendElement(dsf); } } @@ -1344,8 +1390,16 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile) nsString compositePath; aFile->GetCompositePath(compositePath); - nsCOMPtr blob = new nsDOMFileFile(aFile->mFile, compositePath, - EmptyString()); + + // This check is useful to know if somewhere the DeviceStorageFile + // has not been properly set. Mimetype is not checked because it can be + // empty. + NS_ASSERTION(aFile->mLength != UINT64_MAX, "Size not set"); + NS_ASSERTION(aFile->mLastModifiedDate != UINT64_MAX, "LastModifiedDate not set"); + + nsCOMPtr blob = new nsDOMFileFile(compositePath, aFile->mMimeType, + aFile->mLength, aFile->mFile, + aFile->mLastModifiedDate); return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob)); } @@ -1486,6 +1540,8 @@ ContinueCursorEvent::GetNextFile() if (!typeChecker->Check(cursorStorageType, file->mFile)) { continue; } + + file->CalculateMimeType(); return file.forget(); } @@ -1867,6 +1923,7 @@ public: : mFile(aFile) { mRequest.swap(aRequest); + mFile->CalculateMimeType(); } ~ReadFileEvent() {} @@ -1884,6 +1941,13 @@ public: } } + if (!r) { + nsresult rv = mFile->CalculateSizeAndModifiedDate(); + if (NS_FAILED(rv)) { + r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_UNKNOWN); + } + } + if (!r) { r = new PostResultEvent(mRequest, mFile); } diff --git a/dom/devicestorage/test/test_app_permissions.html b/dom/devicestorage/test/test_app_permissions.html index 0afae425bfb..dac1feb86b5 100644 --- a/dom/devicestorage/test/test_app_permissions.html +++ b/dom/devicestorage/test/test_app_permissions.html @@ -476,21 +476,25 @@ var gData = [ { type: 'pictures', shouldPass: false, + fileExtension: '.png', test: TestEnumerate }, { type: 'videos', shouldPass: false, + fileExtension: '.ogv', test: TestEnumerate }, { type: 'music', shouldPass: false, + fileExtension: '.ogg', test: TestEnumerate }, { type: 'sdcard', shouldPass: false, + fileExtension: '.txt', test: TestEnumerate }, @@ -498,6 +502,7 @@ var gData = [ { type: 'pictures', shouldPass: true, + fileExtension: '.png', permissions: ["device-storage:pictures"], @@ -506,6 +511,7 @@ var gData = [ { type: 'videos', shouldPass: true, + fileExtension: '.ogv', permissions: ["device-storage:videos"], @@ -514,6 +520,7 @@ var gData = [ { type: 'music', shouldPass: true, + fileExtension: '.ogg', permissions: ["device-storage:music"], @@ -522,6 +529,7 @@ var gData = [ { type: 'sdcard', shouldPass: true, + fileExtension: '.txt', permissions: ["device-storage:sdcard"], @@ -532,6 +540,7 @@ var gData = [ { type: 'pictures', shouldPass: true, + fileExtension: '.png', app: "https://example.com/manifest_cert.webapp", permissions: ["device-storage:pictures"], @@ -541,6 +550,7 @@ var gData = [ { type: 'videos', shouldPass: true, + fileExtension: '.ogv', app: "https://example.com/manifest_cert.webapp", permissions: ["device-storage:videos"], @@ -550,6 +560,7 @@ var gData = [ { type: 'music', shouldPass: true, + fileExtension: '.ogg', app: "https://example.com/manifest_cert.webapp", permissions: ["device-storage:music"], @@ -559,6 +570,7 @@ var gData = [ { type: 'sdcard', shouldPass: true, + fileExtension: '.txt', app: "https://example.com/manifest_cert.webapp", permissions: ["device-storage:sdcard"],