]>
git.proxmox.com Git - ceph.git/blob - ceph/src/fmt/src/posix.cc
1 // A C++ interface to POSIX functions.
3 // Copyright (c) 2012 - 2016, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
8 // Disable bogus MSVC warnings.
9 #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
10 # define _CRT_SECURE_NO_WARNINGS
13 #include "fmt/posix.h"
17 #include <sys/types.h>
22 # ifndef WIN32_LEAN_AND_MEAN
23 # define WIN32_LEAN_AND_MEAN
28 # define O_CREAT _O_CREAT
29 # define O_TRUNC _O_TRUNC
32 # define S_IRUSR _S_IREAD
36 # define S_IWUSR _S_IWRITE
40 # define _SH_DENYNO 0x40
51 // Return type of read and write functions.
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
;
60 // Return type of read and write functions.
61 typedef ssize_t RWResult
;
63 inline std::size_t convert_rwcount(std::size_t count
) { return count
; }
69 buffered_file::~buffered_file() FMT_NOEXCEPT
{
70 if (file_
&& FMT_SYSTEM(fclose(file_
)) != 0)
71 report_system_error(errno
, "cannot close file");
74 buffered_file::buffered_file(cstring_view filename
, cstring_view mode
) {
75 FMT_RETRY_VAL(file_
, FMT_SYSTEM(fopen(filename
.c_str(), mode
.c_str())),
78 FMT_THROW(system_error(errno
, "cannot open file {}", filename
.c_str()));
81 void buffered_file::close() {
83 int result
= FMT_SYSTEM(fclose(file_
));
85 if (result
!= 0) FMT_THROW(system_error(errno
, "cannot close file"));
88 // A macro used to prevent expansion of fileno on broken versions of MinGW.
91 int buffered_file::fileno() const {
92 int fd
= FMT_POSIX_CALL(fileno
FMT_ARGS(file_
));
93 if (fd
== -1) FMT_THROW(system_error(errno
, "cannot get file descriptor"));
97 file::file(cstring_view 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 FMT_THROW(system_error(errno
, "cannot open file {}", path
.c_str()));
109 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 report_system_error(errno
, "cannot close file");
117 if (fd_
== -1) return;
118 // Don't retry close in case of EINTR!
119 // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
120 int result
= FMT_POSIX_CALL(close(fd_
));
122 if (result
!= 0) FMT_THROW(system_error(errno
, "cannot close file"));
125 long long file::size() const {
127 // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
128 // is less than 0x0500 as is the case with some default MinGW builds.
129 // Both functions support large file sizes.
130 DWORD size_upper
= 0;
131 HANDLE handle
= reinterpret_cast<HANDLE
>(_get_osfhandle(fd_
));
132 DWORD size_lower
= FMT_SYSTEM(GetFileSize(handle
, &size_upper
));
133 if (size_lower
== INVALID_FILE_SIZE
) {
134 DWORD error
= GetLastError();
135 if (error
!= NO_ERROR
)
136 FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
138 unsigned long long long_size
= size_upper
;
139 return (long_size
<< sizeof(DWORD
) * CHAR_BIT
) | size_lower
;
141 typedef struct stat Stat
;
142 Stat file_stat
= Stat();
143 if (FMT_POSIX_CALL(fstat(fd_
, &file_stat
)) == -1)
144 FMT_THROW(system_error(errno
, "cannot get file attributes"));
145 static_assert(sizeof(long long) >= sizeof(file_stat
.st_size
),
146 "return type of file::size is not large enough");
147 return file_stat
.st_size
;
151 std::size_t file::read(void* buffer
, std::size_t count
) {
153 FMT_RETRY(result
, FMT_POSIX_CALL(read(fd_
, buffer
, convert_rwcount(count
))));
154 if (result
< 0) FMT_THROW(system_error(errno
, "cannot read from file"));
155 return internal::to_unsigned(result
);
158 std::size_t file::write(const void* buffer
, std::size_t count
) {
160 FMT_RETRY(result
, FMT_POSIX_CALL(write(fd_
, buffer
, convert_rwcount(count
))));
161 if (result
< 0) FMT_THROW(system_error(errno
, "cannot write to file"));
162 return internal::to_unsigned(result
);
165 file
file::dup(int fd
) {
166 // Don't retry as dup doesn't return EINTR.
167 // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
168 int new_fd
= FMT_POSIX_CALL(dup(fd
));
170 FMT_THROW(system_error(errno
, "cannot duplicate file descriptor {}", fd
));
174 void file::dup2(int fd
) {
176 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
178 FMT_THROW(system_error(errno
, "cannot duplicate file descriptor {} to {}",
183 void file::dup2(int fd
, error_code
& ec
) FMT_NOEXCEPT
{
185 FMT_RETRY(result
, FMT_POSIX_CALL(dup2(fd_
, fd
)));
186 if (result
== -1) ec
= error_code(errno
);
189 void file::pipe(file
& read_end
, file
& write_end
) {
190 // Close the descriptors first to make sure that assignments don't throw
191 // and there are no leaks.
196 // Make the default pipe capacity same as on Linux 2.6.11+.
197 enum { DEFAULT_CAPACITY
= 65536 };
198 int result
= FMT_POSIX_CALL(pipe(fds
, DEFAULT_CAPACITY
, _O_BINARY
));
200 // Don't retry as the pipe function doesn't return EINTR.
201 // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
202 int result
= FMT_POSIX_CALL(pipe(fds
));
204 if (result
!= 0) FMT_THROW(system_error(errno
, "cannot create pipe"));
205 // The following assignments don't throw because read_fd and write_fd
207 read_end
= file(fds
[0]);
208 write_end
= file(fds
[1]);
211 buffered_file
file::fdopen(const char* mode
) {
212 // Don't retry as fdopen doesn't return EINTR.
213 FILE* f
= FMT_POSIX_CALL(fdopen(fd_
, mode
));
216 system_error(errno
, "cannot associate stream with file descriptor"));
226 return si
.dwPageSize
;
228 long size
= FMT_POSIX_CALL(sysconf(_SC_PAGESIZE
));
229 if (size
< 0) FMT_THROW(system_error(errno
, "cannot get memory page size"));