diff --git a/lix/libutil/args.cc b/lix/libutil/args.cc index e6f88f346..08d0f66b5 100644 --- a/lix/libutil/args.cc +++ b/lix/libutil/args.cc @@ -9,6 +9,7 @@ #include "lix/libutil/logging.hh" +#include #include namespace nix { @@ -395,8 +396,19 @@ static bool isAcceptableLixSubcommandExe(const std::filesystem::path & exe_path) { namespace fs = std::filesystem; - return fs::is_regular_file(exe_path) && - (fs::status(exe_path).permissions() & (fs::perms::owner_exec | fs::perms::group_exec | fs::perms::others_exec)) != fs::perms::none; + try { + return fs::is_regular_file(exe_path) + && (fs::status(exe_path).permissions() + & (fs::perms::owner_exec | fs::perms::group_exec | fs::perms::others_exec)) + != fs::perms::none; + } catch (fs::filesystem_error & fs_exc) { // NOLINT(lix-foreign-exceptions) + if (fs_exc.code() != std::errc::no_such_file_or_directory + && fs_exc.code() != std::errc::not_a_directory && fs_exc.code() != std::errc::permission_denied) + { + throw Error("%s", Uncolored(fs_exc.what())); + } + return false; + } } std::optional> searchForCustomSubcommand(AsyncIoRoot & aio, const std::string_view & command, const std::string_view & prefix, const Strings & searchPaths) @@ -412,10 +424,10 @@ std::optional> searchForCustomSubcommand(AsyncIoRoot & aio, const s debug("Found requested external subcommand '%s' in '%s'", command, path); return make_ref(aio, path); } - } catch (fs::filesystem_error & fs_exc) { // NOLINT(lix-foreign-exceptions) - if (fs_exc.code() != std::errc::no_such_file_or_directory && fs_exc.code() != std::errc::not_a_directory && fs_exc.code() != std::errc::permission_denied) { - throw SysError("while searching for the subcommand '%1%' in search path '%2%': '%3%'", command, searchPath, fs_exc.what()); - } + } catch (Error & exc) { + exc.addTrace( + {}, "while searching for the subcommand '%1%' in search path '%2%'", command, searchPath + ); } } @@ -430,33 +442,42 @@ Strings searchForAllAvailableCustomSubcommands(const std::string_view & prefix, for (auto searchPath : searchPaths) { if (searchPath.empty()) continue; - if (!fs::exists(searchPath) || !fs::is_directory(searchPath)) { - // TODO(Raito): this will break all the time our functional tests - // for people with garbage in their $PATH which is my personal case. + try { + if (!fs::exists(searchPath) || !fs::is_directory(searchPath)) { + // TODO(Raito): this will break all the time our functional tests + // for people with garbage in their $PATH which is my personal case. - // warn("The search path '%s' for custom subcommands does not exist or is not a directory, ignoring...", searchPath); - continue; - } + // warn("The search path '%s' for custom subcommands does not exist or is not a directory, + // ignoring...", searchPath); + continue; + } - // Browse per prefix. - for (const auto& entry : fs::directory_iterator(searchPath)) { - try { - if (isAcceptableLixSubcommandExe(entry.path())) { - auto filename = entry.path().filename().string(); + // Browse per prefix. + for (const auto & entry : fs::directory_iterator(searchPath)) { + try { + if (isAcceptableLixSubcommandExe(entry.path())) { + auto filename = entry.path().filename().string(); - if (filename.starts_with(prefix)) { - auto suffix = filename.substr(prefix.size()); + if (filename.starts_with(prefix)) { + auto suffix = filename.substr(prefix.size()); - debug("Found custom subcommand ('%s') '%s'", filename, suffix); + debug("Found custom subcommand ('%s') '%s'", filename, suffix); - commandNames.push_back(suffix); + commandNames.push_back(suffix); + } } - } - } catch (fs::filesystem_error & fs_exc) { // NOLINT(lix-foreign-exceptions) - if (fs_exc.code() != std::errc::no_such_file_or_directory && fs_exc.code() != std::errc::not_a_directory && fs_exc.code() != std::errc::permission_denied) { - throw SysError("while searching for all available commands in search path '%1%', while analyzing '%2%': %3%'", searchPath, entry.path(), fs_exc.what()); + } catch (Error & exc) { + exc.addTrace( + {}, + "while searching for all available commands in search path '%1%', while analyzing " + "'%2%'", + searchPath, + entry.path() + ); } } + } catch (fs::filesystem_error & exc) { // NOLINT(lix-foreign-exceptions) + throw Error("failed to look up available subcommands in %s: %s", searchPath, exc.what()); } } diff --git a/lix/libutil/file-system.cc b/lix/libutil/file-system.cc index 1beccf7ee..0e688ec20 100644 --- a/lix/libutil/file-system.cc +++ b/lix/libutil/file-system.cc @@ -767,7 +767,7 @@ void setWriteTime(const fs::path & p, const struct stat & st) } void copy(const fs::directory_entry & from, const fs::path & to, CopyFileFlags flags) -{ +try { // TODO: Rewrite the `is_*` to use `symlink_status()` auto statOfFrom = lstat(from.path()); auto fromStatus = from.symlink_status(); @@ -801,9 +801,10 @@ void copy(const fs::directory_entry & from, const fs::path & to, CopyFileFlags f fs::permissions(from.path(), fs::perms::owner_write, fs::perm_options::add | fs::perm_options::nofollow); fs::remove(from.path()); } +} catch (fs::filesystem_error & e) { // NOLINT(lix-foreign-exceptions) + throw Error("failed to copy %s to %s: %s", from.path(), to, e.what()); } - void copyFile(const Path & oldPath, const Path & newPath, CopyFileFlags flags) { return copy(fs::directory_entry(fs::path(oldPath)), fs::path(newPath), flags); @@ -811,28 +812,35 @@ void copyFile(const Path & oldPath, const Path & newPath, CopyFileFlags flags) void renameFile(const Path & oldName, const Path & newName) { - fs::rename(oldName, newName); + try { + fs::rename(oldName, newName); + } catch (fs::filesystem_error & e) { // NOLINT(lix-foreign-exceptions) + throw Error("failed to rename %s to %s: %s", oldName, newName, e.what()); + } } void moveFile(const Path & oldName, const Path & newName) { try { - renameFile(oldName, newName); + fs::rename(oldName, newName); } catch (fs::filesystem_error & e) { // NOLINT(lix-foreign-exceptions) auto oldPath = fs::path(oldName); auto newPath = fs::path(newName); // For the move to be as atomic as possible, copy to a temporary // directory - fs::path temp = createTempSubdir(newPath.parent_path(), "rename-tmp"); - Finally removeTemp = [&]() { fs::remove(temp); }; - auto tempCopyTarget = temp / "copy-target"; - if (e.code().value() == EXDEV) { - fs::remove(newPath); - printTaggedWarning("Can’t rename %s as %s, copying instead", oldName, newName); - copy(fs::directory_entry(oldPath), tempCopyTarget, { .deleteAfter = true }); - renameFile(tempCopyTarget, newPath); + try { + fs::path temp = createTempSubdir(newPath.parent_path(), "rename-tmp"); + Finally removeTemp = [&]() { fs::remove(temp); }; + auto tempCopyTarget = temp / "copy-target"; + if (e.code().value() == EXDEV) { + fs::remove(newPath); + printTaggedWarning("Can’t rename %s as %s, copying instead", oldName, newName); + copy(fs::directory_entry(oldPath), tempCopyTarget, {.deleteAfter = true}); + fs::rename(tempCopyTarget, newPath); + } + } catch (fs::filesystem_error & e) { // NOLINT(lix-foreign-exceptions) + throw Error("failed to move %s to %s: %s", oldName, newName, e.what()); } } } - }