Apache Mesos
read.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_OS_READ_HPP__
14 #define __STOUT_OS_READ_HPP__
15 
16 #include <assert.h>
17 #include <stdio.h>
18 #ifndef __WINDOWS__
19 #include <unistd.h>
20 #endif // __WINDOWS__
21 
22 #include <string>
23 
24 #if defined(__sun) || defined(__WINDOWS__)
25 #include <fstream>
26 #endif // __sun || __WINDOWS__
27 
28 #include <stout/error.hpp>
29 #include <stout/result.hpp>
30 #include <stout/try.hpp>
31 #ifdef __WINDOWS__
32 #include <stout/stringify.hpp>
33 #include <stout/windows.hpp>
34 #endif // __WINDOWS__
35 
36 #include <stout/os/int_fd.hpp>
37 #include <stout/os/socket.hpp>
38 
39 #ifdef __WINDOWS__
41 #endif // __WINDOWS__
42 
43 #ifdef __WINDOWS__
45 #else
46 #include <stout/os/posix/read.hpp>
47 #endif // __WINDOWS__
48 
49 
50 namespace os {
51 
52 // Reads 'size' bytes from a file from its current offset.
53 // If EOF is encountered before reading 'size' bytes then the result
54 // will contain the bytes read and a subsequent read will return None.
55 inline Result<std::string> read(int_fd fd, size_t size)
56 {
57  char* buffer = new char[size];
58  size_t offset = 0;
59 
60  while (offset < size) {
61  ssize_t length = os::read(fd, buffer + offset, size - offset);
62 
63 #ifdef __WINDOWS__
64  // NOTE: There is no actual difference between `WSAGetLastError` and
65  // `GetLastError`, the former is an alias for the latter. As such, there is
66  // no difference between `WindowsError` and `WindowsSocketError`, so we can
67  // simply use the former here for both `HANDLE` and `SOCKET` types of
68  // `int_fd`. See MESOS-8764.
70 #else
72 #endif // __WINDOWS__
73 
74  if (length < 0) {
75  // TODO(bmahler): Handle a non-blocking fd? (EAGAIN, EWOULDBLOCK)
76  if (net::is_restartable_error(error.code)) {
77  continue;
78  }
79  delete[] buffer;
80  return error;
81  } else if (length == 0) {
82  // Reached EOF before expected! Only return as much data as
83  // available or None if we haven't read anything yet.
84  if (offset > 0) {
85  std::string result(buffer, offset);
86  delete[] buffer;
87  return result;
88  }
89  delete[] buffer;
90  return None();
91  }
92 
93  offset += length;
94  }
95 
96  std::string result(buffer, size);
97  delete[] buffer;
98  return result;
99 }
100 
101 
102 // Returns the contents of the file.
103 // NOTE: getline is not available on Solaris so we use STL.
104 #if defined(__sun)
105 inline Try<std::string> read(const std::string& path)
106 {
107  std::ifstream file(path.c_str());
108  if (!file.is_open()) {
109  // Does ifstream actually set errno?
110  return ErrnoError("Failed to open file");
111  }
112  return std::string((std::istreambuf_iterator<char>(file)),
113  (std::istreambuf_iterator<char>()));
114 }
115 // NOTE: Windows needs Unicode long path support.
116 #elif defined(__WINDOWS__)
117 inline Try<std::string> read(const std::string& path)
118 {
119  const std::wstring longpath = ::internal::windows::longpath(path);
120  // NOTE: The `wchar_t` constructor of `ifstream` is an MSVC
121  // extension.
122  //
123  // TODO(andschwa): This might need `io_base::binary` like other
124  // streams on Windows.
125  std::ifstream file(longpath.data());
126  if (!file.is_open()) {
127  return Error("Failed to open file");
128  }
129 
130  return std::string((std::istreambuf_iterator<char>(file)),
131  (std::istreambuf_iterator<char>()));
132 }
133 #else
134 inline Try<std::string> read(const std::string& path)
135 {
136  FILE* file = ::fopen(path.c_str(), "r");
137  if (file == nullptr) {
138  return ErrnoError();
139  }
140 
141  // Use a buffer to read the file in BUFSIZ
142  // chunks and append it to the string we return.
143  //
144  // NOTE: We aren't able to use fseek() / ftell() here
145  // to find the file size because these functions don't
146  // work properly for in-memory files like /proc/*/stat.
147  char* buffer = new char[BUFSIZ];
148  std::string result;
149 
150  while (true) {
151  size_t read = ::fread(buffer, 1, BUFSIZ, file);
152 
153  if (::ferror(file)) {
154  // NOTE: ferror() will not modify errno if the stream
155  // is valid, which is the case here since it is open.
157  delete[] buffer;
158  ::fclose(file);
159  return error;
160  }
161 
162  result.append(buffer, read);
163 
164  if (read != BUFSIZ) {
165  assert(feof(file));
166  break;
167  }
168  };
169 
170  ::fclose(file);
171  delete[] buffer;
172  return result;
173 }
174 #endif // __sun || __WINDOWS__
175 
176 } // namespace os {
177 
178 #endif // __STOUT_OS_READ_HPP__
SSIZE_T ssize_t
Definition: windows.hpp:186
Definition: path.hpp:29
Definition: errorbase.hpp:36
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:130
Definition: check.hpp:33
Definition: error.hpp:108
Definition: errorbase.hpp:50
Definition: posix_signalhandler.hpp:23
Definition: check.hpp:30
bool is_restartable_error(int error)
Definition: socket.hpp:65
URI file(const std::string &path)
Creates a file URI with the given path on the local host.
Definition: file.hpp:33
Result< std::string > read(int_fd fd, size_t size)
Definition: read.hpp:55
Definition: none.hpp:27
std::string error(const std::string &msg, uint32_t code)
const int code
Definition: errorbase.hpp:63
std::wstring longpath(const std::string &path)
Definition: longpath.hpp:38
int int_fd
Definition: int_fd.hpp:35