Compare commits
4 Commits
cloneable-
...
system-err
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f3de0f3e5 | ||
|
|
bbcf2041e1 | ||
|
|
96bcf5928f | ||
|
|
db853cf4fb |
@@ -9,9 +9,3 @@ endif
|
||||
if 'address' in get_option('b_sanitize')
|
||||
deps_other += declare_dependency(sources : 'asan-options.cc')
|
||||
endif
|
||||
|
||||
if 'undefined' in get_option('b_sanitize')
|
||||
add_project_arguments('-DNIX_UBSAN_ENABLED=1', language : 'cpp')
|
||||
else
|
||||
add_project_arguments('-DNIX_UBSAN_ENABLED=0', language : 'cpp')
|
||||
endif
|
||||
|
||||
@@ -710,7 +710,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS)
|
||||
try {
|
||||
cwd = std::filesystem::current_path();
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
throw SysError("cannot determine current working directory");
|
||||
throw SystemError(e.code(), "cannot determine current working directory");
|
||||
}
|
||||
|
||||
auto flakeRef = parseFlakeRef(fetchSettings, flakeRefS, cwd.string(), true);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace nix::eval_cache {
|
||||
|
||||
CachedEvalError::CachedEvalError(ref<AttrCursor> cursor, Symbol attr)
|
||||
: CloneableError(cursor->root->state, "cached failure of attribute '%s'", cursor->getAttrPathStr(attr))
|
||||
: EvalError(cursor->root->state, "cached failure of attribute '%s'", cursor->getAttrPathStr(attr))
|
||||
, cursor(cursor)
|
||||
, attr(attr)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace nix::eval_cache {
|
||||
struct AttrDb;
|
||||
class AttrCursor;
|
||||
|
||||
struct CachedEvalError : CloneableError<CachedEvalError, EvalError>
|
||||
struct CachedEvalError : EvalError
|
||||
{
|
||||
const ref<AttrCursor> cursor;
|
||||
const Symbol attr;
|
||||
|
||||
@@ -18,7 +18,7 @@ class EvalErrorBuilder;
|
||||
*
|
||||
* Most subclasses should inherit from `EvalError` instead of this class.
|
||||
*/
|
||||
class EvalBaseError : public CloneableError<EvalBaseError, Error>
|
||||
class EvalBaseError : public Error
|
||||
{
|
||||
template<class T>
|
||||
friend class EvalErrorBuilder;
|
||||
@@ -26,14 +26,14 @@ public:
|
||||
EvalState & state;
|
||||
|
||||
EvalBaseError(EvalState & state, ErrorInfo && errorInfo)
|
||||
: CloneableError(errorInfo)
|
||||
: Error(errorInfo)
|
||||
, state(state)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
explicit EvalBaseError(EvalState & state, const std::string & formatString, const Args &... formatArgs)
|
||||
: CloneableError(formatString, formatArgs...)
|
||||
: Error(formatString, formatArgs...)
|
||||
, state(state)
|
||||
{
|
||||
}
|
||||
@@ -60,23 +60,23 @@ MakeError(InfiniteRecursionError, EvalError);
|
||||
* Inherits from EvalBaseError (not EvalError) because resource exhaustion
|
||||
* should not be cached.
|
||||
*/
|
||||
struct StackOverflowError : public CloneableError<StackOverflowError, EvalBaseError>
|
||||
struct StackOverflowError : public EvalBaseError
|
||||
{
|
||||
StackOverflowError(EvalState & state)
|
||||
: CloneableError(state, "stack overflow; max-call-depth exceeded")
|
||||
: EvalBaseError(state, "stack overflow; max-call-depth exceeded")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
MakeError(IFDError, EvalBaseError);
|
||||
|
||||
struct InvalidPathError : public CloneableError<InvalidPathError, EvalError>
|
||||
struct InvalidPathError : public EvalError
|
||||
{
|
||||
public:
|
||||
Path path;
|
||||
|
||||
InvalidPathError(EvalState & state, const Path & path)
|
||||
: CloneableError(state, "path '%s' is not valid", path)
|
||||
: EvalError(state, "path '%s' is not valid", path)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
class BadNixStringContextElem final : public CloneableError<BadNixStringContextElem, Error>
|
||||
class BadNixStringContextElem : public Error
|
||||
{
|
||||
public:
|
||||
std::string_view raw;
|
||||
|
||||
template<typename... Args>
|
||||
BadNixStringContextElem(std::string_view raw_, const Args &... args)
|
||||
: CloneableError("")
|
||||
: Error("")
|
||||
{
|
||||
raw = raw_;
|
||||
auto hf = HintFmt(args...);
|
||||
|
||||
@@ -1312,12 +1312,11 @@ static void prim_warn(EvalState & state, const PosIdx pos, Value ** args, Value
|
||||
state.forceString(*args[0], pos, "while evaluating the first argument; the message passed to builtins.warn");
|
||||
|
||||
{
|
||||
ErrorInfo info{
|
||||
.level = lvlWarn,
|
||||
.msg = HintFmt(std::string(msgStr)),
|
||||
.pos = state.positions[pos],
|
||||
.isFromExpr = true,
|
||||
};
|
||||
BaseError msg(std::string{msgStr});
|
||||
msg.atPos(state.positions[pos]);
|
||||
auto info = msg.info();
|
||||
info.level = lvlWarn;
|
||||
info.isFromExpr = true;
|
||||
logWarning(info);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,11 +74,11 @@ namespace nix {
|
||||
|
||||
struct GitSourceAccessor;
|
||||
|
||||
struct GitError final : public CloneableError<GitError, Error>
|
||||
struct GitError : public Error
|
||||
{
|
||||
template<typename... Ts>
|
||||
GitError(const git_error & error, Ts &&... args)
|
||||
: CloneableError("")
|
||||
: Error("")
|
||||
{
|
||||
auto hf = HintFmt(std::forward<Ts>(args)...);
|
||||
err.msg = HintFmt("%1%: %2% (libgit2 error code = %3%)", Uncolored(hf.str()), error.message, error.klass);
|
||||
@@ -247,7 +247,8 @@ static void initRepoAtomically(std::filesystem::path & path, GitRepo::Options op
|
||||
|| e.code() == std::errc::directory_not_empty) {
|
||||
return;
|
||||
} else
|
||||
throw SysError("moving temporary git repository from %s to %s", PathFmt(tmpDir), PathFmt(path));
|
||||
throw SystemError(
|
||||
e.code(), "moving temporary git repository from %s to %s", PathFmt(tmpDir), PathFmt(path));
|
||||
}
|
||||
// we successfully moved the repository, so the temporary directory no longer exists.
|
||||
delTmpDir.cancel();
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace nix {
|
||||
|
||||
AwsAuthError::AwsAuthError(int errorCode)
|
||||
: CloneableError("AWS authentication error: '%s' (%d)", aws_error_str(errorCode), errorCode)
|
||||
: Error("AWS authentication error: '%s' (%d)", aws_error_str(errorCode), errorCode)
|
||||
, errorCode(errorCode)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "nix/store/build/goal.hh"
|
||||
#include "nix/store/build/worker.hh"
|
||||
#include "nix/store/worker-settings.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TimedOut::TimedOut(time_t maxDuration)
|
||||
: CloneableError(BuildResult::Failure::TimedOut, "timed out after %1% seconds", maxDuration)
|
||||
: BuildError(BuildResult::Failure::TimedOut, "timed out after %1% seconds", maxDuration)
|
||||
, maxDuration(maxDuration)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ static void builtinUnpackChannel(const BuiltinBuilderContext & ctx)
|
||||
auto target = out / channelName;
|
||||
try {
|
||||
std::filesystem::rename(fileName, target);
|
||||
} catch (std::filesystem::filesystem_error &) {
|
||||
throw SysError("failed to rename %1% to %2%", fileName, target.string());
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
throw SystemError(e.code(), "failed to rename %1% to %2%", fileName, target.string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,12 +60,12 @@ namespace {
|
||||
using curlSList = std::unique_ptr<::curl_slist, decltype([](::curl_slist * list) { ::curl_slist_free_all(list); })>;
|
||||
using curlMulti = std::unique_ptr<::CURLM, decltype([](::CURLM * multi) { ::curl_multi_cleanup(multi); })>;
|
||||
|
||||
struct curlMultiError final : CloneableError<curlMultiError, Error>
|
||||
struct curlMultiError : Error
|
||||
{
|
||||
::CURLMcode code;
|
||||
|
||||
curlMultiError(::CURLMcode code)
|
||||
: CloneableError{"unexpected curl multi error: %s", ::curl_multi_strerror(code)}
|
||||
: Error{"unexpected curl multi error: %s", ::curl_multi_strerror(code)}
|
||||
{
|
||||
assert(code != CURLM_OK);
|
||||
}
|
||||
@@ -1212,7 +1212,7 @@ void FileTransfer::download(
|
||||
template<typename... Args>
|
||||
FileTransferError::FileTransferError(
|
||||
FileTransfer::Error error, std::optional<std::string> response, const Args &... args)
|
||||
: CloneableError(args...)
|
||||
: Error(args...)
|
||||
, error(error)
|
||||
, response(response)
|
||||
{
|
||||
|
||||
@@ -272,7 +272,7 @@ void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, R
|
||||
|| e.code() == std::errc::not_a_directory)
|
||||
printInfo("cannot read potential root '%1%'", path);
|
||||
else
|
||||
throw;
|
||||
throw SystemError(e.code(), "finding GC roots in '%1%'", path);
|
||||
}
|
||||
|
||||
catch (SystemError & e) {
|
||||
|
||||
@@ -34,13 +34,12 @@ struct AwsCredentials
|
||||
}
|
||||
};
|
||||
|
||||
class AwsAuthError final : public CloneableError<AwsAuthError, Error>
|
||||
class AwsAuthError : public Error
|
||||
{
|
||||
std::optional<int> errorCode;
|
||||
|
||||
public:
|
||||
using CloneableError::CloneableError;
|
||||
|
||||
using Error::Error;
|
||||
AwsAuthError(int errorCode);
|
||||
|
||||
std::optional<int> getErrorCode() const
|
||||
|
||||
@@ -58,7 +58,7 @@ enum struct BuildResultFailureStatus : uint8_t {
|
||||
* This is both an exception type (inherits from Error) and serves as
|
||||
* the failure variant in BuildResult::inner.
|
||||
*/
|
||||
struct BuildError : public CloneableError<BuildError, Error>
|
||||
struct BuildError : public Error
|
||||
{
|
||||
using Status = BuildResultFailureStatus;
|
||||
using enum Status;
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
BuildError(Status status, const Args &... args)
|
||||
: CloneableError(args...)
|
||||
: Error(args...)
|
||||
, status{status}
|
||||
{
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
* Also used for deserialization.
|
||||
*/
|
||||
BuildError(Args args)
|
||||
: CloneableError(std::move(args.msg))
|
||||
: Error(std::move(args.msg))
|
||||
, status{args.status}
|
||||
, isNonDeterministic{args.isNonDeterministic}
|
||||
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
* Default constructor for deserialization.
|
||||
*/
|
||||
BuildError()
|
||||
: CloneableError("")
|
||||
: Error("")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,14 @@ namespace nix {
|
||||
* Denotes a build failure that stemmed from the builder exiting with a
|
||||
* failing exist status.
|
||||
*/
|
||||
struct BuilderFailureError final : CloneableError<BuilderFailureError, BuildError>
|
||||
struct BuilderFailureError : BuildError
|
||||
{
|
||||
int builderStatus;
|
||||
|
||||
std::string extraMsgAfter;
|
||||
|
||||
BuilderFailureError(BuildResult::Failure::Status status, int builderStatus, std::string extraMsgAfter)
|
||||
: CloneableError{
|
||||
: BuildError{
|
||||
status,
|
||||
/* No message for now, because the caller will make for
|
||||
us, with extra context */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct TimedOut final : CloneableError<TimedOut, BuildError>
|
||||
struct TimedOut : BuildError
|
||||
{
|
||||
time_t maxDuration;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Package
|
||||
}
|
||||
};
|
||||
|
||||
class BuildEnvFileConflictError final : public CloneableError<BuildEnvFileConflictError, Error>
|
||||
class BuildEnvFileConflictError : public Error
|
||||
{
|
||||
public:
|
||||
const Path fileA;
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
int priority;
|
||||
|
||||
BuildEnvFileConflictError(const Path fileA, const Path fileB, int priority)
|
||||
: CloneableError(
|
||||
: Error(
|
||||
"Unable to build profile. There is a conflict for the following files:\n"
|
||||
"\n"
|
||||
" %1%\n"
|
||||
|
||||
@@ -403,7 +403,7 @@ ref<FileTransfer> getFileTransfer();
|
||||
*/
|
||||
ref<FileTransfer> makeFileTransfer(const FileTransferSettings & settings = fileTransferSettings);
|
||||
|
||||
class FileTransferError final : public CloneableError<FileTransferError, Error>
|
||||
class FileTransferError : public Error
|
||||
{
|
||||
public:
|
||||
FileTransfer::Error error;
|
||||
|
||||
@@ -146,7 +146,7 @@ struct RealisedPath
|
||||
auto operator<=>(const RealisedPath &) const = default;
|
||||
};
|
||||
|
||||
class MissingRealisation final : public CloneableError<MissingRealisation, Error>
|
||||
class MissingRealisation : public Error
|
||||
{
|
||||
public:
|
||||
MissingRealisation(DrvOutput & outputId)
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
}
|
||||
|
||||
MissingRealisation(std::string_view drv, OutputName outputName)
|
||||
: CloneableError(
|
||||
: Error(
|
||||
"cannot operate on output '%s' of the "
|
||||
"unbuilt derivation '%s'",
|
||||
outputName,
|
||||
|
||||
@@ -166,7 +166,7 @@ struct SQLiteTxn
|
||||
~SQLiteTxn();
|
||||
};
|
||||
|
||||
struct SQLiteError : CloneableError<SQLiteError, Error>
|
||||
struct SQLiteError : Error
|
||||
{
|
||||
std::string path;
|
||||
std::string errMsg;
|
||||
|
||||
@@ -35,7 +35,7 @@ static void readProcLink(const std::filesystem::path & file, UncheckedRoots & ro
|
||||
if (e.code() == std::errc::no_such_file_or_directory || e.code() == std::errc::permission_denied
|
||||
|| e.code() == std::errc::no_such_process)
|
||||
return;
|
||||
throw;
|
||||
throw SystemError(e.code(), "reading symlink '%s'", PathFmt(file));
|
||||
}
|
||||
if (buf.is_absolute())
|
||||
roots[buf.string()].emplace(file.string());
|
||||
|
||||
@@ -111,8 +111,8 @@ static std::vector<std::string> expandBuilderLines(const std::string & builders)
|
||||
std::string text;
|
||||
try {
|
||||
text = readFile(path);
|
||||
} catch (const SysError & e) {
|
||||
if (e.errNo != ENOENT)
|
||||
} catch (const SystemError & e) {
|
||||
if (!e.is(std::errc::no_such_file_or_directory))
|
||||
throw;
|
||||
debug("cannot find machines file '%s'", path);
|
||||
continue;
|
||||
|
||||
@@ -202,14 +202,13 @@ void LocalStore::optimisePath_(
|
||||
full. When that happens, it's fine to ignore it: we
|
||||
just effectively disable deduplication of this
|
||||
file.
|
||||
TODO: Get rid of errno, use error code.
|
||||
*/
|
||||
printInfo("cannot link %s to '%s': %s", PathFmt(linkPath), path, strerror(errno));
|
||||
printInfo("cannot link %s to '%s': %s", PathFmt(linkPath), path, e.code().message());
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
throw;
|
||||
throw SystemError(e.code(), "creating hard link from %1% to %2%", PathFmt(linkPath), path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +249,7 @@ void LocalStore::optimisePath_(
|
||||
printInfo("%1% has maximum number of links", PathFmt(linkPath));
|
||||
return;
|
||||
}
|
||||
throw;
|
||||
throw SystemError(e.code(), "creating hard link from %1% to %2%", PathFmt(linkPath), PathFmt(tempLink));
|
||||
}
|
||||
|
||||
/* Atomically replace the old file with the new hard link. */
|
||||
@@ -271,7 +270,7 @@ void LocalStore::optimisePath_(
|
||||
debug("%s has reached maximum number of links", PathFmt(linkPath));
|
||||
return;
|
||||
}
|
||||
throw;
|
||||
throw SystemError(e.code(), "renaming %1% to %2%", PathFmt(tempLink), path);
|
||||
}
|
||||
|
||||
stats.filesLinked++;
|
||||
|
||||
@@ -103,7 +103,7 @@ static void removeFile(const std::filesystem::path & path)
|
||||
try {
|
||||
std::filesystem::remove(path);
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
throw SysError("removing file %1%", PathFmt(path));
|
||||
throw SystemError(e.code(), "removing file %1%", PathFmt(path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,8 +324,6 @@ std::filesystem::path getDefaultProfile(ProfileDirsOptions settings)
|
||||
return absPath(readLink(profileLink), &linkDir);
|
||||
} catch (Error &) {
|
||||
return profileLink;
|
||||
} catch (std::filesystem::filesystem_error &) {
|
||||
return profileLink;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace nix {
|
||||
|
||||
SQLiteError::SQLiteError(
|
||||
const char * path, const char * errMsg, int errNo, int extendedErrNo, int offset, HintFmt && hf)
|
||||
: CloneableError("")
|
||||
: Error("")
|
||||
, path(path)
|
||||
, errMsg(errMsg)
|
||||
, errNo(errNo)
|
||||
|
||||
@@ -18,11 +18,11 @@ static std::string parsePublicHostKey(std::string_view host, std::string_view ss
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidSSHAuthority final : public CloneableError<InvalidSSHAuthority, Error>
|
||||
class InvalidSSHAuthority : public Error
|
||||
{
|
||||
public:
|
||||
InvalidSSHAuthority(const ParsedURL::Authority & authority, std::string_view reason)
|
||||
: CloneableError("invalid SSH authority: '%s': %s", authority.to_string(), reason)
|
||||
: Error("invalid SSH authority: '%s': %s", authority.to_string(), reason)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,10 +55,10 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct NotDeterministic final : CloneableError<NotDeterministic, BuildError>
|
||||
struct NotDeterministic : BuildError
|
||||
{
|
||||
NotDeterministic(auto &&... args)
|
||||
: CloneableError(BuildResult::Failure::NotDeterministic, args...)
|
||||
: BuildError(BuildResult::Failure::NotDeterministic, args...)
|
||||
{
|
||||
isNonDeterministic = true;
|
||||
}
|
||||
|
||||
@@ -56,26 +56,24 @@ bool lockFile(Descriptor desc, LockType lockType, bool wait)
|
||||
switch (lockType) {
|
||||
case ltNone: {
|
||||
OVERLAPPED ov = {0};
|
||||
if (!UnlockFileEx(desc, 0, 2, 0, &ov)) {
|
||||
WinError winError("Failed to unlock file desc %s", desc);
|
||||
throw winError;
|
||||
}
|
||||
if (!UnlockFileEx(desc, 0, 2, 0, &ov))
|
||||
throw WinError("Failed to unlock file desc %s", desc);
|
||||
return true;
|
||||
}
|
||||
case ltRead: {
|
||||
OVERLAPPED ov = {0};
|
||||
if (!LockFileEx(desc, wait ? 0 : LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ov)) {
|
||||
WinError winError("Failed to lock file desc %s", desc);
|
||||
if (winError.lastError == ERROR_LOCK_VIOLATION)
|
||||
auto lastError = GetLastError();
|
||||
if (lastError == ERROR_LOCK_VIOLATION)
|
||||
return false;
|
||||
throw winError;
|
||||
throw WinError(lastError, "Failed to lock file desc %s", desc);
|
||||
}
|
||||
|
||||
ov.Offset = 1;
|
||||
if (!UnlockFileEx(desc, 0, 1, 0, &ov)) {
|
||||
WinError winError("Failed to unlock file desc %s", desc);
|
||||
if (winError.lastError != ERROR_NOT_LOCKED)
|
||||
throw winError;
|
||||
auto lastError = GetLastError();
|
||||
if (lastError != ERROR_NOT_LOCKED)
|
||||
throw WinError(lastError, "Failed to unlock file desc %s", desc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -83,17 +81,17 @@ bool lockFile(Descriptor desc, LockType lockType, bool wait)
|
||||
OVERLAPPED ov = {0};
|
||||
ov.Offset = 1;
|
||||
if (!LockFileEx(desc, LOCKFILE_EXCLUSIVE_LOCK | (wait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ov)) {
|
||||
WinError winError("Failed to lock file desc %s", desc);
|
||||
if (winError.lastError == ERROR_LOCK_VIOLATION)
|
||||
auto lastError = GetLastError();
|
||||
if (lastError == ERROR_LOCK_VIOLATION)
|
||||
return false;
|
||||
throw winError;
|
||||
throw WinError(lastError, "Failed to lock file desc %s", desc);
|
||||
}
|
||||
|
||||
ov.Offset = 0;
|
||||
if (!UnlockFileEx(desc, 0, 1, 0, &ov)) {
|
||||
WinError winError("Failed to unlock file desc %s", desc);
|
||||
if (winError.lastError != ERROR_NOT_LOCKED)
|
||||
throw winError;
|
||||
auto lastError = GetLastError();
|
||||
if (lastError != ERROR_NOT_LOCKED)
|
||||
throw WinError(lastError, "Failed to unlock file desc %s", desc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ TEST(chmodIfNeeded, works)
|
||||
|
||||
TEST(chmodIfNeeded, nonexistent)
|
||||
{
|
||||
ASSERT_THROW(chmodIfNeeded("/schnitzel/darmstadt/pommes", 0755), SysError);
|
||||
ASSERT_THROW(chmodIfNeeded("/schnitzel/darmstadt/pommes", 0755), SystemError);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
@@ -340,7 +340,7 @@ TEST(DirectoryIterator, works)
|
||||
|
||||
TEST(DirectoryIterator, nonexistent)
|
||||
{
|
||||
ASSERT_THROW(DirectoryIterator("/schnitzel/darmstadt/pommes"), SysError);
|
||||
ASSERT_THROW(DirectoryIterator("/schnitzel/darmstadt/pommes"), SystemError);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
|
||||
@@ -47,16 +47,16 @@ TEST(fchmodatTryNoFollow, works)
|
||||
/* Check that symlinks are not followed and targets are not changed. */
|
||||
|
||||
EXPECT_NO_THROW(
|
||||
try { fchmodatTryNoFollow(dirFd.get(), CanonPath("filelink"), 0777); } catch (SysError & e) {
|
||||
if (e.errNo != EOPNOTSUPP)
|
||||
try { fchmodatTryNoFollow(dirFd.get(), CanonPath("filelink"), 0777); } catch (SystemError & e) {
|
||||
if (!e.is(std::errc::operation_not_supported))
|
||||
throw;
|
||||
});
|
||||
ASSERT_EQ(stat((tmpDir / "file").c_str(), &st), 0);
|
||||
EXPECT_EQ(st.st_mode & 0777, 0644);
|
||||
|
||||
EXPECT_NO_THROW(
|
||||
try { fchmodatTryNoFollow(dirFd.get(), CanonPath("dirlink"), 0777); } catch (SysError & e) {
|
||||
if (e.errNo != EOPNOTSUPP)
|
||||
try { fchmodatTryNoFollow(dirFd.get(), CanonPath("dirlink"), 0777); } catch (SystemError & e) {
|
||||
if (!e.is(std::errc::operation_not_supported))
|
||||
throw;
|
||||
});
|
||||
ASSERT_EQ(stat((tmpDir / "dir").c_str(), &st), 0);
|
||||
@@ -110,14 +110,14 @@ TEST(fchmodatTryNoFollow, fallbackWithoutProc)
|
||||
|
||||
try {
|
||||
fchmodatTryNoFollow(dirFd.get(), CanonPath("file"), 0600);
|
||||
} catch (SysError & e) {
|
||||
} catch (SystemError & e) {
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
fchmodatTryNoFollow(dirFd.get(), CanonPath("link"), 0777);
|
||||
} catch (SysError & e) {
|
||||
if (e.errNo == EOPNOTSUPP)
|
||||
} catch (SystemError & e) {
|
||||
if (e.is(std::errc::operation_not_supported))
|
||||
_exit(0); /* Success. */
|
||||
}
|
||||
|
||||
|
||||
@@ -378,7 +378,7 @@ std::set<ExperimentalFeature> parseFeatures(const StringSet & rawFeatures)
|
||||
}
|
||||
|
||||
MissingExperimentalFeature::MissingExperimentalFeature(ExperimentalFeature feature, std::string reason)
|
||||
: CloneableError(
|
||||
: Error(
|
||||
"experimental Nix feature '%1%' is disabled%2%; add '--extra-experimental-features %1%' to enable it",
|
||||
showExperimentalFeature(feature),
|
||||
Uncolored(optionalBracket(" (", reason, ")")))
|
||||
|
||||
@@ -40,9 +40,9 @@ DirectoryIterator::DirectoryIterator(const std::filesystem::path & p)
|
||||
// **Attempt to create the underlying directory_iterator**
|
||||
it_ = std::filesystem::directory_iterator(p);
|
||||
} catch (const std::filesystem::filesystem_error & e) {
|
||||
// **Catch filesystem_error and throw SysError**
|
||||
// Adapt the error message as needed for SysError
|
||||
throw SysError("cannot read directory %s", PathFmt(p));
|
||||
// **Catch filesystem_error and throw SystemError**
|
||||
// Adapt the error message as needed for SystemError
|
||||
throw SystemError(e.code(), "cannot read directory %s", PathFmt(p));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,11 @@ bool pathAccessible(const std::filesystem::path & path)
|
||||
std::filesystem::path readLink(const std::filesystem::path & path)
|
||||
{
|
||||
checkInterrupt();
|
||||
return std::filesystem::read_symlink(path);
|
||||
try {
|
||||
return std::filesystem::read_symlink(path);
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
throw SystemError(e.code(), "reading symbolic link '%s'", PathFmt(path));
|
||||
}
|
||||
}
|
||||
|
||||
Path readLink(const Path & path)
|
||||
@@ -463,7 +467,7 @@ void createDirs(const std::filesystem::path & path)
|
||||
try {
|
||||
std::filesystem::create_directories(path);
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
throw SysError("creating directory '%1%'", path.string());
|
||||
throw SystemError(e.code(), "creating directory '%1%'", path.string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,7 +668,7 @@ void replaceSymlink(const std::filesystem::path & target, const std::filesystem:
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
if (e.code() == std::errc::file_exists)
|
||||
continue;
|
||||
throw SysError("creating symlink %1% -> %2%", PathFmt(tmp), PathFmt(target));
|
||||
throw SystemError(e.code(), "creating symlink %1% -> %2%", PathFmt(tmp), PathFmt(target));
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -672,7 +676,7 @@ void replaceSymlink(const std::filesystem::path & target, const std::filesystem:
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
if (e.code() == std::errc::file_exists)
|
||||
continue;
|
||||
throw SysError("renaming %1% to %2%", PathFmt(tmp), PathFmt(link));
|
||||
throw SystemError(e.code(), "renaming %1% to %2%", PathFmt(tmp), PathFmt(link));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -773,7 +777,7 @@ std::filesystem::path makeParentCanonical(const std::filesystem::path & rawPath)
|
||||
}
|
||||
return std::filesystem::canonical(parent) / path.filename();
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
throw SysError("canonicalising parent path of %1%", PathFmt(path));
|
||||
throw SystemError(e.code(), "canonicalising parent path of %1%", PathFmt(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "nix/util/suggestions.hh"
|
||||
#include "nix/util/fmt.hh"
|
||||
#include "nix/util/config.hh"
|
||||
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
@@ -126,20 +127,20 @@ public:
|
||||
BaseError & operator=(BaseError &&) = default;
|
||||
|
||||
template<typename... Args>
|
||||
BaseError(unsigned int status, const Args &... args)
|
||||
: err{.level = lvlError, .msg = HintFmt(args...), .pos = {}, .status = status}
|
||||
BaseError(unsigned int status, Args &&... args)
|
||||
: err{.level = lvlError, .msg = HintFmt(std::forward<Args>(args)...), .pos = {}, .status = status}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
explicit BaseError(const std::string & fs, const Args &... args)
|
||||
: err{.level = lvlError, .msg = HintFmt(fs, args...), .pos = {}}
|
||||
explicit BaseError(const std::string & fs, Args &&... args)
|
||||
: err{.level = lvlError, .msg = HintFmt(fs, std::forward<Args>(args)...), .pos = {}}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BaseError(const Suggestions & sug, const Args &... args)
|
||||
: err{.level = lvlError, .msg = HintFmt(args...), .pos = {}, .suggestions = sug}
|
||||
BaseError(const Suggestions & sug, Args &&... args)
|
||||
: err{.level = lvlError, .msg = HintFmt(std::forward<Args>(args)...), .pos = {}, .suggestions = sug}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -203,9 +204,9 @@ public:
|
||||
* @param args... Format string arguments.
|
||||
*/
|
||||
template<typename... Args>
|
||||
void addTrace(std::shared_ptr<const Pos> && pos, std::string_view fs, const Args &... args)
|
||||
void addTrace(std::shared_ptr<const Pos> && pos, std::string_view fs, Args &&... args)
|
||||
{
|
||||
addTrace(std::move(pos), HintFmt(std::string(fs), args...));
|
||||
addTrace(std::move(pos), HintFmt(std::string(fs), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,31 +227,13 @@ public:
|
||||
{
|
||||
return err;
|
||||
};
|
||||
|
||||
[[noreturn]] virtual void throwClone() const = 0;
|
||||
};
|
||||
|
||||
template<typename Derived, typename Base>
|
||||
class CloneableError : public Base
|
||||
{
|
||||
public:
|
||||
using Base::Base;
|
||||
|
||||
/**
|
||||
* Rethrow a copy of this exception. Useful when the exception can get
|
||||
* modified when appending traces.
|
||||
*/
|
||||
[[noreturn]] void throwClone() const override
|
||||
{
|
||||
throw Derived(static_cast<const Derived &>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
#define MakeError(newClass, superClass) \
|
||||
class newClass : public CloneableError<newClass, superClass> \
|
||||
{ \
|
||||
public: \
|
||||
using CloneableError<newClass, superClass>::CloneableError; \
|
||||
#define MakeError(newClass, superClass) \
|
||||
class newClass : public superClass \
|
||||
{ \
|
||||
public: \
|
||||
using superClass::superClass; \
|
||||
}
|
||||
|
||||
MakeError(Error, BaseError);
|
||||
@@ -262,23 +245,113 @@ MakeError(UnimplementedError, Error);
|
||||
* std::error_code. Use when you want to catch and check an error condition like
|
||||
* no_such_file_or_directory (ENOENT) without ifdefs.
|
||||
*/
|
||||
class SystemError : public CloneableError<SystemError, Error>
|
||||
class SystemError : public Error
|
||||
{
|
||||
std::error_code errorCode;
|
||||
std::string errorDetails;
|
||||
|
||||
/**
|
||||
* Just here to allow the static methods to use the right constructor
|
||||
* (the private one).
|
||||
*/
|
||||
struct Disambig
|
||||
{};
|
||||
|
||||
/**
|
||||
* Private constructor with explicit error message string.
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError(Disambig, std::error_code errorCode, std::string_view errorDetails, Args &&... args)
|
||||
: Error("")
|
||||
, errorCode(errorCode)
|
||||
, errorDetails(errorDetails)
|
||||
{
|
||||
auto hf = HintFmt(std::forward<Args>(args)...);
|
||||
err.msg = HintFmt("%s: %s", Uncolored(hf.str()), errorDetails);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct with an error code. The error code's message is automatically
|
||||
* appended to the error message.
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError(std::errc posixErrNo, Args &&... args)
|
||||
: CloneableError(std::forward<Args>(args)...)
|
||||
, errorCode(std::make_error_code(posixErrNo))
|
||||
SystemError(std::error_code errorCode, Args &&... args)
|
||||
: SystemError(Disambig{}, errorCode, errorCode.message(), std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a POSIX error using the explicitly-provided error number.
|
||||
* `strerror` will be used to try to add additional information to the message.
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError(std::error_code errorCode, Args &&... args)
|
||||
: CloneableError(std::forward<Args>(args)...)
|
||||
, errorCode(errorCode)
|
||||
static SystemError fromPosixExplicit(int errNo, Args &&... args)
|
||||
{
|
||||
return SystemError(
|
||||
Disambig{},
|
||||
std::make_error_code(static_cast<std::errc>(errNo)),
|
||||
strerror(errNo),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a POSIX error using the ambient `errno`.
|
||||
*
|
||||
* Be sure to not perform another `errno`-modifying operation before
|
||||
* calling this!
|
||||
*/
|
||||
template<typename... Args>
|
||||
static SystemError fromPosix(Args &&... args)
|
||||
{
|
||||
return fromPosixExplicit(errno, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* Construct a Windows error using the explicitly-provided error number.
|
||||
* `FormatMessageA` will be used to try to add additional information
|
||||
* to the message.
|
||||
*/
|
||||
template<typename... Args>
|
||||
static SystemError fromWindowsExplicit(DWORD lastError, Args &&... args)
|
||||
{
|
||||
return SystemError(
|
||||
Disambig{},
|
||||
std::error_code(lastError, std::system_category()),
|
||||
renderWindowsError(lastError),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Windows error using `GetLastError()`.
|
||||
*
|
||||
* Be sure to not perform another last-error-modifying operation
|
||||
* before calling this!
|
||||
*/
|
||||
template<typename... Args>
|
||||
static SystemError fromWindows(Args &&... args)
|
||||
{
|
||||
return fromWindowsExplicit(GetLastError(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string renderWindowsError(DWORD lastError);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Construct using the native error (errno on POSIX, GetLastError() on Windows).
|
||||
*/
|
||||
template<typename... Args>
|
||||
static SystemError fromNative(Args &&... args)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return fromWindows(std::forward<Args>(args)...);
|
||||
#else
|
||||
return fromPosix(std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
const std::error_code ec() const &
|
||||
@@ -293,51 +366,58 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* POSIX system error, created using `errno`, `strerror` friends.
|
||||
*
|
||||
* Throw this, but prefer not to catch this, and catch `SystemError`
|
||||
* instead. This allows implementations to freely switch between this
|
||||
* and `windows::WinError` without breaking catch blocks.
|
||||
*
|
||||
* However, it is permissible to catch this and rethrow so long as
|
||||
* certain conditions are not met (e.g. to catch only if `errNo =
|
||||
* EFooBar`). In that case, try to also catch the equivalent `windows::WinError`
|
||||
* code.
|
||||
*
|
||||
* @todo Rename this to `PosixError` or similar. At this point Windows
|
||||
* support is too WIP to justify the code churn, but if it is finished
|
||||
* then a better identifier becomes moe worth it.
|
||||
* Wrapper to avoid churn
|
||||
*/
|
||||
class SysError final : public CloneableError<SysError, SystemError>
|
||||
template<typename... Args>
|
||||
SystemError SysError(int errNo, Args &&... args)
|
||||
{
|
||||
public:
|
||||
int errNo;
|
||||
return SystemError::fromPosixExplicit(errNo, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct using the explicitly-provided error number. `strerror`
|
||||
* will be used to try to add additional information to the message.
|
||||
*/
|
||||
template<typename... Args>
|
||||
SysError(int errNo, const Args &... args)
|
||||
: CloneableError(static_cast<std::errc>(errNo), "")
|
||||
, errNo(errNo)
|
||||
{
|
||||
auto hf = HintFmt(args...);
|
||||
err.msg = HintFmt("%1%: %2%", Uncolored(hf.str()), strerror(errNo));
|
||||
}
|
||||
/**
|
||||
* Wrapper to avoid churn
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError SysError(Args &&... args)
|
||||
{
|
||||
return SystemError::fromPosix(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct using the ambient `errno`.
|
||||
*
|
||||
* Be sure to not perform another `errno`-modifying operation before
|
||||
* calling this constructor!
|
||||
*/
|
||||
template<typename... Args>
|
||||
SysError(const Args &... args)
|
||||
: SysError(errno, args...)
|
||||
{
|
||||
}
|
||||
};
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace windows {
|
||||
|
||||
/**
|
||||
* Wrapper to avoid churn
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError WinError(DWORD lastError, Args &&... args)
|
||||
{
|
||||
return SystemError::fromWindowsExplicit(lastError, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to avoid churn
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError WinError(Args &&... args)
|
||||
{
|
||||
return SystemError::fromWindows(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Convenience wrapper for when we use `errno`-based error handling
|
||||
* on Unix, and `GetLastError()`-based error handling on Windows.
|
||||
*/
|
||||
template<typename... Args>
|
||||
SystemError NativeSysError(Args &&... args)
|
||||
{
|
||||
return SystemError::fromNative(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception for the purpose of checking that exception
|
||||
@@ -368,7 +448,7 @@ int handleExceptions(const std::string & programName, std::function<void()> fun)
|
||||
*/
|
||||
[[gnu::noinline, gnu::cold, noreturn]] void unreachable(std::source_location loc = std::source_location::current());
|
||||
|
||||
#if NIX_UBSAN_ENABLED == 1
|
||||
#if NIX_UBSAN_ENABLED
|
||||
/* When building with sanitizers, also enable expensive unreachable checks. In
|
||||
optimised builds this explicitly invokes UB with std::unreachable for better
|
||||
optimisations. */
|
||||
@@ -377,67 +457,4 @@ int handleExceptions(const std::string & programName, std::function<void()> fun)
|
||||
# define nixUnreachableWhenHardened std::unreachable
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace windows {
|
||||
|
||||
/**
|
||||
* Windows Error type.
|
||||
*
|
||||
* Unless you need to catch a specific error number, don't catch this in
|
||||
* portable code. Catch `SystemError` instead.
|
||||
*/
|
||||
class WinError : public CloneableError<WinError, SystemError>
|
||||
{
|
||||
public:
|
||||
DWORD lastError;
|
||||
|
||||
/**
|
||||
* Construct using the explicitly-provided error number.
|
||||
* `FormatMessageA` will be used to try to add additional
|
||||
* information to the message.
|
||||
*/
|
||||
template<typename... Args>
|
||||
WinError(DWORD lastError, const Args &... args)
|
||||
: CloneableError(std::error_code(lastError, std::system_category()), "")
|
||||
, lastError(lastError)
|
||||
{
|
||||
auto hf = HintFmt(args...);
|
||||
err.msg = HintFmt("%1%: %2%", Uncolored(hf.str()), renderError(lastError));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct using `GetLastError()` and the ambient "last error".
|
||||
*
|
||||
* Be sure to not perform another last-error-modifying operation
|
||||
* before calling this constructor!
|
||||
*/
|
||||
template<typename... Args>
|
||||
WinError(const Args &... args)
|
||||
: WinError(GetLastError(), args...)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::string renderError(DWORD lastError);
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Convenience alias for when we use a `errno`-based error handling
|
||||
* function on Unix, and `GetLastError()`-based error handling on on
|
||||
* Windows.
|
||||
*/
|
||||
using NativeSysError =
|
||||
#ifdef _WIN32
|
||||
windows::WinError
|
||||
#else
|
||||
SysError
|
||||
#endif
|
||||
;
|
||||
|
||||
} // namespace nix
|
||||
|
||||
@@ -80,7 +80,7 @@ std::set<ExperimentalFeature> parseFeatures(const StringSet &);
|
||||
* An experimental feature was required for some (experimental)
|
||||
* operation, but was not enabled.
|
||||
*/
|
||||
class MissingExperimentalFeature final : public CloneableError<MissingExperimentalFeature, Error>
|
||||
class MissingExperimentalFeature : public Error
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace linux {
|
||||
*
|
||||
* @see https://man7.org/linux/man-pages/man2/openat2.2.html
|
||||
* @see https://man7.org/linux/man-pages/man2/open_how.2type.html
|
||||
v*
|
||||
*
|
||||
* @param flags O_* flags
|
||||
* @param mode Mode for O_{CREAT,TMPFILE}
|
||||
* @param resolve RESOLVE_* flags
|
||||
@@ -97,7 +97,7 @@ namespace unix {
|
||||
* AT_SYMLINK_NOFOLLOW, since it's the best we can do without failing.
|
||||
*
|
||||
* @pre path.isRoot() is false
|
||||
* @throws SysError if any operation fails
|
||||
* @throws SystemError if any operation fails
|
||||
*/
|
||||
void fchmodatTryNoFollow(Descriptor dirFd, const CanonPath & path, mode_t mode);
|
||||
|
||||
|
||||
@@ -189,21 +189,19 @@ Path readLink(const Path & path);
|
||||
*/
|
||||
std::filesystem::path readLink(const std::filesystem::path & path);
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace windows {
|
||||
|
||||
/**
|
||||
* Get the path associated with a file handle.
|
||||
* Get the path associated with a file descriptor.
|
||||
*
|
||||
* @note One MUST only use this for error handling, because it creates
|
||||
* TOCTOU issues. We don't mind if error messages point to out of date
|
||||
* paths (that is a rather trivial TOCTOU --- the error message is best
|
||||
* effort) but for anything else we do.
|
||||
*
|
||||
* @note this function will clobber `errno` (Unix) / "last error"
|
||||
* (Windows), so care must be used to get those error codes, then call
|
||||
* this, then build a `SystemError` with the saved error code.
|
||||
*/
|
||||
std::filesystem::path handleToPath(Descriptor handle);
|
||||
|
||||
} // namespace windows
|
||||
#endif
|
||||
std::filesystem::path descriptorToPath(Descriptor fd);
|
||||
|
||||
/**
|
||||
* Open a `Descriptor` with read-only access to the given directory.
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
include_dirs = [ include_directories('../..') ]
|
||||
|
||||
headers = files(
|
||||
config_pub_h = configure_file(
|
||||
configuration : configdata_pub,
|
||||
output : 'config.hh',
|
||||
)
|
||||
|
||||
headers = [ config_pub_h ] + files(
|
||||
'abstract-setting-to-json.hh',
|
||||
'alignment.hh',
|
||||
'ansicolor.hh',
|
||||
|
||||
@@ -133,14 +133,14 @@ std::pair<int, std::string> runProgram(RunOptions && options);
|
||||
|
||||
void runProgram2(const RunOptions & options);
|
||||
|
||||
class ExecError final : public CloneableError<ExecError, Error>
|
||||
class ExecError : public Error
|
||||
{
|
||||
public:
|
||||
int status;
|
||||
|
||||
template<typename... Args>
|
||||
ExecError(int status, const Args &... args)
|
||||
: CloneableError(args...)
|
||||
: Error(args...)
|
||||
, status(status)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -231,19 +231,19 @@ ref<SourceAccessor> makeEmptySourceAccessor();
|
||||
*/
|
||||
MakeError(RestrictedPathError, Error);
|
||||
|
||||
struct SymlinkNotAllowed final : public CloneableError<SymlinkNotAllowed, Error>
|
||||
struct SymlinkNotAllowed : public Error
|
||||
{
|
||||
CanonPath path;
|
||||
|
||||
SymlinkNotAllowed(CanonPath path)
|
||||
: CloneableError("relative path '%s' points to a symlink, which is not allowed", path.rel())
|
||||
: Error("relative path '%s' points to a symlink, which is not allowed", path.rel())
|
||||
, path(std::move(path))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
SymlinkNotAllowed(CanonPath path, const std::string & fs, Args &&... args)
|
||||
: CloneableError(fs, std::forward<Args>(args)...)
|
||||
: Error(fs, std::forward<Args>(args)...)
|
||||
, path(std::move(path))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ bool userNamespacesSupported()
|
||||
|
||||
auto r = pid.wait();
|
||||
assert(!r);
|
||||
} catch (SysError & e) {
|
||||
} catch (SystemError & e) {
|
||||
debug("user namespaces do not work on this system: %s", e.msg());
|
||||
return false;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ bool mountAndPidNamespacesSupported()
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (SysError & e) {
|
||||
} catch (SystemError & e) {
|
||||
debug("mount namespaces do not work on this system: %s", e.msg());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
configdata_pub = configuration_data()
|
||||
configdata_priv = configuration_data()
|
||||
|
||||
deps_private_maybe_subproject = []
|
||||
deps_public_maybe_subproject = []
|
||||
@@ -34,9 +35,15 @@ check_funcs = [
|
||||
foreach funcspec : check_funcs
|
||||
define_name = 'HAVE_' + funcspec[0].underscorify().to_upper()
|
||||
define_value = cxx.has_function(funcspec[0]).to_int()
|
||||
configdata.set(define_name, define_value, description : funcspec[1])
|
||||
configdata_priv.set(define_name, define_value, description : funcspec[1])
|
||||
endforeach
|
||||
|
||||
configdata_pub.set(
|
||||
'NIX_UBSAN_ENABLED',
|
||||
('undefined' in get_option('b_sanitize')).to_int(),
|
||||
description : 'Whether nix has been built with UBSan enabled',
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/libatomic')
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
@@ -104,7 +111,7 @@ cpuid = dependency(
|
||||
version : '>= 0.7.0',
|
||||
required : cpuid_required,
|
||||
)
|
||||
configdata.set('HAVE_LIBCPUID', cpuid.found().to_int())
|
||||
configdata_priv.set('HAVE_LIBCPUID', cpuid.found().to_int())
|
||||
deps_private += cpuid
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
@@ -113,7 +120,7 @@ deps_public += nlohmann_json
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
config_priv_h = configure_file(
|
||||
configuration : configdata,
|
||||
configuration : configdata_priv,
|
||||
output : 'util-config-private.hh',
|
||||
)
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ SourceAccessor::DirEntries PosixSourceAccessor::readDirectory(const CanonPath &
|
||||
if (e.code() == std::errc::permission_denied || e.code() == std::errc::operation_not_permitted)
|
||||
return std::nullopt;
|
||||
else
|
||||
throw;
|
||||
throw SystemError(e.code(), "getting status of '%s'", PathFmt(entry.path()));
|
||||
}
|
||||
}();
|
||||
res.emplace(entry.path().filename().string(), type);
|
||||
|
||||
@@ -78,8 +78,8 @@ bindConnectProcHelper(std::string_view operationName, auto && operation, Socket
|
||||
if (operation(fd, psaddr, sizeof(addr)) == -1)
|
||||
throw SysError("cannot %s to socket at '%s'", operationName, path);
|
||||
writeFull(pipe.writeSide.get(), "0\n");
|
||||
} catch (SysError & e) {
|
||||
writeFull(pipe.writeSide.get(), fmt("%d\n", e.errNo));
|
||||
} catch (SystemError & e) {
|
||||
writeFull(pipe.writeSide.get(), fmt("%d\n", e.ec().value()));
|
||||
} catch (...) {
|
||||
writeFull(pipe.writeSide.get(), "-1\n");
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ void readFull(int fd, char * buf, size_t count)
|
||||
pollFD(fd, POLLIN);
|
||||
continue;
|
||||
}
|
||||
throw SysError("reading from file");
|
||||
auto savedErrno = errno;
|
||||
throw SysError(savedErrno, "reading from file %s", PathFmt(descriptorToPath(fd)));
|
||||
}
|
||||
if (res == 0)
|
||||
throw EndOfFile("unexpected end-of-file");
|
||||
@@ -72,7 +73,8 @@ void writeFull(int fd, std::string_view s, bool allowInterrupts)
|
||||
pollFD(fd, POLLOUT);
|
||||
continue;
|
||||
}
|
||||
throw SysError("writing to file");
|
||||
auto savedErrno = errno;
|
||||
throw SysError(savedErrno, "writing to file %s", PathFmt(descriptorToPath(fd)));
|
||||
}
|
||||
if (res > 0)
|
||||
s.remove_prefix(res);
|
||||
@@ -95,8 +97,10 @@ std::string readLine(int fd, bool eofOk, char terminator)
|
||||
pollFD(fd, POLLIN);
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
throw SysError("reading a line");
|
||||
default: {
|
||||
auto savedErrno = errno;
|
||||
throw SysError(savedErrno, "reading a line from %s", PathFmt(descriptorToPath(fd)));
|
||||
}
|
||||
}
|
||||
} else if (rd == 0) {
|
||||
if (eofOk)
|
||||
@@ -184,7 +188,7 @@ void unix::closeExtraFDs()
|
||||
}
|
||||
}
|
||||
return;
|
||||
} catch (SysError &) {
|
||||
} catch (SystemError &) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -71,8 +71,10 @@ void unix::fchmodatTryNoFollow(Descriptor dirFd, const CanonPath & path, mode_t
|
||||
if (res < 0) {
|
||||
if (errno == ENOSYS)
|
||||
fchmodat2Unsupported.test_and_set();
|
||||
else
|
||||
throw SysError("fchmodat2 '%s' relative to parent directory", path.rel());
|
||||
else {
|
||||
auto savedErrno = errno;
|
||||
throw SysError(savedErrno, "fchmodat2 %s", PathFmt(descriptorToPath(dirFd) / path.rel()));
|
||||
}
|
||||
} else
|
||||
return;
|
||||
}
|
||||
@@ -80,10 +82,13 @@ void unix::fchmodatTryNoFollow(Descriptor dirFd, const CanonPath & path, mode_t
|
||||
|
||||
#ifdef __linux__
|
||||
AutoCloseFD pathFd = ::openat(dirFd, path.rel_c_str(), O_PATH | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (!pathFd)
|
||||
if (!pathFd) {
|
||||
auto savedErrno = errno;
|
||||
throw SysError(
|
||||
"opening '%s' relative to parent directory to get an O_PATH file descriptor (fchmodat2 is unsupported)",
|
||||
path.rel());
|
||||
savedErrno,
|
||||
"opening %s to get an O_PATH file descriptor (fchmodat2 is unsupported)",
|
||||
PathFmt(descriptorToPath(dirFd) / path.rel()));
|
||||
}
|
||||
|
||||
struct ::stat st;
|
||||
/* Possible since https://github.com/torvalds/linux/commit/55815f70147dcfa3ead5738fd56d3574e2e3c1c2 (3.6) */
|
||||
@@ -91,7 +96,7 @@ void unix::fchmodatTryNoFollow(Descriptor dirFd, const CanonPath & path, mode_t
|
||||
throw SysError("statting '%s' relative to parent directory via O_PATH file descriptor", path.rel());
|
||||
|
||||
if (S_ISLNK(st.st_mode))
|
||||
throw SysError(EOPNOTSUPP, "can't change mode of symlink '%s' relative to parent directory", path.rel());
|
||||
throw SysError(EOPNOTSUPP, "can't change mode of symlink %s", PathFmt(descriptorToPath(dirFd) / path.rel()));
|
||||
|
||||
static std::atomic_flag dontHaveProc{};
|
||||
if (!dontHaveProc.test()) {
|
||||
@@ -101,8 +106,11 @@ void unix::fchmodatTryNoFollow(Descriptor dirFd, const CanonPath & path, mode_t
|
||||
if (int res = ::chmod(selfProcFdPath.c_str(), mode); res == -1) {
|
||||
if (errno == ENOENT)
|
||||
dontHaveProc.test_and_set();
|
||||
else
|
||||
throw SysError("chmod '%s' ('%s' relative to parent directory)", selfProcFdPath, path);
|
||||
else {
|
||||
auto savedErrno = errno;
|
||||
throw SysError(
|
||||
savedErrno, "chmod %s (%s)", selfProcFdPath, PathFmt(descriptorToPath(dirFd) / path.rel()));
|
||||
}
|
||||
} else
|
||||
return;
|
||||
}
|
||||
@@ -122,8 +130,10 @@ void unix::fchmodatTryNoFollow(Descriptor dirFd, const CanonPath & path, mode_t
|
||||
#endif
|
||||
);
|
||||
|
||||
if (res == -1)
|
||||
throw SysError("fchmodat '%s' relative to parent directory", path.rel());
|
||||
if (res == -1) {
|
||||
auto savedErrno = errno;
|
||||
throw SysError(savedErrno, "fchmodat %s", PathFmt(descriptorToPath(dirFd) / path.rel()));
|
||||
}
|
||||
}
|
||||
|
||||
static Descriptor
|
||||
@@ -206,9 +216,10 @@ OsString readLinkAt(Descriptor dirFd, const CanonPath & path)
|
||||
checkInterrupt();
|
||||
buf.resize(bufSize);
|
||||
ssize_t rlSize = ::readlinkat(dirFd, path.rel_c_str(), buf.data(), bufSize);
|
||||
if (rlSize == -1)
|
||||
throw SysError("reading symbolic link '%1%' relative to parent directory", path.rel());
|
||||
else if (rlSize < bufSize)
|
||||
if (rlSize == -1) {
|
||||
auto savedErrno = errno;
|
||||
throw SysError(savedErrno, "reading symbolic link %1%", PathFmt(descriptorToPath(dirFd) / path.rel()));
|
||||
} else if (rlSize < bufSize)
|
||||
return {buf.data(), static_cast<std::size_t>(rlSize)};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,31 @@ Descriptor openNewFileForWrite(const std::filesystem::path & path, mode_t mode,
|
||||
return open(path.c_str(), flags, mode);
|
||||
}
|
||||
|
||||
std::filesystem::path descriptorToPath(Descriptor fd)
|
||||
{
|
||||
if (fd == STDIN_FILENO)
|
||||
return "<stdin>";
|
||||
if (fd == STDOUT_FILENO)
|
||||
return "<stdout>";
|
||||
if (fd == STDERR_FILENO)
|
||||
return "<stderr>";
|
||||
|
||||
#if defined(__linux__)
|
||||
try {
|
||||
return readLink("/proc/self/fd/" + std::to_string(fd));
|
||||
} catch (SystemError &) {
|
||||
}
|
||||
#elif HAVE_F_GETPATH
|
||||
/* F_GETPATH requires PATH_MAX buffer per POSIX */
|
||||
char buf[PATH_MAX];
|
||||
if (fcntl(fd, F_GETPATH, buf) != -1)
|
||||
return buf;
|
||||
#endif
|
||||
|
||||
/* Fallback for unknown fd or unsupported platform */
|
||||
return "<fd " + std::to_string(fd) + ">";
|
||||
}
|
||||
|
||||
std::filesystem::path defaultTempDir()
|
||||
{
|
||||
return getEnvNonEmpty("TMPDIR").value_or("/tmp");
|
||||
@@ -161,9 +186,9 @@ static void _deletePath(
|
||||
if ((st.st_mode & PERM_MASK) != PERM_MASK)
|
||||
try {
|
||||
unix::fchmodatTryNoFollow(parentfd, CanonPath(name), st.st_mode | PERM_MASK);
|
||||
} catch (SysError & e) {
|
||||
} catch (SystemError & e) {
|
||||
e.addTrace({}, "while making directory %1% accessible for deletion", PathFmt(path));
|
||||
if (e.errNo == EOPNOTSUPP)
|
||||
if (e.is(std::errc::operation_not_supported))
|
||||
e.addTrace({}, "%1% is now a symlink, expected directory", PathFmt(path));
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ inline void MonitorFdHup::runThread(int watchFd, int notifyFd)
|
||||
{
|
||||
int kqResult = kqueue();
|
||||
if (kqResult < 0) {
|
||||
throw SysError("MonitorFdHup kqueue");
|
||||
throw SystemError::fromPosix("MonitorFdHup kqueue");
|
||||
}
|
||||
AutoCloseFD kq{kqResult};
|
||||
|
||||
@@ -78,14 +78,14 @@ inline void MonitorFdHup::runThread(int watchFd, int notifyFd)
|
||||
|
||||
int result = kevent(kq.get(), kevs.data(), kevs.size(), nullptr, 0, nullptr);
|
||||
if (result < 0) {
|
||||
throw SysError("MonitorFdHup kevent add");
|
||||
throw SystemError::fromPosix("MonitorFdHup kevent add");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
struct kevent event;
|
||||
int numEvents = kevent(kq.get(), nullptr, 0, &event, 1, nullptr);
|
||||
if (numEvents < 0) {
|
||||
throw SysError("MonitorFdHup kevent watch");
|
||||
throw SystemError::fromPosix("MonitorFdHup kevent watch");
|
||||
}
|
||||
|
||||
if (numEvents > 0 && (event.flags & EV_EOF)) {
|
||||
@@ -112,7 +112,7 @@ inline void MonitorFdHup::runThread(int watchFd, int notifyFd)
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
throw SysError("in MonitorFdHup poll()");
|
||||
throw SystemError::fromPosix("in MonitorFdHup poll()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@ configdata_unix.set(
|
||||
description : 'Optionally used for changing the files and symlinks.',
|
||||
)
|
||||
|
||||
configdata_unix.set(
|
||||
'HAVE_F_GETPATH',
|
||||
cxx.has_header_symbol('fcntl.h', 'F_GETPATH').to_int(),
|
||||
description : 'Optionally used for getting the path of a file descriptor (macOS).',
|
||||
)
|
||||
|
||||
# Check for each of these functions, and create a define like `#define
|
||||
# HAVE_CLOSE_RANGE 1`.
|
||||
check_funcs_unix = [
|
||||
|
||||
@@ -39,7 +39,7 @@ std::filesystem::path getHome()
|
||||
auto st = maybeStat(homeDir->c_str());
|
||||
if (st && st->st_uid != geteuid())
|
||||
unownedUserHomeDir.swap(homeDir);
|
||||
} catch (SysError & e) {
|
||||
} catch (SystemError & e) {
|
||||
warn(
|
||||
"couldn't stat $HOME ('%s') for reason other than not existing, falling back to the one defined in the 'passwd' file: %s",
|
||||
*homeDir,
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
using namespace nix::windows;
|
||||
|
||||
std::chrono::microseconds getCpuUserTime()
|
||||
{
|
||||
FILETIME creationTime;
|
||||
@@ -17,7 +19,7 @@ std::chrono::microseconds getCpuUserTime()
|
||||
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime)) {
|
||||
auto lastError = GetLastError();
|
||||
throw windows::WinError(lastError, "failed to get CPU time");
|
||||
throw WinError(lastError, "failed to get CPU time");
|
||||
}
|
||||
|
||||
ULARGE_INTEGER uLargeInt;
|
||||
|
||||
@@ -45,9 +45,9 @@ void writeFull(HANDLE handle, std::string_view s, bool allowInterrupts)
|
||||
checkInterrupt();
|
||||
DWORD res;
|
||||
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
||||
// Do this because `handleToPath` will overwrite the last error.
|
||||
// Do this because `descriptorToPath` will overwrite the last error.
|
||||
auto lastError = GetLastError();
|
||||
auto path = handleToPath(handle);
|
||||
auto path = descriptorToPath(handle);
|
||||
throw WinError(lastError, "writing to file %d:%s", handle, PathFmt(path));
|
||||
}
|
||||
if (res > 0)
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
using namespace nix::windows;
|
||||
|
||||
namespace windows {
|
||||
|
||||
namespace {
|
||||
@@ -156,13 +154,13 @@ OsString readSymlinkTarget(HANDLE linkHandle)
|
||||
size_t path_buf_offset = offsetof(ReparseDataBuffer, SymbolicLinkReparseBuffer.PathBuffer[0]);
|
||||
|
||||
if (out < path_buf_offset) {
|
||||
auto fullPath = handleToPath(linkHandle);
|
||||
auto fullPath = descriptorToPath(linkHandle);
|
||||
throw WinError(
|
||||
DWORD{ERROR_REPARSE_TAG_INVALID}, "invalid reparse data for %d:%s", linkHandle, PathFmt(fullPath));
|
||||
}
|
||||
|
||||
if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
|
||||
auto fullPath = handleToPath(linkHandle);
|
||||
auto fullPath = descriptorToPath(linkHandle);
|
||||
throw WinError(DWORD{ERROR_REPARSE_TAG_INVALID}, "not a symlink: %d:%s", linkHandle, PathFmt(fullPath));
|
||||
}
|
||||
|
||||
@@ -179,7 +177,7 @@ OsString readSymlinkTarget(HANDLE linkHandle)
|
||||
}
|
||||
|
||||
if (path_buf_offset + name_offset + name_length > out) {
|
||||
auto fullPath = handleToPath(linkHandle);
|
||||
auto fullPath = descriptorToPath(linkHandle);
|
||||
throw WinError(
|
||||
DWORD{ERROR_REPARSE_TAG_INVALID}, "invalid symlink data for %d:%s", linkHandle, PathFmt(fullPath));
|
||||
}
|
||||
@@ -210,6 +208,8 @@ bool isReparsePoint(HANDLE handle)
|
||||
|
||||
} // namespace windows
|
||||
|
||||
using namespace nix::windows;
|
||||
|
||||
Descriptor openFileEnsureBeneathNoSymlinks(
|
||||
Descriptor dirFd, const CanonPath & path, ACCESS_MASK desiredAccess, ULONG createOptions, ULONG createDisposition)
|
||||
{
|
||||
@@ -259,9 +259,10 @@ Descriptor openFileEnsureBeneathNoSymlinks(
|
||||
FILE_TRAVERSE | SYNCHRONIZE, // Just need traversal rights
|
||||
FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT // Open directory, don't follow symlinks
|
||||
);
|
||||
} catch (WinError & e) {
|
||||
} catch (SystemError & e) {
|
||||
/* Check if this is because it's a symlink */
|
||||
if (e.lastError == ERROR_CANT_ACCESS_FILE || e.lastError == ERROR_ACCESS_DENIED) {
|
||||
auto err = e.ec().value();
|
||||
if (err == ERROR_CANT_ACCESS_FILE || err == ERROR_ACCESS_DENIED) {
|
||||
throwIfSymlink(wcomponent, pathUpTo(std::next(it)));
|
||||
}
|
||||
throw;
|
||||
@@ -286,9 +287,9 @@ Descriptor openFileEnsureBeneathNoSymlinks(
|
||||
desiredAccess,
|
||||
createOptions | FILE_OPEN_REPARSE_POINT, // Don't follow symlinks on final component either
|
||||
createDisposition);
|
||||
} catch (WinError & e) {
|
||||
} catch (SystemError & e) {
|
||||
/* Check if final component is a symlink when we requested to not follow it */
|
||||
if (e.lastError == ERROR_CANT_ACCESS_FILE) {
|
||||
if (e.ec().value() == ERROR_CANT_ACCESS_FILE) {
|
||||
throwIfSymlink(finalComponent, path);
|
||||
}
|
||||
throw;
|
||||
|
||||
@@ -83,7 +83,7 @@ void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
|
||||
deletePath(path);
|
||||
}
|
||||
|
||||
std::filesystem::path windows::handleToPath(HANDLE handle)
|
||||
std::filesystem::path descriptorToPath(Descriptor handle)
|
||||
{
|
||||
std::vector<wchar_t> buf(0x100);
|
||||
DWORD dw = GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED);
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
namespace nix::windows::known_folders {
|
||||
|
||||
using namespace nix::windows;
|
||||
|
||||
static std::filesystem::path getKnownFolder(REFKNOWNFOLDERID rfid)
|
||||
{
|
||||
PWSTR str = nullptr;
|
||||
|
||||
@@ -7,15 +7,17 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
using namespace nix::windows;
|
||||
|
||||
void MuxablePipePollState::poll(HANDLE ioport, std::optional<unsigned int> timeout)
|
||||
{
|
||||
/* We are on at least Windows Vista / Server 2008 and can get many
|
||||
(countof(oentries)) statuses in one API call. */
|
||||
if (!GetQueuedCompletionStatusEx(
|
||||
ioport, oentries, sizeof(oentries) / sizeof(*oentries), &removed, timeout ? *timeout : INFINITE, false)) {
|
||||
windows::WinError winError("GetQueuedCompletionStatusEx");
|
||||
if (winError.lastError != WAIT_TIMEOUT)
|
||||
throw winError;
|
||||
auto lastError = GetLastError();
|
||||
if (lastError != WAIT_TIMEOUT)
|
||||
throw WinError(lastError, "GetQueuedCompletionStatusEx");
|
||||
assert(removed == 0);
|
||||
} else {
|
||||
assert(0 < removed && removed <= sizeof(oentries) / sizeof(*oentries));
|
||||
@@ -52,12 +54,12 @@ void MuxablePipePollState::iterate(
|
||||
// here is possible (but not obligatory) to call
|
||||
// `handleRead` and repeat ReadFile immediately
|
||||
} else {
|
||||
windows::WinError winError("ReadFile(%s, ..)", (*p)->readSide.get());
|
||||
if (winError.lastError == ERROR_BROKEN_PIPE) {
|
||||
auto lastError = GetLastError();
|
||||
if (lastError == ERROR_BROKEN_PIPE) {
|
||||
handleEOF((*p)->readSide.get());
|
||||
nextp = channels.erase(p); // no need to maintain `channels` ?
|
||||
} else if (winError.lastError != ERROR_IO_PENDING)
|
||||
throw winError;
|
||||
} else if (lastError != ERROR_IO_PENDING)
|
||||
throw WinError(lastError, "ReadFile(%s, ..)", (*p)->readSide.get());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
|
||||
namespace nix::windows {
|
||||
namespace nix {
|
||||
|
||||
std::string WinError::renderError(DWORD lastError)
|
||||
std::string SystemError::renderWindowsError(DWORD lastError)
|
||||
{
|
||||
LPSTR errorText = NULL;
|
||||
|
||||
@@ -32,5 +32,5 @@ std::string WinError::renderError(DWORD lastError)
|
||||
return fmt("CODE=%d", lastError);
|
||||
}
|
||||
|
||||
} // namespace nix::windows
|
||||
} // namespace nix
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@ void showManPage(const std::string & name)
|
||||
setEnv("MANPATH", (getNixManDir().string() + ":").c_str());
|
||||
execlp("man", "man", name.c_str(), nullptr);
|
||||
if (errno == ENOENT) {
|
||||
// Not SysError because we don't want to suffix the errno, aka No such file or directory.
|
||||
// Not SystemError because we don't want to suffix the errno, aka No such file or directory.
|
||||
throw Error(
|
||||
"The '%1%' command was not found, but it is needed for '%2%' and some other '%3%' commands' help text. Perhaps you could install the '%1%' command?",
|
||||
"man",
|
||||
|
||||
@@ -43,8 +43,8 @@ void removeOldGenerations(std::filesystem::path dir)
|
||||
std::string link;
|
||||
try {
|
||||
link = readLink(path);
|
||||
} catch (std::filesystem::filesystem_error & e) {
|
||||
if (e.code() == std::errc::no_such_file_or_directory)
|
||||
} catch (SystemError & e) {
|
||||
if (e.is(std::errc::no_such_file_or_directory))
|
||||
continue;
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -1419,7 +1419,6 @@ static int main_nix_env(int argc, char ** argv)
|
||||
replaceSymlink(defaultChannelsDir(profilesDirOpts), nixExprPath / "channels");
|
||||
if (!isRootUser())
|
||||
replaceSymlink(rootChannelsDir(profilesDirOpts), nixExprPath / "channels_root");
|
||||
} catch (std::filesystem::filesystem_error &) {
|
||||
} catch (Error &) {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user