summaryrefslogtreecommitdiffstats
path: root/net/base/file_stream_win.cc
diff options
context:
space:
mode:
authorerikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-03 17:18:14 +0000
committererikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-03 17:18:14 +0000
commit21da6eb1f8a9740de03cb1435bf935f5a3609a37 (patch)
tree47e6bdd8db72ee4b66f526bbe79cbca74ef85560 /net/base/file_stream_win.cc
parent0a173a23af355f6b4eceeb18f28b453063e4287c (diff)
downloadchromium_src-21da6eb1f8a9740de03cb1435bf935f5a3609a37.zip
chromium_src-21da6eb1f8a9740de03cb1435bf935f5a3609a37.tar.gz
chromium_src-21da6eb1f8a9740de03cb1435bf935f5a3609a37.tar.bz2
* Add write and read/write support to FileStream (renamed from FileInputStream).
* Moved net/disk_cache/os_file to base/platform_file. Review URL: http://codereview.chromium.org/8843 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4454 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base/file_stream_win.cc')
-rw-r--r--net/base/file_stream_win.cc254
1 files changed, 254 insertions, 0 deletions
diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc
new file mode 100644
index 0000000..e59ef0d
--- /dev/null
+++ b/net/base/file_stream_win.cc
@@ -0,0 +1,254 @@
+// Copyright (c) 2008 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.
+
+#include "net/base/file_stream.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+// Ensure that we can just use our Whence values directly.
+COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin);
+COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current);
+COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end);
+
+static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
+ overlapped->Offset = offset.LowPart;
+ overlapped->OffsetHigh = offset.HighPart;
+}
+
+static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
+ LARGE_INTEGER offset;
+ offset.LowPart = overlapped->Offset;
+ offset.HighPart = overlapped->OffsetHigh;
+ offset.QuadPart += static_cast<LONGLONG>(count);
+ SetOffset(overlapped, offset);
+}
+
+static int MapErrorCode(DWORD err) {
+ switch (err) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ return ERR_FILE_NOT_FOUND;
+ case ERROR_ACCESS_DENIED:
+ return ERR_ACCESS_DENIED;
+ case ERROR_SUCCESS:
+ return OK;
+ default:
+ LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
+ return ERR_FAILED;
+ }
+}
+
+// FileStream::AsyncContext ----------------------------------------------
+
+class FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
+ public:
+ AsyncContext(FileStream* owner)
+ : owner_(owner), overlapped_(), callback_(NULL) {
+ overlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ }
+
+ ~AsyncContext() {
+ if (callback_)
+ MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL);
+ CloseHandle(overlapped_.hEvent);
+ }
+
+ void IOCompletionIsPending(CompletionCallback* callback);
+
+ OVERLAPPED* overlapped() { return &overlapped_; }
+ CompletionCallback* callback() const { return callback_; }
+
+ private:
+ // MessageLoopForIO::IOHandler implementation:
+ virtual void OnIOCompleted(OVERLAPPED* context, DWORD num_bytes,
+ DWORD error);
+
+ FileStream* owner_;
+ OVERLAPPED overlapped_;
+ CompletionCallback* callback_;
+};
+
+void FileStream::AsyncContext::IOCompletionIsPending(
+ CompletionCallback* callback) {
+ DCHECK(!callback_);
+ callback_ = callback;
+
+ MessageLoopForIO::current()->RegisterIOContext(&overlapped_, this);
+}
+
+void FileStream::AsyncContext::OnIOCompleted(OVERLAPPED* context,
+ DWORD num_bytes,
+ DWORD error) {
+ DCHECK(&overlapped_ == context);
+ DCHECK(callback_);
+
+ MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL);
+
+ HANDLE handle = owner_->file_;
+
+ int result = static_cast<int>(num_bytes);
+ if (error && error != ERROR_HANDLE_EOF)
+ result = MapErrorCode(error);
+
+ if (num_bytes)
+ IncrementOffset(&overlapped_, num_bytes);
+
+ CompletionCallback* temp = NULL;
+ std::swap(temp, callback_);
+ temp->Run(result);
+}
+
+// FileStream ------------------------------------------------------------
+
+FileStream::FileStream() : file_(INVALID_HANDLE_VALUE) {
+}
+
+FileStream::~FileStream() {
+ Close();
+}
+
+void FileStream::Close() {
+ if (file_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(file_);
+ file_ = INVALID_HANDLE_VALUE;
+ }
+ async_context_.reset();
+}
+
+int FileStream::Open(const std::wstring& path, int open_flags) {
+ if (IsOpen()) {
+ DLOG(FATAL) << "File is already open!";
+ return ERR_UNEXPECTED;
+ }
+
+ open_flags_ = open_flags;
+ file_ = base::CreatePlatformFile(path, open_flags_, NULL);
+ if (file_ == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ LOG(WARNING) << "Failed to open file: " << error;
+ return MapErrorCode(error);
+ }
+
+ if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
+ async_context_.reset(new AsyncContext(this));
+ MessageLoopForIO::current()->RegisterIOHandler(file_,
+ async_context_.get());
+ }
+
+ return OK;
+}
+
+bool FileStream::IsOpen() const {
+ return file_ != INVALID_HANDLE_VALUE;
+}
+
+int64 FileStream::Seek(Whence whence, int64 offset) {
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+ DCHECK(!async_context_.get() || !async_context_->callback());
+
+ LARGE_INTEGER distance, result;
+ distance.QuadPart = offset;
+ DWORD move_method = static_cast<DWORD>(whence);
+ if (!SetFilePointerEx(file_, distance, &result, move_method)) {
+ DWORD error = GetLastError();
+ LOG(WARNING) << "SetFilePointerEx failed: " << error;
+ return MapErrorCode(error);
+ }
+ if (async_context_.get())
+ SetOffset(async_context_->overlapped(), result);
+ return result.QuadPart;
+}
+
+int64 FileStream::Available() {
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ int64 cur_pos = Seek(FROM_CURRENT, 0);
+ if (cur_pos < 0)
+ return cur_pos;
+
+ LARGE_INTEGER file_size;
+ if (!GetFileSizeEx(file_, &file_size)) {
+ DWORD error = GetLastError();
+ LOG(WARNING) << "GetFileSizeEx failed: " << error;
+ return MapErrorCode(error);
+ }
+
+ return file_size.QuadPart - cur_pos;
+}
+
+int FileStream::Read(
+ char* buf, int buf_len, CompletionCallback* callback) {
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+ DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
+
+ OVERLAPPED* overlapped = NULL;
+ if (async_context_.get()) {
+ DCHECK(!async_context_->callback());
+ overlapped = async_context_->overlapped();
+ }
+
+ int rv;
+
+ DWORD bytes_read;
+ if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
+ DWORD error = GetLastError();
+ if (async_context_.get() && error == ERROR_IO_PENDING) {
+ async_context_->IOCompletionIsPending(callback);
+ rv = ERR_IO_PENDING;
+ } else if (error == ERROR_HANDLE_EOF) {
+ rv = 0; // Report EOF by returning 0 bytes read.
+ } else {
+ LOG(WARNING) << "ReadFile failed: " << error;
+ rv = MapErrorCode(error);
+ }
+ } else {
+ if (overlapped)
+ IncrementOffset(overlapped, bytes_read);
+ rv = static_cast<int>(bytes_read);
+ }
+ return rv;
+}
+
+int FileStream::Write(
+ const char* buf, int buf_len, CompletionCallback* callback) {
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+ DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
+
+ OVERLAPPED* overlapped = NULL;
+ if (async_context_.get()) {
+ DCHECK(!async_context_->callback());
+ overlapped = async_context_->overlapped();
+ }
+
+ int rv;
+ DWORD bytes_written;
+ if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) {
+ DWORD error = GetLastError();
+ if (async_context_.get() && error == ERROR_IO_PENDING) {
+ async_context_->IOCompletionIsPending(callback);
+ rv = ERR_IO_PENDING;
+ } else {
+ LOG(WARNING) << "WriteFile failed: " << error;
+ rv = MapErrorCode(error);
+ }
+ } else {
+ if (overlapped)
+ IncrementOffset(overlapped, bytes_written);
+ rv = static_cast<int>(bytes_written);
+ }
+ return rv;
+}
+
+} // namespace net
+