From 3f2323dae243d7654d3319fe7f53b87062b0d62e Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 17 Feb 2017 09:27:02 +0000 Subject: Fix cpfile() to throw system_error only --- butl/fdstream.cxx | 9 ++++---- butl/filesystem.cxx | 58 ++++++++++++++++++++++++++++++++++++++++++------- tests/cpfile/driver.cxx | 4 ++-- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/butl/fdstream.cxx b/butl/fdstream.cxx index e28eb0f..bdbfa08 100644 --- a/butl/fdstream.cxx +++ b/butl/fdstream.cxx @@ -39,8 +39,8 @@ namespace butl // throw_ios_failure // template - static inline void - throw_ios_failure (error_code e, typename enable_if::type m) + static inline typename enable_if::type + throw_ios_failure (error_code e, const char* m) { // The idea here is to make an error code to be saved into failure // exception and to make a string returned by what() to contain the error @@ -57,9 +57,8 @@ namespace butl } template - static inline void - throw_ios_failure (error_code e, - typename enable_if::type m) + static inline typename enable_if::type + throw_ios_failure (error_code e, const char* m) { throw ios_base::failure (m != nullptr ? m : e.message ().c_str ()); } diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx index 1553324..e792bef 100644 --- a/butl/filesystem.cxx +++ b/butl/filesystem.cxx @@ -288,10 +288,18 @@ namespace butl } #endif - void - cpfile (const path& from, const path& to, cpflags fl) + // For I/O operations cpfile() can throw ios_base::failure exception that is + // not derived from system_error for old versions of g++ (as of 4.9). From + // the other hand cpfile() must throw system_error only. Let's catch + // ios_base::failure and rethrow as system_error in such a case. + // + template + static inline typename enable_if::type + cpfile (const path& from, const path& to, + cpflags fl, + permissions perm, + auto_rmfile& rm) { - permissions perm (path_permissions (from)); ifdstream ifs (from, fdopen_mode::binary); fdopen_mode om (fdopen_mode::out | @@ -302,11 +310,6 @@ namespace butl if ((fl & cpflags::overwrite_content) != cpflags::overwrite_content) om |= fdopen_mode::exclusive; - // Create prior to the output file stream creation so that the file is - // removed after it is closed. - // - auto_rmfile rm; - ofdstream ofs (fdopen (to, om, perm)); rm = auto_rmfile (to); @@ -321,6 +324,45 @@ namespace butl ifs.close (); // Throws ios::failure on failure. ofs.close (); // Throws ios::failure on flush/close failure. + } + + template + static inline typename enable_if::type + cpfile (const path& from, const path& to, + cpflags fl, + permissions perm, + auto_rmfile& rm) + { + try + { + cpfile (from, to, fl, perm, rm); + } + catch (const ios_base::failure& e) + { + // While we try to preserve the original error information, we can not + // make the description to be exactly the same, for example + // + // Is a directory + // + // becomes + // + // Is a directory: Input/output error + // + // Note that our custom operator<<(ostream, exception) doesn't strip this + // suffix. This is a temporary code after all. + // + throw system_error (EIO, system_category (), e.what ()); + } + } + + void + cpfile (const path& from, const path& to, cpflags fl) + { + permissions perm (path_permissions (from)); + auto_rmfile rm; + + cpfile::value> ( + from, to, fl, perm, rm); if ((fl & cpflags::overwrite_permissions) == cpflags::overwrite_permissions) diff --git a/tests/cpfile/driver.cxx b/tests/cpfile/driver.cxx index 7276405..732b364 100644 --- a/tests/cpfile/driver.cxx +++ b/tests/cpfile/driver.cxx @@ -101,7 +101,7 @@ main () cpfile (from, to, cpflags::none); assert (false); } - catch (const ios::failure&) + catch (const system_error&) { } @@ -174,7 +174,7 @@ main () cpfile (from, tslink, cpflags::none); assert (false); } - catch (const ios::failure&) + catch (const system_error&) { } -- cgit v1.1