// file : tests/cpfile/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #include <cassert> #ifndef __cpp_lib_modules_ts #include <ios> #include <string> #include <system_error> #endif // Other includes. #ifdef __cpp_modules_ts #ifdef __cpp_lib_modules_ts import std.core; import std.io; #endif import butl.path; import butl.fdstream; import butl.filesystem; #else #include <libbutl/path.mxx> #include <libbutl/fdstream.mxx> #include <libbutl/filesystem.mxx> #endif using namespace std; using namespace butl; static const char text1[] = "ABCDEF\nXYZ"; static const char text2[] = "12345\nDEF"; static const char text3[] = "XAB\r\n9"; static string from_file (const path& f) { ifdstream ifs (f, fdopen_mode::binary); string s (ifs.read_text ()); ifs.close (); // Not to miss failed close of the underlying file descriptor. return s; } static void to_file (const path& f, const char* s) { ofdstream ofs (f, fdopen_mode::binary); ofs << s; ofs.close (); } int main () { dir_path td (dir_path::temp_directory () / dir_path ("butl-cpfile")); // Recreate the temporary directory (that possibly exists from the previous // faulty run) for the test files. Delete the directory only if the test // succeeds to simplify the failure research. // try_rmdir_r (td); assert (try_mkdir (td) == mkdir_status::success); path from (td / path ("from")); path to (td / path ("to")); // Copy empty file. // to_file (from, ""); cpfile (from, to); assert (from_file (to) == ""); assert (try_rmfile (to) == rmfile_status::success); // Check that content and permissions of newly created destination file are // the same as that ones of the source file. // to_file (from, text1); permissions p (path_permissions (from)); path_permissions (from, permissions::ru | permissions::xu); cpfile (from, to, cpflags::none); assert (from_file (to) == text1); assert (path_permissions (to) == path_permissions (from)); // Check that permissions of an existent destination file stays intact if // their overwrite is not requested. // path_permissions (to, p); cpfile (from, to, cpflags::overwrite_content); assert (from_file (to) == text1); assert (path_permissions (to) == p); // Check that permissions of an existent destination file get overwritten if // requested. // cpfile ( from, to, cpflags::overwrite_content | cpflags::overwrite_permissions); assert (from_file (to) == text1); assert (path_permissions (to) == path_permissions (from)); path_permissions (to, p); path_permissions (from, p); try { cpfile (from, to, cpflags::none); assert (false); } catch (const system_error&) { } // Copy to the directory. // dir_path sd (td / dir_path ("sub")); assert (try_mkdir (sd) == mkdir_status::success); cpfile_into (from, sd, cpflags::none); assert (from_file (sd / path ("from")) == text1); // Check that a hard link to the destination file is preserved. // path hlink (td / path ("hlink")); mkhardlink (to, hlink); to_file (hlink, text1); to_file (from, text2); cpfile (from, to, cpflags::overwrite_content); assert (from_file (hlink) == text2); // Note that on Windows regular file symlinks may not be supported (see // mksymlink() for details), so the following tests are allowed to fail // with ENOSYS on Windows. // try { // Check that 'from' being a symbolic link is properly resolved. // path fslink (td / path ("fslink")); mksymlink (from, fslink); cpfile (fslink, to, cpflags::overwrite_content); // Make sure 'to' is not a symbolic link to 'from' and from_file() just // follows it. // assert (try_rmfile (from) == rmfile_status::success); assert (from_file (to) == text2); // Check that 'to' being a symbolic link is properly resolved. // path tslink (td / path ("tslink")); mksymlink (to, tslink); to_file (from, text3); cpfile (from, tslink, cpflags::overwrite_content); assert (from_file (to) == text3); // Check that permissions are properly overwritten when 'to' is a symbolic // link. // to_file (from, text1); path_permissions (from, permissions::ru | permissions::xu); cpfile ( from, tslink, cpflags::overwrite_content | cpflags::overwrite_permissions); assert (from_file (to) == text1); assert (path_permissions (to) == path_permissions (from)); path_permissions (to, p); path_permissions (from, p); // Check that no-overwrite file copy fails even if 'to' symlink points to // non-existent file. // assert (try_rmfile (to) == rmfile_status::success); try { cpfile (from, tslink, cpflags::none); assert (false); } catch (const system_error&) { } // Check that copy fail if 'from' symlink points to non-existent file. The // std::system_error is thrown as cpfile() fails to obtain permissions for // the 'from' symlink target. // try { cpfile (tslink, from, cpflags::none); assert (false); } catch (const system_error&) { } } catch (const system_error& e) { #ifndef _WIN32 assert (false); #else assert (e.code ().category () == generic_category () && e.code ().value () == ENOSYS); #endif } rmdir_r (td); }