summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authorsatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-17 22:10:34 +0000
committersatorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-17 22:10:34 +0000
commite3d66fde2328cc9220c25b51d06cc17b2f8522e7 (patch)
treec5da44e3c8bfcc898eb19e3176f57491fba16523 /net/base
parent17cb8a80ed6014b9071fb2a7daef0dc52bf8ab45 (diff)
downloadchromium_src-e3d66fde2328cc9220c25b51d06cc17b2f8522e7.zip
chromium_src-e3d66fde2328cc9220c25b51d06cc17b2f8522e7.tar.gz
chromium_src-e3d66fde2328cc9220c25b51d06cc17b2f8522e7.tar.bz2
net: Add FileStream::Open() and Close() that perform asynchronously.
However, these aren't used yet. Clients of FileStream that reads/writes files asynchronously should be migrated to use the new functions. BUG=72001,114783 TEST=net_unittests. Review URL: https://chromiumcodereview.appspot.com/9415031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122601 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r--net/base/file_stream.h54
-rw-r--r--net/base/file_stream_posix.cc157
-rw-r--r--net/base/file_stream_unittest.cc95
-rw-r--r--net/base/file_stream_win.cc163
4 files changed, 416 insertions, 53 deletions
diff --git a/net/base/file_stream.h b/net/base/file_stream.h
index b9efb25..00e97d2 100644
--- a/net/base/file_stream.h
+++ b/net/base/file_stream.h
@@ -12,6 +12,7 @@
#pragma once
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
@@ -47,21 +48,52 @@ class NET_EXPORT FileStream {
// is destructed.
FileStream(base::PlatformFile file, int flags, net::NetLog* net_log);
+ // If the file stream was opened with Open() or OpenSync(), the underlying
+ // file will be closed automatically by the destructor, if not closed
+ // manually.
+ //
+ // If the file was opened in the async mode, there must never be any
+ // pending async operations by the time the destructor is called.
virtual ~FileStream();
- // Call this method to close the FileStream synchronously.
- // It is OK to call Close multiple times. Redundant calls are ignored.
- // Note that if there are any pending async operations, they'll be aborted.
+ // Call this method to close the FileStream, which was previously opened in
+ // the async mode (PLATFORM_FILE_ASYNC) asynchronously.
+ //
+ // Once the operation is done |callback| is run with OK (i.e. an error is
+ // not propagated just like CloseSync() does not).
//
- // TODO(satorux): Implement the asynchronous version of this.
+ // It is not OK to call Close() multiple times. The behavior is not defined.
+ //
+ // Note that there must never be any pending async operations.
+ virtual void Close(const CompletionCallback& callback);
+
+ // Call this method to close the FileStream synchronously.
+ // It is OK to call CloseSync() multiple times. Redundant calls are
+ // ignored. Note that if there are any pending async operations, they'll
+ // be aborted.
virtual void CloseSync();
+ // Call this method to open the FileStream asynchronously. The remaining
+ // methods cannot be used unless the file is opened successfully. Returns
+ // ERR_IO_PENDING if the operation is started. If the operation cannot be
+ // started then an error code is returned. Once the operation is done,
+ // |callback| is run with the result code. open_flags is a bitfield of
+ // base::PlatformFileFlags.
+ //
+ // If the file stream is not closed manually, the underlying file will be
+ // automatically closed when FileStream is destructed in an asynchronous
+ // manner (i.e. the file stream is closed in the background but you don't
+ // know when).
+ virtual int Open(const FilePath& path, int open_flags,
+ const CompletionCallback& callback);
+
// Call this method to open the FileStream synchronously.
// The remaining methods cannot be used unless this method returns OK. If
// the file cannot be opened then an error code is returned. open_flags is
// a bitfield of base::PlatformFileFlags
//
- // TODO(satorux): Implement the asynchronous version of this.
+ // If the file stream is not closed manually, the underlying file will be
+ // automatically closed when FileStream is destructed.
virtual int OpenSync(const FilePath& path, int open_flags);
// Returns true if Open succeeded and Close has not been called.
@@ -152,7 +184,7 @@ class NET_EXPORT FileStream {
// Truncates the file to be |bytes| length. This is only valid for writable
// files. After truncation the file stream is positioned at |bytes|. The new
- // position is retured, or a value < 0 on error.
+ // position is returned, or a value < 0 on error.
// WARNING: one may not truncate a file beyond its current length on any
// platform with this call.
virtual int64 Truncate(int64 bytes);
@@ -182,6 +214,14 @@ class NET_EXPORT FileStream {
friend class AsyncContext;
friend class FileStreamTest;
+ // Called when the file_ is opened asynchronously. |file| contains the
+ // platform file opened. |result| contains the result as a network error
+ // code.
+ void OnOpened(base::PlatformFile *file, int* result);
+
+ // Called when the file_ is closed asynchronously.
+ void OnClosed();
+
// This member is used to support asynchronous reads. It is non-null when
// the FileStream was opened with PLATFORM_FILE_ASYNC.
scoped_ptr<AsyncContext> async_context_;
@@ -191,6 +231,8 @@ class NET_EXPORT FileStream {
bool auto_closed_;
bool record_uma_;
net::BoundNetLog bound_net_log_;
+ base::WeakPtrFactory<FileStream> weak_ptr_factory_;
+ CompletionCallback callback_;
DISALLOW_COPY_AND_ASSIGN(FileStream);
};
diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc
index 86bf728..835d520 100644
--- a/net/base/file_stream_posix.cc
+++ b/net/base/file_stream_posix.cc
@@ -69,6 +69,41 @@ int RecordAndMapError(int error,
return net_error;
}
+// Opens a file with some network logging.
+// The opened file and the result code are written to |file| and |result|.
+void OpenFile(const FilePath& path,
+ int open_flags,
+ bool record_uma,
+ const net::BoundNetLog& bound_net_log,
+ base::PlatformFile* file,
+ int* result) {
+ bound_net_log.BeginEvent(
+ net::NetLog::TYPE_FILE_STREAM_OPEN,
+ make_scoped_refptr(
+ new net::NetLogStringParameter("file_name",
+ path.AsUTF8Unsafe())));
+
+ *result = OK;
+ *file = base::CreatePlatformFile(path, open_flags, NULL, NULL);
+ if (*file == base::kInvalidPlatformFileValue) {
+ bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
+ *result = RecordAndMapError(errno, FILE_ERROR_SOURCE_OPEN, record_uma,
+ bound_net_log);
+ }
+}
+
+// Closes a file with some network logging.
+void CloseFile(base::PlatformFile file,
+ const net::BoundNetLog& bound_net_log) {
+ bound_net_log.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE, NULL);
+ if (file == base::kInvalidPlatformFileValue)
+ return;
+
+ if (!base::ClosePlatformFile(file))
+ NOTREACHED();
+ bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
+}
+
// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapSystemError() to map errno to net error codes.
int ReadFile(base::PlatformFile file,
@@ -328,7 +363,8 @@ FileStream::FileStream(net::NetLog* net_log)
auto_closed_(true),
record_uma_(false),
bound_net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_FILESTREAM)) {
+ net::NetLog::SOURCE_FILESTREAM)),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL);
}
@@ -338,7 +374,8 @@ FileStream::FileStream(base::PlatformFile file, int flags, net::NetLog* net_log)
auto_closed_(false),
record_uma_(false),
bound_net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_FILESTREAM)) {
+ net::NetLog::SOURCE_FILESTREAM)),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL);
// If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
@@ -349,25 +386,80 @@ FileStream::FileStream(base::PlatformFile file, int flags, net::NetLog* net_log)
}
FileStream::~FileStream() {
- if (auto_closed_)
- CloseSync();
+ if (auto_closed_) {
+ if (async_context_.get()) {
+ // Make sure we don't have a request in flight.
+ DCHECK(async_context_->callback().is_null());
+
+ // Close the file in the background.
+ const bool posted = base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&CloseFile, file_, bound_net_log_),
+ true /* task_is_slow */);
+ DCHECK(posted);
+ } else {
+ CloseSync();
+ }
+ }
bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL);
}
-void FileStream::CloseSync() {
- bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE, NULL);
+void FileStream::Close(const CompletionCallback& callback) {
+ DCHECK(callback_.is_null());
+ callback_ = callback;
+
+ // Make sure we don't have a request in flight. Unlike CloseSync(), don't
+ // abort existing asynchronous operations, as it'd block.
+ DCHECK(async_context_.get());
+ DCHECK(async_context_->callback().is_null());
+
+ const bool posted = base::WorkerPool::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&CloseFile, file_, bound_net_log_),
+ base::Bind(&FileStream::OnClosed, weak_ptr_factory_.GetWeakPtr()),
+ true /* task_is_slow */);
+ DCHECK(posted);
+}
+void FileStream::CloseSync() {
// Abort any existing asynchronous operations.
+
+ // TODO(satorux): Remove this once all async clients are migrated to use
+ // Close(). crbug.com/114783
async_context_.reset();
- if (file_ != base::kInvalidPlatformFileValue) {
- if (!base::ClosePlatformFile(file_))
- NOTREACHED();
- file_ = base::kInvalidPlatformFileValue;
+ CloseFile(file_, bound_net_log_);
+ file_ = base::kInvalidPlatformFileValue;
+}
- bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
+int FileStream::Open(const FilePath& path, int open_flags,
+ const CompletionCallback& callback) {
+ if (IsOpen()) {
+ DLOG(FATAL) << "File is already open!";
+ return ERR_UNEXPECTED;
}
+
+ DCHECK(callback_.is_null());
+ callback_ = callback;
+
+ open_flags_ = open_flags;
+ DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
+
+ base::PlatformFile* file =
+ new base::PlatformFile(base::kInvalidPlatformFileValue);
+ int* result = new int(OK);
+ const bool posted = base::WorkerPool::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&OpenFile, path, open_flags, record_uma_, bound_net_log_,
+ file, result),
+ base::Bind(&FileStream::OnOpened,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(file),
+ base::Owned(result)),
+ true /* task_is_slow */);
+ DCHECK(posted);
+ return ERR_IO_PENDING;
}
int FileStream::OpenSync(const FilePath& path, int open_flags) {
@@ -376,27 +468,19 @@ int FileStream::OpenSync(const FilePath& path, int open_flags) {
return ERR_UNEXPECTED;
}
- bound_net_log_.BeginEvent(
- net::NetLog::TYPE_FILE_STREAM_OPEN,
- make_scoped_refptr(
- new net::NetLogStringParameter("file_name",
- path.AsUTF8Unsafe())));
-
open_flags_ = open_flags;
- file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
- if (file_ == base::kInvalidPlatformFileValue) {
- int net_error = RecordAndMapError(errno,
- FILE_ERROR_SOURCE_OPEN,
- record_uma_,
- bound_net_log_);
- bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
- return net_error;
- }
+ int result = OK;
+ OpenFile(path, open_flags_, record_uma_, bound_net_log_, &file_, &result);
+ if (result != OK)
+ return result;
+
+ // TODO(satorux): Remove this once all async clients are migrated to use
+ // Open(). crbug.com/114783
if (open_flags_ & base::PLATFORM_FILE_ASYNC)
async_context_.reset(new AsyncContext());
- return OK;
+ return result;
}
bool FileStream::IsOpen() const {
@@ -596,4 +680,23 @@ void FileStream::SetBoundNetLogSource(
bound_net_log_.source())));
}
+void FileStream::OnClosed() {
+ file_ = base::kInvalidPlatformFileValue;
+
+ CompletionCallback temp = callback_;
+ callback_.Reset();
+ temp.Run(OK);
+}
+
+void FileStream::OnOpened(base::PlatformFile* file, int* result) {
+ file_ = *file;
+
+ if (*result == OK)
+ async_context_.reset(new AsyncContext());
+
+ CompletionCallback temp = callback_;
+ callback_.Reset();
+ temp.Run(*result);
+}
+
} // namespace net
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
index 537e6b1..91eb075 100644
--- a/net/base/file_stream_unittest.cc
+++ b/net/base/file_stream_unittest.cc
@@ -10,6 +10,9 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/platform_file.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "net/base/capturing_net_log.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
@@ -30,6 +33,45 @@ IOBufferWithSize* CreateTestDataBuffer() {
return buf;
}
+// This NetLog is used for notifying when a file stream is closed
+// (i.e. TYPE_FILE_STREAM_CLOSE event is recorded).
+class NetLogForNotifyingFileClosure : public NetLog {
+ public:
+ NetLogForNotifyingFileClosure()
+ : id_(0),
+ on_closure_(false /* manual_reset */, false /* initially_signaled */) {
+ }
+
+ // Wait until a file closure event is recorded.
+ bool WaitForClosure() {
+ const base::TimeDelta timeout(
+ base::TimeDelta::FromMilliseconds(
+ TestTimeouts::action_max_timeout_ms()));
+ return on_closure_.TimedWait(timeout);
+ }
+
+ // NetLog overrides:
+ virtual void AddEntry(EventType type,
+ const base::TimeTicks& time,
+ const Source& source,
+ EventPhase phase,
+ EventParameters* extra_parameters) {
+ if (type == TYPE_FILE_STREAM_CLOSE) {
+ on_closure_.Signal();
+ }
+ }
+
+ virtual uint32 NextID() { return id_++; }
+ virtual LogLevel GetLogLevel() const { return LOG_ALL; }
+ virtual void AddThreadSafeObserver(ThreadSafeObserver* observer) {}
+ virtual void RemoveThreadSafeObserver(ThreadSafeObserver* observer) {};
+
+
+ private:
+ uint32 id_;
+ base::WaitableEvent on_closure_;
+};
+
} // namespace
class FileStreamTest : public PlatformTest {
@@ -972,6 +1014,59 @@ TEST_F(FileStreamTest, Truncate) {
EXPECT_EQ("01230123", read_contents);
}
+TEST_F(FileStreamTest, AsyncBasicOpenClose) {
+ FileStream stream(NULL);
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_ASYNC;
+ TestCompletionCallback callback;
+ int rv = stream.Open(temp_file_path(), flags, callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_TRUE(stream.IsOpen());
+
+ stream.Close(callback.callback());
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_FALSE(stream.IsOpen());
+}
+
+TEST_F(FileStreamTest, SyncCloseTwice) {
+ FileStream stream(NULL);
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ;
+ int rv = stream.OpenSync(temp_file_path(), flags);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(stream.IsOpen());
+
+ // Closing twice should be safe.
+ stream.CloseSync();
+ EXPECT_FALSE(stream.IsOpen());
+
+ stream.CloseSync();
+ EXPECT_FALSE(stream.IsOpen());
+}
+
+TEST_F(FileStreamTest, AsyncCloseTwice) {
+ FileStream stream(NULL);
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_ASYNC;
+ TestCompletionCallback callback;
+ int rv = stream.Open(temp_file_path(), flags, callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_TRUE(stream.IsOpen());
+
+ // Closing twice should be safe.
+ stream.Close(callback.callback());
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_FALSE(stream.IsOpen());
+
+ stream.Close(callback.callback());
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_FALSE(stream.IsOpen());
+}
+
} // namespace
} // namespace net
diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc
index aa2b045..8ee7cbe 100644
--- a/net/base/file_stream_win.cc
+++ b/net/base/file_stream_win.cc
@@ -11,6 +11,7 @@
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/threading/thread_restrictions.h"
+#include "base/threading/worker_pool.h"
#include "net/base/file_stream_metrics.h"
#include "net/base/file_stream_net_log_parameters.h"
#include "net/base/io_buffer.h"
@@ -56,6 +57,47 @@ int RecordAndMapError(int error,
return net_error;
}
+// Opens a file with some network logging.
+// The opened file and the result code are written to |file| and |result|.
+void OpenFile(const FilePath& path,
+ int open_flags,
+ bool record_uma,
+ const net::BoundNetLog& bound_net_log,
+ base::PlatformFile* file,
+ int* result) {
+ bound_net_log.BeginEvent(
+ net::NetLog::TYPE_FILE_STREAM_OPEN,
+ make_scoped_refptr(
+ new net::NetLogStringParameter("file_name",
+ path.AsUTF8Unsafe())));
+
+ *file = base::CreatePlatformFile(path, open_flags, NULL, NULL);
+ if (*file == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ LOG(WARNING) << "Failed to open file: " << error;
+ *result = RecordAndMapError(error,
+ FILE_ERROR_SOURCE_OPEN,
+ record_uma,
+ bound_net_log);
+ bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
+ return;
+ }
+}
+
+// Closes a file with some network logging.
+void CloseFile(base::PlatformFile file,
+ const net::BoundNetLog& bound_net_log) {
+ bound_net_log.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE, NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return;
+
+ CancelIo(file);
+
+ if (!base::ClosePlatformFile(file))
+ NOTREACHED();
+ bound_net_log.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
+}
+
} // namespace
// FileStream::AsyncContext ----------------------------------------------
@@ -153,7 +195,8 @@ FileStream::FileStream(net::NetLog* net_log)
auto_closed_(true),
record_uma_(false),
bound_net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_FILESTREAM)) {
+ net::NetLog::SOURCE_FILESTREAM)),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL);
}
@@ -163,7 +206,8 @@ FileStream::FileStream(base::PlatformFile file, int flags, net::NetLog* net_log)
auto_closed_(false),
record_uma_(false),
bound_net_log_(net::BoundNetLog::Make(net_log,
- net::NetLog::SOURCE_FILESTREAM)) {
+ net::NetLog::SOURCE_FILESTREAM)),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
bound_net_log_.BeginEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL);
// If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
@@ -176,18 +220,54 @@ FileStream::FileStream(base::PlatformFile file, int flags, net::NetLog* net_log)
}
FileStream::~FileStream() {
- if (auto_closed_)
- CloseSync();
+ if (auto_closed_) {
+ if (async_context_.get()) {
+ // Make sure we don't have a request in flight.
+ DCHECK(async_context_->callback().is_null());
+
+ // Close the file in the background.
+ const bool posted = base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&CloseFile, file_, bound_net_log_),
+ true /* task_is_slow */);
+ DCHECK(posted);
+ } else {
+ CloseSync();
+ }
+ }
bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_ALIVE, NULL);
}
+void FileStream::Close(const CompletionCallback& callback) {
+ DCHECK(callback_.is_null());
+ callback_ = callback;
+
+ // Make sure we don't have a request in flight. Unlike CloseSync(), don't
+ // abort existing asynchronous operations, as it'd block.
+ DCHECK(async_context_.get());
+ DCHECK(async_context_->callback().is_null());
+
+ const bool posted = base::WorkerPool::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&CloseFile, file_, bound_net_log_),
+ base::Bind(&FileStream::OnClosed, weak_ptr_factory_.GetWeakPtr()),
+ true /* task_is_slow */);
+ DCHECK(posted);
+}
+
void FileStream::CloseSync() {
+ // The logic here is similar to CloseFile() but async_context_.reset() is
+ // caled in this function.
+
bound_net_log_.AddEvent(net::NetLog::TYPE_FILE_STREAM_CLOSE, NULL);
if (file_ != INVALID_HANDLE_VALUE)
CancelIo(file_);
+ // TODO(satorux): Remove this once all async clients are migrated to use
+ // Close(). crbug.com/114783
async_context_.reset();
+
if (file_ != INVALID_HANDLE_VALUE) {
if (!base::ClosePlatformFile(file_))
NOTREACHED();
@@ -197,31 +277,50 @@ void FileStream::CloseSync() {
}
}
-int FileStream::OpenSync(const FilePath& path, int open_flags) {
+int FileStream::Open(const FilePath& path, int open_flags,
+ const CompletionCallback& callback) {
if (IsOpen()) {
DLOG(FATAL) << "File is already open!";
return ERR_UNEXPECTED;
}
- bound_net_log_.BeginEvent(
- net::NetLog::TYPE_FILE_STREAM_OPEN,
- make_scoped_refptr(
- new net::NetLogStringParameter("file_name",
- path.AsUTF8Unsafe())));
+ DCHECK(callback_.is_null());
+ callback_ = callback;
open_flags_ = open_flags;
- file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
- if (file_ == INVALID_HANDLE_VALUE) {
- DWORD error = GetLastError();
- LOG(WARNING) << "Failed to open file: " << error;
- int net_error = RecordAndMapError(error,
- FILE_ERROR_SOURCE_OPEN,
- record_uma_,
- bound_net_log_);
- bound_net_log_.EndEvent(net::NetLog::TYPE_FILE_STREAM_OPEN, NULL);
- return net_error;
+ DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
+
+ base::PlatformFile* file =
+ new base::PlatformFile(base::kInvalidPlatformFileValue);
+ int* result = new int(OK);
+ const bool posted = base::WorkerPool::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&OpenFile, path, open_flags, record_uma_, bound_net_log_,
+ file, result),
+ base::Bind(&FileStream::OnOpened,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Owned(file),
+ base::Owned(result)),
+ true /* task_is_slow */);
+ DCHECK(posted);
+ return ERR_IO_PENDING;
+}
+
+int FileStream::OpenSync(const FilePath& path, int open_flags) {
+ if (IsOpen()) {
+ DLOG(FATAL) << "File is already open!";
+ return ERR_UNEXPECTED;
}
+ open_flags_ = open_flags;
+
+ int result = OK;
+ OpenFile(path, open_flags_, record_uma_, bound_net_log_, &file_, &result);
+ if (result != OK)
+ return result;
+
+ // TODO(satorux): Remove this once all async clients are migrated to use
+ // Open(). crbug.com/114783
if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
async_context_.reset(new AsyncContext(bound_net_log_));
if (record_uma_)
@@ -515,4 +614,28 @@ void FileStream::SetBoundNetLogSource(
bound_net_log_.source())));
}
+void FileStream::OnClosed() {
+ file_ = INVALID_HANDLE_VALUE;
+
+ CompletionCallback temp = callback_;
+ callback_.Reset();
+ temp.Run(OK);
+}
+
+void FileStream::OnOpened(base::PlatformFile* file, int* result) {
+ file_ = *file;
+
+ if (*result == OK) {
+ async_context_.reset(new AsyncContext(bound_net_log_));
+ if (record_uma_)
+ async_context_->EnableErrorStatistics();
+ MessageLoopForIO::current()->RegisterIOHandler(file_,
+ async_context_.get());
+ }
+
+ CompletionCallback temp = callback_;
+ callback_.Reset();
+ temp.Run(*result);
+}
+
} // namespace net