1 // Copyright 2015 The Chromium OS 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 #include "bsdiff/file.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #ifdef __linux__ 10 #include <linux/fs.h> 11 #endif // __linux__ 12 #include <string.h> 13 #include <sys/ioctl.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 #include <unistd.h> 17 18 // TEMP_FAILURE_RETRY is defined by some versions of <unistd.h>. 19 #ifndef TEMP_FAILURE_RETRY 20 #include <utils/Compat.h> 21 #endif 22 23 #include <algorithm> 24 25 namespace bsdiff { 26 27 std::unique_ptr<File> File::FOpen(const char* pathname, int flags) { 28 int fd = TEMP_FAILURE_RETRY(open(pathname, flags, 0644)); 29 if (fd < 0) 30 return std::unique_ptr<File>(); 31 return std::unique_ptr<File>(new File(fd)); 32 } 33 34 File::~File() { 35 Close(); 36 } 37 38 bool File::Read(void* buf, size_t count, size_t* bytes_read) { 39 if (fd_ < 0) { 40 errno = EBADF; 41 return false; 42 } 43 ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, buf, count)); 44 if (rc == -1) 45 return false; 46 *bytes_read = static_cast<size_t>(rc); 47 return true; 48 } 49 50 bool File::Write(const void* buf, size_t count, size_t* bytes_written) { 51 if (fd_ < 0) { 52 errno = EBADF; 53 return false; 54 } 55 ssize_t rc = TEMP_FAILURE_RETRY(write(fd_, buf, count)); 56 if (rc == -1) 57 return false; 58 *bytes_written = static_cast<size_t>(rc); 59 return true; 60 } 61 62 bool File::Seek(off_t pos) { 63 if (fd_ < 0) { 64 errno = EBADF; 65 return false; 66 } 67 68 off_t newpos = lseek(fd_, pos, SEEK_SET); 69 if (newpos < 0) 70 return false; 71 if (newpos != pos) { 72 errno = EINVAL; 73 return false; 74 } 75 return true; 76 } 77 78 bool File::Close() { 79 if (fd_ < 0) { 80 errno = EBADF; 81 return false; 82 } 83 bool success = close(fd_) == 0; 84 if (!success && errno == EINTR) 85 success = true; 86 fd_ = -1; 87 return success; 88 } 89 90 bool File::GetSize(uint64_t* size) { 91 struct stat stbuf; 92 if (fstat(fd_, &stbuf) == -1) 93 return false; 94 if (S_ISREG(stbuf.st_mode)) { 95 *size = stbuf.st_size; 96 return true; 97 } 98 if (S_ISBLK(stbuf.st_mode)) { 99 #if defined(BLKGETSIZE64) 100 return ioctl(fd_, BLKGETSIZE64, size); 101 #elif defined(DKIOCGETBLOCKCOUNT) 102 uint64_t sectors = 0; 103 if (ioctl(fd_, DKIOCGETBLOCKCOUNT, §ors) == 0) { 104 *size = sectors << 9; 105 return true; 106 } 107 return false; 108 #else 109 // Fall back to doing seeks to know the EOF. 110 off_t pos = lseek(fd_, 0, SEEK_CUR); 111 if (pos == -1) 112 return false; 113 off_t end_pos = lseek(fd_, 0, SEEK_END); 114 if (end_pos == -1) 115 return false; 116 *size = end_pos; 117 lseek(fd_, 0, SEEK_END); 118 return true; 119 #endif 120 } 121 return false; 122 } 123 124 File::File(int fd) 125 : fd_(fd) {} 126 127 } // namespace bsdiff 128