• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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   // 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);
73   if (newpos < 0)
74     return false;
75   if (newpos != pos) {
76     errno = EINVAL;
77     return false;
78   }
79   return true;
80 }
81 
Close()82 bool 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 
GetSize(uint64_t * size)94 bool 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     *size = stbuf.st_size;
100     return true;
101   }
102   if (S_ISBLK(stbuf.st_mode)) {
103 #if defined(BLKGETSIZE64)
104     return ioctl(fd_, BLKGETSIZE64, size);
105 #elif defined(DKIOCGETBLOCKCOUNT)
106     uint64_t sectors = 0;
107     if (ioctl(fd_, DKIOCGETBLOCKCOUNT, &sectors) == 0) {
108       *size = sectors << 9;
109       return true;
110     }
111     return false;
112 #else
113     // Fall back to doing seeks to know the EOF.
114     off_t pos = lseek(fd_, 0, SEEK_CUR);
115     if (pos == -1)
116       return false;
117     off_t end_pos = lseek(fd_, 0, SEEK_END);
118     if (end_pos == -1)
119       return false;
120     *size = end_pos;
121     lseek(fd_, 0, SEEK_END);
122     return true;
123 #endif
124   }
125   return false;
126 }
127 
File(int fd)128 File::File(int fd)
129     : fd_(fd) {}
130 
131 }  // namespace bsdiff
132