1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the 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_stream_context.h" 9 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <sys/stat.h> 13 #include <sys/types.h> 14 #include <unistd.h> 15 16 #include "base/basictypes.h" 17 #include "base/bind.h" 18 #include "base/bind_helpers.h" 19 #include "base/callback.h" 20 #include "base/files/file_path.h" 21 #include "base/location.h" 22 #include "base/logging.h" 23 #include "base/metrics/histogram.h" 24 #include "base/posix/eintr_wrapper.h" 25 #include "base/task_runner_util.h" 26 #include "net/base/io_buffer.h" 27 #include "net/base/net_errors.h" 28 29 #if defined(OS_ANDROID) 30 // Android's bionic libc only supports the LFS transitional API. 31 #define off_t off64_t 32 #define lseek lseek64 33 #define stat stat64 34 #define fstat fstat64 35 #endif 36 37 namespace net { 38 39 // We cast back and forth, so make sure it's the size we're expecting. 40 COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit); 41 42 // Make sure our Whence mappings match the system headers. 43 COMPILE_ASSERT(FROM_BEGIN == SEEK_SET && 44 FROM_CURRENT == SEEK_CUR && 45 FROM_END == SEEK_END, whence_matches_system); 46 47 FileStream::Context::Context(const BoundNetLog& bound_net_log, 48 const scoped_refptr<base::TaskRunner>& task_runner) 49 : file_(base::kInvalidPlatformFileValue), 50 record_uma_(false), 51 async_in_progress_(false), 52 orphaned_(false), 53 bound_net_log_(bound_net_log), 54 task_runner_(task_runner) { 55 } 56 57 FileStream::Context::Context(base::PlatformFile file, 58 const BoundNetLog& bound_net_log, 59 int /* open_flags */, 60 const scoped_refptr<base::TaskRunner>& task_runner) 61 : file_(file), 62 record_uma_(false), 63 async_in_progress_(false), 64 orphaned_(false), 65 bound_net_log_(bound_net_log), 66 task_runner_(task_runner) { 67 } 68 69 FileStream::Context::~Context() { 70 } 71 72 int64 FileStream::Context::GetFileSize() const { 73 struct stat info; 74 if (fstat(file_, &info) != 0) { 75 IOResult result = IOResult::FromOSError(errno); 76 RecordError(result, FILE_ERROR_SOURCE_GET_SIZE); 77 return result.result; 78 } 79 80 return static_cast<int64>(info.st_size); 81 } 82 83 int FileStream::Context::ReadAsync(IOBuffer* in_buf, 84 int buf_len, 85 const CompletionCallback& callback) { 86 DCHECK(!async_in_progress_); 87 88 scoped_refptr<IOBuffer> buf = in_buf; 89 const bool posted = base::PostTaskAndReplyWithResult( 90 task_runner_.get(), 91 FROM_HERE, 92 base::Bind(&Context::ReadFileImpl, base::Unretained(this), buf, buf_len), 93 base::Bind(&Context::ProcessAsyncResult, 94 base::Unretained(this), 95 IntToInt64(callback), 96 FILE_ERROR_SOURCE_READ)); 97 DCHECK(posted); 98 99 async_in_progress_ = true; 100 return ERR_IO_PENDING; 101 } 102 103 int FileStream::Context::ReadSync(char* in_buf, int buf_len) { 104 scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(in_buf); 105 IOResult result = ReadFileImpl(buf, buf_len); 106 RecordError(result, FILE_ERROR_SOURCE_READ); 107 return result.result; 108 } 109 110 int FileStream::Context::WriteAsync(IOBuffer* in_buf, 111 int buf_len, 112 const CompletionCallback& callback) { 113 DCHECK(!async_in_progress_); 114 115 scoped_refptr<IOBuffer> buf = in_buf; 116 const bool posted = base::PostTaskAndReplyWithResult( 117 task_runner_.get(), 118 FROM_HERE, 119 base::Bind(&Context::WriteFileImpl, base::Unretained(this), buf, buf_len), 120 base::Bind(&Context::ProcessAsyncResult, 121 base::Unretained(this), 122 IntToInt64(callback), 123 FILE_ERROR_SOURCE_WRITE)); 124 DCHECK(posted); 125 126 async_in_progress_ = true; 127 return ERR_IO_PENDING; 128 } 129 130 int FileStream::Context::WriteSync(const char* in_buf, int buf_len) { 131 scoped_refptr<IOBuffer> buf = new WrappedIOBuffer(in_buf); 132 IOResult result = WriteFileImpl(buf, buf_len); 133 RecordError(result, FILE_ERROR_SOURCE_WRITE); 134 return result.result; 135 } 136 137 int FileStream::Context::Truncate(int64 bytes) { 138 if (ftruncate(file_, bytes) != 0) { 139 IOResult result = IOResult::FromOSError(errno); 140 RecordError(result, FILE_ERROR_SOURCE_SET_EOF); 141 return result.result; 142 } 143 144 return bytes; 145 } 146 147 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(Whence whence, 148 int64 offset) { 149 off_t res = lseek(file_, static_cast<off_t>(offset), 150 static_cast<int>(whence)); 151 if (res == static_cast<off_t>(-1)) 152 return IOResult::FromOSError(errno); 153 154 return IOResult(res, 0); 155 } 156 157 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() { 158 ssize_t res = HANDLE_EINTR(fsync(file_)); 159 if (res == -1) 160 return IOResult::FromOSError(errno); 161 162 return IOResult(res, 0); 163 } 164 165 FileStream::Context::IOResult FileStream::Context::ReadFileImpl( 166 scoped_refptr<IOBuffer> buf, 167 int buf_len) { 168 // Loop in the case of getting interrupted by a signal. 169 ssize_t res = HANDLE_EINTR(read(file_, buf->data(), 170 static_cast<size_t>(buf_len))); 171 if (res == -1) 172 return IOResult::FromOSError(errno); 173 174 return IOResult(res, 0); 175 } 176 177 FileStream::Context::IOResult FileStream::Context::WriteFileImpl( 178 scoped_refptr<IOBuffer> buf, 179 int buf_len) { 180 ssize_t res = HANDLE_EINTR(write(file_, buf->data(), buf_len)); 181 if (res == -1) 182 return IOResult::FromOSError(errno); 183 184 return IOResult(res, 0); 185 } 186 187 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() { 188 bool success = base::ClosePlatformFile(file_); 189 file_ = base::kInvalidPlatformFileValue; 190 if (!success) 191 return IOResult::FromOSError(errno); 192 193 return IOResult(OK, 0); 194 } 195 196 } // namespace net 197