1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FileManager.h"
9 #include "mozIStorageConnection.h"
10 #include "mozIStorageStatement.h"
11 #include "nsIInputStream.h"
12 #include "nsISimpleEnumerator.h"
14 #include "mozilla/dom/quota/Utilities.h"
15 #include "mozStorageCID.h"
16 #include "mozStorageHelper.h"
20 #include "IndexedDatabaseManager.h"
21 #include "OpenDatabaseHelper.h"
23 #include "IndexedDatabaseInlines.h"
26 USING_INDEXEDDB_NAMESPACE
27 using mozilla::dom::quota::AssertIsOnIOThread
;
32 EnumerateToTArray(const uint64_t& aKey
,
36 NS_ASSERTION(aValue
, "Null pointer!");
37 NS_ASSERTION(aUserArg
, "Null pointer!");
39 nsTArray
<FileInfo
*>* array
=
40 static_cast<nsTArray
<FileInfo
*>*>(aUserArg
);
42 array
->AppendElement(aValue
);
47 already_AddRefed
<nsIFile
>
48 GetDirectoryFor(const nsAString
& aDirectoryPath
)
50 nsCOMPtr
<nsIFile
> directory
=
51 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
);
52 NS_ENSURE_TRUE(directory
, nullptr);
54 nsresult rv
= directory
->InitWithPath(aDirectoryPath
);
55 NS_ENSURE_SUCCESS(rv
, nullptr);
57 return directory
.forget();
60 } // anonymous namespace
63 FileManager::Init(nsIFile
* aDirectory
,
64 mozIStorageConnection
* aConnection
)
67 NS_ASSERTION(aDirectory
, "Null directory!");
68 NS_ASSERTION(aConnection
, "Null connection!");
71 nsresult rv
= aDirectory
->Exists(&exists
);
72 NS_ENSURE_SUCCESS(rv
, rv
);
76 rv
= aDirectory
->IsDirectory(&isDirectory
);
77 NS_ENSURE_SUCCESS(rv
, rv
);
78 NS_ENSURE_TRUE(isDirectory
, NS_ERROR_FAILURE
);
81 rv
= aDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
82 NS_ENSURE_SUCCESS(rv
, rv
);
85 rv
= aDirectory
->GetPath(mDirectoryPath
);
86 NS_ENSURE_SUCCESS(rv
, rv
);
88 nsCOMPtr
<nsIFile
> journalDirectory
;
89 rv
= aDirectory
->Clone(getter_AddRefs(journalDirectory
));
90 NS_ENSURE_SUCCESS(rv
, rv
);
92 rv
= journalDirectory
->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME
));
93 NS_ENSURE_SUCCESS(rv
, rv
);
95 rv
= journalDirectory
->Exists(&exists
);
96 NS_ENSURE_SUCCESS(rv
, rv
);
100 rv
= journalDirectory
->IsDirectory(&isDirectory
);
101 NS_ENSURE_SUCCESS(rv
, rv
);
102 NS_ENSURE_TRUE(isDirectory
, NS_ERROR_FAILURE
);
105 rv
= journalDirectory
->GetPath(mJournalDirectoryPath
);
106 NS_ENSURE_SUCCESS(rv
, rv
);
108 nsCOMPtr
<mozIStorageStatement
> stmt
;
109 rv
= aConnection
->CreateStatement(NS_LITERAL_CSTRING(
110 "SELECT id, refcount "
112 ), getter_AddRefs(stmt
));
113 NS_ENSURE_SUCCESS(rv
, rv
);
116 while (NS_SUCCEEDED(stmt
->ExecuteStep(&hasResult
)) && hasResult
) {
118 rv
= stmt
->GetInt64(0, &id
);
119 NS_ENSURE_SUCCESS(rv
, rv
);
122 rv
= stmt
->GetInt32(1, &refcount
);
123 NS_ENSURE_SUCCESS(rv
, rv
);
125 NS_ASSERTION(refcount
, "This shouldn't happen!");
127 nsRefPtr
<FileInfo
> fileInfo
= FileInfo::Create(this, id
);
128 fileInfo
->mDBRefCnt
= refcount
;
130 mFileInfos
.Put(id
, fileInfo
);
132 mLastFileId
= std::max(id
, mLastFileId
);
139 FileManager::Invalidate()
141 if (IndexedDatabaseManager::IsClosed()) {
142 NS_ERROR("Shouldn't be called after shutdown!");
143 return NS_ERROR_UNEXPECTED
;
146 nsTArray
<FileInfo
*> fileInfos
;
148 MutexAutoLock
lock(IndexedDatabaseManager::FileMutex());
150 NS_ASSERTION(!mInvalidated
, "Invalidate more than once?!");
153 fileInfos
.SetCapacity(mFileInfos
.Count());
154 mFileInfos
.EnumerateRead(EnumerateToTArray
, &fileInfos
);
157 for (uint32_t i
= 0; i
< fileInfos
.Length(); i
++) {
158 FileInfo
* fileInfo
= fileInfos
.ElementAt(i
);
159 fileInfo
->ClearDBRefs();
165 already_AddRefed
<nsIFile
>
166 FileManager::GetDirectory()
168 return GetDirectoryFor(mDirectoryPath
);
171 already_AddRefed
<nsIFile
>
172 FileManager::GetJournalDirectory()
174 return GetDirectoryFor(mJournalDirectoryPath
);
177 already_AddRefed
<nsIFile
>
178 FileManager::EnsureJournalDirectory()
180 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
182 nsCOMPtr
<nsIFile
> journalDirectory
= GetDirectoryFor(mJournalDirectoryPath
);
183 NS_ENSURE_TRUE(journalDirectory
, nullptr);
186 nsresult rv
= journalDirectory
->Exists(&exists
);
187 NS_ENSURE_SUCCESS(rv
, nullptr);
191 rv
= journalDirectory
->IsDirectory(&isDirectory
);
192 NS_ENSURE_SUCCESS(rv
, nullptr);
193 NS_ENSURE_TRUE(isDirectory
, nullptr);
196 rv
= journalDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
197 NS_ENSURE_SUCCESS(rv
, nullptr);
200 return journalDirectory
.forget();
203 already_AddRefed
<FileInfo
>
204 FileManager::GetFileInfo(int64_t aId
)
206 if (IndexedDatabaseManager::IsClosed()) {
207 NS_ERROR("Shouldn't be called after shutdown!");
211 FileInfo
* fileInfo
= nullptr;
213 MutexAutoLock
lock(IndexedDatabaseManager::FileMutex());
214 fileInfo
= mFileInfos
.Get(aId
);
216 nsRefPtr
<FileInfo
> result
= fileInfo
;
217 return result
.forget();
220 already_AddRefed
<FileInfo
>
221 FileManager::GetNewFileInfo()
223 if (IndexedDatabaseManager::IsClosed()) {
224 NS_ERROR("Shouldn't be called after shutdown!");
228 nsAutoPtr
<FileInfo
> fileInfo
;
231 MutexAutoLock
lock(IndexedDatabaseManager::FileMutex());
233 int64_t id
= mLastFileId
+ 1;
235 fileInfo
= FileInfo::Create(this, id
);
237 mFileInfos
.Put(id
, fileInfo
);
242 nsRefPtr
<FileInfo
> result
= fileInfo
.forget();
243 return result
.forget();
247 already_AddRefed
<nsIFile
>
248 FileManager::GetFileForId(nsIFile
* aDirectory
, int64_t aId
)
250 NS_ASSERTION(aDirectory
, "Null pointer!");
255 nsCOMPtr
<nsIFile
> file
;
256 nsresult rv
= aDirectory
->Clone(getter_AddRefs(file
));
257 NS_ENSURE_SUCCESS(rv
, nullptr);
259 rv
= file
->Append(id
);
260 NS_ENSURE_SUCCESS(rv
, nullptr);
262 return file
.forget();
267 FileManager::InitDirectory(nsIFile
* aDirectory
,
268 nsIFile
* aDatabaseFile
,
269 PersistenceType aPersistenceType
,
270 const nsACString
& aGroup
,
271 const nsACString
& aOrigin
)
273 AssertIsOnIOThread();
274 NS_ASSERTION(aDirectory
, "Null directory!");
275 NS_ASSERTION(aDatabaseFile
, "Null database file!");
278 nsresult rv
= aDirectory
->Exists(&exists
);
279 NS_ENSURE_SUCCESS(rv
, rv
);
286 rv
= aDirectory
->IsDirectory(&isDirectory
);
287 NS_ENSURE_SUCCESS(rv
, rv
);
288 NS_ENSURE_TRUE(isDirectory
, NS_ERROR_FAILURE
);
290 nsCOMPtr
<nsIFile
> journalDirectory
;
291 rv
= aDirectory
->Clone(getter_AddRefs(journalDirectory
));
292 NS_ENSURE_SUCCESS(rv
, rv
);
294 rv
= journalDirectory
->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME
));
295 NS_ENSURE_SUCCESS(rv
, rv
);
297 rv
= journalDirectory
->Exists(&exists
);
298 NS_ENSURE_SUCCESS(rv
, rv
);
301 rv
= journalDirectory
->IsDirectory(&isDirectory
);
302 NS_ENSURE_SUCCESS(rv
, rv
);
303 NS_ENSURE_TRUE(isDirectory
, NS_ERROR_FAILURE
);
305 nsCOMPtr
<nsISimpleEnumerator
> entries
;
306 rv
= journalDirectory
->GetDirectoryEntries(getter_AddRefs(entries
));
307 NS_ENSURE_SUCCESS(rv
, rv
);
310 rv
= entries
->HasMoreElements(&hasElements
);
311 NS_ENSURE_SUCCESS(rv
, rv
);
314 nsCOMPtr
<mozIStorageConnection
> connection
;
315 rv
= OpenDatabaseHelper::CreateDatabaseConnection(aDatabaseFile
,
316 aDirectory
, NullString(), aPersistenceType
, aGroup
, aOrigin
,
317 getter_AddRefs(connection
));
318 NS_ENSURE_SUCCESS(rv
, rv
);
320 mozStorageTransaction
transaction(connection
, false);
322 rv
= connection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
323 "CREATE VIRTUAL TABLE fs USING filesystem;"
325 NS_ENSURE_SUCCESS(rv
, rv
);
327 nsCOMPtr
<mozIStorageStatement
> stmt
;
328 rv
= connection
->CreateStatement(NS_LITERAL_CSTRING(
329 "SELECT name, (name IN (SELECT id FROM file)) FROM fs "
331 ), getter_AddRefs(stmt
));
332 NS_ENSURE_SUCCESS(rv
, rv
);
335 rv
= journalDirectory
->GetPath(path
);
336 NS_ENSURE_SUCCESS(rv
, rv
);
338 rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("path"), path
);
339 NS_ENSURE_SUCCESS(rv
, rv
);
342 while (NS_SUCCEEDED(stmt
->ExecuteStep(&hasResult
)) && hasResult
) {
344 rv
= stmt
->GetString(0, name
);
345 NS_ENSURE_SUCCESS(rv
, rv
);
347 int32_t flag
= stmt
->AsInt32(1);
350 nsCOMPtr
<nsIFile
> file
;
351 rv
= aDirectory
->Clone(getter_AddRefs(file
));
352 NS_ENSURE_SUCCESS(rv
, rv
);
354 rv
= file
->Append(name
);
355 NS_ENSURE_SUCCESS(rv
, rv
);
357 if (NS_FAILED(file
->Remove(false))) {
358 NS_WARNING("Failed to remove orphaned file!");
362 nsCOMPtr
<nsIFile
> journalFile
;
363 rv
= journalDirectory
->Clone(getter_AddRefs(journalFile
));
364 NS_ENSURE_SUCCESS(rv
, rv
);
366 rv
= journalFile
->Append(name
);
367 NS_ENSURE_SUCCESS(rv
, rv
);
369 if (NS_FAILED(journalFile
->Remove(false))) {
370 NS_WARNING("Failed to remove journal file!");
374 rv
= connection
->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
377 NS_ENSURE_SUCCESS(rv
, rv
);
379 transaction
.Commit();
388 FileManager::GetUsage(nsIFile
* aDirectory
, uint64_t* aUsage
)
390 AssertIsOnIOThread();
393 nsresult rv
= aDirectory
->Exists(&exists
);
394 NS_ENSURE_SUCCESS(rv
, rv
);
401 nsCOMPtr
<nsISimpleEnumerator
> entries
;
402 rv
= aDirectory
->GetDirectoryEntries(getter_AddRefs(entries
));
403 NS_ENSURE_SUCCESS(rv
, rv
);
408 while (NS_SUCCEEDED((rv
= entries
->HasMoreElements(&hasMore
))) && hasMore
) {
409 nsCOMPtr
<nsISupports
> entry
;
410 rv
= entries
->GetNext(getter_AddRefs(entry
));
411 NS_ENSURE_SUCCESS(rv
, rv
);
413 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(entry
);
414 NS_ENSURE_TRUE(file
, NS_NOINTERFACE
);
417 rv
= file
->GetLeafName(leafName
);
418 NS_ENSURE_SUCCESS(rv
, rv
);
420 if (leafName
.EqualsLiteral(JOURNAL_DIRECTORY_NAME
)) {
425 rv
= file
->GetFileSize(&fileSize
);
426 NS_ENSURE_SUCCESS(rv
, rv
);
428 quota::IncrementUsage(&usage
, uint64_t(fileSize
));