summaryrefslogtreecommitdiffstats
path: root/net/base/file_stream_context.h
blob: 42fc0eb573c914039b08ecb6a91b07ac6a323ca5 (plain)
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file defines FileStream::Context class.
// The general design of FileStream is as follows: file_stream.h defines
// FileStream class which basically is just an "wrapper" not containing any
// specific implementation details. It re-routes all its method calls to
// the instance of FileStream::Context (FileStream holds a scoped_ptr to
// FileStream::Context instance). Context was extracted into a different class
// to be able to do and finish all async operations even when FileStream
// instance is deleted. So FileStream's destructor can schedule file
// closing to be done by Context in WorkerPool and then just return (releasing
// Context pointer from scoped_ptr) without waiting for actual closing to
// complete.
// Implementation of FileStream::Context is divided in two parts: some methods
// and members are platform-independent and some depend on the platform. This
// header file contains the complete definition of Context class including all
// platform-dependent parts (because of that it has a lot of #if-#else
// branching). Implementations of all platform-independent methods are
// located in file_stream_context.cc, and all platform-dependent methods are
// in file_stream_context_{win,posix}.cc. This separation provides better
// readability of Context's code. And we tried to make as much Context code
// platform-independent as possible. So file_stream_context_{win,posix}.cc are
// much smaller than file_stream_context.cc now.

#ifndef NET_BASE_FILE_STREAM_CONTEXT_H_
#define NET_BASE_FILE_STREAM_CONTEXT_H_

#include "base/message_loop.h"
#include "base/platform_file.h"
#include "net/base/completion_callback.h"
#include "net/base/file_stream.h"
#include "net/base/file_stream_metrics.h"
#include "net/base/file_stream_whence.h"
#include "net/base/net_log.h"

#if defined(OS_POSIX)
#include <errno.h>
#endif

namespace base {
class FilePath;
}

namespace net {

class IOBuffer;

#if defined(OS_WIN)
class FileStream::Context : public MessageLoopForIO::IOHandler {
#elif defined(OS_POSIX)
class FileStream::Context {
#endif
 public:
  ////////////////////////////////////////////////////////////////////////////
  // Platform-dependent methods implemented in
  // file_stream_context_{win,posix}.cc.
  ////////////////////////////////////////////////////////////////////////////

  explicit Context(const BoundNetLog& bound_net_log);
  Context(base::PlatformFile file,
          const BoundNetLog& bound_net_log,
          int open_flags);
#if defined(OS_WIN)
  virtual ~Context();
#elif defined(OS_POSIX)
  ~Context();
#endif

  int64 GetFileSize() const;

  int ReadAsync(IOBuffer* buf,
                int buf_len,
                const CompletionCallback& callback);
  int ReadSync(char* buf, int buf_len);

  int WriteAsync(IOBuffer* buf,
                 int buf_len,
                 const CompletionCallback& callback);
  int WriteSync(const char* buf, int buf_len);

  int Truncate(int64 bytes);

  ////////////////////////////////////////////////////////////////////////////
  // Inline methods.
  ////////////////////////////////////////////////////////////////////////////

  void set_record_uma(bool value) { record_uma_ = value; }
  base::PlatformFile file() const { return file_; }
  bool async_in_progress() const { return async_in_progress_; }

  ////////////////////////////////////////////////////////////////////////////
  // Platform-independent methods implemented in file_stream_context.cc.
  ////////////////////////////////////////////////////////////////////////////

  // Destroys the context. It can be deleted in the method or deletion can be
  // deferred if some asynchronous operation is now in progress or if file is
  // not closed yet.
  void Orphan();

  void OpenAsync(const base::FilePath& path,
                 int open_flags,
                 const CompletionCallback& callback);
  int OpenSync(const base::FilePath& path, int open_flags);

  void CloseSync();

  void SeekAsync(Whence whence,
                 int64 offset,
                 const Int64CompletionCallback& callback);
  int64 SeekSync(Whence whence, int64 offset);

  void FlushAsync(const CompletionCallback& callback);
  int FlushSync();

 private:
  ////////////////////////////////////////////////////////////////////////////
  // Error code that is platform-dependent but is used in the platform-
  // independent code implemented in file_stream_context.cc.
  ////////////////////////////////////////////////////////////////////////////
  enum {
#if defined(OS_WIN)
    ERROR_BAD_FILE = ERROR_INVALID_HANDLE
#elif defined(OS_POSIX)
    ERROR_BAD_FILE = EBADF
#endif
  };

  ////////////////////////////////////////////////////////////////////////////
  // Platform-independent methods implemented in file_stream_context.cc.
  ////////////////////////////////////////////////////////////////////////////

  struct OpenResult {
    base::PlatformFile file;
    int error_code;
  };

  // Map system error into network error code and log it with |bound_net_log_|.
  int RecordAndMapError(int error, FileErrorSource source) const;

  void BeginOpenEvent(const base::FilePath& path);

  OpenResult OpenFileImpl(const base::FilePath& path, int open_flags);

  int ProcessOpenError(int error_code);
  void OnOpenCompleted(const CompletionCallback& callback, OpenResult result);

  void CloseAndDelete();
  void OnCloseCompleted();

  Int64CompletionCallback IntToInt64(const CompletionCallback& callback);

  // Checks for IO error that probably happened in async methods.
  // If there was error reports it.
  void CheckForIOError(int64* result, FileErrorSource source);

  // Called when asynchronous Seek() is completed.
  // Reports error if needed and calls callback.
  void ProcessAsyncResult(const Int64CompletionCallback& callback,
                          FileErrorSource source,
                          int64 result);

  // Called when asynchronous Open() or Seek()
  // is completed. |result| contains the result or a network error code.
  void OnAsyncCompleted(const Int64CompletionCallback& callback, int64 result);

  ////////////////////////////////////////////////////////////////////////////
  // Helper stuff which is platform-dependent but is used in the platform-
  // independent code implemented in file_stream_context.cc. These helpers were
  // introduced solely to implement as much of the Context methods as
  // possible independently from platform.
  ////////////////////////////////////////////////////////////////////////////

#if defined(OS_WIN)
  int GetLastErrno() { return GetLastError(); }
  void OnAsyncFileOpened();
#elif defined(OS_POSIX)
  int GetLastErrno() { return errno; }
  void OnAsyncFileOpened() {}
  void CancelIo(base::PlatformFile) {}
#endif

  ////////////////////////////////////////////////////////////////////////////
  // Platform-dependent methods implemented in
  // file_stream_context_{win,posix}.cc.
  ////////////////////////////////////////////////////////////////////////////

  // Adjusts the position from where the data is read.
  int64 SeekFileImpl(Whence whence, int64 offset);

  // Flushes all data written to the stream.
  int64 FlushFileImpl();

#if defined(OS_WIN)
  void IOCompletionIsPending(const CompletionCallback& callback, IOBuffer* buf);

  // Implementation of MessageLoopForIO::IOHandler
  virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
                             DWORD bytes_read,
                             DWORD error) OVERRIDE;
#elif defined(OS_POSIX)
  // ReadFileImpl() is a simple wrapper around read() that handles EINTR
  // signals and calls RecordAndMapError() to map errno to net error codes.
  int64 ReadFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);

  // WriteFileImpl() is a simple wrapper around write() that handles EINTR
  // signals and calls MapSystemError() to map errno to net error codes.
  // It tries to write to completion.
  int64 WriteFileImpl(scoped_refptr<IOBuffer> buf, int buf_len);
#endif

  base::PlatformFile file_;
  bool record_uma_;
  bool async_in_progress_;
  bool orphaned_;
  BoundNetLog bound_net_log_;

#if defined(OS_WIN)
  MessageLoopForIO::IOContext io_context_;
  CompletionCallback callback_;
  scoped_refptr<IOBuffer> in_flight_buf_;
  FileErrorSource error_source_;
#endif

  DISALLOW_COPY_AND_ASSIGN(Context);
};

}  // namespace net

#endif  // NET_BASE_FILE_STREAM_CONTEXT_H_