File: fusebox_read_writer.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (205 lines) | stat: -rw-r--r-- 8,445 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_FUSEBOX_FUSEBOX_READ_WRITER_H_
#define CHROME_BROWSER_ASH_FUSEBOX_FUSEBOX_READ_WRITER_H_

#include <utility>

#include "base/files/scoped_file.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/types/expected.h"
#include "chrome/browser/ash/fusebox/fusebox.pb.h"
#include "net/base/io_buffer.h"
#include "storage/browser/file_system/file_stream_reader.h"
#include "storage/browser/file_system/file_stream_writer.h"
#include "storage/browser/file_system/file_system_context.h"

namespace fusebox {

// Caches a storage::FileStreamReader (and FileStreamWriter) and their offsets
// so that, when consecutive reads (or consecutive writes) are adjacent (the
// second one starts where the first one ends), the FileStreamReader (or
// FileStreamWriter) is re-used.
//
// When serving a "stateless" I/O API that passes an offset each time (such as
// the FUSE API), but the underlying storage::AsyncFileUtil doesn't support
// seeking, then re-using a cached FileStreamReader can often avoid "Shlemiel
// the Painter" quadratic performance. See
// https://wiki.c2.com/?ShlemielThePainter
//
// Each ReadWriter instance lives entirely on the I/O thread, but its owner
// (and the callbacks) must live on the UI thread (and wrap the ReadWriter in a
// base::SequenceBound).
//
// The owner is also responsible for ensuring that only one operation is in
// flight at any one time. "An operation" starts with a Read or Write call and
// ends just before the corresponding callback is run.
class ReadWriter {
 public:
  using Close2Callback =
      base::OnceCallback<void(const Close2ResponseProto& response)>;
  using FlushCallback =
      base::OnceCallback<void(const FlushResponseProto& response)>;
  using Read2Callback =
      base::OnceCallback<void(const Read2ResponseProto& response)>;
  using Write2Callback =
      base::OnceCallback<void(const Write2ResponseProto& response)>;

  // |use_temp_file| is for the case when the |fs_url| storage system does not
  // support incremental writes, only atomic "here's the entire contents"
  // writes, such as MTP (Media Transfer Protocol, e.g. phones attached to a
  // Chromebook, which is a file-oriented rather than block-oriented protocol).
  // In this case, the Write calls are diverted to a temporary file and the
  // Close call saves that temporary file to |fs_url|.
  //
  // |temp_file_starts_with_copy| states whether to initialize that temporary
  // file with a copy of the underlying file. If |temp_file_starts_with_copy|
  // false, the temporary file is initially empty. When |use_temp_file| is
  // false, |temp_file_starts_with_copy| is ignored.
  ReadWriter(const storage::FileSystemURL& fs_url,
             const std::string& profile_path,
             bool use_temp_file,
             bool temp_file_starts_with_copy);
  ~ReadWriter();

  void Close(scoped_refptr<storage::FileSystemContext> fs_context,
             Close2Callback callback);

  void Flush(scoped_refptr<storage::FileSystemContext> fs_context,
             FlushCallback callback);

  void Read(scoped_refptr<storage::FileSystemContext> fs_context,
            int64_t offset,
            int64_t length,
            Read2Callback callback);

  void Write(scoped_refptr<storage::FileSystemContext> fs_context,
             scoped_refptr<net::StringIOBuffer> buffer,
             int64_t offset,
             int length,
             Write2Callback callback);

  // The int is a POSIX error code.
  using WriteTempFileResult = std::pair<base::ScopedFD, int>;

 private:
  // Saves the |temp_file_| to the |fs_url_|.
  void Save();

  // The CallXxx and OnXxx methods are static (but take a WeakPtr) so that the
  // callback will run even if the WeakPtr is invalidated.

  static void OnDefaultFlush(
      base::WeakPtr<ReadWriter> weak_ptr,
      FlushCallback callback,
      scoped_refptr<storage::FileSystemContext> fs_context,
      int flush_posix_error_code);

  static void OnEOFFlushBeforeActualClose(
      base::WeakPtr<ReadWriter> weak_ptr,
      Close2Callback callback,
      scoped_refptr<storage::FileSystemContext> fs_context,
      std::unique_ptr<storage::FileStreamWriter> fs_writer,
      int flush_posix_error_code);

  static void OnTempFileInitialized(base::WeakPtr<ReadWriter> weak_ptr,
                                    scoped_refptr<net::StringIOBuffer> buffer,
                                    int64_t offset,
                                    int length,
                                    Write2Callback callback,
                                    base::expected<base::ScopedFD, int> result);

  static void CallWriteTempFile(base::WeakPtr<ReadWriter> weak_ptr,
                                scoped_refptr<net::StringIOBuffer> buffer,
                                int64_t offset,
                                int length,
                                Write2Callback callback);

  static void OnRead(base::WeakPtr<ReadWriter> weak_ptr,
                     Read2Callback callback,
                     scoped_refptr<storage::FileSystemContext> fs_context,
                     std::unique_ptr<storage::FileStreamReader> fs_reader,
                     scoped_refptr<net::IOBuffer> buffer,
                     int64_t offset,
                     int length);

  static void OnWriteTempFile(base::WeakPtr<ReadWriter> weak_ptr,
                              Write2Callback callback,
                              WriteTempFileResult result);

  static void OnEOFFlushBeforeCallWriteDirect(
      base::WeakPtr<ReadWriter> weak_ptr,
      Write2Callback callback,
      scoped_refptr<storage::FileSystemContext> fs_context,
      scoped_refptr<net::IOBuffer> buffer,
      int64_t offset,
      int length,
      std::unique_ptr<storage::FileStreamWriter> fs_writer,
      int flush_posix_error_code);

  void CallWriteDirect(Write2Callback callback,
                       scoped_refptr<storage::FileSystemContext> fs_context,
                       std::unique_ptr<storage::FileStreamWriter> fs_writer,
                       scoped_refptr<net::IOBuffer> buffer,
                       int64_t offset,
                       int length);

  static void OnWriteDirect(
      base::WeakPtr<ReadWriter> weak_ptr,
      Write2Callback callback,
      scoped_refptr<storage::FileSystemContext> fs_context,
      std::unique_ptr<storage::FileStreamWriter> fs_writer,
      scoped_refptr<net::IOBuffer> buffer,
      int64_t offset,
      int length);

  const storage::FileSystemURL fs_url_;
  const std::string profile_path_;

  std::unique_ptr<storage::FileStreamReader> fs_reader_;
  // Unused (and set to -1) whenever fs_reader_ is nullptr. When std::move'ing
  // (or otherwise changing) the fs_reader_, we therefore assign (via = or
  // std::exchange) to read_offset_ at the same time.
  int64_t read_offset_ = -1;

  std::unique_ptr<storage::FileStreamWriter> fs_writer_;
  // Unused (and set to -1) whenever fs_writer_ is nullptr. When std::move'ing
  // (or otherwise changing) the fs_writer_, we therefore assign (via = or
  // std::exchange) to write_offset_ at the same time.
  int64_t write_offset_ = -1;

  scoped_refptr<storage::FileSystemContext> close2_fs_context_;
  Close2Callback close2_callback_;

  base::ScopedFD temp_file_;

  // The first (if any) write error we encounter. When non-zero, all future
  // Write calls fail and Save-on-Close is a no-op (other than running the
  // Close2Callback).
  int write_posix_error_code_ = 0;

  // True when the FD in |temp_file_| has been loaned out to a separate thread
  // (separate from the content::BrowserThread::IO thread that this lives on,
  // which should not be used for blocking I/O).
  bool is_loaning_temp_file_scoped_fd_ = false;

  bool is_in_flight_ = false;
  bool closed_ = false;
  bool created_temp_file_ = false;
  // storage::FileStreamWriter::Flush takes a storage::FlushMode parameter.
  // This bool field is about calling with FlushMode::kEndOfFile, not with
  // FlushMode::kDefault.
  bool fs_writer_needs_eof_flushing_ = false;

  const bool use_temp_file_;
  const bool temp_file_starts_with_copy_;

  base::WeakPtrFactory<ReadWriter> weak_ptr_factory_{this};
};

}  // namespace fusebox

#endif  // CHROME_BROWSER_ASH_FUSEBOX_FUSEBOX_READ_WRITER_H_