- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / safe_browsing / safe_browsing_store_file.h
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_FILE_H_
6 #define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_FILE_H_
7
8 #include <set>
9 #include <vector>
10
11 #include "chrome/browser/safe_browsing/safe_browsing_store.h"
12
13 #include "base/callback.h"
14 #include "base/file_util.h"
15
16 // Implement SafeBrowsingStore in terms of a flat file.  The file
17 // format is pretty literal:
18 //
19 // int32 magic;             // magic number "validating" file
20 // int32 version;           // format version
21 //
22 // // Counts for the various data which follows the header.
23 // uint32 add_chunk_count;   // Chunks seen, including empties.
24 // uint32 sub_chunk_count;   // Ditto.
25 // uint32 add_prefix_count;
26 // uint32 sub_prefix_count;
27 // uint32 add_hash_count;
28 // uint32 sub_hash_count;
29 //
30 // array[add_chunk_count] {
31 //   int32 chunk_id;
32 // }
33 // array[sub_chunk_count] {
34 //   int32 chunk_id;
35 // }
36 // array[add_prefix_count] {
37 //   int32 chunk_id;
38 //   int32 prefix;
39 // }
40 // array[sub_prefix_count] {
41 //   int32 chunk_id;
42 //   int32 add_chunk_id;
43 //   int32 add_prefix;
44 // }
45 // array[add_hash_count] {
46 //   int32 chunk_id;
47 //   int32 received_time;     // From base::Time::ToTimeT().
48 //   char[32] full_hash;
49 // array[sub_hash_count] {
50 //   int32 chunk_id;
51 //   int32 add_chunk_id;
52 //   char[32] add_full_hash;
53 // }
54 // MD5Digest checksum;      // Checksum over preceeding data.
55 //
56 // During the course of an update, uncommitted data is stored in a
57 // temporary file (which is later re-used to commit).  This is an
58 // array of chunks, with the count kept in memory until the end of the
59 // transaction.  The format of this file is like the main file, with
60 // the list of chunks seen omitted, as that data is tracked in-memory:
61 //
62 // array[] {
63 //   uint32 add_prefix_count;
64 //   uint32 sub_prefix_count;
65 //   uint32 add_hash_count;
66 //   uint32 sub_hash_count;
67 //   array[add_prefix_count] {
68 //     int32 chunk_id;
69 //     int32 prefix;
70 //   }
71 //   array[sub_prefix_count] {
72 //     int32 chunk_id;
73 //     int32 add_chunk_id;
74 //     int32 add_prefix;
75 //   }
76 //   array[add_hash_count] {
77 //     int32 chunk_id;
78 //     int32 received_time;     // From base::Time::ToTimeT().
79 //     char[32] full_hash;
80 //   }
81 //   array[sub_hash_count] {
82 //     int32 chunk_id;
83 //     int32 add_chunk_id;
84 //     char[32] add_full_hash;
85 //   }
86 // }
87 //
88 // The overall transaction works like this:
89 // - Open the original file to get the chunks-seen data.
90 // - Open a temp file for storing new chunk info.
91 // - Write new chunks to the temp file.
92 // - When the transaction is finished:
93 //   - Read the rest of the original file's data into buffers.
94 //   - Rewind the temp file and merge the new data into buffers.
95 //   - Process buffers for deletions and apply subs.
96 //   - Rewind and write the buffers out to temp file.
97 //   - Delete original file.
98 //   - Rename temp file to original filename.
99
100 // TODO(shess): By using a checksum, this code can avoid doing an
101 // fsync(), at the possible cost of more frequently retrieving the
102 // full dataset.  Measure how often this occurs, and if it occurs too
103 // often, consider retaining the last known-good file for recovery
104 // purposes, rather than deleting it.
105
106 class SafeBrowsingStoreFile : public SafeBrowsingStore {
107  public:
108   SafeBrowsingStoreFile();
109   virtual ~SafeBrowsingStoreFile();
110
111   virtual void Init(const base::FilePath& filename,
112                     const base::Closure& corruption_callback) OVERRIDE;
113
114   // Delete any on-disk files, including the permanent storage.
115   virtual bool Delete() OVERRIDE;
116
117   // Get all add hash prefixes and full-length hashes, respectively, from
118   // the store.
119   virtual bool GetAddPrefixes(SBAddPrefixes* add_prefixes) OVERRIDE;
120   virtual bool GetAddFullHashes(
121       std::vector<SBAddFullHash>* add_full_hashes) OVERRIDE;
122
123   virtual bool BeginChunk() OVERRIDE;
124
125   virtual bool WriteAddPrefix(int32 chunk_id, SBPrefix prefix) OVERRIDE;
126   virtual bool WriteAddHash(int32 chunk_id,
127                             base::Time receive_time,
128                             const SBFullHash& full_hash) OVERRIDE;
129   virtual bool WriteSubPrefix(int32 chunk_id,
130                               int32 add_chunk_id, SBPrefix prefix) OVERRIDE;
131   virtual bool WriteSubHash(int32 chunk_id, int32 add_chunk_id,
132                             const SBFullHash& full_hash) OVERRIDE;
133   virtual bool FinishChunk() OVERRIDE;
134
135   virtual bool BeginUpdate() OVERRIDE;
136   // Store updates with pending add full hashes in file store and
137   // return |add_prefixes_result| and |add_full_hashes_result|.
138   virtual bool FinishUpdate(
139       const std::vector<SBAddFullHash>& pending_adds,
140       const std::set<SBPrefix>& prefix_misses,
141       SBAddPrefixes* add_prefixes_result,
142       std::vector<SBAddFullHash>* add_full_hashes_result) OVERRIDE;
143   virtual bool CancelUpdate() OVERRIDE;
144
145   virtual void SetAddChunk(int32 chunk_id) OVERRIDE;
146   virtual bool CheckAddChunk(int32 chunk_id) OVERRIDE;
147   virtual void GetAddChunks(std::vector<int32>* out) OVERRIDE;
148   virtual void SetSubChunk(int32 chunk_id) OVERRIDE;
149   virtual bool CheckSubChunk(int32 chunk_id) OVERRIDE;
150   virtual void GetSubChunks(std::vector<int32>* out) OVERRIDE;
151
152   virtual void DeleteAddChunk(int32 chunk_id) OVERRIDE;
153   virtual void DeleteSubChunk(int32 chunk_id) OVERRIDE;
154
155   // Verify |file_|'s checksum, calling the corruption callback if it
156   // does not check out.  Empty input is considered valid.
157   virtual bool CheckValidity() OVERRIDE;
158
159   // Returns the name of the temporary file used to buffer data for
160   // |filename|.  Exported for unit tests.
161   static const base::FilePath TemporaryFileForFilename(
162       const base::FilePath& filename) {
163     return base::FilePath(filename.value() + FILE_PATH_LITERAL("_new"));
164   }
165
166   // Delete any on-disk files, including the permanent storage.
167   static bool DeleteStore(const base::FilePath& basename);
168
169  private:
170   // Update store file with pending full hashes.
171   virtual bool DoUpdate(const std::vector<SBAddFullHash>& pending_adds,
172                         const std::set<SBPrefix>& prefix_misses,
173                         SBAddPrefixes* add_prefixes_result,
174                         std::vector<SBAddFullHash>* add_full_hashes_result);
175
176   // Enumerate different format-change events for histogramming
177   // purposes.  DO NOT CHANGE THE ORDERING OF THESE VALUES.
178   // TODO(shess): Remove this once the format change is complete.
179   enum FormatEventType {
180     // Corruption detected, broken down by file format.
181     FORMAT_EVENT_FILE_CORRUPT,
182     FORMAT_EVENT_SQLITE_CORRUPT,  // Obsolete
183
184     // The type of format found in the file.  The expected case (new
185     // file format) is intentionally not covered.
186     FORMAT_EVENT_FOUND_SQLITE,
187     FORMAT_EVENT_FOUND_UNKNOWN,
188
189     // The number of SQLite-format files deleted should be the same as
190     // FORMAT_EVENT_FOUND_SQLITE.  It can differ if the delete fails,
191     // or if a failure prevents the update from succeeding.
192     FORMAT_EVENT_SQLITE_DELETED,  // Obsolete
193     FORMAT_EVENT_SQLITE_DELETE_FAILED,  // Obsolete
194
195     // Found and deleted (or failed to delete) the ancient "Safe
196     // Browsing" file.
197     FORMAT_EVENT_DELETED_ORIGINAL,
198     FORMAT_EVENT_DELETED_ORIGINAL_FAILED,
199
200     // The checksum did not check out in CheckValidity() or in
201     // FinishUpdate().  This most likely indicates that the machine
202     // crashed before the file was fully sync'ed to disk.
203     FORMAT_EVENT_VALIDITY_CHECKSUM_FAILURE,
204     FORMAT_EVENT_UPDATE_CHECKSUM_FAILURE,
205
206     // Memory space for histograms is determined by the max.  ALWAYS
207     // ADD NEW VALUES BEFORE THIS ONE.
208     FORMAT_EVENT_MAX
209   };
210
211   // Helper to record an event related to format conversion from
212   // SQLite to file.
213   static void RecordFormatEvent(FormatEventType event_type);
214
215   // Some very lucky users have an original-format file still in their
216   // profile.  Check for it and delete, recording a histogram for the
217   // result (no histogram for not-found).  Logically this
218   // would make more sense at the SafeBrowsingDatabase level, but
219   // practically speaking that code doesn't touch files directly.
220   static void CheckForOriginalAndDelete(const base::FilePath& filename);
221
222   // Close all files and clear all buffers.
223   bool Close();
224
225   // Calls |corruption_callback_| if non-NULL, always returns false as
226   // a convenience to the caller.
227   bool OnCorruptDatabase();
228
229   // Helper for creating a corruption callback for |old_store_|.
230   // TODO(shess): Remove after migration.
231   void HandleCorruptDatabase();
232
233   // Clear temporary buffers used to accumulate chunk data.
234   bool ClearChunkBuffers() {
235     // NOTE: .clear() doesn't release memory.
236     // TODO(shess): Figure out if this is overkill.  Some amount of
237     // pre-reserved space is probably reasonable between each chunk
238     // collected.
239     SBAddPrefixes().swap(add_prefixes_);
240     SBSubPrefixes().swap(sub_prefixes_);
241     std::vector<SBAddFullHash>().swap(add_hashes_);
242     std::vector<SBSubFullHash>().swap(sub_hashes_);
243     return true;
244   }
245
246   // Clear all buffers used during update.
247   void ClearUpdateBuffers() {
248     ClearChunkBuffers();
249     chunks_written_ = 0;
250     std::set<int32>().swap(add_chunks_cache_);
251     std::set<int32>().swap(sub_chunks_cache_);
252     base::hash_set<int32>().swap(add_del_cache_);
253     base::hash_set<int32>().swap(sub_del_cache_);
254   }
255
256   // Buffers for collecting data between BeginChunk() and
257   // FinishChunk().
258   SBAddPrefixes add_prefixes_;
259   SBSubPrefixes sub_prefixes_;
260   std::vector<SBAddFullHash> add_hashes_;
261   std::vector<SBSubFullHash> sub_hashes_;
262
263   // Count of chunks collected in |new_file_|.
264   int chunks_written_;
265
266   // Name of the main database file.
267   base::FilePath filename_;
268
269   // Handles to the main and scratch files.  |empty_| is true if the
270   // main file didn't exist when the update was started.
271   file_util::ScopedFILE file_;
272   file_util::ScopedFILE new_file_;
273   bool empty_;
274
275   // Cache of chunks which have been seen.  Loaded from the database
276   // on BeginUpdate() so that it can be queried during the
277   // transaction.
278   std::set<int32> add_chunks_cache_;
279   std::set<int32> sub_chunks_cache_;
280
281   // Cache the set of deleted chunks during a transaction, applied on
282   // FinishUpdate().
283   // TODO(shess): If the set is small enough, hash_set<> might be
284   // slower than plain set<>.
285   base::hash_set<int32> add_del_cache_;
286   base::hash_set<int32> sub_del_cache_;
287
288   base::Closure corruption_callback_;
289
290   // Tracks whether corruption has already been seen in the current
291   // update, so that only one instance is recorded in the stats.
292   // TODO(shess): Remove with format-migration support.
293   bool corruption_seen_;
294
295   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingStoreFile);
296 };
297
298 #endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_STORE_FILE_H_