OLD | NEW |
| (Empty) |
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this | |
2 // source code is governed by a BSD-style license that can be found in the | |
3 // LICENSE file. | |
4 | |
5 // For 64-bit file access (off_t = off64_t, lseek64, etc). | |
6 #define _FILE_OFFSET_BITS 64 | |
7 | |
8 #include "net/base/file_input_stream.h" | |
9 | |
10 #include <sys/types.h> | |
11 #include <sys/stat.h> | |
12 #include <fcntl.h> | |
13 #include <unistd.h> | |
14 #include <errno.h> | |
15 | |
16 #include "base/basictypes.h" | |
17 #include "base/logging.h" | |
18 #include "base/message_loop.h" | |
19 #include "base/string_util.h" | |
20 #include "net/base/net_errors.h" | |
21 | |
22 // We cast back and forth, so make sure it's the size we're expecting. | |
23 COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit); | |
24 | |
25 // Make sure our Whence mappings match the system headers. | |
26 COMPILE_ASSERT(net::FROM_BEGIN == SEEK_SET && | |
27 net::FROM_CURRENT == SEEK_CUR && | |
28 net::FROM_END == SEEK_END, whence_matches_system); | |
29 | |
30 namespace net { | |
31 | |
32 // FileInputStream::AsyncContext ---------------------------------------------- | |
33 | |
34 // TODO(deanm): Figure out how to best do async IO. | |
35 class FileInputStream::AsyncContext { | |
36 public: | |
37 | |
38 CompletionCallback* callback() const { return NULL; } | |
39 private: | |
40 | |
41 DISALLOW_COPY_AND_ASSIGN(AsyncContext); | |
42 }; | |
43 | |
44 // FileInputStream ------------------------------------------------------------ | |
45 | |
46 FileInputStream::FileInputStream() : fd_(-1) { | |
47 DCHECK(!IsOpen()); | |
48 } | |
49 | |
50 FileInputStream::~FileInputStream() { | |
51 Close(); | |
52 } | |
53 | |
54 void FileInputStream::Close() { | |
55 if (fd_ != -1) { | |
56 if (close(fd_) != 0) { | |
57 NOTREACHED(); | |
58 } | |
59 fd_ = -1; | |
60 } | |
61 async_context_.reset(); | |
62 } | |
63 | |
64 // Map from errno to net error codes. | |
65 static int64 MapErrorCode(int err) { | |
66 switch(err) { | |
67 case ENOENT: | |
68 return ERR_FILE_NOT_FOUND; | |
69 case EACCES: | |
70 return ERR_ACCESS_DENIED; | |
71 default: | |
72 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | |
73 return ERR_FAILED; | |
74 } | |
75 } | |
76 | |
77 int FileInputStream::Open(const std::wstring& path, bool asynchronous_mode) { | |
78 // We don't need O_LARGEFILE here since we set the 64-bit off_t feature. | |
79 fd_ = open(WideToUTF8(path).c_str(), 0, O_RDONLY); | |
80 if (fd_ == -1) | |
81 return MapErrorCode(errno); | |
82 | |
83 return OK; | |
84 } | |
85 | |
86 bool FileInputStream::IsOpen() const { | |
87 return fd_ != -1; | |
88 } | |
89 | |
90 int64 FileInputStream::Seek(Whence whence, int64 offset) { | |
91 if (!IsOpen()) | |
92 return ERR_UNEXPECTED; | |
93 | |
94 // If we're in async, make sure we don't have a request in flight. | |
95 DCHECK(!async_context_.get() || !async_context_->callback()); | |
96 | |
97 off_t res = lseek(fd_, static_cast<off_t>(offset), static_cast<int>(whence)); | |
98 if (res == static_cast<off_t>(-1)) | |
99 return MapErrorCode(errno); | |
100 | |
101 return res; | |
102 } | |
103 | |
104 int64 FileInputStream::Available() { | |
105 if (!IsOpen()) | |
106 return ERR_UNEXPECTED; | |
107 | |
108 int64 cur_pos = Seek(FROM_CURRENT, 0); | |
109 if (cur_pos < 0) | |
110 return cur_pos; | |
111 | |
112 struct stat info; | |
113 if (fstat(fd_, &info) != 0) | |
114 return MapErrorCode(errno); | |
115 | |
116 int64 size = static_cast<int64>(info.st_size); | |
117 DCHECK(size >= cur_pos); | |
118 | |
119 return size - cur_pos; | |
120 } | |
121 | |
122 // TODO(deanm): async. | |
123 int FileInputStream::Read( | |
124 char* buf, int buf_len, CompletionCallback* callback) { | |
125 // read(..., 0) will return 0, which indicates end-of-file. | |
126 DCHECK(buf_len > 0 && buf_len <= SSIZE_MAX); | |
127 | |
128 if (!IsOpen()) | |
129 return ERR_UNEXPECTED; | |
130 | |
131 // Loop in the case of getting interrupted by a signal. | |
132 for (;;) { | |
133 ssize_t res = read(fd_, buf, static_cast<size_t>(buf_len)); | |
134 if (res == static_cast<ssize_t>(-1)) { | |
135 if (errno == EINTR) | |
136 continue; | |
137 return MapErrorCode(errno); | |
138 } | |
139 return static_cast<int>(res); | |
140 } | |
141 } | |
142 | |
143 } // namespace net | |
OLD | NEW |