Flow123d  release_3.0.0-880-gc768b7a
posix.cc
Go to the documentation of this file.
1 /*
2  A C++ interface to POSIX functions.
3 
4  Copyright (c) 2014 - 2016, Victor Zverovich
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice, this
11  list of conditions and the following disclaimer.
12  2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 // Disable bogus MSVC warnings.
29 #ifndef _CRT_SECURE_NO_WARNINGS
30 # define _CRT_SECURE_NO_WARNINGS
31 #endif
32 
33 #include "system/fmt/posix.h"
34 
35 #include <limits.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 
39 #ifndef _WIN32
40 # include <unistd.h>
41 #else
42 # include <windows.h>
43 # include <io.h>
44 
45 # define O_CREAT _O_CREAT
46 # define O_TRUNC _O_TRUNC
47 
48 # ifndef S_IRUSR
49 # define S_IRUSR _S_IREAD
50 # endif
51 
52 # ifndef S_IWUSR
53 # define S_IWUSR _S_IWRITE
54 # endif
55 
56 # ifdef __MINGW32__
57 # define _SH_DENYNO 0x40
58 # endif
59 
60 #endif // _WIN32
61 
62 #ifdef fileno
63 # undef fileno
64 #endif
65 
66 namespace {
67 #ifdef _WIN32
68 // Return type of read and write functions.
69 typedef int RWResult;
70 
71 // On Windows the count argument to read and write is unsigned, so convert
72 // it from size_t preventing integer overflow.
73 inline unsigned convert_rwcount(std::size_t count) {
74  return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
75 }
76 #else
77 // Return type of read and write functions.
78 typedef ssize_t RWResult;
79 
80 inline std::size_t convert_rwcount(std::size_t count) { return count; }
81 #endif
82 }
83 
85  if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
86  fmt::report_system_error(errno, "cannot close file");
87 }
88 
90  fmt::CStringRef filename, fmt::CStringRef mode) {
91  FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
92  if (!file_)
93  throw SystemError(errno, "cannot open file {}", filename);
94 }
95 
97  if (!file_)
98  return;
99  int result = FMT_SYSTEM(fclose(file_));
100  file_ = 0;
101  if (result != 0)
102  throw SystemError(errno, "cannot close file");
103 }
104 
105 // A macro used to prevent expansion of fileno on broken versions of MinGW.
106 #define FMT_ARGS
107 
109  int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
110  if (fd == -1)
111  throw SystemError(errno, "cannot get file descriptor");
112  return fd;
113 }
114 
116  int mode = S_IRUSR | S_IWUSR;
117 #if defined(_WIN32) && !defined(__MINGW32__)
118  fd_ = -1;
119  FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
120 #else
121  FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
122 #endif
123  if (fd_ == -1)
124  throw SystemError(errno, "cannot open file {}", path);
125 }
126 
128  // Don't retry close in case of EINTR!
129  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
130  if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
131  fmt::report_system_error(errno, "cannot close file");
132 }
133 
135  if (fd_ == -1)
136  return;
137  // Don't retry close in case of EINTR!
138  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
139  int result = FMT_POSIX_CALL(close(fd_));
140  fd_ = -1;
141  if (result != 0)
142  throw SystemError(errno, "cannot close file");
143 }
144 
146 #ifdef _WIN32
147  // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
148  // is less than 0x0500 as is the case with some default MinGW builds.
149  // Both functions support large file sizes.
150  DWORD size_upper = 0;
151  HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
152  DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
153  if (size_lower == INVALID_FILE_SIZE) {
154  DWORD error = GetLastError();
155  if (error != NO_ERROR)
156  throw WindowsError(GetLastError(), "cannot get file size");
157  }
158  fmt::ULongLong long_size = size_upper;
159  return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
160 #else
161  typedef struct stat Stat;
162  Stat file_stat = Stat();
163  if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
164  throw SystemError(errno, "cannot get file attributes");
165  FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
166  "return type of File::size is not large enough");
167  return file_stat.st_size;
168 #endif
169 }
170 
171 std::size_t fmt::File::read(void *buffer, std::size_t count) {
172  RWResult result = 0;
173  FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
174  if (result < 0)
175  throw SystemError(errno, "cannot read from file");
176  return internal::to_unsigned(result);
177 }
178 
179 std::size_t fmt::File::write(const void *buffer, std::size_t count) {
180  RWResult result = 0;
181  FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
182  if (result < 0)
183  throw SystemError(errno, "cannot write to file");
184  return internal::to_unsigned(result);
185 }
186 
188  // Don't retry as dup doesn't return EINTR.
189  // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
190  int new_fd = FMT_POSIX_CALL(dup(fd));
191  if (new_fd == -1)
192  throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
193  return File(new_fd);
194 }
195 
196 void fmt::File::dup2(int fd) {
197  int result = 0;
198  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
199  if (result == -1) {
200  throw SystemError(errno,
201  "cannot duplicate file descriptor {} to {}", fd_, fd);
202  }
203 }
204 
206  int result = 0;
207  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
208  if (result == -1)
209  ec = ErrorCode(errno);
210 }
211 
212 void fmt::File::pipe(File &read_end, File &write_end) {
213  // Close the descriptors first to make sure that assignments don't throw
214  // and there are no leaks.
215  read_end.close();
216  write_end.close();
217  int fds[2] = {};
218 #ifdef _WIN32
219  // Make the default pipe capacity same as on Linux 2.6.11+.
220  enum { DEFAULT_CAPACITY = 65536 };
221  int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
222 #else
223  // Don't retry as the pipe function doesn't return EINTR.
224  // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
225  int result = FMT_POSIX_CALL(pipe(fds));
226 #endif
227  if (result != 0)
228  throw SystemError(errno, "cannot create pipe");
229  // The following assignments don't throw because read_fd and write_fd
230  // are closed.
231  read_end = File(fds[0]);
232  write_end = File(fds[1]);
233 }
234 
236  // Don't retry as fdopen doesn't return EINTR.
237  FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
238  if (!f)
239  throw SystemError(errno, "cannot associate stream with file descriptor");
240  BufferedFile file(f);
241  fd_ = -1;
242  return file;
243 }
244 
246 #ifdef _WIN32
247  SYSTEM_INFO si;
248  GetSystemInfo(&si);
249  return si.dwPageSize;
250 #else
251  long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
252  if (size < 0)
253  throw SystemError(errno, "cannot get memory page size");
254  return size;
255 #endif
256 }
void close()
Definition: posix.cc:96
#define FMT_STATIC_ASSERT(cond, message)
Definition: posix.h:87
static File dup(int fd)
Definition: posix.cc:187
#define FMT_NOEXCEPT
Definition: format.h:190
#define FMT_ARGS
Definition: posix.cc:106
~File() FMT_NOEXCEPT
Definition: posix.cc:127
const Char * c_str() const
Definition: format.h:528
FMT_GCC_EXTENSION typedef unsigned long long ULongLong
Definition: format.h:369
void close()
Definition: posix.cc:134
void write(const mValue &value, std::ostream &os, unsigned int options=0)
#define FMT_RETRY_VAL(result, expression, error_result)
Definition: posix.h:94
std::size_t write(const void *buffer, std::size_t count)
Definition: posix.cc:179
File() FMT_NOEXCEPT
Definition: posix.h:234
#define FMT_RETRY(result, expression)
Definition: posix.h:102
int() fileno() const
Definition: posix.cc:108
MakeUnsigned< Int >::Type to_unsigned(Int value)
Definition: format.h:561
FMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT
Definition: format.cc:475
LongLong size() const
Definition: posix.cc:145
BufferedFile() FMT_NOEXCEPT
Definition: posix.h:128
FILE * file_
Definition: posix.h:120
long getpagesize()
Definition: posix.cc:245
bool read(const std::string &s, mValue &value)
void dup2(int fd)
Definition: posix.cc:196
static void pipe(File &read_end, File &write_end)
Definition: posix.cc:212
BufferedFile fdopen(const char *mode)
Definition: posix.cc:235
std::size_t read(void *buffer, std::size_t count)
Definition: posix.cc:171
~BufferedFile() FMT_NOEXCEPT
Definition: posix.cc:84
#define FMT_POSIX_CALL(call)
Definition: posix.h:68
#define FMT_SYSTEM(call)
Definition: posix.h:63
friend class File
Definition: posix.h:122
FMT_GCC_EXTENSION typedef long long LongLong
Definition: format.h:368