nsresult OpenStorageFile(const nsCString& aRecordName, const nsString& aNodeId, const OpenFileMode aMode, PRFileDesc** aOutFD) { MOZ_ASSERT(aOutFD); nsCOMPtr<nsIFile> f; nsresult rv = GetGMPStorageDir(getter_AddRefs(f), aNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsAutoString recordNameHash; recordNameHash.AppendInt(HashString(aRecordName.get())); f->Append(recordNameHash); auto mode = PR_RDWR | PR_CREATE_FILE; if (aMode == Truncate) { mode |= PR_TRUNCATE; } return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD); }
nsresult RemoveStorageFile(const nsString& aFilename) { nsCOMPtr<nsIFile> f; nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } rv = f->Append(aFilename); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return f->Remove(/* bool recursive= */ false); }
nsresult OpenStorageFile(const nsAString& aFileLeafName, const OpenFileMode aMode, PRFileDesc** aOutFD) { MOZ_ASSERT(aOutFD); nsCOMPtr<nsIFile> f; nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } f->Append(aFileLeafName); auto mode = PR_RDWR | PR_CREATE_FILE; if (aMode == Truncate) { mode |= PR_TRUNCATE; } return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD); }
// We store records in a file which is a hash of the record name. // If there is a hash collision, we just keep adding 1 to the hash // code, until we find a free slot. nsresult GetUnusedFilename(const nsACString& aRecordName, nsString& aOutFilename) { nsCOMPtr<nsIFile> storageDir; nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } uint64_t recordNameHash = HashString(PromiseFlatCString(aRecordName).get()); for (int i = 0; i < 1000000; i++) { nsCOMPtr<nsIFile> f; rv = storageDir->Clone(getter_AddRefs(f)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsAutoString hashStr; hashStr.AppendInt(recordNameHash); rv = f->Append(hashStr); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } bool exists = false; f->Exists(&exists); if (!exists) { // Filename not in use, we can write into this file. aOutFilename = hashStr; return NS_OK; } else { // Hash collision; just increment the hash name and try that again. ++recordNameHash; continue; } } // Somehow, we've managed to completely fail to find a vacant file name. // Give up. NS_WARNING("GetUnusedFilename had extreme hash collision!"); return NS_ERROR_FAILURE; }
nsresult Init() { // Build our index of records on disk. nsCOMPtr<nsIFile> storageDir; nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } DirectoryEnumerator iter(storageDir, DirectoryEnumerator::FilesAndDirs); for (nsCOMPtr<nsIFile> dirEntry; (dirEntry = iter.Next()) != nullptr;) { PRFileDesc* fd = nullptr; if (NS_FAILED(dirEntry->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) { continue; } int32_t recordLength = 0; nsCString recordName; nsresult err = ReadRecordMetadata(fd, recordLength, recordName); PR_Close(fd); if (NS_FAILED(err)) { // File is not a valid storage file. Don't index it. Delete the file, // to make our indexing faster in future. dirEntry->Remove(false); continue; } nsAutoString filename; rv = dirEntry->GetLeafName(filename); if (NS_FAILED(rv)) { continue; } mRecords.Put(recordName, new Record(filename, recordName)); } return NS_OK; }