NGL  6.5
The NCCA Graphics Library
posix.cc
Go to the documentation of this file.
1 /*
2  A C++ interface to POSIX functions.
3 
4  Copyright (c) 2012 - 2016, Victor Zverovich
5  All rights reserved.
6 
7  For the license information refer to format.h.
8  */
9 
10 // Disable bogus MSVC warnings.
11 #ifndef _CRT_SECURE_NO_WARNINGS
12 # define _CRT_SECURE_NO_WARNINGS
13 #endif
14 
15 #include "fmt/posix.h"
16 
17 #include <limits.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 
21 #ifndef _WIN32
22 # include <unistd.h>
23 #else
24 # include <windows.h>
25 # include <io.h>
26 
27 # define O_CREAT _O_CREAT
28 # define O_TRUNC _O_TRUNC
29 
30 # ifndef S_IRUSR
31 # define S_IRUSR _S_IREAD
32 # endif
33 
34 # ifndef S_IWUSR
35 # define S_IWUSR _S_IWRITE
36 # endif
37 
38 # ifdef __MINGW32__
39 # define _SH_DENYNO 0x40
40 # endif
41 
42 #endif // _WIN32
43 
44 #ifdef fileno
45 # undef fileno
46 #endif
47 
48 namespace {
49 #ifdef _WIN32
50 // Return type of read and write functions.
51 typedef int RWResult;
52 
53 // On Windows the count argument to read and write is unsigned, so convert
54 // it from size_t preventing integer overflow.
55 inline unsigned convert_rwcount(std::size_t count) {
57 }
58 #else
59 // Return type of read and write functions.
60 typedef ssize_t RWResult;
61 
62 inline std::size_t convert_rwcount(std::size_t count) { return count; }
63 #endif
64 }
65 
67  if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
68  fmt::report_system_error(errno, "cannot close file");
69 }
70 
73  FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
74  if (!file_)
75  throw SystemError(errno, "cannot open file {}", filename);
76 }
77 
79  if (!file_)
80  return;
81  int result = FMT_SYSTEM(fclose(file_));
82  file_ = 0;
83  if (result != 0)
84  throw SystemError(errno, "cannot close file");
85 }
86 
87 // A macro used to prevent expansion of fileno on broken versions of MinGW.
88 #define FMT_ARGS
89 
92  if (fd == -1)
93  throw SystemError(errno, "cannot get file descriptor");
94  return fd;
95 }
96 
98  int mode = S_IRUSR | S_IWUSR;
99 #if defined(_WIN32) && !defined(__MINGW32__)
100  fd_ = -1;
101  FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
102 #else
103  FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
104 #endif
105  if (fd_ == -1)
106  throw SystemError(errno, "cannot open file {}", path);
107 }
108 
110  // Don't retry close in case of EINTR!
111  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
112  if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
113  fmt::report_system_error(errno, "cannot close file");
114 }
115 
117  if (fd_ == -1)
118  return;
119  // Don't retry close in case of EINTR!
120  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
121  int result = FMT_POSIX_CALL(close(fd_));
122  fd_ = -1;
123  if (result != 0)
124  throw SystemError(errno, "cannot close file");
125 }
126 
128 #ifdef _WIN32
129  // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
130  // is less than 0x0500 as is the case with some default MinGW builds.
131  // Both functions support large file sizes.
132  DWORD size_upper = 0;
133  HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
134  DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
135  if (size_lower == INVALID_FILE_SIZE) {
136  DWORD error = GetLastError();
137  if (error != NO_ERROR)
138  throw WindowsError(GetLastError(), "cannot get file size");
139  }
140  fmt::ULongLong long_size = size_upper;
141  return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
142 #else
143  typedef struct stat Stat;
144  Stat file_stat = Stat();
145  if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
146  throw SystemError(errno, "cannot get file attributes");
147  FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
148  "return type of File::size is not large enough");
149  return file_stat.st_size;
150 #endif
151 }
152 
153 std::size_t fmt::File::read(void *buffer, std::size_t count) {
154  RWResult result = 0;
155  FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
156  if (result < 0)
157  throw SystemError(errno, "cannot read from file");
158  return internal::to_unsigned(result);
159 }
160 
161 std::size_t fmt::File::write(const void *buffer, std::size_t count) {
162  RWResult result = 0;
163  FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
164  if (result < 0)
165  throw SystemError(errno, "cannot write to file");
166  return internal::to_unsigned(result);
167 }
168 
170  // Don't retry as dup doesn't return EINTR.
171  // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
172  int new_fd = FMT_POSIX_CALL(dup(fd));
173  if (new_fd == -1)
174  throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
175  return File(new_fd);
176 }
177 
178 void fmt::File::dup2(int fd) {
179  int result = 0;
180  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
181  if (result == -1) {
182  throw SystemError(errno,
183  "cannot duplicate file descriptor {} to {}", fd_, fd);
184  }
185 }
186 
188  int result = 0;
189  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
190  if (result == -1)
191  ec = ErrorCode(errno);
192 }
193 
194 void fmt::File::pipe(File &read_end, File &write_end) {
195  // Close the descriptors first to make sure that assignments don't throw
196  // and there are no leaks.
197  read_end.close();
198  write_end.close();
199  int fds[2] = {};
200 #ifdef _WIN32
201  // Make the default pipe capacity same as on Linux 2.6.11+.
202  enum { DEFAULT_CAPACITY = 65536 };
203  int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
204 #else
205  // Don't retry as the pipe function doesn't return EINTR.
206  // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
207  int result = FMT_POSIX_CALL(pipe(fds));
208 #endif
209  if (result != 0)
210  throw SystemError(errno, "cannot create pipe");
211  // The following assignments don't throw because read_fd and write_fd
212  // are closed.
213  read_end = File(fds[0]);
214  write_end = File(fds[1]);
215 }
216 
218  // Don't retry as fdopen doesn't return EINTR.
219  FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
220  if (!f)
221  throw SystemError(errno, "cannot associate stream with file descriptor");
222  BufferedFile file(f);
223  fd_ = -1;
224  return file;
225 }
226 
228 #ifdef _WIN32
229  SYSTEM_INFO si;
230  GetSystemInfo(&si);
231  return si.dwPageSize;
232 #else
233  long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
234  if (size < 0)
235  throw SystemError(errno, "cannot get memory page size");
236  return size;
237 #endif
238 }
~BufferedFile() FMT_NOEXCEPT
Definition: posix.cc:66
#define FMT_NOEXCEPT
Definition: format.h:190
void close()
Definition: posix.cc:116
FMT_FUNC void write(std::ostream &os, Writer &w)
Definition: ostream.cc:15
#define FMT_ARGS
Definition: posix.cc:88
int() fileno() const
Definition: posix.cc:90
FMT_GCC_EXTENSION typedef unsigned long long ULongLong
Definition: format.h:369
#define FMT_STATIC_ASSERT(cond, message)
Definition: format.h:1159
GLsizei const GLchar *const * path
Definition: glew.h:6489
GLenum mode
Definition: glew.h:2166
friend class File
Definition: posix.h:85
const Char * c_str() const
Definition: format.h:531
FMT_FUNC void report_system_error(int error_code, fmt::StringRef message) FMT_NOEXCEPT
Definition: format.cc:472
LongLong size() const
Definition: posix.cc:127
File() FMT_NOEXCEPT
Definition: posix.h:197
GLuint64EXT * result
Definition: glew.h:14309
~File() FMT_NOEXCEPT
Definition: posix.cc:109
#define FMT_RETRY_VAL(result, expression, error_result)
Definition: posix.h:57
std::size_t read(void *buffer, std::size_t count)
Definition: posix.cc:153
#define FMT_RETRY(result, expression)
Definition: posix.h:65
GLuint GLuint GLsizei count
Definition: glew.h:1256
MakeUnsigned< Int >::Type to_unsigned(Int value)
Definition: format.h:564
GLuint buffer
Definition: glew.h:1683
static File dup(int fd)
Definition: posix.cc:169
std::size_t write(const void *buffer, std::size_t count)
Definition: posix.cc:161
BufferedFile fdopen(const char *mode)
Definition: posix.cc:217
void close()
Definition: posix.cc:78
FILE * file_
Definition: posix.h:83
long getpagesize()
Definition: posix.cc:227
GLsizeiptr size
Definition: glew.h:1684
void dup2(int fd)
Definition: posix.cc:178
BufferedFile() FMT_NOEXCEPT
Definition: posix.h:91
static void pipe(File &read_end, File &write_end)
Definition: posix.cc:194
#define FMT_POSIX_CALL(call)
Definition: posix.h:50
#define FMT_SYSTEM(call)
Definition: posix.h:45
FMT_GCC_EXTENSION typedef long long LongLong
Definition: format.h:368
GLclampf f
Definition: glew.h:3511
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC