From 56e49a09b4f1d268bfee83324bbcd44eb925815b Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 11 Mar 2020 22:50:15 +0300 Subject: Add readsymlink(), followsymlink(), and try_followsymlink() --- tests/link/buildfile | 2 +- tests/link/driver.cxx | 91 ++++++++++++++++++++++++++++++++++++++++++++- tests/link/testscript | 79 +++++++++++++++++++++++++++++++++++++++ tests/path-entry/driver.cxx | 29 ++++++++++----- tests/path-entry/testscript | 21 +++++++---- 5 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 tests/link/testscript (limited to 'tests') diff --git a/tests/link/buildfile b/tests/link/buildfile index 462f60d..9b108b0 100644 --- a/tests/link/buildfile +++ b/tests/link/buildfile @@ -3,4 +3,4 @@ import libs = libbutl%lib{butl} -exe{driver}: {hxx cxx}{*} $libs +exe{driver}: {hxx cxx}{*} $libs testscript diff --git a/tests/link/driver.cxx b/tests/link/driver.cxx index a77df6f..231da4b 100644 --- a/tests/link/driver.cxx +++ b/tests/link/driver.cxx @@ -53,6 +53,12 @@ link_file (const path& target, const path& link, mklink ml, bool check_content) case mklink::hard: mkhardlink (target, link); break; case mklink::any: mkanylink (target, link, true /* copy */); break; } + + pair es (path_entry (link)); + assert (es.first); + + if (es.second.type == entry_type::symlink && readsymlink (link) != target) + return false; } catch (const system_error&) { @@ -87,6 +93,12 @@ link_dir (const dir_path& target, mkhardlink (target, link); else mksymlink (target, link); + + pair es (path_entry (link)); + assert (es.first); + + if (es.second.type == entry_type::symlink) + readsymlink (link); // // Check for errors. } catch (const system_error&) { @@ -120,9 +132,86 @@ link_dir (const dir_path& target, return te == le; } +// Usages: +// +// argv[0] +// argv[0] -s +// argv[0] -f +// +// In the first form run the basic symbolic and hard link tests. +// +// In the second form create a symlink. On error print the diagnostics to +// stderr and exit with the one code. +// +// In the third form follow symlinks and print the resulting target path to +// stdout. On error print the diagnostics to stderr and exit with the one +// code. +// int -main () +main (int argc, const char* argv[]) { + bool create_symlink (false); + bool follow_symlinks (false); + + int i (1); + for (; i != argc; ++i) + { + string v (argv[i]); + + if (v == "-s") + create_symlink = true; + else if (v == "-f") + follow_symlinks = true; + else + break; + } + + if (create_symlink) + { + assert (!follow_symlinks); + assert (i + 2 == argc); + + try + { + path t (argv[i]); + path l (argv[i + 1]); + + bool dir (dir_exists (t.relative () ? l.directory () / t : t)); + mksymlink (t, l, dir); + + path lt (readsymlink (l)); + + // The targets may only differ for Windows directory junctions. + // + assert (lt == t || dir); + + return 0; + } + catch (const system_error& e) + { + cerr << "error: " << e << endl; + return 1; + } + } + else if (follow_symlinks) + { + assert (!create_symlink); + assert (i + 1 == argc); + + try + { + cout << try_followsymlink (path (argv[i])).first << endl; + return 0; + } + catch (const system_error& e) + { + cerr << "error: " << e << endl; + return 1; + } + } + else + assert (i == argc); + dir_path td (dir_path::temp_directory () / dir_path ("butl-link")); // Recreate the temporary directory (that possibly exists from the previous diff --git a/tests/link/testscript b/tests/link/testscript new file mode 100644 index 0000000..194b093 --- /dev/null +++ b/tests/link/testscript @@ -0,0 +1,79 @@ +# file : tests/link/testscript +# license : MIT; see accompanying LICENSE file + +: basics +: +$* + +: follow-symlinks +: +: Note that we may not be able to create symlinks on Windows and so test on +: POSIX only. But that'is ok since the follow_symlinks() implementation is not +: platform-specific. +: +if ($cxx.target.class != 'windows') +{ + : not-symlink + : + { + touch f; + $* -f f >f + } + + : not-exists + : + { + $* -f f >f + } + + : single-link + : + { + : absolute + : + { + $* -s $~/f l &l; + $* -f l >/"$~/f" + } + + : relative + : + { + $* -s d/f l &l; + $* -f l >/'d/f' + } + } + + : multiple-links + : + { + : relative-path + : + { + mkdir -p d1/d2; + $* -s ../d3/f d1/d2/l1 &d1/d2/l1; + + $* -f d1/d2/l1 >/'d1/d3/f'; + $* -f ../relative-path/d1/d2/l1 >/'../relative-path/d1/d3/f'; + + mkdir d4; + $* -s ../d1/d2/l1 d4/l2 &d4/l2; + + $* -f d4/l2 >/'d1/d3/f'; + $* -f $~/d4/l2 >/"$~/d1/d3/f" + } + + : absolute-path + : + { + mkdir -p d1/d2; + $* -s ../d3/f d1/d2/l1 &d1/d2/l1; + + mkdir d4; + $* -s $~/d1/d2/l1 d4/l2 &d4/l2; + + $* -f d4/l2 >/"$~/d1/d3/f"; + $* -f $~/d4/l2 >/"$~/d1/d3/f" + } + } +} diff --git a/tests/path-entry/driver.cxx b/tests/path-entry/driver.cxx index 51ac04d..30aae92 100644 --- a/tests/path-entry/driver.cxx +++ b/tests/path-entry/driver.cxx @@ -18,12 +18,14 @@ import std.core; import std.io; #endif import butl.path; +import butl.path-io; import butl.utility; // operator<<(ostream, exception) import butl.optional; import butl.timestamp; import butl.filesystem; #else #include +#include #include #include #include @@ -36,11 +38,12 @@ using namespace butl; // Usage: argv[0] [-l] [-t] [-p ] [-m