• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file defines FileStream::Context class.
6 // The general design of FileStream is as follows: file_stream.h defines
7 // FileStream class which basically is just an "wrapper" not containing any
8 // specific implementation details. It re-routes all its method calls to
9 // the instance of FileStream::Context (FileStream holds a scoped_ptr to
10 // FileStream::Context instance). Context was extracted into a different class
11 // to be able to do and finish all async operations even when FileStream
12 // instance is deleted. So FileStream's destructor can schedule file
13 // closing to be done by Context in WorkerPool (or the TaskRunner passed to
14 // constructor) and then just return (releasing Context pointer from
15 // scoped_ptr) without waiting for actual closing to complete.
16 // Implementation of FileStream::Context is divided in two parts: some methods
17 // and members are platform-independent and some depend on the platform. This
18 // header file contains the complete definition of Context class including all
19 // platform-dependent parts (because of that it has a lot of #if-#else
20 // branching). Implementations of all platform-independent methods are
21 // located in file_stream_context.cc, and all platform-dependent methods are
22 // in file_stream_context_{win,posix}.cc. This separation provides better
23 // readability of Context's code. And we tried to make as much Context code
24 // platform-independent as possible. So file_stream_context_{win,posix}.cc are
25 // much smaller than file_stream_context.cc now.
26 
27 #ifndef NET_BASE_FILE_STREAM_CONTEXT_H_
28 #define NET_BASE_FILE_STREAM_CONTEXT_H_
29 
30 #include <stdint.h>
31 
32 #include "base/files/file.h"
33 #include "base/logging.h"
34 #include "base/memory/weak_ptr.h"
35 #include "base/message_loop/message_pump_for_io.h"
36 #include "base/task/single_thread_task_runner.h"
37 #include "base/task/task_runner.h"
38 #include "build/build_config.h"
39 #include "net/base/completion_once_callback.h"
40 #include "net/base/file_stream.h"
41 
42 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
43 #include <errno.h>
44 #endif
45 
46 namespace base {
47 class FilePath;
48 }
49 
50 namespace net {
51 
52 class IOBuffer;
53 
54 // Implementation for a FileStream. See file_stream.h for documentation.
55 #if BUILDFLAG(IS_WIN)
56 class FileStream::Context : public base::MessagePumpForIO::IOHandler {
57 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
58 class FileStream::Context {
59 #endif
60 
61  public:
62   ////////////////////////////////////////////////////////////////////////////
63   // Platform-dependent methods implemented in
64   // file_stream_context_{win,posix}.cc.
65   ////////////////////////////////////////////////////////////////////////////
66 
67   explicit Context(scoped_refptr<base::TaskRunner> task_runner);
68   Context(base::File file, scoped_refptr<base::TaskRunner> task_runner);
69   Context(const Context&) = delete;
70   Context& operator=(const Context&) = delete;
71 #if BUILDFLAG(IS_WIN)
72   ~Context() override;
73 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
74   ~Context();
75 #endif
76 
77   int Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback);
78 
79   int Write(IOBuffer* buf, int buf_len, CompletionOnceCallback callback);
80 
81 #if BUILDFLAG(IS_WIN)
82   int ConnectNamedPipe(CompletionOnceCallback callback);
83 #endif
84 
async_in_progress()85   bool async_in_progress() const { return async_in_progress_; }
86 
87   ////////////////////////////////////////////////////////////////////////////
88   // Platform-independent methods implemented in file_stream_context.cc.
89   ////////////////////////////////////////////////////////////////////////////
90 
91   // Destroys the context. It can be deleted in the method or deletion can be
92   // deferred if some asynchronous operation is now in progress or if file is
93   // not closed yet.
94   void Orphan();
95 
96   void Open(const base::FilePath& path,
97             int open_flags,
98             CompletionOnceCallback callback);
99 
100   void Close(CompletionOnceCallback callback);
101 
102   // Seeks |offset| bytes from the start of the file.
103   void Seek(int64_t offset, Int64CompletionOnceCallback callback);
104 
105   void GetFileInfo(base::File::Info* file_info,
106                    CompletionOnceCallback callback);
107 
108   void Flush(CompletionOnceCallback callback);
109 
110   bool IsOpen() const;
111 
112  private:
113   struct IOResult {
114     IOResult();
115     IOResult(int64_t result, logging::SystemErrorCode os_error);
116     static IOResult FromOSError(logging::SystemErrorCode os_error);
117 
118     int64_t result;
119     logging::SystemErrorCode os_error;  // Set only when result < 0.
120   };
121 
122   struct OpenResult {
123    public:
124     OpenResult();
125     OpenResult(base::File file, IOResult error_code);
126     OpenResult(OpenResult&& other);
127     OpenResult& operator=(OpenResult&& other);
128     OpenResult(const OpenResult&) = delete;
129     OpenResult& operator=(const OpenResult&) = delete;
130 
131     base::File file;
132     IOResult error_code;
133   };
134 
135   ////////////////////////////////////////////////////////////////////////////
136   // Platform-independent methods implemented in file_stream_context.cc.
137   ////////////////////////////////////////////////////////////////////////////
138 
139   OpenResult OpenFileImpl(const base::FilePath& path, int open_flags);
140 
141   IOResult GetFileInfoImpl(base::File::Info* file_info);
142 
143   IOResult CloseFileImpl();
144 
145   IOResult FlushFileImpl();
146 
147   void OnOpenCompleted(CompletionOnceCallback callback, OpenResult open_result);
148 
149   void CloseAndDelete();
150 
151   Int64CompletionOnceCallback IntToInt64(CompletionOnceCallback callback);
152 
153   // Called when Open() or Seek() completes. |result| contains the result or a
154   // network error code.
155   void OnAsyncCompleted(Int64CompletionOnceCallback callback,
156                         const IOResult& result);
157 
158   ////////////////////////////////////////////////////////////////////////////
159   // Platform-dependent methods implemented in
160   // file_stream_context_{win,posix}.cc.
161   ////////////////////////////////////////////////////////////////////////////
162 
163   // Adjusts the position from where the data is read.
164   IOResult SeekFileImpl(int64_t offset);
165 
166   void OnFileOpened();
167 
168 #if BUILDFLAG(IS_WIN)
169   void IOCompletionIsPending(CompletionOnceCallback callback, IOBuffer* buf);
170 
171   // Implementation of MessagePumpForIO::IOHandler.
172   void OnIOCompleted(base::MessagePumpForIO::IOContext* context,
173                      DWORD bytes_read,
174                      DWORD error) override;
175 
176   // Invokes the user callback.
177   void InvokeUserCallback();
178 
179   // Deletes an orphaned context.
180   void DeleteOrphanedContext();
181 
182   // The ReadFile call on Windows can execute synchronously at times.
183   // http://support.microsoft.com/kb/156932. This ends up blocking the calling
184   // thread which is undesirable. To avoid this we execute the ReadFile call
185   // on a worker thread.
186   // The |context| parameter is a pointer to the current Context instance. It
187   // is safe to pass this as is to the pool as the Context instance should
188   // remain valid until the pending Read operation completes.
189   // The |file| parameter is the handle to the file being read.
190   // The |buf| parameter is the buffer where we want the ReadFile to read the
191   // data into.
192   // The |buf_len| parameter contains the number of bytes to be read.
193   // The |overlapped| parameter is a pointer to the OVERLAPPED structure being
194   // used.
195   // The |origin_thread_task_runner| is a task runner instance used to post
196   // tasks back to the originating thread.
197   static void ReadAsync(
198       FileStream::Context* context,
199       HANDLE file,
200       scoped_refptr<IOBuffer> buf,
201       int buf_len,
202       OVERLAPPED* overlapped,
203       scoped_refptr<base::SingleThreadTaskRunner> origin_thread_task_runner);
204 
205   // This callback executes on the main calling thread. It informs the caller
206   // about the result of the ReadFile call.
207   // The |read_file_ret| parameter contains the return value of the ReadFile
208   // call.
209   // The |bytes_read| contains the number of bytes read from the file, if
210   // ReadFile succeeds.
211   // The |os_error| parameter contains the value of the last error returned by
212   // the ReadFile API.
213   void ReadAsyncResult(BOOL read_file_ret, DWORD bytes_read, DWORD os_error);
214 
215 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
216   // ReadFileImpl() is a simple wrapper around read() that handles EINTR
217   // signals and calls RecordAndMapError() to map errno to net error codes.
218   IOResult ReadFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
219 
220   // WriteFileImpl() is a simple wrapper around write() that handles EINTR
221   // signals and calls MapSystemError() to map errno to net error codes.
222   // It tries to write to completion.
223   IOResult WriteFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
224 #endif  // BUILDFLAG(IS_WIN)
225 
226   base::File file_;
227   bool async_in_progress_ = false;
228 
229   bool orphaned_ = false;
230   const scoped_refptr<base::TaskRunner> task_runner_;
231 
232 #if BUILDFLAG(IS_WIN)
233   base::MessagePumpForIO::IOContext io_context_;
234   CompletionOnceCallback callback_;
235   scoped_refptr<IOBuffer> in_flight_buf_;
236   // This flag is set to true when we receive a Read request which is queued to
237   // the thread pool.
238   bool async_read_initiated_ = false;
239   // This flag is set to true when we receive a notification ReadAsyncResult()
240   // on the calling thread which indicates that the asynchronous Read
241   // operation is complete.
242   bool async_read_completed_ = false;
243   // This flag is set to true when we receive an IO completion notification for
244   // an asynchronously initiated Read operation. OnIOComplete().
245   bool io_complete_for_read_received_ = false;
246   // Tracks the result of the IO completion operation. Set in OnIOComplete.
247   int result_ = 0;
248 #endif
249 };
250 
251 }  // namespace net
252 
253 #endif  // NET_BASE_FILE_STREAM_CONTEXT_H_
254