| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  A C++ interface to POSIX functions. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Copyright (c) 2014, Victor Zverovich | 
					
						
							|  |  |  |  All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |     list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |     this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |     and/or other materials provided with the distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | 
					
						
							|  |  |  |  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
					
						
							|  |  |  |  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | 
					
						
							|  |  |  |  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
					
						
							|  |  |  |  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
					
						
							|  |  |  |  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
					
						
							|  |  |  |  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
					
						
							|  |  |  |  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "posix.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <limits.h>
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef _WIN32
 | 
					
						
							|  |  |  | # include <unistd.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | # include <io.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # define O_CREAT _O_CREAT
 | 
					
						
							|  |  |  | # define O_TRUNC _O_TRUNC
 | 
					
						
							| 
									
										
										
										
											2014-07-09 08:39:01 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef S_IRUSR
 | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | # define S_IRUSR _S_IREAD
 | 
					
						
							| 
									
										
										
										
											2014-07-09 08:39:01 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef S_IWUSR
 | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | # define S_IWUSR _S_IWRITE
 | 
					
						
							| 
									
										
										
										
											2014-07-09 08:39:01 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-11 02:38:57 +04:00
										 |  |  | # ifdef __MINGW32__
 | 
					
						
							|  |  |  | #  define _SH_DENYNO 0x40
 | 
					
						
							|  |  |  | # endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | #endif  // _WIN32
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | // On Windows the count argument to read and write is unsigned, so convert
 | 
					
						
							|  |  |  | // it from size_t preventing integer overflow.
 | 
					
						
							| 
									
										
										
										
											2014-07-27 12:53:42 -07:00
										 |  |  | inline unsigned convert_rwcount(std::size_t count) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2014-07-27 12:53:42 -07:00
										 |  |  | inline std::size_t convert_rwcount(std::size_t count) { return count; } | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT(true) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   if (file_ && FMT_SYSTEM(fclose(file_)) != 0) | 
					
						
							| 
									
										
										
										
											2014-07-28 08:41:50 -07:00
										 |  |  |     fmt::report_system_error(errno, "cannot close file"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:53:05 -07:00
										 |  |  | fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) { | 
					
						
							| 
									
										
										
										
											2014-08-28 12:13:03 -07:00
										 |  |  |   FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); | 
					
						
							|  |  |  |   if (!file_) | 
					
						
							| 
									
										
										
										
											2014-08-28 14:51:01 -07:00
										 |  |  |     throw SystemError(errno, "cannot open file {}", filename); | 
					
						
							| 
									
										
										
										
											2014-08-28 11:53:05 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | void fmt::BufferedFile::close() { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   if (!file_) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   int result = FMT_SYSTEM(fclose(file_)); | 
					
						
							|  |  |  |   file_ = 0; | 
					
						
							|  |  |  |   if (result != 0) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot close file"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | int fmt::BufferedFile::fileno() const { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   int fd = FMT_POSIX_CALL(fileno(file_)); | 
					
						
							|  |  |  |   if (fd == -1) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot get file descriptor"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   return fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | fmt::File::File(const char *path, int oflag) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   int mode = S_IRUSR | S_IWUSR; | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  |   fd_ = -1; | 
					
						
							|  |  |  |   FMT_POSIX_CALL(sopen_s(&fd_, path, oflag, _SH_DENYNO, mode)); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   FMT_RETRY(fd_, FMT_POSIX_CALL(open(path, oflag, mode))); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |   if (fd_ == -1) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot open file {}", path); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | fmt::File::~File() FMT_NOEXCEPT(true) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   // Don't retry close in case of EINTR!
 | 
					
						
							|  |  |  |   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
 | 
					
						
							|  |  |  |   if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) | 
					
						
							| 
									
										
										
										
											2014-07-28 08:41:50 -07:00
										 |  |  |     fmt::report_system_error(errno, "cannot close file"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | void fmt::File::close() { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   if (fd_ == -1) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   // Don't retry close in case of EINTR!
 | 
					
						
							|  |  |  |   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
 | 
					
						
							|  |  |  |   int result = FMT_POSIX_CALL(close(fd_)); | 
					
						
							|  |  |  |   fd_ = -1; | 
					
						
							|  |  |  |   if (result != 0) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot close file"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | std::streamsize fmt::File::read(void *buffer, std::size_t count) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   std::streamsize result = 0; | 
					
						
							| 
									
										
										
										
											2014-07-27 12:53:42 -07:00
										 |  |  |   FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   if (result == -1) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot read from file"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | std::streamsize fmt::File::write(const void *buffer, std::size_t count) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   std::streamsize result = 0; | 
					
						
							| 
									
										
										
										
											2014-07-27 12:53:42 -07:00
										 |  |  |   FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   if (result == -1) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot write to file"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | fmt::File fmt::File::dup(int fd) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   // Don't retry as dup doesn't return EINTR.
 | 
					
						
							|  |  |  |   // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
 | 
					
						
							|  |  |  |   int new_fd = FMT_POSIX_CALL(dup(fd)); | 
					
						
							|  |  |  |   if (new_fd == -1) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot duplicate file descriptor {}", fd); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   return File(new_fd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | void fmt::File::dup2(int fd) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   int result = 0; | 
					
						
							|  |  |  |   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); | 
					
						
							|  |  |  |   if (result == -1) { | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, | 
					
						
							|  |  |  |       "cannot duplicate file descriptor {} to {}", fd_, fd); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT(true) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   int result = 0; | 
					
						
							|  |  |  |   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); | 
					
						
							|  |  |  |   if (result == -1) | 
					
						
							|  |  |  |     ec = ErrorCode(errno); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | void fmt::File::pipe(File &read_end, File &write_end) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   // Close the descriptors first to make sure that assignments don't throw
 | 
					
						
							|  |  |  |   // and there are no leaks.
 | 
					
						
							|  |  |  |   read_end.close(); | 
					
						
							|  |  |  |   write_end.close(); | 
					
						
							|  |  |  |   int fds[2] = {}; | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  |   // Make the default pipe capacity same as on Linux 2.6.11+.
 | 
					
						
							|  |  |  |   enum { DEFAULT_CAPACITY = 65536 }; | 
					
						
							|  |  |  |   int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   // Don't retry as the pipe function doesn't return EINTR.
 | 
					
						
							|  |  |  |   // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
 | 
					
						
							|  |  |  |   int result = FMT_POSIX_CALL(pipe(fds)); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |   if (result != 0) | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     throw SystemError(errno, "cannot create pipe"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   // The following assignments don't throw because read_fd and write_fd
 | 
					
						
							|  |  |  |   // are closed.
 | 
					
						
							|  |  |  |   read_end = File(fds[0]); | 
					
						
							|  |  |  |   write_end = File(fds[1]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-09 09:07:27 -07:00
										 |  |  | fmt::BufferedFile fmt::File::fdopen(const char *mode) { | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   // Don't retry as fdopen doesn't return EINTR.
 | 
					
						
							|  |  |  |   FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |   if (!f) | 
					
						
							|  |  |  |     throw SystemError(errno, "cannot associate stream with file descriptor"); | 
					
						
							| 
									
										
										
										
											2014-06-09 08:33:48 -07:00
										 |  |  |   BufferedFile file(f); | 
					
						
							|  |  |  |   fd_ = -1; | 
					
						
							|  |  |  |   return file; | 
					
						
							|  |  |  | } |