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 "mp/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   	struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive-
25   	# include <windows.h>
26   	# include <io.h>
27   	
28   	# define O_CREAT _O_CREAT
29   	# define O_TRUNC _O_TRUNC
30   	
31   	# ifndef S_IRUSR
32   	#  define S_IRUSR _S_IREAD
33   	# endif
34   	
35   	# ifndef S_IWUSR
36   	#  define S_IWUSR _S_IWRITE
37   	# endif
38   	
39   	# ifdef __MINGW32__
40   	#  define _SH_DENYNO 0x40
41   	# endif
42   	
43   	#endif  // _WIN32
44   	
45   	#ifdef fileno
46   	# undef fileno
47   	#endif
48   	
49   	namespace {
50   	#ifdef _WIN32
51   	// Return type of read and write functions.
52   	typedef int RWResult;
53   	
54   	// On Windows the count argument to read and write is unsigned, so convert
55   	// it from size_t preventing integer overflow.
56   	inline unsigned convert_rwcount(std::size_t count) {
57   	  return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
58   	}
59   	#else
60   	// Return type of read and write functions.
61   	typedef ssize_t RWResult;
62   	
63   	inline std::size_t convert_rwcount(std::size_t count) { return count; }
64   	#endif
65   	}
66   	
(4) Event destructor: User-defined destructor.
Also see events: [rule_of_five_violation][remediation][remediation][move_ctor][move_assign]
67   	fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
68   	  if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
69   	    fmt::report_system_error(errno, "cannot close file");
70   	}
71   	
72   	fmt::BufferedFile::BufferedFile(
73   	    fmt::CStringRef filename, fmt::CStringRef mode) {
74   	  FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
75   	  if (!file_)
76   	    FMT_THROW(SystemError(errno, "cannot open file {}", filename));
77   	}
78   	
79   	void fmt::BufferedFile::close() {
80   	  if (!file_)
81   	    return;
82   	  int result = FMT_SYSTEM(fclose(file_));
83   	  file_ = 0;
84   	  if (result != 0)
85   	    FMT_THROW(SystemError(errno, "cannot close file"));
86   	}
87   	
88   	// A macro used to prevent expansion of fileno on broken versions of MinGW.
89   	#define FMT_ARGS
90   	
91   	int fmt::BufferedFile::fileno() const {
92   	  int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
93   	  if (fd == -1)
94   	    FMT_THROW(SystemError(errno, "cannot get file descriptor"));
95   	  return fd;
96   	}
97   	
98   	fmt::File::File(fmt::CStringRef path, int oflag) {
99   	  int mode = S_IRUSR | S_IWUSR;
100  	#if defined(_WIN32) && !defined(__MINGW32__)
101  	  fd_ = -1;
102  	  FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
103  	#else
104  	  FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
105  	#endif
106  	  if (fd_ == -1)
107  	    FMT_THROW(SystemError(errno, "cannot open file {}", path));
108  	}
109  	
110  	fmt::File::~File() FMT_NOEXCEPT {
111  	  // Don't retry close in case of EINTR!
112  	  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
113  	  if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
114  	    fmt::report_system_error(errno, "cannot close file");
115  	}
116  	
117  	void fmt::File::close() {
118  	  if (fd_ == -1)
119  	    return;
120  	  // Don't retry close in case of EINTR!
121  	  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
122  	  int result = FMT_POSIX_CALL(close(fd_));
123  	  fd_ = -1;
124  	  if (result != 0)
125  	    FMT_THROW(SystemError(errno, "cannot close file"));
126  	}
127  	
128  	fmt::LongLong fmt::File::size() const {
129  	#ifdef _WIN32
130  	  // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
131  	  // is less than 0x0500 as is the case with some default MinGW builds.
132  	  // Both functions support large file sizes.
133  	  DWORD size_upper = 0;
134  	  HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
135  	  DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
136  	  if (size_lower == INVALID_FILE_SIZE) {
137  	    DWORD error = GetLastError();
138  	    if (error != NO_ERROR)
139  	      FMT_THROW(WindowsError(GetLastError(), "cannot get file size"));
140  	  }
141  	  fmt::ULongLong long_size = size_upper;
142  	  return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
143  	#else
144  	  typedef struct stat Stat;
145  	  Stat file_stat = Stat();
146  	  if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
147  	    FMT_THROW(SystemError(errno, "cannot get file attributes"));
148  	  FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
149  	      "return type of File::size is not large enough");
150  	  return file_stat.st_size;
151  	#endif
152  	}
153  	
154  	std::size_t fmt::File::read(void *buffer, std::size_t count) {
155  	  RWResult result = 0;
156  	  FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
157  	  if (result < 0)
158  	    FMT_THROW(SystemError(errno, "cannot read from file"));
159  	  return internal::to_unsigned(result);
160  	}
161  	
162  	std::size_t fmt::File::write(const void *buffer, std::size_t count) {
163  	  RWResult result = 0;
164  	  FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
165  	  if (result < 0)
166  	    FMT_THROW(SystemError(errno, "cannot write to file"));
167  	  return internal::to_unsigned(result);
168  	}
169  	
170  	fmt::File fmt::File::dup(int fd) {
171  	  // Don't retry as dup doesn't return EINTR.
172  	  // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
173  	  int new_fd = FMT_POSIX_CALL(dup(fd));
174  	  if (new_fd == -1)
175  	    FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd));
176  	  return File(new_fd);
177  	}
178  	
179  	void fmt::File::dup2(int fd) {
180  	  int result = 0;
181  	  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
182  	  if (result == -1) {
183  	    FMT_THROW(SystemError(errno,
184  	      "cannot duplicate file descriptor {} to {}", fd_, fd));
185  	  }
186  	}
187  	
188  	void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT {
189  	  int result = 0;
190  	  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
191  	  if (result == -1)
192  	    ec = ErrorCode(errno);
193  	}
194  	
195  	void fmt::File::pipe(File &read_end, File &write_end) {
196  	  // Close the descriptors first to make sure that assignments don't throw
197  	  // and there are no leaks.
198  	  read_end.close();
199  	  write_end.close();
200  	  int fds[2] = {};
201  	#ifdef _WIN32
202  	  // Make the default pipe capacity same as on Linux 2.6.11+.
203  	  enum { DEFAULT_CAPACITY = 65536 };
204  	  int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
205  	#else
206  	  // Don't retry as the pipe function doesn't return EINTR.
207  	  // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
208  	  int result = FMT_POSIX_CALL(pipe(fds));
209  	#endif
210  	  if (result != 0)
211  	    FMT_THROW(SystemError(errno, "cannot create pipe"));
212  	  // The following assignments don't throw because read_fd and write_fd
213  	  // are closed.
214  	  read_end = File(fds[0]);
215  	  write_end = File(fds[1]);
216  	}
217  	
218  	fmt::BufferedFile fmt::File::fdopen(const char *mode) {
219  	  // Don't retry as fdopen doesn't return EINTR.
220  	  FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
221  	  if (!f)
222  	    FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor"));
223  	  BufferedFile file(f);
224  	  fd_ = -1;
225  	  return file;
226  	}
227  	
228  	long fmt::getpagesize() {
229  	#ifdef _WIN32
230  	  SYSTEM_INFO si;
231  	  GetSystemInfo(&si);
232  	  return si.dwPageSize;
233  	#else
234  	  long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
235  	  if (size < 0)
236  	    FMT_THROW(SystemError(errno, "cannot get memory page size"));
237  	  return size;
238  	#endif
239  	}
240