aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/filesystem.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/filesystem.cxx')
-rw-r--r--libbuild2/filesystem.cxx138
1 files changed, 113 insertions, 25 deletions
diff --git a/libbuild2/filesystem.cxx b/libbuild2/filesystem.cxx
index fbe145c..f340dd7 100644
--- a/libbuild2/filesystem.cxx
+++ b/libbuild2/filesystem.cxx
@@ -15,7 +15,12 @@ namespace build2
touch (context& ctx, const path& p, bool create, uint16_t v)
{
if (verb >= v)
- text << "touch " << p;
+ {
+ if (verb >= 2)
+ text << "touch " << p;
+ else if (verb)
+ print_diag ("touch", p);
+ }
if (ctx.dry_run)
return;
@@ -50,25 +55,30 @@ namespace build2
// We don't want to print the command if the directory already exists.
// This makes the below code a bit ugly.
//
- mkdir_status ms;
+ auto print = [v, &d] (bool ovr)
+ {
+ if (verb >= v || ovr)
+ {
+ if (verb >= 2)
+ text << "mkdir " << d;
+ else if (verb)
+ print_diag ("mkdir", d);
+ }
+ };
+ mkdir_status ms;
try
{
ms = try_mkdir (d);
}
catch (const system_error& e)
{
- if (verb >= v)
- text << "mkdir " << d;
-
+ print (true);
fail << "unable to create directory " << d << ": " << e << endf;
}
if (ms == mkdir_status::success)
- {
- if (verb >= v)
- text << "mkdir " << d;
- }
+ print (false);
return ms;
}
@@ -79,25 +89,30 @@ namespace build2
// We don't want to print the command if the directory already exists.
// This makes the below code a bit ugly.
//
- mkdir_status ms;
+ auto print = [v, &d] (bool ovr)
+ {
+ if (verb >= v || ovr)
+ {
+ if (verb >= 2)
+ text << "mkdir -p " << d;
+ else if (verb)
+ print_diag ("mkdir -p", d);
+ }
+ };
+ mkdir_status ms;
try
{
ms = try_mkdir_p (d);
}
catch (const system_error& e)
{
- if (verb >= v)
- text << "mkdir -p " << d;
-
+ print (true);
fail << "unable to create directory " << d << ": " << e << endf;
}
if (ms == mkdir_status::success)
- {
- if (verb >= v)
- text << "mkdir -p " << d;
- }
+ print (false);
return ms;
}
@@ -106,7 +121,12 @@ namespace build2
mvfile (const path& f, const path& t, uint16_t v)
{
if (verb >= v)
- text << "mv " << f << ' ' << t;
+ {
+ if (verb >= 2)
+ text << "mv " << f << ' ' << t;
+ else if (verb)
+ print_diag ("mv", f, t);
+ }
try
{
@@ -126,10 +146,18 @@ namespace build2
fs_status<rmfile_status>
rmsymlink (context& ctx, const path& p, bool d, uint16_t v)
{
- auto print = [&p, v] ()
+ auto print = [&p, v] (bool ovr)
{
- if (verb >= v)
- text << "rm " << p.string ();
+ if (verb >= v || ovr)
+ {
+ // Note: strip trailing directory separator (but keep as path for
+ // relative).
+ //
+ if (verb >= 2)
+ text << "rm " << p.string ();
+ else if (verb)
+ print_diag ("rm", p.to_directory () ? path (p.string ()) : p);
+ }
};
rmfile_status rs;
@@ -144,12 +172,12 @@ namespace build2
}
catch (const system_error& e)
{
- print ();
+ print (true);
fail << "unable to remove symlink " << p.string () << ": " << e << endf;
}
if (rs == rmfile_status::success)
- print ();
+ print (false);
return rs;
}
@@ -166,7 +194,12 @@ namespace build2
return rmdir_status::not_exist;
if (verb >= v)
- text << "rmdir -r " << d;
+ {
+ if (verb >= 2)
+ text << "rmdir -r " << d;
+ else if (verb)
+ print_diag ("rmdir -r", d);
+ }
if (!ctx.dry_run)
{
@@ -258,7 +291,7 @@ namespace build2
{
try
{
- for (const dir_entry& de: dir_iterator (d, false /* ignore_dangling */))
+ for (const dir_entry& de: dir_iterator (d, dir_iterator::no_follow))
{
// The .buildignore filesystem entry should be of the regular file
// type.
@@ -323,4 +356,59 @@ namespace build2
fail << "unable to set path " << p << " permissions: " << e;
}
}
+
+ void
+ normalize_external (path& f, const char* what)
+ {
+ // The main motivating case for this logic are C/C++ headers.
+ //
+ // Interestingly, on most paltforms and with most compilers (Clang on
+ // Linux being a notable exception) most system/compiler headers are
+ // already normalized.
+ //
+ path_abnormality a (f.abnormalities ());
+ if (a != path_abnormality::none)
+ {
+ // While we can reasonably expect this path to exit, things do go south
+ // from time to time (like compiling under wine with file wlantypes.h
+ // included as WlanTypes.h).
+ //
+ try
+ {
+ // If we have any parent components, then we have to verify the
+ // normalized path matches realized.
+ //
+ path r;
+ if ((a & path_abnormality::parent) == path_abnormality::parent)
+ {
+ r = f;
+ r.realize ();
+ }
+
+ try
+ {
+ f.normalize ();
+
+ // Note that we might still need to resolve symlinks in the
+ // normalized path.
+ //
+ if (!r.empty () && f != r && path (f).realize () != r)
+ f = move (r);
+ }
+ catch (const invalid_path&)
+ {
+ assert (!r.empty ()); // Shouldn't have failed if no `..`.
+ f = move (r); // Fallback to realize.
+ }
+ }
+ catch (const invalid_path&)
+ {
+ fail << "invalid " << what << " path '" << f.string () << "'";
+ }
+ catch (const system_error& e)
+ {
+ fail << "invalid " << what << " path '" << f.string () << "': " << e;
+ }
+ }
+ }
}