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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Indexed Database.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "FileManager.h"
40 :
41 : #include "mozIStorageConnection.h"
42 : #include "mozIStorageServiceQuotaManagement.h"
43 : #include "mozIStorageStatement.h"
44 : #include "nsISimpleEnumerator.h"
45 :
46 : #include "mozStorageCID.h"
47 : #include "mozStorageHelper.h"
48 : #include "nsContentUtils.h"
49 :
50 : #include "FileInfo.h"
51 : #include "IndexedDatabaseManager.h"
52 :
53 : USING_INDEXEDDB_NAMESPACE
54 :
55 : namespace {
56 :
57 : PLDHashOperator
58 0 : EnumerateToTArray(const PRUint64& aKey,
59 : FileInfo* aValue,
60 : void* aUserArg)
61 : {
62 0 : NS_ASSERTION(aValue, "Null pointer!");
63 0 : NS_ASSERTION(aUserArg, "Null pointer!");
64 :
65 : nsTArray<FileInfo*>* array =
66 0 : static_cast<nsTArray<FileInfo*>*>(aUserArg);
67 :
68 0 : array->AppendElement(aValue);
69 :
70 0 : return PL_DHASH_NEXT;
71 : }
72 :
73 : } // anonymous namespace
74 :
75 : nsresult
76 52 : FileManager::Init(nsIFile* aDirectory,
77 : mozIStorageConnection* aConnection)
78 : {
79 52 : NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
80 :
81 52 : NS_ENSURE_TRUE(mFileInfos.Init(), NS_ERROR_OUT_OF_MEMORY);
82 :
83 : bool exists;
84 52 : nsresult rv = aDirectory->Exists(&exists);
85 52 : NS_ENSURE_SUCCESS(rv, rv);
86 :
87 52 : if (exists) {
88 : bool isDirectory;
89 0 : rv = aDirectory->IsDirectory(&isDirectory);
90 0 : NS_ENSURE_SUCCESS(rv, rv);
91 0 : NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE);
92 : }
93 : else {
94 52 : rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
95 52 : NS_ENSURE_SUCCESS(rv, rv);
96 : }
97 :
98 104 : mozStorageTransaction transaction(aConnection, false);
99 :
100 52 : rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
101 : "CREATE VIRTUAL TABLE fs USING filesystem;"
102 52 : ));
103 52 : NS_ENSURE_SUCCESS(rv, rv);
104 :
105 104 : nsCOMPtr<mozIStorageStatement> stmt;
106 52 : rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
107 : "SELECT name, (name IN (SELECT id FROM file)) FROM fs "
108 : "WHERE path = :path"
109 104 : ), getter_AddRefs(stmt));
110 52 : NS_ENSURE_SUCCESS(rv, rv);
111 :
112 104 : nsString path;
113 52 : rv = aDirectory->GetPath(path);
114 52 : NS_ENSURE_SUCCESS(rv, rv);
115 :
116 52 : rv = stmt->BindStringByName(NS_LITERAL_CSTRING("path"), path);
117 52 : NS_ENSURE_SUCCESS(rv, rv);
118 :
119 : nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
120 104 : do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
121 52 : NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
122 :
123 : bool hasResult;
124 104 : while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
125 0 : nsString name;
126 0 : rv = stmt->GetString(0, name);
127 0 : NS_ENSURE_SUCCESS(rv, rv);
128 :
129 0 : PRInt32 flag = stmt->AsInt32(1);
130 :
131 0 : nsCOMPtr<nsIFile> file;
132 0 : rv = aDirectory->Clone(getter_AddRefs(file));
133 0 : NS_ENSURE_SUCCESS(rv, rv);
134 :
135 0 : rv = file->Append(name);
136 0 : NS_ENSURE_SUCCESS(rv, rv);
137 :
138 0 : if (flag) {
139 0 : rv = ss->UpdateQuotaInformationForFile(file);
140 0 : NS_ENSURE_SUCCESS(rv, rv);
141 : }
142 : else {
143 0 : rv = file->Remove(false);
144 0 : if (NS_FAILED(rv)) {
145 0 : NS_WARNING("Failed to remove orphaned file!");
146 : }
147 : }
148 : }
149 :
150 52 : rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
151 : "DROP TABLE fs;"
152 52 : ));
153 52 : NS_ENSURE_SUCCESS(rv, rv);
154 :
155 52 : rv = aDirectory->GetPath(mDirectoryPath);
156 52 : NS_ENSURE_SUCCESS(rv, rv);
157 :
158 52 : transaction.Commit();
159 52 : return NS_OK;
160 : }
161 :
162 : nsresult
163 52 : FileManager::Load(mozIStorageConnection* aConnection)
164 : {
165 52 : NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
166 :
167 104 : nsCOMPtr<mozIStorageStatement> stmt;
168 52 : nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
169 : "SELECT id, refcount "
170 : "FROM file"
171 104 : ), getter_AddRefs(stmt));
172 52 : NS_ENSURE_SUCCESS(rv, rv);
173 :
174 : bool hasResult;
175 104 : while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
176 : PRInt64 id;
177 0 : rv = stmt->GetInt64(0, &id);
178 0 : NS_ENSURE_SUCCESS(rv, rv);
179 :
180 : PRInt32 refcount;
181 0 : rv = stmt->GetInt32(1, &refcount);
182 0 : NS_ENSURE_SUCCESS(rv, rv);
183 :
184 0 : NS_ASSERTION(refcount, "This shouldn't happen!");
185 :
186 0 : nsRefPtr<FileInfo> fileInfo = FileInfo::Create(this, id);
187 0 : fileInfo->mDBRefCnt = refcount;
188 :
189 0 : if (!mFileInfos.Put(id, fileInfo)) {
190 0 : NS_WARNING("Out of memory?");
191 0 : return NS_ERROR_OUT_OF_MEMORY;
192 : }
193 :
194 0 : mLastFileId = NS_MAX(id, mLastFileId);
195 : }
196 :
197 52 : mLoaded = true;
198 :
199 52 : return NS_OK;
200 : }
201 :
202 : nsresult
203 52 : FileManager::Invalidate()
204 : {
205 52 : if (IndexedDatabaseManager::IsClosed()) {
206 0 : NS_ERROR("Shouldn't be called after shutdown!");
207 0 : return NS_ERROR_UNEXPECTED;
208 : }
209 :
210 104 : nsTArray<FileInfo*> fileInfos;
211 : {
212 104 : MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
213 :
214 52 : NS_ASSERTION(!mInvalidated, "Invalidate more than once?!");
215 52 : mInvalidated = true;
216 :
217 52 : fileInfos.SetCapacity(mFileInfos.Count());
218 52 : mFileInfos.EnumerateRead(EnumerateToTArray, &fileInfos);
219 : }
220 :
221 52 : for (PRUint32 i = 0; i < fileInfos.Length(); i++) {
222 0 : FileInfo* fileInfo = fileInfos.ElementAt(i);
223 0 : fileInfo->ClearDBRefs();
224 : }
225 :
226 52 : return NS_OK;
227 : }
228 :
229 : already_AddRefed<nsIFile>
230 1837 : FileManager::GetDirectory()
231 : {
232 : nsCOMPtr<nsILocalFile> directory =
233 3674 : do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
234 1837 : NS_ENSURE_TRUE(directory, nsnull);
235 :
236 1837 : nsresult rv = directory->InitWithPath(mDirectoryPath);
237 1837 : NS_ENSURE_SUCCESS(rv, nsnull);
238 :
239 1837 : return directory.forget();
240 : }
241 :
242 : already_AddRefed<FileInfo>
243 0 : FileManager::GetFileInfo(PRInt64 aId)
244 : {
245 0 : if (IndexedDatabaseManager::IsClosed()) {
246 0 : NS_ERROR("Shouldn't be called after shutdown!");
247 0 : return nsnull;
248 : }
249 :
250 0 : FileInfo* fileInfo = nsnull;
251 : {
252 0 : MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
253 0 : fileInfo = mFileInfos.Get(aId);
254 : }
255 0 : nsRefPtr<FileInfo> result = fileInfo;
256 0 : return result.forget();
257 : }
258 :
259 : already_AddRefed<FileInfo>
260 0 : FileManager::GetNewFileInfo()
261 : {
262 0 : if (IndexedDatabaseManager::IsClosed()) {
263 0 : NS_ERROR("Shouldn't be called after shutdown!");
264 0 : return nsnull;
265 : }
266 :
267 0 : nsAutoPtr<FileInfo> fileInfo;
268 :
269 : {
270 0 : MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
271 :
272 0 : PRInt64 id = mLastFileId + 1;
273 :
274 0 : fileInfo = FileInfo::Create(this, id);
275 :
276 0 : if (!mFileInfos.Put(id, fileInfo)) {
277 0 : NS_WARNING("Out of memory?");
278 0 : return nsnull;
279 : }
280 :
281 0 : mLastFileId = id;
282 : }
283 :
284 0 : nsRefPtr<FileInfo> result = fileInfo.forget();
285 0 : return result.forget();
286 : }
287 :
288 : already_AddRefed<nsIFile>
289 0 : FileManager::GetFileForId(nsIFile* aDirectory, PRInt64 aId)
290 : {
291 0 : NS_ASSERTION(aDirectory, "Null pointer!");
292 :
293 0 : nsAutoString id;
294 0 : id.AppendInt(aId);
295 :
296 0 : nsCOMPtr<nsIFile> file;
297 0 : nsresult rv = aDirectory->Clone(getter_AddRefs(file));
298 0 : NS_ENSURE_SUCCESS(rv, nsnull);
299 :
300 0 : rv = file->Append(id);
301 0 : NS_ENSURE_SUCCESS(rv, nsnull);
302 :
303 0 : return file.forget();
304 : }
|