$search
00001 #include <utilmm/system/system.hh> 00002 00003 #include <exception> // for std::exception 00004 #include <sys/types.h> 00005 #include <sys/stat.h> 00006 #include <errno.h> 00007 #include <string.h> // for strerror 00008 #include <unistd.h> // for close 00009 #include <boost/noncopyable.hpp> 00010 #include <boost/filesystem/operations.hpp> 00011 #include <vector> 00012 #include <stdio.h> 00013 00014 using namespace utilmm; 00015 00016 void unix_error::init_description(std::string const& desc) 00017 { 00018 size_t desc_len = desc.length(); 00019 strncpy(m_desc, desc.c_str(), 500); 00020 m_desc[500] = 0; 00021 strcat(m_desc, ": "); 00022 // I wanted to use strerror_r, but no way to force the use 00023 // of the POSIX compliant version 00024 strncat(m_desc, strerror(m_error), 500 - desc_len); 00025 } 00026 unix_error::unix_error(std::string const& desc, int error_ = errno) 00027 : m_error(error_) { init_description(desc); } 00028 unix_error::unix_error(std::string const& desc) 00029 : m_error(errno) { init_description(desc); } 00030 unix_error::unix_error(int error_) 00031 : m_error(error_) { init_description(""); } 00032 unix_error::unix_error() 00033 : m_error(errno) { init_description(""); } 00034 unix_error::~unix_error() throw () {} 00035 00036 int unix_error::error() const { return m_error; } 00037 char const* unix_error::what() const throw() 00038 { return m_desc; } 00039 00040 auto_close::auto_close() 00041 : m_fileno(-1), m_stream(0) {} 00042 auto_close::auto_close(int fileno) 00043 : m_fileno(fileno), m_stream(0) {} 00044 auto_close::auto_close(FILE* stream) 00045 : m_fileno(-1), m_stream(stream) {} 00046 auto_close::~auto_close() { close(); } 00047 00048 void auto_close::close() 00049 { 00050 int ret = 0; 00051 if (m_stream) 00052 ret = fclose(m_stream); 00053 else if (m_fileno != -1) 00054 ret = ::close(m_fileno); 00055 00056 detach(); 00057 00058 if (ret == -1) 00059 throw unix_error(); 00060 } 00061 00062 void auto_close::detach() 00063 { m_fileno = -1; m_stream = 0; } 00064 00065 template<> 00066 FILE* auto_close::handle<FILE*>() const 00067 { 00068 if (m_stream == 0) throw std::bad_cast(); 00069 return m_stream; 00070 } 00071 00072 template<> 00073 int auto_close::handle<int>() const 00074 { 00075 if (m_fileno == -1) throw std::bad_cast(); 00076 return m_fileno; 00077 } 00078 00079 void auto_close::reset(int fileno) 00080 { 00081 close(); 00082 m_fileno = fileno; 00083 } 00084 void auto_close::reset(FILE* stream) 00085 { 00086 close(); 00087 m_stream = stream; 00088 } 00089 00090 00091 00092 00093 00094 FILE* tempfile::create() 00095 { 00096 FILE* fd = tmpfile(); 00097 if (!fd) 00098 throw unix_error(); 00099 return fd; 00100 } 00101 00102 FILE* tempfile::mkstemp(std::string const& base, boost::filesystem::path& path) 00103 { 00104 int const base_length(base.length()); 00105 00106 std::vector<char> value; 00107 value.resize( base_length + 6 + 1 ); 00108 strncpy(&value[0], base.c_str(), base_length); 00109 memset(&value[base_length], 'X', 6); 00110 value[base_length + 6] = '\0'; 00111 00112 int handle = ::mkstemp(&value[0]); 00113 if (handle < 0) 00114 throw unix_error(); 00115 00116 path = std::string(&value[0]); 00117 return fdopen(handle, "w"); 00118 } 00119 00120 tempfile::tempfile(std::string const& base) 00121 : m_path(), m_guard(mkstemp(base, m_path)) 00122 { 00123 if (! handle()) 00124 throw unix_error(); 00125 } 00126 00127 tempfile::tempfile() 00128 : m_guard(create()) {} 00129 00130 tempfile::~tempfile() 00131 { 00132 if (! m_path.empty()) 00133 { 00134 try { 00135 m_guard.close(); 00136 boost::filesystem::remove(m_path); 00137 } catch(...) {} 00138 } 00139 } 00140 00141 FILE* tempfile::handle() const { 00142 if (m_path.empty()) 00143 return 0; 00144 else 00145 return m_guard.handle<FILE*>(); 00146 } 00147 FILE* tempfile::detach() 00148 { 00149 FILE* h = handle(); 00150 m_guard.detach(); 00151 m_path = boost::filesystem::path(); 00152 return h; 00153 } 00154 00155 boost::filesystem::path tempfile::path() const { return m_path; } 00156