summaryrefslogtreecommitdiffstats
path: root/net/base
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
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')
-rw-r--r--net/base/file_input_stream_unittest.cc205
-rw-r--r--net/base/file_stream.h (renamed from net/base/file_input_stream.h)63
-rw-r--r--net/base/file_stream_posix.cc (renamed from net/base/file_input_stream_posix.cc)78
-rw-r--r--net/base/file_stream_unittest.cc369
-rw-r--r--net/base/file_stream_win.cc (renamed from net/base/file_input_stream_win.cc)110
-rw-r--r--net/base/upload_data_stream.cc4
-rw-r--r--net/base/upload_data_stream.h4
7 files changed, 537 insertions, 296 deletions
diff --git a/net/base/file_input_stream_unittest.cc b/net/base/file_input_stream_unittest.cc
deleted file mode 100644
index b259de8..0000000
--- a/net/base/file_input_stream_unittest.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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 "base/file_util.h"
-#include "base/path_service.h"
-#include "base/platform_test.h"
-#include "net/base/file_input_stream.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-static const char kTestData[] = "0123456789";
-
-class FileInputStreamTest : public PlatformTest {
- public:
- virtual void SetUp() {
- PlatformTest::SetUp();
-
- file_util::CreateTemporaryFileName(&temp_file_path_);
- file_util::WriteFile(temp_file_path_, kTestData, arraysize(kTestData)-1);
- }
- virtual void TearDown() {
- file_util::Delete(temp_file_path_, false);
-
- PlatformTest::TearDown();
- }
- const std::wstring temp_file_path() const { return temp_file_path_; }
- private:
- std::wstring temp_file_path_;
-};
-
-TEST_F(FileInputStreamTest, BasicOpenClose) {
- net::FileInputStream stream;
- int rv = stream.Open(temp_file_path(), false);
- EXPECT_EQ(net::OK, rv);
-}
-
-TEST_F(FileInputStreamTest, UseClosedStream) {
- net::FileInputStream stream;
-
- EXPECT_FALSE(stream.IsOpen());
-
- // Try seeking...
- int64 new_offset = stream.Seek(net::FROM_BEGIN, 5);
- EXPECT_EQ(net::ERR_UNEXPECTED, new_offset);
-
- // Try available...
- int64 avail = stream.Available();
- EXPECT_EQ(net::ERR_UNEXPECTED, avail);
-
- // Try reading...
- char buf[10];
- int rv = stream.Read(buf, sizeof(buf), NULL);
- EXPECT_EQ(net::ERR_UNEXPECTED, rv);
-}
-
-TEST_F(FileInputStreamTest, BasicRead) {
- int64 file_size;
- bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
- EXPECT_TRUE(ok);
-
- net::FileInputStream stream;
- int rv = stream.Open(temp_file_path(), false);
- EXPECT_EQ(net::OK, rv);
-
- int64 total_bytes_avail = stream.Available();
- EXPECT_EQ(file_size, total_bytes_avail);
-
- int64 total_bytes_read = 0;
-
- std::string data_read;
- for (;;) {
- char buf[4];
- rv = stream.Read(buf, sizeof(buf), NULL);
- EXPECT_LE(0, rv);
- if (rv <= 0)
- break;
- total_bytes_read += rv;
- data_read.append(buf, rv);
- }
- EXPECT_EQ(file_size, total_bytes_read);
- EXPECT_TRUE(data_read == kTestData);
-}
-
-TEST_F(FileInputStreamTest, AsyncRead) {
- int64 file_size;
- bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
- EXPECT_TRUE(ok);
-
- net::FileInputStream stream;
- int rv = stream.Open(temp_file_path(), true);
- EXPECT_EQ(net::OK, rv);
-
- int64 total_bytes_avail = stream.Available();
- EXPECT_EQ(file_size, total_bytes_avail);
-
- TestCompletionCallback callback;
-
- int64 total_bytes_read = 0;
-
- std::string data_read;
- for (;;) {
- char buf[4];
- rv = stream.Read(buf, sizeof(buf), &callback);
- if (rv == net::ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_LE(0, rv);
- if (rv <= 0)
- break;
- total_bytes_read += rv;
- data_read.append(buf, rv);
- }
- EXPECT_EQ(file_size, total_bytes_read);
- EXPECT_TRUE(data_read == kTestData);
-}
-
-TEST_F(FileInputStreamTest, BasicRead_FromOffset) {
- int64 file_size;
- bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
- EXPECT_TRUE(ok);
-
- net::FileInputStream stream;
- int rv = stream.Open(temp_file_path(), false);
- EXPECT_EQ(net::OK, rv);
-
- const int64 kOffset = 3;
- int64 new_offset = stream.Seek(net::FROM_BEGIN, kOffset);
- EXPECT_EQ(kOffset, new_offset);
-
- int64 total_bytes_avail = stream.Available();
- EXPECT_EQ(file_size - kOffset, total_bytes_avail);
-
- int64 total_bytes_read = 0;
-
- std::string data_read;
- for (;;) {
- char buf[4];
- rv = stream.Read(buf, sizeof(buf), NULL);
- EXPECT_LE(0, rv);
- if (rv <= 0)
- break;
- total_bytes_read += rv;
- data_read.append(buf, rv);
- }
- EXPECT_EQ(file_size - kOffset, total_bytes_read);
- EXPECT_TRUE(data_read == kTestData + kOffset);
-}
-
-TEST_F(FileInputStreamTest, AsyncRead_FromOffset) {
- int64 file_size;
- bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
- EXPECT_TRUE(ok);
-
- net::FileInputStream stream;
- int rv = stream.Open(temp_file_path(), true);
- EXPECT_EQ(net::OK, rv);
-
- const int64 kOffset = 3;
- int64 new_offset = stream.Seek(net::FROM_BEGIN, kOffset);
- EXPECT_EQ(kOffset, new_offset);
-
- int64 total_bytes_avail = stream.Available();
- EXPECT_EQ(file_size - kOffset, total_bytes_avail);
-
- TestCompletionCallback callback;
-
- int64 total_bytes_read = 0;
-
- std::string data_read;
- for (;;) {
- char buf[4];
- rv = stream.Read(buf, sizeof(buf), &callback);
- if (rv == net::ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_LE(0, rv);
- if (rv <= 0)
- break;
- total_bytes_read += rv;
- data_read.append(buf, rv);
- }
- EXPECT_EQ(file_size - kOffset, total_bytes_read);
- EXPECT_TRUE(data_read == kTestData + kOffset);
-}
-
-TEST_F(FileInputStreamTest, SeekAround) {
- net::FileInputStream stream;
- int rv = stream.Open(temp_file_path(), true);
- EXPECT_EQ(net::OK, rv);
-
- const int64 kOffset = 3;
- int64 new_offset = stream.Seek(net::FROM_BEGIN, kOffset);
- EXPECT_EQ(kOffset, new_offset);
-
- new_offset = stream.Seek(net::FROM_CURRENT, kOffset);
- EXPECT_EQ(2 * kOffset, new_offset);
-
- new_offset = stream.Seek(net::FROM_CURRENT, -kOffset);
- EXPECT_EQ(kOffset, new_offset);
-
- const int kTestDataLen = arraysize(kTestData) - 1;
-
- new_offset = stream.Seek(net::FROM_END, -kTestDataLen);
- EXPECT_EQ(0, new_offset);
-}
diff --git a/net/base/file_input_stream.h b/net/base/file_stream.h
index eb4b2ae..b98cb15 100644
--- a/net/base/file_input_stream.h
+++ b/net/base/file_stream.h
@@ -2,18 +2,17 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
-// This file defines FileInputStream, a basic interface for reading files
+// This file defines FileStream, a basic interface for reading and writing files
// synchronously or asynchronously with support for seeking to an offset.
+// Note that even when used asynchronously, only one operation is supported at
+// a time.
-#ifndef NET_BASE_FILE_INPUT_STREAM_H_
-#define NET_BASE_FILE_INPUT_STREAM_H_
+#ifndef NET_BASE_FILE_STREAM_H_
+#define NET_BASE_FILE_STREAM_H_
+#include "base/platform_file.h"
#include "net/base/completion_callback.h"
-#if defined(OS_WIN)
-typedef void* HANDLE;
-#endif
-
namespace net {
// TODO(darin): Move this to a more generic location.
@@ -24,20 +23,21 @@ enum Whence {
FROM_END = 2
};
-class FileInputStream {
+class FileStream {
public:
- FileInputStream();
- ~FileInputStream();
+ FileStream();
+ ~FileStream();
- // Call this method to close the FileInputStream. It is OK to call Close
+ // Call this method to close the FileStream. 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.
void Close();
- // Call this method to open the FileInputStream. The remaining methods
+ // Call this method to open the FileStream. The remaining methods
// cannot be used unless this method returns OK. If the file cannot be
// opened then an error code is returned.
- // NOTE: The underlying file is opened with non-exclusive access.
- int Open(const std::wstring& path, bool asynchronous_mode);
+ // open_flags is a bitfield of base::PlatformFileFlags
+ int Open(const std::wstring& path, int open_flags);
// Returns true if Open succeeded and Close has not been called.
bool IsOpen() const;
@@ -57,7 +57,7 @@ class FileInputStream {
// allowed.) Returns the number of bytes copied, 0 if at end-of-file, or an
// error code if the operation could not be performed.
//
- // If opened with |asynchronous_mode| set to true, then a non-null callback
+ // If opened with PLATFORM_FILE_ASYNC, then a non-null callback
// must be passed to this method. In asynchronous mode, if the read could
// not complete synchronously, then ERR_IO_PENDING is returned, and the
// callback will be notified on the current thread (via the MessageLoop) when
@@ -68,25 +68,42 @@ class FileInputStream {
// destroy or close the file stream while there is an asynchronous read in
// progress. That will cancel the read and allow the buffer to be freed.
//
+ // This method should not be called if the stream was opened WRITE_ONLY.
int Read(char* buf, int buf_len, CompletionCallback* callback);
+ // Call this method to write data at the current stream position. Up to
+ // buf_len bytes will be written from buf. (In other words, partial writes are
+ // allowed.) Returns the number of bytes written, or an error code if the
+ // operation could not be performed.
+ //
+ // If opened with PLATFORM_FILE_ASYNC, then a non-null callback
+ // must be passed to this method. In asynchronous mode, if the write could
+ // not complete synchronously, then ERR_IO_PENDING is returned, and the
+ // callback will be notified on the current thread (via the MessageLoop) when
+ // the write has completed.
+ //
+ // In the case of an asychronous write, the memory pointed to by |buf| must
+ // remain valid until the callback is notified. However, it is valid to
+ // destroy or close the file stream while there is an asynchronous write in
+ // progress. That will cancel the write and allow the buffer to be freed.
+ //
+ // This method should not be called if the stream was opened READ_ONLY.
+ int Write(const char* buf, int buf_len, CompletionCallback* callback);
+
private:
class AsyncContext;
friend class AsyncContext;
// This member is used to support asynchronous reads. It is non-null when
- // the FileInputStream was opened with asynchronous_mode set to true.
+ // the FileStream was opened with PLATFORM_FILE_ASYNC.
scoped_ptr<AsyncContext> async_context_;
-#if defined(OS_WIN)
- HANDLE handle_;
-#elif defined(OS_POSIX)
- int fd_;
-#endif
+ base::PlatformFile file_;
+ int open_flags_;
- DISALLOW_COPY_AND_ASSIGN(FileInputStream);
+ DISALLOW_COPY_AND_ASSIGN(FileStream);
};
} // namespace net
-#endif // NET_BASE_FILE_INPUT_STREAM_H_
+#endif // NET_BASE_FILE_STREAM_H_
diff --git a/net/base/file_input_stream_posix.cc b/net/base/file_stream_posix.cc
index 4f2eb937..53589166 100644
--- a/net/base/file_input_stream_posix.cc
+++ b/net/base/file_stream_posix.cc
@@ -5,7 +5,7 @@
// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64
-#include "net/base/file_input_stream.h"
+#include "net/base/file_stream.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -29,10 +29,10 @@ COMPILE_ASSERT(net::FROM_BEGIN == SEEK_SET &&
namespace net {
-// FileInputStream::AsyncContext ----------------------------------------------
+// FileStream::AsyncContext ----------------------------------------------
// TODO(deanm): Figure out how to best do async IO.
-class FileInputStream::AsyncContext {
+class FileStream::AsyncContext {
public:
CompletionCallback* callback() const { return NULL; }
@@ -41,22 +41,22 @@ class FileInputStream::AsyncContext {
DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};
-// FileInputStream ------------------------------------------------------------
+// FileStream ------------------------------------------------------------
-FileInputStream::FileInputStream() : fd_(-1) {
+FileStream::FileStream() : file_(base::kInvalidPlatformFileValue) {
DCHECK(!IsOpen());
}
-FileInputStream::~FileInputStream() {
+FileStream::~FileStream() {
Close();
}
-void FileInputStream::Close() {
- if (fd_ != -1) {
- if (close(fd_) != 0) {
+void FileStream::Close() {
+ if (file_ != base::kInvalidPlatformFileValue) {
+ if (close(file_) != 0) {
NOTREACHED();
}
- fd_ = -1;
+ file_ = base::kInvalidPlatformFileValue;
}
async_context_.reset();
}
@@ -74,34 +74,42 @@ static int64 MapErrorCode(int err) {
}
}
-int FileInputStream::Open(const std::wstring& path, bool asynchronous_mode) {
- // We don't need O_LARGEFILE here since we set the 64-bit off_t feature.
- fd_ = open(WideToUTF8(path).c_str(), 0, O_RDONLY);
- if (fd_ == -1)
+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_ == base::kInvalidPlatformFileValue) {
+ LOG(WARNING) << "Failed to open file: " << errno;
return MapErrorCode(errno);
+ }
return OK;
}
-bool FileInputStream::IsOpen() const {
- return fd_ != -1;
+bool FileStream::IsOpen() const {
+ return file_ != base::kInvalidPlatformFileValue;
}
-int64 FileInputStream::Seek(Whence whence, int64 offset) {
+int64 FileStream::Seek(Whence whence, int64 offset) {
if (!IsOpen())
return ERR_UNEXPECTED;
// If we're in async, make sure we don't have a request in flight.
DCHECK(!async_context_.get() || !async_context_->callback());
- off_t res = lseek(fd_, static_cast<off_t>(offset), static_cast<int>(whence));
+ off_t res = lseek(file_, static_cast<off_t>(offset),
+ static_cast<int>(whence));
if (res == static_cast<off_t>(-1))
return MapErrorCode(errno);
return res;
}
-int64 FileInputStream::Available() {
+int64 FileStream::Available() {
if (!IsOpen())
return ERR_UNEXPECTED;
@@ -110,7 +118,7 @@ int64 FileInputStream::Available() {
return cur_pos;
struct stat info;
- if (fstat(fd_, &info) != 0)
+ if (fstat(file_, &info) != 0)
return MapErrorCode(errno);
int64 size = static_cast<int64>(info.st_size);
@@ -120,7 +128,7 @@ int64 FileInputStream::Available() {
}
// TODO(deanm): async.
-int FileInputStream::Read(
+int FileStream::Read(
char* buf, int buf_len, CompletionCallback* callback) {
// read(..., 0) will return 0, which indicates end-of-file.
DCHECK(buf_len > 0 && buf_len <= SSIZE_MAX);
@@ -130,7 +138,7 @@ int FileInputStream::Read(
// Loop in the case of getting interrupted by a signal.
for (;;) {
- ssize_t res = read(fd_, buf, static_cast<size_t>(buf_len));
+ ssize_t res = read(file_, buf, static_cast<size_t>(buf_len));
if (res == static_cast<ssize_t>(-1)) {
if (errno == EINTR)
continue;
@@ -140,4 +148,30 @@ int FileInputStream::Read(
}
}
+// TODO(deanm): async.
+int FileStream::Write(
+ const char* buf, int buf_len, CompletionCallback* callback) {
+
+ // read(..., 0) will return 0, which indicates end-of-file.
+ DCHECK(buf_len > 0 && buf_len <= SSIZE_MAX);
+
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ int total_bytes_written = 0;
+ size_t len = static_cast<size_t>(buf_len);
+ while (total_bytes_written < buf_len) {
+ ssize_t res = write(file_, buf, len);
+ if (res == static_cast<ssize_t>(-1)) {
+ if (errno == EINTR)
+ continue;
+ return MapErrorCode(errno);
+ }
+ total_bytes_written += res;
+ buf += res;
+ len -= res;
+ }
+ return total_bytes_written;
+}
+
} // namespace net
diff --git a/net/base/file_stream_unittest.cc b/net/base/file_stream_unittest.cc
new file mode 100644
index 0000000..f3f208b
--- /dev/null
+++ b/net/base/file_stream_unittest.cc
@@ -0,0 +1,369 @@
+// 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 "base/file_util.h"
+#include "base/path_service.h"
+#include "base/platform_test.h"
+#include "net/base/file_stream.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+static const char kTestData[] = "0123456789";
+static const int kTestDataSize = arraysize(kTestData) - 1;
+
+class FileStreamTest : public PlatformTest {
+ public:
+ virtual void SetUp() {
+ PlatformTest::SetUp();
+
+ file_util::CreateTemporaryFileName(&temp_file_path_);
+ file_util::WriteFile(temp_file_path_, kTestData, kTestDataSize);
+ }
+ virtual void TearDown() {
+ file_util::Delete(temp_file_path_, false);
+
+ PlatformTest::TearDown();
+ }
+ const std::wstring temp_file_path() const { return temp_file_path_; }
+ private:
+ std::wstring temp_file_path_;
+};
+
+TEST_F(FileStreamTest, BasicOpenClose) {
+ net::FileStream stream;
+ int rv = stream.Open(temp_file_path(),
+ base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
+ EXPECT_EQ(net::OK, rv);
+}
+
+TEST_F(FileStreamTest, UseClosedStream) {
+ net::FileStream stream;
+
+ EXPECT_FALSE(stream.IsOpen());
+
+ // Try seeking...
+ int64 new_offset = stream.Seek(net::FROM_BEGIN, 5);
+ EXPECT_EQ(net::ERR_UNEXPECTED, new_offset);
+
+ // Try available...
+ int64 avail = stream.Available();
+ EXPECT_EQ(net::ERR_UNEXPECTED, avail);
+
+ // Try reading...
+ char buf[10];
+ int rv = stream.Read(buf, sizeof(buf), NULL);
+ EXPECT_EQ(net::ERR_UNEXPECTED, rv);
+}
+
+TEST_F(FileStreamTest, BasicRead) {
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ int64 total_bytes_avail = stream.Available();
+ EXPECT_EQ(file_size, total_bytes_avail);
+
+ int64 total_bytes_read = 0;
+
+ std::string data_read;
+ for (;;) {
+ char buf[4];
+ rv = stream.Read(buf, sizeof(buf), NULL);
+ EXPECT_LE(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_read += rv;
+ data_read.append(buf, rv);
+ }
+ EXPECT_EQ(file_size, total_bytes_read);
+ EXPECT_TRUE(data_read == kTestData);
+}
+
+TEST_F(FileStreamTest, AsyncRead) {
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_ASYNC;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ int64 total_bytes_avail = stream.Available();
+ EXPECT_EQ(file_size, total_bytes_avail);
+
+ TestCompletionCallback callback;
+
+ int64 total_bytes_read = 0;
+
+ std::string data_read;
+ for (;;) {
+ char buf[4];
+ rv = stream.Read(buf, sizeof(buf), &callback);
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_LE(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_read += rv;
+ data_read.append(buf, rv);
+ }
+ EXPECT_EQ(file_size, total_bytes_read);
+ EXPECT_TRUE(data_read == kTestData);
+}
+
+TEST_F(FileStreamTest, BasicRead_FromOffset) {
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ const int64 kOffset = 3;
+ int64 new_offset = stream.Seek(net::FROM_BEGIN, kOffset);
+ EXPECT_EQ(kOffset, new_offset);
+
+ int64 total_bytes_avail = stream.Available();
+ EXPECT_EQ(file_size - kOffset, total_bytes_avail);
+
+ int64 total_bytes_read = 0;
+
+ std::string data_read;
+ for (;;) {
+ char buf[4];
+ rv = stream.Read(buf, sizeof(buf), NULL);
+ EXPECT_LE(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_read += rv;
+ data_read.append(buf, rv);
+ }
+ EXPECT_EQ(file_size - kOffset, total_bytes_read);
+ EXPECT_TRUE(data_read == kTestData + kOffset);
+}
+
+TEST_F(FileStreamTest, AsyncRead_FromOffset) {
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_ASYNC;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ const int64 kOffset = 3;
+ int64 new_offset = stream.Seek(net::FROM_BEGIN, kOffset);
+ EXPECT_EQ(kOffset, new_offset);
+
+ int64 total_bytes_avail = stream.Available();
+ EXPECT_EQ(file_size - kOffset, total_bytes_avail);
+
+ TestCompletionCallback callback;
+
+ int64 total_bytes_read = 0;
+
+ std::string data_read;
+ for (;;) {
+ char buf[4];
+ rv = stream.Read(buf, sizeof(buf), &callback);
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_LE(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_read += rv;
+ data_read.append(buf, rv);
+ }
+ EXPECT_EQ(file_size - kOffset, total_bytes_read);
+ EXPECT_TRUE(data_read == kTestData + kOffset);
+}
+
+TEST_F(FileStreamTest, SeekAround) {
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ const int64 kOffset = 3;
+ int64 new_offset = stream.Seek(net::FROM_BEGIN, kOffset);
+ EXPECT_EQ(kOffset, new_offset);
+
+ new_offset = stream.Seek(net::FROM_CURRENT, kOffset);
+ EXPECT_EQ(2 * kOffset, new_offset);
+
+ new_offset = stream.Seek(net::FROM_CURRENT, -kOffset);
+ EXPECT_EQ(kOffset, new_offset);
+
+ const int kTestDataLen = arraysize(kTestData) - 1;
+
+ new_offset = stream.Seek(net::FROM_END, -kTestDataLen);
+ EXPECT_EQ(0, new_offset);
+}
+
+TEST_F(FileStreamTest, BasicWrite) {
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(0, file_size);
+
+ rv = stream.Write(kTestData, kTestDataSize, NULL);
+ EXPECT_EQ(kTestDataSize, rv);
+ stream.Close();
+
+ ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(kTestDataSize, file_size);
+}
+
+TEST_F(FileStreamTest, AsyncWrite) {
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(0, file_size);
+
+ TestCompletionCallback callback;
+ int64 total_bytes_written = 0;
+
+ while (total_bytes_written != kTestDataSize) {
+ rv = stream.Write(kTestData, kTestDataSize, &callback);
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_LT(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_written += rv;
+ }
+ ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(file_size, total_bytes_written);
+}
+
+TEST_F(FileStreamTest, BasicWrite_FromOffset) {
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_WRITE;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(kTestDataSize, file_size);
+
+ const int64 kOffset = 0;
+ int64 new_offset = stream.Seek(net::FROM_END, kOffset);
+ EXPECT_EQ(kTestDataSize, new_offset);
+
+ rv = stream.Write(kTestData, kTestDataSize, NULL);
+ EXPECT_EQ(kTestDataSize, rv);
+ stream.Close();
+
+ ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(kTestDataSize * 2, file_size);
+}
+
+TEST_F(FileStreamTest, AsyncWrite_FromOffset) {
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_WRITE |
+ base::PLATFORM_FILE_ASYNC;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ const int64 kOffset = 0;
+ int64 new_offset = stream.Seek(net::FROM_END, kOffset);
+ EXPECT_EQ(kTestDataSize, new_offset);
+
+ TestCompletionCallback callback;
+ int64 total_bytes_written = 0;
+
+ while (total_bytes_written != kTestDataSize) {
+ rv = stream.Write(kTestData, kTestDataSize, &callback);
+ if (rv == net::ERR_IO_PENDING)
+ rv = callback.WaitForResult();
+ EXPECT_LT(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_written += rv;
+ }
+ ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(file_size, kTestDataSize * 2);
+}
+
+TEST_F(FileStreamTest, BasicReadWrite) {
+ int64 file_size;
+ bool ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+
+ net::FileStream stream;
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE;
+ int rv = stream.Open(temp_file_path(), flags);
+ EXPECT_EQ(net::OK, rv);
+
+ int64 total_bytes_avail = stream.Available();
+ EXPECT_EQ(file_size, total_bytes_avail);
+
+ int64 total_bytes_read = 0;
+
+ std::string data_read;
+ for (;;) {
+ char buf[4];
+ rv = stream.Read(buf, sizeof(buf), NULL);
+ EXPECT_LE(0, rv);
+ if (rv <= 0)
+ break;
+ total_bytes_read += rv;
+ data_read.append(buf, rv);
+ }
+ EXPECT_EQ(file_size, total_bytes_read);
+ EXPECT_TRUE(data_read == kTestData);
+
+ rv = stream.Write(kTestData, kTestDataSize, NULL);
+ EXPECT_EQ(kTestDataSize, rv);
+ stream.Close();
+
+ ok = file_util::GetFileSize(temp_file_path(), &file_size);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(kTestDataSize * 2, file_size);
+}
+
+// TODO(erikkay): more READ_WRITE tests?
diff --git a/net/base/file_input_stream_win.cc b/net/base/file_stream_win.cc
index f964362..e59ef0d 100644
--- a/net/base/file_input_stream_win.cc
+++ b/net/base/file_stream_win.cc
@@ -2,7 +2,7 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
-#include "net/base/file_input_stream.h"
+#include "net/base/file_stream.h"
#include <windows.h>
@@ -45,11 +45,11 @@ static int MapErrorCode(DWORD err) {
}
}
-// FileInputStream::AsyncContext ----------------------------------------------
+// FileStream::AsyncContext ----------------------------------------------
-class FileInputStream::AsyncContext : public MessageLoopForIO::IOHandler {
+class FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
public:
- AsyncContext(FileInputStream* owner)
+ AsyncContext(FileStream* owner)
: owner_(owner), overlapped_(), callback_(NULL) {
overlapped_.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}
@@ -67,15 +67,15 @@ class FileInputStream::AsyncContext : public MessageLoopForIO::IOHandler {
private:
// MessageLoopForIO::IOHandler implementation:
- virtual void OnIOCompleted(OVERLAPPED* context, DWORD bytes_read,
+ virtual void OnIOCompleted(OVERLAPPED* context, DWORD num_bytes,
DWORD error);
- FileInputStream* owner_;
+ FileStream* owner_;
OVERLAPPED overlapped_;
CompletionCallback* callback_;
};
-void FileInputStream::AsyncContext::IOCompletionIsPending(
+void FileStream::AsyncContext::IOCompletionIsPending(
CompletionCallback* callback) {
DCHECK(!callback_);
callback_ = callback;
@@ -83,82 +83,73 @@ void FileInputStream::AsyncContext::IOCompletionIsPending(
MessageLoopForIO::current()->RegisterIOContext(&overlapped_, this);
}
-void FileInputStream::AsyncContext::OnIOCompleted(OVERLAPPED* context,
- DWORD bytes_read,
+void FileStream::AsyncContext::OnIOCompleted(OVERLAPPED* context,
+ DWORD num_bytes,
DWORD error) {
DCHECK(&overlapped_ == context);
DCHECK(callback_);
MessageLoopForIO::current()->RegisterIOContext(&overlapped_, NULL);
- HANDLE handle = owner_->handle_;
+ HANDLE handle = owner_->file_;
- int result = static_cast<int>(bytes_read);
+ int result = static_cast<int>(num_bytes);
if (error && error != ERROR_HANDLE_EOF)
result = MapErrorCode(error);
- if (bytes_read)
- IncrementOffset(&overlapped_, bytes_read);
+ if (num_bytes)
+ IncrementOffset(&overlapped_, num_bytes);
CompletionCallback* temp = NULL;
std::swap(temp, callback_);
temp->Run(result);
}
-// FileInputStream ------------------------------------------------------------
+// FileStream ------------------------------------------------------------
-FileInputStream::FileInputStream() : handle_(INVALID_HANDLE_VALUE) {
+FileStream::FileStream() : file_(INVALID_HANDLE_VALUE) {
}
-FileInputStream::~FileInputStream() {
+FileStream::~FileStream() {
Close();
}
-void FileInputStream::Close() {
- if (handle_ != INVALID_HANDLE_VALUE) {
- CloseHandle(handle_);
- handle_ = INVALID_HANDLE_VALUE;
+void FileStream::Close() {
+ if (file_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(file_);
+ file_ = INVALID_HANDLE_VALUE;
}
async_context_.reset();
}
-int FileInputStream::Open(const std::wstring& path, bool asynchronous_mode) {
+int FileStream::Open(const std::wstring& path, int open_flags) {
if (IsOpen()) {
DLOG(FATAL) << "File is already open!";
return ERR_UNEXPECTED;
}
- // Optimize for streaming, not seeking. If someone does a lot of random
- // access operations, then we should consider revising this.
- DWORD create_file_flags = FILE_FLAG_SEQUENTIAL_SCAN;
-
- if (asynchronous_mode)
- create_file_flags |= FILE_FLAG_OVERLAPPED;
-
- handle_ =
- CreateFile(path.c_str(), GENERIC_READ | SYNCHRONIZE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, create_file_flags, NULL);
- if (handle_ == INVALID_HANDLE_VALUE) {
+ 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 (asynchronous_mode) {
+ if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
async_context_.reset(new AsyncContext(this));
- MessageLoopForIO::current()->RegisterIOHandler(handle_,
+ MessageLoopForIO::current()->RegisterIOHandler(file_,
async_context_.get());
}
return OK;
}
-bool FileInputStream::IsOpen() const {
- return handle_ != INVALID_HANDLE_VALUE;
+bool FileStream::IsOpen() const {
+ return file_ != INVALID_HANDLE_VALUE;
}
-int64 FileInputStream::Seek(Whence whence, int64 offset) {
+int64 FileStream::Seek(Whence whence, int64 offset) {
if (!IsOpen())
return ERR_UNEXPECTED;
DCHECK(!async_context_.get() || !async_context_->callback());
@@ -166,7 +157,7 @@ int64 FileInputStream::Seek(Whence whence, int64 offset) {
LARGE_INTEGER distance, result;
distance.QuadPart = offset;
DWORD move_method = static_cast<DWORD>(whence);
- if (!SetFilePointerEx(handle_, distance, &result, move_method)) {
+ if (!SetFilePointerEx(file_, distance, &result, move_method)) {
DWORD error = GetLastError();
LOG(WARNING) << "SetFilePointerEx failed: " << error;
return MapErrorCode(error);
@@ -176,7 +167,7 @@ int64 FileInputStream::Seek(Whence whence, int64 offset) {
return result.QuadPart;
}
-int64 FileInputStream::Available() {
+int64 FileStream::Available() {
if (!IsOpen())
return ERR_UNEXPECTED;
@@ -185,7 +176,7 @@ int64 FileInputStream::Available() {
return cur_pos;
LARGE_INTEGER file_size;
- if (!GetFileSizeEx(handle_, &file_size)) {
+ if (!GetFileSizeEx(file_, &file_size)) {
DWORD error = GetLastError();
LOG(WARNING) << "GetFileSizeEx failed: " << error;
return MapErrorCode(error);
@@ -194,10 +185,11 @@ int64 FileInputStream::Available() {
return file_size.QuadPart - cur_pos;
}
-int FileInputStream::Read(
+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()) {
@@ -208,7 +200,7 @@ int FileInputStream::Read(
int rv;
DWORD bytes_read;
- if (!ReadFile(handle_, buf, buf_len, &bytes_read, overlapped)) {
+ if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
DWORD error = GetLastError();
if (async_context_.get() && error == ERROR_IO_PENDING) {
async_context_->IOCompletionIsPending(callback);
@@ -227,4 +219,36 @@ int FileInputStream::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
+
diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc
index df5ef0f..e874439 100644
--- a/net/base/upload_data_stream.cc
+++ b/net/base/upload_data_stream.cc
@@ -68,7 +68,9 @@ void UploadDataStream::FillBuf() {
DCHECK(element.type() == UploadData::TYPE_FILE);
if (!next_element_stream_.IsOpen()) {
- int rv = next_element_stream_.Open(element.file_path(), false);
+ int flags = base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ;
+ int rv = next_element_stream_.Open(element.file_path(), flags);
// If the file does not exist, that's technically okay.. we'll just
// upload an empty file. This is for consistency with Mozilla.
DLOG_IF(WARNING, rv != OK) << "Failed to open \"" <<
diff --git a/net/base/upload_data_stream.h b/net/base/upload_data_stream.h
index 9d22d2e..7c2bb6d 100644
--- a/net/base/upload_data_stream.h
+++ b/net/base/upload_data_stream.h
@@ -5,7 +5,7 @@
#ifndef NET_BASE_UPLOAD_DATA_STREAM_H_
#define NET_BASE_UPLOAD_DATA_STREAM_H_
-#include "net/base/file_input_stream.h"
+#include "net/base/file_stream.h"
#include "net/base/upload_data.h"
namespace net {
@@ -53,7 +53,7 @@ class UploadDataStream {
// A stream to the currently open file, for next_element_ if the next element
// is a TYPE_FILE element.
- FileInputStream next_element_stream_;
+ FileStream next_element_stream_;
// The number of bytes remaining to be read from the currently open file
// if the next element is of TYPE_FILE.