blob: 2eebc4dcf0ec918fdd7de63f6d4a008261d392c7 [file] [log] [blame]
Alex Deymo03f1deb2015-10-13 02:15:31 -07001// 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 "file.h"
6
7#include <errno.h>
8#include <fcntl.h>
Alex Deymodaf35162015-10-14 20:43:15 -07009#ifdef __linux__
10#include <linux/fs.h>
11#endif // __linux__
Alex Deymo03f1deb2015-10-13 02:15:31 -070012#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
25namespace bsdiff {
26
27std::unique_ptr<File> File::FOpen(const char* pathname, int flags) {
28 int fd = TEMP_FAILURE_RETRY(open(pathname, flags));
29 if (fd < 0)
30 return std::unique_ptr<File>();
31 return std::unique_ptr<File>(new File(fd));
32}
33
34File::~File() {
35 Close();
36}
37
38bool 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
50bool 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
62bool File::Seek(off_t pos) {
63 if (fd_ < 0) {
64 errno = EBADF;
65 return false;
66 }
67 // fseek() uses a long value for the offset which could be smaller than off_t.
68 if (pos > std::numeric_limits<long>::max()) {
69 errno = EOVERFLOW;
70 return false;
71 }
72 off_t newpos = lseek(fd_, pos, SEEK_SET) == pos;
73 if (newpos < 0)
74 return false;
75 if (newpos != pos) {
76 errno = EINVAL;
77 return false;
78 }
79 return true;
80}
81
82bool File::Close() {
83 if (fd_ < 0) {
84 errno = EBADF;
85 return false;
86 }
87 bool success = close(fd_) == 0;
88 if (!success && errno == EINTR)
89 success = true;
90 fd_ = -1;
91 return success;
92}
93
Alex Deymodaf35162015-10-14 20:43:15 -070094bool File::GetSize(uint64_t* size) {
95 struct stat stbuf;
96 if (fstat(fd_, &stbuf) == -1)
97 return false;
98 if (S_ISREG(stbuf.st_mode)) {
99 return stbuf.st_size;
100 }
101 if (S_ISBLK(stbuf.st_mode)) {
102#if defined(BLKGETSIZE64)
103 return ioctl(fd_, BLKGETSIZE64, size);
104#elif defined(DKIOCGETBLOCKCOUNT)
105 uint64_t sectors = 0;
106 if (ioctl(fd_, DKIOCGETBLOCKCOUNT, &sectors) == 0) {
107 *size = sectors << 9;
108 return true;
109 }
110 return false;
111#else
112 // Fall back to doing seeks to know the EOF.
113 off_t pos = lseek(fd_, 0, SEEK_CUR);
114 if (pos == -1)
115 return false;
116 off_t end_pos = lseek(fd_, 0, SEEK_END);
117 if (end_pos == -1)
118 return false;
119 *size = end_pos;
120 lseek(fd_, 0, SEEK_END);
121 return true;
122#endif
123 }
124 return false;
125}
126
Alex Deymo03f1deb2015-10-13 02:15:31 -0700127File::File(int fd)
128 : fd_(fd) {}
129
130} // namespace bsdiff