Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(750)

Side by Side Diff: components/filesystem/file_impl.cc

Issue 1158253002: mandoline filesystem: Rewrite using base::File. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Get the error from the right object. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/filesystem/file_impl.h ('k') | components/filesystem/file_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/filesystem/file_impl.h" 5 #include "components/filesystem/file_impl.h"
6 6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <limits> 7 #include <limits>
14 8
9 #include "base/files/file_path.h"
15 #include "base/files/scoped_file.h" 10 #include "base/files/scoped_file.h"
16 #include "base/logging.h" 11 #include "base/logging.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "components/filesystem/shared_impl.h"
19 #include "components/filesystem/util.h" 12 #include "components/filesystem/util.h"
20 13
21 static_assert(sizeof(off_t) <= sizeof(int64_t), "off_t too big"); 14 static_assert(sizeof(off_t) <= sizeof(int64_t), "off_t too big");
22 static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t too small"); 15 static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t too small");
23 16
17 using base::Time;
18
24 namespace filesystem { 19 namespace filesystem {
25 20
26 const size_t kMaxReadSize = 1 * 1024 * 1024; // 1 MB. 21 const size_t kMaxReadSize = 1 * 1024 * 1024; // 1 MB.
27 22
28 FileImpl::FileImpl(mojo::InterfaceRequest<File> request, base::ScopedFD file_fd) 23 FileImpl::FileImpl(mojo::InterfaceRequest<File> request,
29 : binding_(this, request.Pass()), file_fd_(file_fd.Pass()) { 24 const base::FilePath& path,
30 DCHECK(file_fd_.is_valid()); 25 uint32 flags)
26 : binding_(this, request.Pass()), file_(path, flags) {
27 DCHECK(file_.IsValid());
28 }
29
30 FileImpl::FileImpl(mojo::InterfaceRequest<File> request, base::File file)
31 : binding_(this, request.Pass()), file_(file.Pass()) {
32 DCHECK(file_.IsValid());
31 } 33 }
32 34
33 FileImpl::~FileImpl() { 35 FileImpl::~FileImpl() {
34 } 36 }
35 37
36 void FileImpl::Close(const CloseCallback& callback) { 38 void FileImpl::Close(const CloseCallback& callback) {
37 if (!file_fd_.is_valid()) { 39 if (!file_.IsValid()) {
38 callback.Run(ERROR_CLOSED); 40 callback.Run(GetError(file_));
39 return;
40 }
41 int fd_to_try_to_close = file_fd_.release();
42 // POSIX.1 (2013) leaves the validity of the FD undefined on EINTR and EIO. On
43 // Linux, the FD is always invalidated, so we'll pretend that the close
44 // succeeded. (On other Unixes, the situation may be different and possibly
45 // totally broken; see crbug.com/269623.)
46 if (IGNORE_EINTR(close(fd_to_try_to_close)) != 0) {
47 // Save errno, since we do a few things and we don't want it trampled.
48 int error = errno;
49 CHECK_NE(error, EBADF); // This should never happen.
50 DCHECK_NE(error, EINTR); // We already ignored EINTR.
51 // I don't know what Linux does on EIO (or any other errors) -- POSIX leaves
52 // it undefined -- so report the error and hope that the FD was invalidated.
53 callback.Run(ErrnoToError(error));
54 return; 41 return;
55 } 42 }
56 43
44 file_.Close();
57 callback.Run(ERROR_OK); 45 callback.Run(ERROR_OK);
58 } 46 }
59 47
60 // TODO(vtl): Move the implementation to a thread pool. 48 // TODO(vtl): Move the implementation to a thread pool.
61 void FileImpl::Read(uint32_t num_bytes_to_read, 49 void FileImpl::Read(uint32_t num_bytes_to_read,
62 int64_t offset, 50 int64_t offset,
63 Whence whence, 51 Whence whence,
64 const ReadCallback& callback) { 52 const ReadCallback& callback) {
65 if (!file_fd_.is_valid()) { 53 if (!file_.IsValid()) {
66 callback.Run(ERROR_CLOSED, mojo::Array<uint8_t>()); 54 callback.Run(GetError(file_), mojo::Array<uint8_t>());
67 return; 55 return;
68 } 56 }
69 if (num_bytes_to_read > kMaxReadSize) { 57 if (num_bytes_to_read > kMaxReadSize) {
70 callback.Run(ERROR_OUT_OF_RANGE, mojo::Array<uint8_t>()); 58 callback.Run(ERROR_INVALID_OPERATION, mojo::Array<uint8_t>());
71 return; 59 return;
72 } 60 }
73 if (Error error = IsOffsetValid(offset)) { 61 if (Error error = IsOffsetValid(offset)) {
74 callback.Run(error, mojo::Array<uint8_t>()); 62 callback.Run(error, mojo::Array<uint8_t>());
75 return; 63 return;
76 } 64 }
77 if (Error error = IsWhenceValid(whence)) { 65 if (Error error = IsWhenceValid(whence)) {
78 callback.Run(error, mojo::Array<uint8_t>()); 66 callback.Run(error, mojo::Array<uint8_t>());
79 return; 67 return;
80 } 68 }
81 69
82 if (offset != 0 || whence != WHENCE_FROM_CURRENT) { 70 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) {
83 // TODO(vtl): Use |pread()| below in the |WHENCE_FROM_START| case. This 71 callback.Run(ERROR_FAILED, mojo::Array<uint8_t>());
84 // implementation is obviously not atomic. (If someone seeks simultaneously, 72 return;
85 // we'll end up writing somewhere else. Or, well, we would if we were
86 // multithreaded.) Maybe we should do an |ftell()| and always use |pread()|.
87 // TODO(vtl): Possibly, at least sometimes we should not change the file
88 // position. See TODO in file.mojom.
89 if (lseek(file_fd_.get(), static_cast<off_t>(offset),
90 WhenceToStandardWhence(whence)) < 0) {
91 callback.Run(ErrnoToError(errno), mojo::Array<uint8_t>());
92 return;
93 }
94 } 73 }
95 74
96 mojo::Array<uint8_t> bytes_read(num_bytes_to_read); 75 mojo::Array<uint8_t> bytes_read(num_bytes_to_read);
97 ssize_t num_bytes_read = HANDLE_EINTR( 76 int num_bytes_read = file_.ReadAtCurrentPos(
98 read(file_fd_.get(), &bytes_read.front(), num_bytes_to_read)); 77 reinterpret_cast<char*>(&bytes_read.front()), num_bytes_to_read);
99 if (num_bytes_read < 0) { 78 if (num_bytes_read < 0) {
100 callback.Run(ErrnoToError(errno), mojo::Array<uint8_t>()); 79 callback.Run(ERROR_FAILED, mojo::Array<uint8_t>());
101 return; 80 return;
102 } 81 }
103 82
104 DCHECK_LE(static_cast<size_t>(num_bytes_read), num_bytes_to_read); 83 DCHECK_LE(static_cast<size_t>(num_bytes_read), num_bytes_to_read);
105 bytes_read.resize(static_cast<size_t>(num_bytes_read)); 84 bytes_read.resize(static_cast<size_t>(num_bytes_read));
106 callback.Run(ERROR_OK, bytes_read.Pass()); 85 callback.Run(ERROR_OK, bytes_read.Pass());
107 } 86 }
108 87
109 // TODO(vtl): Move the implementation to a thread pool. 88 // TODO(vtl): Move the implementation to a thread pool.
110 void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write, 89 void FileImpl::Write(mojo::Array<uint8_t> bytes_to_write,
111 int64_t offset, 90 int64_t offset,
112 Whence whence, 91 Whence whence,
113 const WriteCallback& callback) { 92 const WriteCallback& callback) {
114 DCHECK(!bytes_to_write.is_null()); 93 DCHECK(!bytes_to_write.is_null());
115 94 if (!file_.IsValid()) {
116 if (!file_fd_.is_valid()) { 95 callback.Run(GetError(file_), 0);
117 callback.Run(ERROR_CLOSED, 0);
118 return; 96 return;
119 } 97 }
120 // Who knows what |write()| would return if the size is that big (and it 98 // Who knows what |write()| would return if the size is that big (and it
121 // actually wrote that much). 99 // actually wrote that much).
122 if (bytes_to_write.size() > 100 if (bytes_to_write.size() >
123 static_cast<size_t>(std::numeric_limits<ssize_t>::max())) { 101 static_cast<size_t>(std::numeric_limits<ssize_t>::max())) {
124 callback.Run(ERROR_OUT_OF_RANGE, 0); 102 callback.Run(ERROR_INVALID_OPERATION, 0);
125 return; 103 return;
126 } 104 }
127 if (Error error = IsOffsetValid(offset)) { 105 if (Error error = IsOffsetValid(offset)) {
128 callback.Run(error, 0); 106 callback.Run(error, 0);
129 return; 107 return;
130 } 108 }
131 if (Error error = IsWhenceValid(whence)) { 109 if (Error error = IsWhenceValid(whence)) {
132 callback.Run(error, 0); 110 callback.Run(error, 0);
133 return; 111 return;
134 } 112 }
135 113
136 if (offset != 0 || whence != WHENCE_FROM_CURRENT) { 114 if (file_.Seek(static_cast<base::File::Whence>(whence), offset) == -1) {
137 // TODO(vtl): Use |pwrite()| below in the |WHENCE_FROM_START| case. This 115 callback.Run(ERROR_FAILED, 0);
138 // implementation is obviously not atomic. (If someone seeks simultaneously,
139 // we'll end up writing somewhere else. Or, well, we would if we were
140 // multithreaded.) Maybe we should do an |ftell()| and always use
141 // |pwrite()|.
142 // TODO(vtl): Possibly, at least sometimes we should not change the file
143 // position. See TODO in file.mojom.
144 if (lseek(file_fd_.get(), static_cast<off_t>(offset),
145 WhenceToStandardWhence(whence)) < 0) {
146 callback.Run(ErrnoToError(errno), 0);
147 return;
148 }
149 }
150
151 const void* buf =
152 (bytes_to_write.size() > 0) ? &bytes_to_write.front() : nullptr;
153 ssize_t num_bytes_written =
154 HANDLE_EINTR(write(file_fd_.get(), buf, bytes_to_write.size()));
155 if (num_bytes_written < 0) {
156 callback.Run(ErrnoToError(errno), 0);
157 return; 116 return;
158 } 117 }
159 118
119 const char* buf = (bytes_to_write.size() > 0)
120 ? reinterpret_cast<char*>(&bytes_to_write.front())
121 : nullptr;
122 int num_bytes_written = file_.WriteAtCurrentPos(buf, bytes_to_write.size());
123 if (num_bytes_written < 0) {
124 callback.Run(ERROR_FAILED, 0);
125 return;
126 }
127
160 DCHECK_LE(static_cast<size_t>(num_bytes_written), 128 DCHECK_LE(static_cast<size_t>(num_bytes_written),
161 std::numeric_limits<uint32_t>::max()); 129 std::numeric_limits<uint32_t>::max());
162 callback.Run(ERROR_OK, static_cast<uint32_t>(num_bytes_written)); 130 callback.Run(ERROR_OK, static_cast<uint32_t>(num_bytes_written));
163 } 131 }
164 132
165 void FileImpl::ReadToStream(mojo::ScopedDataPipeProducerHandle source,
166 int64_t offset,
167 Whence whence,
168 int64_t num_bytes_to_read,
169 const ReadToStreamCallback& callback) {
170 if (!file_fd_.is_valid()) {
171 callback.Run(ERROR_CLOSED);
172 return;
173 }
174 if (Error error = IsOffsetValid(offset)) {
175 callback.Run(error);
176 return;
177 }
178 if (Error error = IsWhenceValid(whence)) {
179 callback.Run(error);
180 return;
181 }
182
183 // TODO(vtl): FIXME soon
184 NOTIMPLEMENTED();
185 callback.Run(ERROR_UNIMPLEMENTED);
186 }
187
188 void FileImpl::WriteFromStream(mojo::ScopedDataPipeConsumerHandle sink,
189 int64_t offset,
190 Whence whence,
191 const WriteFromStreamCallback& callback) {
192 if (!file_fd_.is_valid()) {
193 callback.Run(ERROR_CLOSED);
194 return;
195 }
196 if (Error error = IsOffsetValid(offset)) {
197 callback.Run(error);
198 return;
199 }
200 if (Error error = IsWhenceValid(whence)) {
201 callback.Run(error);
202 return;
203 }
204
205 // TODO(vtl): FIXME soon
206 NOTIMPLEMENTED();
207 callback.Run(ERROR_UNIMPLEMENTED);
208 }
209
210 void FileImpl::Tell(const TellCallback& callback) { 133 void FileImpl::Tell(const TellCallback& callback) {
211 Seek(0, WHENCE_FROM_CURRENT, callback); 134 Seek(0, WHENCE_FROM_CURRENT, callback);
212 } 135 }
213 136
214 void FileImpl::Seek(int64_t offset, 137 void FileImpl::Seek(int64_t offset,
215 Whence whence, 138 Whence whence,
216 const SeekCallback& callback) { 139 const SeekCallback& callback) {
217 if (!file_fd_.is_valid()) { 140 if (!file_.IsValid()) {
218 callback.Run(ERROR_CLOSED, 0); 141 callback.Run(GetError(file_), 0);
219 return; 142 return;
220 } 143 }
221 if (Error error = IsOffsetValid(offset)) { 144 if (Error error = IsOffsetValid(offset)) {
222 callback.Run(error, 0); 145 callback.Run(error, 0);
223 return; 146 return;
224 } 147 }
225 if (Error error = IsWhenceValid(whence)) { 148 if (Error error = IsWhenceValid(whence)) {
226 callback.Run(error, 0); 149 callback.Run(error, 0);
227 return; 150 return;
228 } 151 }
229 152
230 off_t position = lseek(file_fd_.get(), static_cast<off_t>(offset), 153 int64 position = file_.Seek(static_cast<base::File::Whence>(whence), offset);
231 WhenceToStandardWhence(whence));
232 if (position < 0) { 154 if (position < 0) {
233 callback.Run(ErrnoToError(errno), 0); 155 callback.Run(ERROR_FAILED, 0);
234 return; 156 return;
235 } 157 }
236 158
237 callback.Run(ERROR_OK, static_cast<int64>(position)); 159 callback.Run(ERROR_OK, static_cast<int64>(position));
238 } 160 }
239 161
240 void FileImpl::Stat(const StatCallback& callback) { 162 void FileImpl::Stat(const StatCallback& callback) {
241 if (!file_fd_.is_valid()) { 163 if (!file_.IsValid()) {
242 callback.Run(ERROR_CLOSED, nullptr); 164 callback.Run(GetError(file_), nullptr);
243 return; 165 return;
244 } 166 }
245 StatFD(file_fd_.get(), FILE_TYPE_REGULAR_FILE, callback); 167
168 base::File::Info info;
169 if (!file_.GetInfo(&info)) {
170 callback.Run(ERROR_FAILED, nullptr);
171 return;
172 }
173
174 callback.Run(ERROR_OK, MakeFileInformation(info).Pass());
246 } 175 }
247 176
248 void FileImpl::Truncate(int64_t size, const TruncateCallback& callback) { 177 void FileImpl::Truncate(int64_t size, const TruncateCallback& callback) {
249 if (!file_fd_.is_valid()) { 178 if (!file_.IsValid()) {
250 callback.Run(ERROR_CLOSED); 179 callback.Run(GetError(file_));
251 return; 180 return;
252 } 181 }
253 if (size < 0) { 182 if (size < 0) {
254 callback.Run(ERROR_INVALID_ARGUMENT); 183 callback.Run(ERROR_INVALID_OPERATION);
255 return; 184 return;
256 } 185 }
257 if (Error error = IsOffsetValid(size)) { 186 if (Error error = IsOffsetValid(size)) {
258 callback.Run(error); 187 callback.Run(error);
259 return; 188 return;
260 } 189 }
261 190
262 if (ftruncate(file_fd_.get(), static_cast<off_t>(size)) != 0) { 191 if (!file_.SetLength(size)) {
263 callback.Run(ErrnoToError(errno)); 192 callback.Run(ERROR_NOT_FOUND);
264 return; 193 return;
265 } 194 }
266 195
267 callback.Run(ERROR_OK); 196 callback.Run(ERROR_OK);
268 } 197 }
269 198
270 void FileImpl::Touch(TimespecOrNowPtr atime, 199 void FileImpl::Touch(TimespecOrNowPtr atime,
271 TimespecOrNowPtr mtime, 200 TimespecOrNowPtr mtime,
272 const TouchCallback& callback) { 201 const TouchCallback& callback) {
273 if (!file_fd_.is_valid()) { 202 if (!file_.IsValid()) {
274 callback.Run(ERROR_CLOSED); 203 callback.Run(GetError(file_));
275 return; 204 return;
276 } 205 }
277 TouchFD(file_fd_.get(), atime.Pass(), mtime.Pass(), callback); 206
207 base::Time base_atime = Time::Now();
208 if (!atime) {
209 base::File::Info info;
210 if (!file_.GetInfo(&info)) {
211 callback.Run(ERROR_FAILED);
212 return;
213 }
214
215 base_atime = info.last_accessed;
216 } else if (!atime->now) {
217 base_atime = Time::FromDoubleT(atime->seconds);
218 }
219
220 base::Time base_mtime = Time::Now();
221 if (!mtime) {
222 base::File::Info info;
223 if (!file_.GetInfo(&info)) {
224 callback.Run(ERROR_FAILED);
225 return;
226 }
227
228 base_mtime = info.last_modified;
229 } else if (!mtime->now) {
230 base_mtime = Time::FromDoubleT(mtime->seconds);
231 }
232
233 file_.SetTimes(base_atime, base_mtime);
234 callback.Run(ERROR_OK);
278 } 235 }
279 236
280 void FileImpl::Dup(mojo::InterfaceRequest<File> file, 237 void FileImpl::Dup(mojo::InterfaceRequest<File> file,
281 const DupCallback& callback) { 238 const DupCallback& callback) {
282 if (!file_fd_.is_valid()) { 239 if (!file_.IsValid()) {
283 callback.Run(ERROR_CLOSED); 240 callback.Run(GetError(file_));
284 return; 241 return;
285 } 242 }
286 243
287 base::ScopedFD file_fd(dup(file_fd_.get())); 244 base::File new_file = file_.Duplicate();
288 if (!file_fd.is_valid()) { 245 if (!new_file.IsValid()) {
289 callback.Run(ErrnoToError(errno)); 246 callback.Run(GetError(new_file));
290 return; 247 return;
291 } 248 }
292 249
293 new FileImpl(file.Pass(), file_fd.Pass()); 250 if (file.is_pending())
251 new FileImpl(file.Pass(), new_file.Pass());
294 callback.Run(ERROR_OK); 252 callback.Run(ERROR_OK);
295 } 253 }
296 254
297 void FileImpl::Reopen(mojo::InterfaceRequest<File> file,
298 uint32_t open_flags,
299 const ReopenCallback& callback) {
300 if (!file_fd_.is_valid()) {
301 callback.Run(ERROR_CLOSED);
302 return;
303 }
304
305 // TODO(vtl): FIXME soon
306 NOTIMPLEMENTED();
307 callback.Run(ERROR_UNIMPLEMENTED);
308 }
309
310 void FileImpl::AsBuffer(const AsBufferCallback& callback) {
311 if (!file_fd_.is_valid()) {
312 callback.Run(ERROR_CLOSED, mojo::ScopedSharedBufferHandle());
313 return;
314 }
315
316 // TODO(vtl): FIXME soon
317 NOTIMPLEMENTED();
318 callback.Run(ERROR_UNIMPLEMENTED, mojo::ScopedSharedBufferHandle());
319 }
320
321 void FileImpl::Ioctl(uint32_t request,
322 mojo::Array<uint32_t> in_values,
323 const IoctlCallback& callback) {
324 if (!file_fd_.is_valid()) {
325 callback.Run(ERROR_CLOSED, mojo::Array<uint32_t>());
326 return;
327 }
328
329 // TODO(vtl): The "correct" error code should be one that can be translated to
330 // ENOTTY!
331 callback.Run(ERROR_UNAVAILABLE, mojo::Array<uint32_t>());
332 }
333
334 } // namespace filesystem 255 } // namespace filesystem
OLDNEW
« no previous file with comments | « components/filesystem/file_impl.h ('k') | components/filesystem/file_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698