Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

os.cc 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Formatting library for C++ - optional OS-specific functionality
  2. //
  3. // Copyright (c) 2012 - 2016, Victor Zverovich
  4. // All rights reserved.
  5. //
  6. // For the license information refer to format.h.
  7. // Disable bogus MSVC warnings.
  8. #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
  9. # define _CRT_SECURE_NO_WARNINGS
  10. #endif
  11. #include "fmt/os.h"
  12. #include <climits>
  13. #if FMT_USE_FCNTL
  14. # include <sys/stat.h>
  15. # include <sys/types.h>
  16. # ifndef _WIN32
  17. # include <unistd.h>
  18. # else
  19. # ifndef WIN32_LEAN_AND_MEAN
  20. # define WIN32_LEAN_AND_MEAN
  21. # endif
  22. # include <io.h>
  23. # include <windows.h>
  24. # define O_CREAT _O_CREAT
  25. # define O_TRUNC _O_TRUNC
  26. # ifndef S_IRUSR
  27. # define S_IRUSR _S_IREAD
  28. # endif
  29. # ifndef S_IWUSR
  30. # define S_IWUSR _S_IWRITE
  31. # endif
  32. # ifdef __MINGW32__
  33. # define _SH_DENYNO 0x40
  34. # endif
  35. # endif // _WIN32
  36. #endif // FMT_USE_FCNTL
  37. #ifdef _WIN32
  38. # include <windows.h>
  39. #endif
  40. #ifdef fileno
  41. # undef fileno
  42. #endif
  43. namespace {
  44. #ifdef _WIN32
  45. // Return type of read and write functions.
  46. using RWResult = int;
  47. // On Windows the count argument to read and write is unsigned, so convert
  48. // it from size_t preventing integer overflow.
  49. inline unsigned convert_rwcount(std::size_t count) {
  50. return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
  51. }
  52. #elif FMT_USE_FCNTL
  53. // Return type of read and write functions.
  54. using RWResult = ssize_t;
  55. inline std::size_t convert_rwcount(std::size_t count) { return count; }
  56. #endif
  57. } // namespace
  58. FMT_BEGIN_NAMESPACE
  59. #ifdef _WIN32
  60. detail::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
  61. if (int error_code = convert(s)) {
  62. FMT_THROW(windows_error(error_code,
  63. "cannot convert string from UTF-16 to UTF-8"));
  64. }
  65. }
  66. int detail::utf16_to_utf8::convert(wstring_view s) {
  67. if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
  68. int s_size = static_cast<int>(s.size());
  69. if (s_size == 0) {
  70. // WideCharToMultiByte does not support zero length, handle separately.
  71. buffer_.resize(1);
  72. buffer_[0] = 0;
  73. return 0;
  74. }
  75. int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
  76. nullptr, nullptr);
  77. if (length == 0) return GetLastError();
  78. buffer_.resize(length + 1);
  79. length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
  80. length, nullptr, nullptr);
  81. if (length == 0) return GetLastError();
  82. buffer_[length] = 0;
  83. return 0;
  84. }
  85. void windows_error::init(int err_code, string_view format_str,
  86. format_args args) {
  87. error_code_ = err_code;
  88. memory_buffer buffer;
  89. detail::format_windows_error(buffer, err_code, vformat(format_str, args));
  90. std::runtime_error& base = *this;
  91. base = std::runtime_error(to_string(buffer));
  92. }
  93. void detail::format_windows_error(detail::buffer<char>& out, int error_code,
  94. string_view message) FMT_NOEXCEPT {
  95. FMT_TRY {
  96. wmemory_buffer buf;
  97. buf.resize(inline_buffer_size);
  98. for (;;) {
  99. wchar_t* system_message = &buf[0];
  100. int result = FormatMessageW(
  101. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
  102. error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
  103. static_cast<uint32_t>(buf.size()), nullptr);
  104. if (result != 0) {
  105. utf16_to_utf8 utf8_message;
  106. if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
  107. format_to(buffer_appender<char>(out), "{}: {}", message,
  108. utf8_message);
  109. return;
  110. }
  111. break;
  112. }
  113. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  114. break; // Can't get error message, report error code instead.
  115. buf.resize(buf.size() * 2);
  116. }
  117. }
  118. FMT_CATCH(...) {}
  119. format_error_code(out, error_code, message);
  120. }
  121. void report_windows_error(int error_code,
  122. fmt::string_view message) FMT_NOEXCEPT {
  123. report_error(detail::format_windows_error, error_code, message);
  124. }
  125. #endif // _WIN32
  126. buffered_file::~buffered_file() FMT_NOEXCEPT {
  127. if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
  128. report_system_error(errno, "cannot close file");
  129. }
  130. buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
  131. FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
  132. nullptr);
  133. if (!file_)
  134. FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
  135. }
  136. void buffered_file::close() {
  137. if (!file_) return;
  138. int result = FMT_SYSTEM(fclose(file_));
  139. file_ = nullptr;
  140. if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
  141. }
  142. // A macro used to prevent expansion of fileno on broken versions of MinGW.
  143. #define FMT_ARGS
  144. int buffered_file::fileno() const {
  145. int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
  146. if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
  147. return fd;
  148. }
  149. #if FMT_USE_FCNTL
  150. file::file(cstring_view path, int oflag) {
  151. int mode = S_IRUSR | S_IWUSR;
  152. # if defined(_WIN32) && !defined(__MINGW32__)
  153. fd_ = -1;
  154. FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
  155. # else
  156. FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
  157. # endif
  158. if (fd_ == -1)
  159. FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
  160. }
  161. file::~file() FMT_NOEXCEPT {
  162. // Don't retry close in case of EINTR!
  163. // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
  164. if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
  165. report_system_error(errno, "cannot close file");
  166. }
  167. void file::close() {
  168. if (fd_ == -1) return;
  169. // Don't retry close in case of EINTR!
  170. // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
  171. int result = FMT_POSIX_CALL(close(fd_));
  172. fd_ = -1;
  173. if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
  174. }
  175. long long file::size() const {
  176. # ifdef _WIN32
  177. // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
  178. // is less than 0x0500 as is the case with some default MinGW builds.
  179. // Both functions support large file sizes.
  180. DWORD size_upper = 0;
  181. HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
  182. DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
  183. if (size_lower == INVALID_FILE_SIZE) {
  184. DWORD error = GetLastError();
  185. if (error != NO_ERROR)
  186. FMT_THROW(windows_error(GetLastError(), "cannot get file size"));
  187. }
  188. unsigned long long long_size = size_upper;
  189. return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
  190. # else
  191. using Stat = struct stat;
  192. Stat file_stat = Stat();
  193. if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
  194. FMT_THROW(system_error(errno, "cannot get file attributes"));
  195. static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
  196. "return type of file::size is not large enough");
  197. return file_stat.st_size;
  198. # endif
  199. }
  200. std::size_t file::read(void* buffer, std::size_t count) {
  201. RWResult result = 0;
  202. FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
  203. if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
  204. return detail::to_unsigned(result);
  205. }
  206. std::size_t file::write(const void* buffer, std::size_t count) {
  207. RWResult result = 0;
  208. FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
  209. if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
  210. return detail::to_unsigned(result);
  211. }
  212. file file::dup(int fd) {
  213. // Don't retry as dup doesn't return EINTR.
  214. // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
  215. int new_fd = FMT_POSIX_CALL(dup(fd));
  216. if (new_fd == -1)
  217. FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
  218. return file(new_fd);
  219. }
  220. void file::dup2(int fd) {
  221. int result = 0;
  222. FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
  223. if (result == -1) {
  224. FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
  225. fd_, fd));
  226. }
  227. }
  228. void file::dup2(int fd, error_code& ec) FMT_NOEXCEPT {
  229. int result = 0;
  230. FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
  231. if (result == -1) ec = error_code(errno);
  232. }
  233. void file::pipe(file& read_end, file& write_end) {
  234. // Close the descriptors first to make sure that assignments don't throw
  235. // and there are no leaks.
  236. read_end.close();
  237. write_end.close();
  238. int fds[2] = {};
  239. # ifdef _WIN32
  240. // Make the default pipe capacity same as on Linux 2.6.11+.
  241. enum { DEFAULT_CAPACITY = 65536 };
  242. int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
  243. # else
  244. // Don't retry as the pipe function doesn't return EINTR.
  245. // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
  246. int result = FMT_POSIX_CALL(pipe(fds));
  247. # endif
  248. if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
  249. // The following assignments don't throw because read_fd and write_fd
  250. // are closed.
  251. read_end = file(fds[0]);
  252. write_end = file(fds[1]);
  253. }
  254. buffered_file file::fdopen(const char* mode) {
  255. // Don't retry as fdopen doesn't return EINTR.
  256. # if defined(__MINGW32__) && defined(_POSIX_)
  257. FILE* f = ::fdopen(fd_, mode);
  258. # else
  259. FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
  260. # endif
  261. if (!f)
  262. FMT_THROW(
  263. system_error(errno, "cannot associate stream with file descriptor"));
  264. buffered_file bf(f);
  265. fd_ = -1;
  266. return bf;
  267. }
  268. long getpagesize() {
  269. # ifdef _WIN32
  270. SYSTEM_INFO si;
  271. GetSystemInfo(&si);
  272. return si.dwPageSize;
  273. # else
  274. long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
  275. if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
  276. return size;
  277. # endif
  278. }
  279. FMT_API void ostream::grow(size_t) {
  280. if (this->size() == this->capacity()) flush();
  281. }
  282. #endif // FMT_USE_FCNTL
  283. FMT_END_NAMESPACE