diff options
Diffstat (limited to 'libbuild2/filesystem.cxx')
-rw-r--r-- | libbuild2/filesystem.cxx | 138 |
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; + } + } + } } |