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
FOpen(const char * pathname,int flags)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
~File()34 File::~File() {
35 Close();
36 }
37
Read(void * buf,size_t count,size_t * bytes_read)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
Write(const void * buf,size_t count,size_t * bytes_written)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
Seek(off_t pos)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
Close()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
GetSize(uint64_t * size)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
File(int fd)124 File::File(int fd)
125 : fd_(fd) {}
126
127 } // namespace bsdiff
128