summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/SConscript2
-rw-r--r--net/base/file_input_stream.h14
-rw-r--r--net/base/file_input_stream_posix.cc110
3 files changed, 107 insertions, 19 deletions
diff --git a/net/SConscript b/net/SConscript
index 28f730b..ed8faa8 100644
--- a/net/SConscript
+++ b/net/SConscript
@@ -230,6 +230,7 @@ unittest_files = [
'base/cookie_policy_unittest.cc',
'base/data_url_unittest.cc',
'base/escape_unittest.cc',
+ 'base/file_input_stream_unittest.cc',
'base/gzip_filter_unittest.cc',
'base/host_resolver_unittest.cc',
'base/mime_sniffer_unittest.cc',
@@ -258,7 +259,6 @@ unittest_files = [
if env['PLATFORM'] == 'win32':
unittest_files.extend([
'base/directory_lister_unittest.cc',
- 'base/file_input_stream_unittest.cc',
'base/sdch_filter_unitest.cc',
'base/ssl_config_service_unittest.cc',
'base/ssl_client_socket_unittest.cc',
diff --git a/net/base/file_input_stream.h b/net/base/file_input_stream.h
index efebadc..eb4b2ae 100644
--- a/net/base/file_input_stream.h
+++ b/net/base/file_input_stream.h
@@ -17,10 +17,11 @@ typedef void* HANDLE;
namespace net {
// TODO(darin): Move this to a more generic location.
+// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
enum Whence {
- FROM_BEGIN,
- FROM_CURRENT,
- FROM_END
+ FROM_BEGIN = 0,
+ FROM_CURRENT = 1,
+ FROM_END = 2
};
class FileInputStream {
@@ -35,10 +36,7 @@ class FileInputStream {
// Call this method to open the FileInputStream. 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 file input stream is opened with non-exclusive access to the
- // underlying file.
- //
+ // NOTE: The underlying file is opened with non-exclusive access.
int Open(const std::wstring& path, bool asynchronous_mode);
// Returns true if Open succeeded and Close has not been called.
@@ -82,6 +80,8 @@ class FileInputStream {
#if defined(OS_WIN)
HANDLE handle_;
+#elif defined(OS_POSIX)
+ int fd_;
#endif
DISALLOW_COPY_AND_ASSIGN(FileInputStream);
diff --git a/net/base/file_input_stream_posix.cc b/net/base/file_input_stream_posix.cc
index 335805c..4f2eb937 100644
--- a/net/base/file_input_stream_posix.cc
+++ b/net/base/file_input_stream_posix.cc
@@ -2,21 +2,49 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
+// For 64-bit file access (off_t = off64_t, lseek64, etc).
+#define _FILE_OFFSET_BITS 64
+
#include "net/base/file_input_stream.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
#include "net/base/net_errors.h"
+// We cast back and forth, so make sure it's the size we're expecting.
+COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
+
+// Make sure our Whence mappings match the system headers.
+COMPILE_ASSERT(net::FROM_BEGIN == SEEK_SET &&
+ net::FROM_CURRENT == SEEK_CUR &&
+ net::FROM_END == SEEK_END, whence_matches_system);
+
namespace net {
// FileInputStream::AsyncContext ----------------------------------------------
+// TODO(deanm): Figure out how to best do async IO.
class FileInputStream::AsyncContext {
+ public:
+
+ CompletionCallback* callback() const { return NULL; }
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};
// FileInputStream ------------------------------------------------------------
-FileInputStream::FileInputStream() {
+FileInputStream::FileInputStream() : fd_(-1) {
+ DCHECK(!IsOpen());
}
FileInputStream::~FileInputStream() {
@@ -24,32 +52,92 @@ FileInputStream::~FileInputStream() {
}
void FileInputStream::Close() {
+ if (fd_ != -1) {
+ if (close(fd_) != 0) {
+ NOTREACHED();
+ }
+ fd_ = -1;
+ }
+ async_context_.reset();
+}
+
+// Map from errno to net error codes.
+static int64 MapErrorCode(int err) {
+ switch(err) {
+ case ENOENT:
+ return ERR_FILE_NOT_FOUND;
+ case EACCES:
+ return ERR_ACCESS_DENIED;
+ default:
+ LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
+ return ERR_FAILED;
+ }
}
int FileInputStream::Open(const std::wstring& path, bool asynchronous_mode) {
- NOTIMPLEMENTED();
- return ERR_FAILED;
+ // 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)
+ return MapErrorCode(errno);
+
+ return OK;
}
bool FileInputStream::IsOpen() const {
- NOTIMPLEMENTED();
- return false;
+ return fd_ != -1;
}
int64 FileInputStream::Seek(Whence whence, int64 offset) {
- NOTIMPLEMENTED();
- return ERR_FAILED;
+ 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));
+ if (res == static_cast<off_t>(-1))
+ return MapErrorCode(errno);
+
+ return res;
}
int64 FileInputStream::Available() {
- NOTIMPLEMENTED();
- return ERR_FAILED;
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ int64 cur_pos = Seek(FROM_CURRENT, 0);
+ if (cur_pos < 0)
+ return cur_pos;
+
+ struct stat info;
+ if (fstat(fd_, &info) != 0)
+ return MapErrorCode(errno);
+
+ int64 size = static_cast<int64>(info.st_size);
+ DCHECK(size >= cur_pos);
+
+ return size - cur_pos;
}
+// TODO(deanm): async.
int FileInputStream::Read(
char* buf, int buf_len, CompletionCallback* callback) {
- NOTIMPLEMENTED();
- return ERR_FAILED;
+ // read(..., 0) will return 0, which indicates end-of-file.
+ DCHECK(buf_len > 0 && buf_len <= SSIZE_MAX);
+
+ if (!IsOpen())
+ return ERR_UNEXPECTED;
+
+ // Loop in the case of getting interrupted by a signal.
+ for (;;) {
+ ssize_t res = read(fd_, buf, static_cast<size_t>(buf_len));
+ if (res == static_cast<ssize_t>(-1)) {
+ if (errno == EINTR)
+ continue;
+ return MapErrorCode(errno);
+ }
+ return static_cast<int>(res);
+ }
}
} // namespace net