// file : tests/cpfile/driver.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include <ios> #include <string> #include <cassert> #include <system_error> #include <butl/path> #include <butl/fdstream> #include <butl/filesystem> 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, ios::binary); string s; // Note that the eof check is important: if the stream is at eof (empty // file) then getline() will fail. // if (ifs.peek () != ifdstream::traits_type::eof ()) getline (ifs, s, '\0'); 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, ios::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); #ifndef _WIN32 // 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&) { } #endif rmdir_r (td); }