2 A C++ interface to POSIX functions.
4 Copyright (c) 2012 - 2016, Victor Zverovich
7 For the license information refer to format.h.
10 // Disable bogus MSVC warnings.
11 #ifndef _CRT_SECURE_NO_WARNINGS
12 # define _CRT_SECURE_NO_WARNINGS
15 #include "fmt/posix.h"
18 #include <sys/types.h>
27 # define O_CREAT _O_CREAT
28 # define O_TRUNC _O_TRUNC
31 # define S_IRUSR _S_IREAD
35 # define S_IWUSR _S_IWRITE
39 # define _SH_DENYNO 0x40
50 // Return type of read and write functions.
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
) {
56 return count
<= UINT_MAX
? static_cast<unsigned>(count
) : UINT_MAX
;
59 // Return type of read and write functions.
60 typedef ssize_t RWResult
;
62 inline std::size_t convert_rwcount(std::size_t count
) { return count
; }
66 fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT
{
67 if (file_
&& FMT_SYSTEM(fclose(file_
)) != 0)
68 fmt::report_system_error(errno
, "cannot close file");
71 fmt::BufferedFile::BufferedFile(
72 fmt::CStringRef filename
, fmt::CStringRef mode
) {
73 FMT_RETRY_VAL(file_
, FMT_SYSTEM(fopen(filename
.c_str(), mode
.c_str())), 0);
75 throw SystemError(errno
, "cannot open file {}", filename
);
78 void fmt::BufferedFile::close() {
81 int result
= FMT_SYSTEM(fclose(file_
));
84 throw SystemError(errno
, "cannot close file");
87 // A macro used to prevent expansion of fileno on broken versions of MinGW.
90 int fmt::BufferedFile::fileno() const {
91 int fd
= FMT_POSIX_CALL(fileno
FMT_ARGS(file_
));
93 throw SystemError(errno
, "cannot get file descriptor");
97 fmt::File::File(fmt::CStringRef path
, int oflag
) {
98 int mode
= S_IRUSR
| S_IWUSR
;
99 #if defined(_WIN32) && !defined(__MINGW32__)
101 FMT_POSIX_CALL(sopen_s(&fd_
, path
.c_str(), oflag
, _SH_DENYNO
, mode
));
103 FMT_RETRY(fd_
, FMT_POSIX_CALL(open(path
.c_str(), oflag
, mode
)));
106 throw SystemError(errno
, "cannot open file {}", path
);
109 fmt::File::~File() FMT_NOEXCEPT
{
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");
116 void fmt::File::close() {
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_
));
124 throw SystemError(errno
, "cannot close file");
127 fmt::LongLong
fmt::File::size() const {
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");
140 fmt::ULongLong long_size
= size_upper
;
141 return (long_size
<< sizeof(DWORD
) * CHAR_BIT
) | size_lower
;
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
;
153 std::size_t fmt::File::read(void *buffer
, std::size_t count
) {
155 FMT_RETRY(result
, FMT_POSIX_CALL(read(fd_
, buffer
, convert_rwcount(count
))));
157 throw SystemError(errno
, "cannot read from file");
158 return internal::to_unsigned(result
);
161 std::size_t fmt::File::write(const void *buffer
, std::size_t count
) {
163 FMT_RETRY(result
, FMT_POSIX_CALL(write(fd_
, buffer
, convert_rwcount(count
))));
165 throw SystemError(errno
, "cannot write to file");
166 return internal::to_unsigned(result
);
169 fmt::File
fmt::File::dup(int fd
) {
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
));
174 throw SystemError(errno
, "cannot duplicate file descriptor {}", fd
);
178 void fmt::File::dup2(int fd
) {
180 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
182 throw SystemError(errno
,
183 "cannot duplicate file descriptor {} to {}", fd_
, fd
);
187 void fmt::File::dup2(int fd
, ErrorCode
&ec
) FMT_NOEXCEPT
{
189 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
191 ec
= ErrorCode(errno
);
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.
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
));
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
));
210 throw SystemError(errno
, "cannot create pipe");
211 // The following assignments don't throw because read_fd and write_fd
213 read_end
= File(fds
[0]);
214 write_end
= File(fds
[1]);
217 fmt::BufferedFile
fmt::File::fdopen(const char *mode
) {
218 // Don't retry as fdopen doesn't return EINTR.
219 FILE *f
= FMT_POSIX_CALL(fdopen(fd_
, mode
));
221 throw SystemError(errno
, "cannot associate stream with file descriptor");
222 BufferedFile
file(f
);
227 long fmt::getpagesize() {
231 return si
.dwPageSize
;
233 long size
= FMT_POSIX_CALL(sysconf(_SC_PAGESIZE
));
235 throw SystemError(errno
, "cannot get memory page size");