From 948ba4cf498fcc8881a86e545d1e040223274c77 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 14 Aug 2019 13:16:08 +0200 Subject: Use new mkanylink() from libbutl --- build2/cc/windows-rpath.cxx | 72 ++++++++++-------------------------- libbuild2/algorithm.cxx | 77 ++++++++++++++++++++------------------- libbuild2/test/script/builtin.cxx | 2 + 3 files changed, 61 insertions(+), 90 deletions(-) diff --git a/build2/cc/windows-rpath.cxx b/build2/cc/windows-rpath.cxx index 5b49033..2d2e100 100644 --- a/build2/cc/windows-rpath.cxx +++ b/build2/cc/windows-rpath.cxx @@ -306,68 +306,36 @@ namespace build2 // First we try to create a symlink. If that fails (e.g., "Windows // happens"), then we resort to hard links. If that doesn't work // out either (e.g., not on the same filesystem), then we fall back - // to copies. So things are going to get a bit nested. + // to copies. + // + // For the symlink use a relative target path if both paths are part + // of the same amalgamation. This way if the amalgamation is moved + // as a whole, the links will remain valid. // try { - // For the symlink use a relative target path if both paths are - // part of the same amalgamation. This way if the amalgamation is - // moved as a whole, the links will remain valid. - // - if (!dry_run) + switch (mkanylink (f, l, + true /* copy */, + f.sub (as.out_path ()) /* relative */)) { - if (f.sub (as.out_path ())) - mksymlink (f.relative (ad), l); - else - mksymlink (f, l); + case entry_type::regular: print ("cp"); break; + case entry_type::symlink: print ("ln -s"); break; + case entry_type::other: print ("ln"); break; + default: assert (false); } - - print ("ln -s"); } - catch (const system_error& e) + catch (const pair& e) { - // Note: can never end up here on dry-run. - - // Note that we are not guaranteed (here and below) that the - // system_error exception is of the generic category. - // - int c (e.code ().value ()); - if (!(e.code ().category () == generic_category () && - (c == ENOSYS || // Not implemented. - c == EPERM))) // Not supported by the filesystem(s). + const char* w (nullptr); + switch (e.first) { - print ("ln -s"); - fail << "unable to create symlink " << l << ": " << e; + case entry_type::regular: print ("cp"); w = "copy"; break; + case entry_type::symlink: print ("ln -s"); w = "symlink"; break; + case entry_type::other: print ("ln"); w = "hardlink"; break; + default: assert (false); } - try - { - mkhardlink (f, l); - print ("ln"); - } - catch (const system_error& e) - { - c = e.code ().value (); - if (!(e.code ().category () == generic_category () && - (c == ENOSYS || // Not implemented. - c == EPERM || // Not supported by the filesystem(s). - c == EXDEV))) // On different filesystems. - { - print ("ln"); - fail << "unable to create hardlink " << l << ": " << e; - } - - try - { - cpfile (f, l); - print ("cp"); - } - catch (const system_error& e) - { - print ("cp"); - fail << "unable to create copy " << l << ": " << e; - } - } + fail << "unable to make " << w << ' ' << l << ": " << e.second; } }; diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx index 2f59c73..75b0f5a 100644 --- a/libbuild2/algorithm.cxx +++ b/libbuild2/algorithm.cxx @@ -1192,22 +1192,31 @@ namespace build2 try { - // Normally will be there. - // - if (!dry_run) - try_rmbacklink (l, m); - - // Skip (ad hoc) targets that don't exist. - // - if (!(d ? dir_exists (p) : file_exists (p))) - return; - - for (; !dry_run; ) // Retry/fallback loop. try { + // Normally will be there. + // + if (!dry_run) + try_rmbacklink (l, m); + + // Skip (ad hoc) targets that don't exist. + // + if (!(d ? dir_exists (p) : file_exists (p))) + return; + switch (m) { case mode::link: + if (!d) + { + mkanylink (p, l, false /* copy */); + break; + } + // Directory hardlinks are not widely supported so for them we will + // only try the symlink. + // + // Fall through. + case mode::symbolic: mksymlink (p, l, d); break; case mode::hard: mkhardlink (p, l, d); break; case mode::copy: @@ -1225,8 +1234,8 @@ namespace build2 try_mkdir (to); - for (const auto& de: dir_iterator (fr, - false /* ignore_dangling */)) + for (const auto& de: + dir_iterator (fr, false /* ignore_dangling */)) { path f (fr / de.path ()); path t (to / de.path ()); @@ -1241,45 +1250,37 @@ namespace build2 break; } } - - break; // Success. } - catch (const system_error& e) + catch (system_error& e) { - // If symlinks not supported, try a hardlink. + // Translate to mkanylink()-like failure. // - if (m == mode::link) + entry_type t (entry_type::unknown); + switch (m) { - // Note that we are not guaranteed that the system_error exception - // is of the generic category. - // - int c (e.code ().value ()); - if (e.code ().category () == generic_category () && - (c == ENOSYS || // Not implemented. - c == EPERM)) // Not supported by the filesystem(s). - { - m = mode::hard; - continue; - } + case mode::link: + case mode::symbolic: t = entry_type::symlink; break; + case mode::hard: t = entry_type::other; break; + case mode::copy: + case mode::overwrite: t = entry_type::regular; break; } - throw; + throw pair (t, move (e)); } } - catch (const system_error& e) + catch (const pair& e) { const char* w (nullptr); - switch (m) + switch (e.first) { - case mode::link: - case mode::symbolic: w = "symbolic link"; break; - case mode::hard: w = "hard link"; break; - case mode::copy: - case mode::overwrite: w = "copy"; break; + case entry_type::regular: w = "copy"; break; + case entry_type::symlink: w = "symlink"; break; + case entry_type::other: w = "hardlink"; break; + default: assert (false); } print (); - fail << "unable to make " << w << ' ' << l << ": " << e; + fail << "unable to make " << w << ' ' << l << ": " << e.second; } print (); diff --git a/libbuild2/test/script/builtin.cxx b/libbuild2/test/script/builtin.cxx index 2c3d83c..ae979da 100644 --- a/libbuild2/test/script/builtin.cxx +++ b/libbuild2/test/script/builtin.cxx @@ -618,6 +618,8 @@ namespace build2 // either (e.g., not on the same filesystem), then we fall back to // copies. So things are going to get a bit nested. // + // Note: similar to mkanylink() but with support for directories. + // try { mksymlink (target, link, dir); -- cgit v1.1