Avi Drissman | 8ba1bad | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 5 | #ifndef COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_BACKEND_H_ |
| 6 | #define COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_BACKEND_H_ |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 7 | |
avi | f57136c1 | 2015-12-25 23:27:45 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | |
dcheng | c51ac9e | 2016-04-22 04:05:53 | [diff] [blame] | 10 | #include <memory> |
Arthur Sonzogni | c571efb | 2024-01-26 20:26:18 | [diff] [blame] | 11 | #include <optional> |
Hans Wennborg | e66cdda | 2021-04-21 11:02:31 | [diff] [blame] | 12 | #include <set> |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 13 | #include <vector> |
| 14 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 15 | #include "base/files/file_path.h" |
Avi Drissman | 12be031 | 2023-01-11 09:16:09 | [diff] [blame] | 16 | #include "base/functional/callback_forward.h" |
Scott Violet | c75ec38 | 2020-01-14 20:14:47 | [diff] [blame] | 17 | #include "base/memory/ref_counted_delete_on_sequence.h" |
Sean Maher | e672a66 | 2023-01-09 21:42:28 | [diff] [blame] | 18 | #include "base/task/sequenced_task_runner.h" |
David Sanders | 2799ee2 | 2022-02-03 05:01:48 | [diff] [blame] | 19 | #include "base/time/time.h" |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 20 | #include "components/sessions/core/command_storage_manager.h" |
blundell | 47c6d8a | 2015-09-24 11:06:40 | [diff] [blame] | 21 | #include "components/sessions/core/session_command.h" |
| 22 | #include "components/sessions/core/sessions_export.h" |
erg@google.com | 92926d9 | 2010-09-02 18:35:06 | [diff] [blame] | 23 | |
hashimoto@chromium.org | aa9b03f | 2014-03-24 13:03:22 | [diff] [blame] | 24 | namespace base { |
Scott Violet | 9604e497 | 2023-03-27 18:38:43 | [diff] [blame] | 25 | class Clock; |
hashimoto@chromium.org | aa9b03f | 2014-03-24 13:03:22 | [diff] [blame] | 26 | class File; |
erg@google.com | 92926d9 | 2010-09-02 18:35:06 | [diff] [blame] | 27 | } |
jhawkins@chromium.org | 5a82010a | 2009-02-14 01:33:02 | [diff] [blame] | 28 | |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 29 | namespace crypto { |
| 30 | class Aead; |
| 31 | } |
| 32 | |
skuhne | d8d83f0b | 2014-11-15 03:51:17 | [diff] [blame] | 33 | namespace sessions { |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 34 | |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 35 | // CommandStorageBackend is the backend used by CommandStorageManager. It writes |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 36 | // SessionCommands to disk with the ability to read back at a later date. |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 37 | // CommandStorageBackend (mostly) does not interpret the commands in any way, it |
| 38 | // simply reads/writes them. |
| 39 | // |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 40 | // CommandStorageBackend writes to a file with a suffix that indicates the |
| 41 | // time the file was opened. The time stamp allows this code to determine the |
| 42 | // most recently written file. When AppendCommands() is supplied a value of true |
| 43 | // for `truncate`, the current file is closed and a new file is created (with |
| 44 | // a newly generated timestamp). When AppendCommands() successfully writes the |
| 45 | // commands to the file an internal command (whose id is |
| 46 | // `kInitialStateMarkerCommandId`) is written. During startup, the most recent |
| 47 | // file that has the internal command written is used. This ensures restore does |
| 48 | // not attempt to use a file that did not have the complete state written |
| 49 | // (this would happen if chrome crashed while writing the commands, or there |
| 50 | // was a file system error part way through writing). |
| 51 | // |
| 52 | // AppendCommands() takes a callback that is called if there is an error in |
| 53 | // writing to the file. The expectation is if there is an error, the consuming |
| 54 | // code must call AppendCommands() again with `truncate` set to true. If there |
| 55 | // was an error in writing to the file, calls to AppendCommands() with a value |
| 56 | // of false for `truncate` are ignored. This is done to ensure the consuming |
| 57 | // code correctly supplies the initial state. |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 58 | class SESSIONS_EXPORT CommandStorageBackend |
| 59 | : public base::RefCountedDeleteOnSequence<CommandStorageBackend> { |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 60 | public: |
Scott Violet | 6de1790 | 2021-01-26 20:56:26 | [diff] [blame] | 61 | struct SESSIONS_EXPORT ReadCommandsResult { |
| 62 | ReadCommandsResult(); |
| 63 | ReadCommandsResult(ReadCommandsResult&& other); |
| 64 | ReadCommandsResult& operator=(ReadCommandsResult&& other); |
| 65 | ReadCommandsResult(const ReadCommandsResult&) = delete; |
| 66 | ReadCommandsResult& operator=(const ReadCommandsResult&) = delete; |
| 67 | ~ReadCommandsResult(); |
| 68 | |
| 69 | std::vector<std::unique_ptr<sessions::SessionCommand>> commands; |
| 70 | bool error_reading = false; |
| 71 | }; |
| 72 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 73 | using id_type = SessionCommand::id_type; |
| 74 | using size_type = SessionCommand::size_type; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 75 | |
| 76 | // Initial size of the buffer used in reading the file. This is exposed |
| 77 | // for testing. |
| 78 | static const int kFileReadBufferSize; |
| 79 | |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 80 | // Number of bytes encryption adds. |
| 81 | static const size_type kEncryptionOverheadInBytes; |
| 82 | |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 83 | // Represents data for a session. Public for tests. |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 84 | // Creates a CommandStorageBackend. This method is invoked on the MAIN thread, |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 85 | // and does no IO. The real work is done from Init, which is invoked on |
Scott Violet | c75ec38 | 2020-01-14 20:14:47 | [diff] [blame] | 86 | // a background task runer. |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 87 | // |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 88 | // See `CommandStorageManager` for details on `type` and `path`. |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 89 | CommandStorageBackend( |
| 90 | scoped_refptr<base::SequencedTaskRunner> owning_task_runner, |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 91 | const base::FilePath& path, |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 92 | CommandStorageManager::SessionType type, |
Scott Violet | 9604e497 | 2023-03-27 18:38:43 | [diff] [blame] | 93 | const std::vector<uint8_t>& decryption_key = {}, |
| 94 | base::Clock* clock = nullptr); |
Scott Violet | 2664a2c | 2020-07-07 20:23:32 | [diff] [blame] | 95 | CommandStorageBackend(const CommandStorageBackend&) = delete; |
| 96 | CommandStorageBackend& operator=(const CommandStorageBackend&) = delete; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 97 | |
Scott Violet | 95a6d68 | 2020-06-11 23:28:32 | [diff] [blame] | 98 | // Returns true if the file at |path| was generated by this class. |
| 99 | static bool IsValidFile(const base::FilePath& path); |
| 100 | |
Scott Violet | 5ac0a9b | 2021-01-05 22:14:45 | [diff] [blame] | 101 | // Returns the path the files are being written to. |
Scott Violet | 9604e497 | 2023-03-27 18:38:43 | [diff] [blame] | 102 | const base::FilePath current_path() const { |
| 103 | return open_file_ ? open_file_->path : base::FilePath(); |
| 104 | } |
| 105 | |
Scott Violet | 143d8f2 | 2023-03-30 22:56:50 | [diff] [blame] | 106 | bool IsFileOpen() const { return open_file_.get() != nullptr; } |
Scott Violet | 5ac0a9b | 2021-01-05 22:14:45 | [diff] [blame] | 107 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 108 | base::SequencedTaskRunner* owning_task_runner() { |
| 109 | return base::RefCountedDeleteOnSequence< |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 110 | CommandStorageBackend>::owning_task_runner(); |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 111 | } |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 112 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 113 | // Appends the specified commands to the current file. If |truncate| is true |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 114 | // the file is truncated. If |truncate| is true and |crypto_key| is non-empty, |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 115 | // then all commands are encrypted using the supplied key. If there is an |
| 116 | // error writing the commands, `error_callback` is run. |
avi | 51f1cd9 | 2017-01-03 18:23:38 | [diff] [blame] | 117 | void AppendCommands( |
| 118 | std::vector<std::unique_ptr<sessions::SessionCommand>> commands, |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 119 | bool truncate, |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 120 | base::OnceClosure error_callback, |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 121 | const std::vector<uint8_t>& crypto_key = std::vector<uint8_t>()); |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 122 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 123 | bool inited() const { return inited_; } |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 124 | |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 125 | // Parses out the timestamp from a path pointing to a session file. |
| 126 | static bool TimestampFromPath(const base::FilePath& path, base::Time& result); |
| 127 | |
Scott Violet | 5ac0a9b | 2021-01-05 22:14:45 | [diff] [blame] | 128 | // Returns the set of possible session files. The returned paths are not |
| 129 | // necessarily valid session files, rather they match the naming criteria |
| 130 | // for session files. |
| 131 | static std::set<base::FilePath> GetSessionFilePaths( |
| 132 | const base::FilePath& path, |
| 133 | CommandStorageManager::SessionType type); |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 134 | |
| 135 | // Returns the commands from the last session file. |
Scott Violet | 6de1790 | 2021-01-26 20:56:26 | [diff] [blame] | 136 | ReadCommandsResult ReadLastSessionCommands(); |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 137 | |
| 138 | // Deletes the file containing the commands for the last session. |
| 139 | void DeleteLastSession(); |
| 140 | |
| 141 | // Moves the current session file to the last session file. This is typically |
| 142 | // called during startup or if the user launches the app and no tabbed |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 143 | // browsers are running. After calling this, set_pending_reset() must be |
| 144 | // called. |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 145 | void MoveCurrentSessionToLastSession(); |
| 146 | |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 147 | // Used in testing to emulate an error in writing to the file. The value is |
| 148 | // automatically reset after the failure. |
| 149 | void ForceAppendCommandsToFailForTesting(); |
| 150 | |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 151 | private: |
| 152 | friend class base::RefCountedDeleteOnSequence<CommandStorageBackend>; |
| 153 | friend class base::DeleteHelper<CommandStorageBackend>; |
| 154 | friend class CommandStorageBackendTest; |
| 155 | |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 156 | struct SessionInfo { |
| 157 | base::FilePath path; |
| 158 | base::Time timestamp; |
| 159 | }; |
| 160 | |
Scott Violet | 9604e497 | 2023-03-27 18:38:43 | [diff] [blame] | 161 | struct OpenFile { |
| 162 | OpenFile(); |
| 163 | ~OpenFile(); |
| 164 | |
| 165 | base::FilePath path; |
| 166 | std::unique_ptr<base::File> file; |
| 167 | // Set to true once `kInitialStateMarkerCommandId` is written. |
| 168 | bool did_write_marker = false; |
| 169 | }; |
| 170 | |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 171 | ~CommandStorageBackend(); |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 172 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 173 | // Performs initialization on the background task run, calling DoInit() if |
| 174 | // necessary. |
| 175 | void InitIfNecessary(); |
| 176 | |
Scott Violet | 5ac0a9b | 2021-01-05 22:14:45 | [diff] [blame] | 177 | // Generates the path to a session file with the given timestamp. |
| 178 | static base::FilePath FilePathFromTime( |
| 179 | CommandStorageManager::SessionType type, |
| 180 | const base::FilePath& path, |
| 181 | base::Time time); |
| 182 | |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 183 | // Reads the commands from the specified file. If |crypto_key| is non-empty, |
Scott Violet | 2664a2c | 2020-07-07 20:23:32 | [diff] [blame] | 184 | // it is used to decrypt the file. |
Scott Violet | 6de1790 | 2021-01-26 20:56:26 | [diff] [blame] | 185 | static ReadCommandsResult ReadCommandsFromFile( |
| 186 | const base::FilePath& path, |
| 187 | const std::vector<uint8_t>& crypto_key); |
albertb@google.com | 3acb70ef | 2010-03-01 18:44:38 | [diff] [blame] | 188 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 189 | // Closes the file. The next time AppendCommands() is called the file will |
| 190 | // implicitly be reopened. |
| 191 | void CloseFile(); |
jam@chromium.org | e6e6ba4 | 2009-11-07 01:56:19 | [diff] [blame] | 192 | |
sky@google.com | a1cf607 | 2009-03-09 18:27:34 | [diff] [blame] | 193 | // If current_session_file_ is open, it is truncated so that it is essentially |
| 194 | // empty (only contains the header). If current_session_file_ isn't open, it |
| 195 | // is is opened and the header is written to it. After this |
| 196 | // current_session_file_ contains no commands. |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 197 | // NOTE: current_session_file_ may be null if the file couldn't be opened or |
sky@google.com | a1cf607 | 2009-03-09 18:27:34 | [diff] [blame] | 198 | // the header couldn't be written. |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 199 | void TruncateOrOpenFile(); |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 200 | |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 201 | // Opens the current file and writes the header. On success a handle to |
| 202 | // the file is returned. |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 203 | std::unique_ptr<base::File> OpenAndWriteHeader( |
| 204 | const base::FilePath& path) const; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 205 | |
| 206 | // Appends the specified commands to the specified file. |
skuhne | b7409dcf | 2014-11-14 04:06:55 | [diff] [blame] | 207 | bool AppendCommandsToFile( |
| 208 | base::File* file, |
avi | 51f1cd9 | 2017-01-03 18:23:38 | [diff] [blame] | 209 | const std::vector<std::unique_ptr<sessions::SessionCommand>>& commands); |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 210 | |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 211 | // Writes |command| to |file|. Returns true on success. |
| 212 | bool AppendCommandToFile(base::File* file, |
| 213 | const sessions::SessionCommand& command); |
| 214 | |
| 215 | // Encrypts |command| and writes it to |file|. Returns true on success. |
| 216 | // The contents of the command and id are encrypted together. This is |
| 217 | // preceded by the length of the command. |
| 218 | bool AppendEncryptedCommandToFile(base::File* file, |
| 219 | const sessions::SessionCommand& command); |
| 220 | |
| 221 | // Returns true if commands are encrypted. |
| 222 | bool IsEncrypted() const { return !crypto_key_.empty(); } |
| 223 | |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 224 | // Gets data for the last session file. |
Arthur Sonzogni | c571efb | 2024-01-26 20:26:18 | [diff] [blame] | 225 | std::optional<SessionInfo> FindLastSessionFile() const; |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 226 | |
| 227 | // Attempt to delete all sessions besides the current and last. This is a |
| 228 | // best effort operation. |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 229 | void DeleteLastSessionFiles() const; |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 230 | |
| 231 | // Gets all sessions files. |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 232 | std::vector<SessionInfo> GetSessionFilesSortedByReverseTimestamp() const { |
| 233 | return GetSessionFilesSortedByReverseTimestamp(supplied_path_, type_); |
Scott Violet | 5ac0a9b | 2021-01-05 22:14:45 | [diff] [blame] | 234 | } |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 235 | static std::vector<SessionInfo> GetSessionFilesSortedByReverseTimestamp( |
Scott Violet | 5ac0a9b | 2021-01-05 22:14:45 | [diff] [blame] | 236 | const base::FilePath& path, |
| 237 | CommandStorageManager::SessionType type); |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 238 | |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 239 | static bool CompareSessionInfoTimestamps(const SessionInfo& a, |
| 240 | const SessionInfo& b) { |
| 241 | return b.timestamp < a.timestamp; |
| 242 | } |
| 243 | |
| 244 | // Returns true if `path` can be used for the last session. |
| 245 | bool CanUseFileForLastSession(const base::FilePath& path) const; |
| 246 | |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 247 | const CommandStorageManager::SessionType type_; |
| 248 | |
| 249 | // This is the path supplied to the constructor. See CommandStorageManager |
| 250 | // constructor for details. |
| 251 | const base::FilePath supplied_path_; |
| 252 | |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 253 | // Used to decode the initial last session file. |
| 254 | // TODO(sky): this is currently required because InitIfNecessary() determines |
| 255 | // the last file. If that can be delayed, then this can be supplied to |
| 256 | // GetLastSessionCommands(). |
| 257 | const std::vector<uint8_t> initial_decryption_key_; |
| 258 | |
| 259 | // TaskRunner that the callback is added to. |
| 260 | scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; |
| 261 | |
Scott Violet | 9604e497 | 2023-03-27 18:38:43 | [diff] [blame] | 262 | raw_ptr<base::Clock> clock_; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 263 | |
Scott Violet | 9604e497 | 2023-03-27 18:38:43 | [diff] [blame] | 264 | // File and path commands are being written. |
| 265 | std::unique_ptr<OpenFile> open_file_; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 266 | |
Scott Violet | 8e3a335 | 2020-01-17 20:37:38 | [diff] [blame] | 267 | // Whether DoInit() was called. DoInit() is called on the background task |
| 268 | // runner. |
| 269 | bool inited_ = false; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 270 | |
Scott Violet | 34e2627 | 2020-01-28 18:19:59 | [diff] [blame] | 271 | std::vector<uint8_t> crypto_key_; |
| 272 | std::unique_ptr<crypto::Aead> aead_; |
| 273 | |
| 274 | // Incremented every time a command is written. |
| 275 | int commands_written_ = 0; |
Scott Violet | 861cfb97 | 2021-01-05 20:07:34 | [diff] [blame] | 276 | |
| 277 | // Timestamp when this session was started. |
| 278 | base::Time timestamp_; |
| 279 | |
| 280 | // Data for the last session. If unset, fallback to legacy session data. |
Arthur Sonzogni | c571efb | 2024-01-26 20:26:18 | [diff] [blame] | 281 | std::optional<SessionInfo> last_session_info_; |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 282 | |
Scott Violet | 143d8f2 | 2023-03-30 22:56:50 | [diff] [blame] | 283 | // Paths of the two most recently written files with a valid marker (the |
| 284 | // first of which may be the currently open file). When a new file is |
| 285 | // successfully opened and the initial set of commands is written, |
| 286 | // `last_or_current_path_with_valid_marker_` is set to the path. At this |
| 287 | // point the previous file (initial value of |
| 288 | // `last_or_current_path_with_valid_marker_`) is no longer needed, and can be |
| 289 | // deleted. As there is no guarantee the commands have actually been written |
| 290 | // to disk, we keep one additional file around. |
| 291 | // `second_to_last_path_with_valid_marker_` maintains the previous valid file |
| 292 | // with a marker. |
Arthur Sonzogni | c571efb | 2024-01-26 20:26:18 | [diff] [blame] | 293 | std::optional<base::FilePath> last_or_current_path_with_valid_marker_; |
| 294 | std::optional<base::FilePath> second_to_last_path_with_valid_marker_; |
Scott Violet | 807acce3 | 2021-01-07 14:39:31 | [diff] [blame] | 295 | |
| 296 | bool force_append_commands_to_fail_for_testing_ = false; |
sky@google.com | 169627b | 2008-12-06 19:30:19 | [diff] [blame] | 297 | }; |
| 298 | |
skuhne | d8d83f0b | 2014-11-15 03:51:17 | [diff] [blame] | 299 | } // namespace sessions |
| 300 | |
Scott Violet | ebfa63c | 2020-01-17 21:17:28 | [diff] [blame] | 301 | #endif // COMPONENTS_SESSIONS_CORE_COMMAND_STORAGE_BACKEND_H_ |