diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/fs.cpp | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/fs.cpp')
| -rw-r--r-- | util/system/fs.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/util/system/fs.cpp b/util/system/fs.cpp new file mode 100644 index 00000000000..d2611a8ccc4 --- /dev/null +++ b/util/system/fs.cpp @@ -0,0 +1,179 @@ +#include "fs.h" +#include "defaults.h" + +#if defined(_win_) + #include "fs_win.h" +#else + #include <unistd.h> + #include <errno.h> +#endif + +#include <util/generic/yexception.h> +#include <util/memory/tempbuf.h> +#include <util/stream/file.h> +#include <util/charset/wide.h> +#include <util/folder/iterator.h> +#include <util/system/fstat.h> +#include <util/folder/path.h> + +bool NFs::Remove(const TString& path) { +#if defined(_win_) + return NFsPrivate::WinRemove(path); +#else + return ::remove(path.data()) == 0; +#endif +} + +void NFs::RemoveRecursive(const TString& path) { + static const TStringBuf errStr = "error while removing "; + + if (!NFs::Exists(path)) { + return; + } + + if (!TFileStat(path).IsDir()) { + if (!NFs::Remove(path)) { + ythrow TSystemError() << errStr << path << " with cwd (" << NFs::CurrentWorkingDirectory() << ")"; + } + } + + TDirIterator dir(path); + + for (auto it = dir.begin(); it != dir.end(); ++it) { + switch (it->fts_info) { + case FTS_DOT: + case FTS_D: + break; + default: + if (!NFs::Remove(it->fts_path)) { + ythrow TSystemError() << errStr << it->fts_path << " with cwd (" << NFs::CurrentWorkingDirectory() << ")"; + } + break; + } + } +} + +bool NFs::MakeDirectory(const TString& path, EFilePermissions mode) { +#if defined(_win_) + Y_UNUSED(mode); + return NFsPrivate::WinMakeDirectory(path); +#else + return mkdir(path.data(), mode) == 0; +#endif +} + +bool NFs::MakeDirectoryRecursive(const TString& path, EFilePermissions mode, bool alwaysCreate) { + if (NFs::Exists(path) && TFileStat(path).IsDir()) { + if (alwaysCreate) { + ythrow TIoException() << "path " << path << " already exists" + << " with cwd (" << NFs::CurrentWorkingDirectory() << ")"; + } + return true; + } else { + //NOTE: recursion is finite due to existence of "." and "/" + if (!NFs::MakeDirectoryRecursive(TFsPath(path).Parent(), mode, false)) { + return false; + } + + bool isDirMade = NFs::MakeDirectory(path, mode); + if (!isDirMade && alwaysCreate) { + ythrow TIoException() << "failed to create " << path << " with cwd (" << NFs::CurrentWorkingDirectory() << ")"; + } + + return TFileStat(path).IsDir(); + } +} + +bool NFs::Rename(const TString& oldPath, const TString& newPath) { +#if defined(_win_) + return NFsPrivate::WinRename(oldPath, newPath); +#else + return ::rename(oldPath.data(), newPath.data()) == 0; +#endif +} + +void NFs::HardLinkOrCopy(const TString& existingPath, const TString& newPath) { + if (!NFs::HardLink(existingPath, newPath)) { + Copy(existingPath, newPath); + } +} + +bool NFs::HardLink(const TString& existingPath, const TString& newPath) { +#if defined(_win_) + return NFsPrivate::WinHardLink(existingPath, newPath); +#elif defined(_unix_) + return (0 == link(existingPath.data(), newPath.data())); +#endif +} + +bool NFs::SymLink(const TString& targetPath, const TString& linkPath) { +#if defined(_win_) + return NFsPrivate::WinSymLink(targetPath, linkPath); +#elif defined(_unix_) + return 0 == symlink(targetPath.data(), linkPath.data()); +#endif +} + +TString NFs::ReadLink(const TString& path) { +#if defined(_win_) + return NFsPrivate::WinReadLink(path); +#elif defined(_unix_) + TTempBuf buf; + while (true) { + ssize_t r = readlink(path.data(), buf.Data(), buf.Size()); + if (r < 0) { + ythrow yexception() << "can't read link " << path << ", errno = " << errno; + } + if (r < (ssize_t)buf.Size()) { + return TString(buf.Data(), r); + } + buf = TTempBuf(buf.Size() * 2); + } +#endif +} + +void NFs::Cat(const TString& dstPath, const TString& srcPath) { + TUnbufferedFileInput src(srcPath); + TUnbufferedFileOutput dst(TFile(dstPath, ForAppend | WrOnly | Seq)); + + TransferData(&src, &dst); +} + +void NFs::Copy(const TString& existingPath, const TString& newPath) { + TUnbufferedFileInput src(existingPath); + TUnbufferedFileOutput dst(TFile(newPath, CreateAlways | WrOnly | Seq)); + + TransferData(&src, &dst); +} + +bool NFs::Exists(const TString& path) { +#if defined(_win_) + return NFsPrivate::WinExists(path); +#elif defined(_unix_) + return access(path.data(), F_OK) == 0; +#endif +} + +TString NFs::CurrentWorkingDirectory() { +#if defined(_win_) + return NFsPrivate::WinCurrentWorkingDirectory(); +#elif defined(_unix_) + TTempBuf result; + char* r = getcwd(result.Data(), result.Size()); + if (r == nullptr) { + throw TIoSystemError() << "failed to getcwd"; + } + return result.Data(); +#endif +} + +void NFs::SetCurrentWorkingDirectory(TString path) { +#ifdef _win_ + bool ok = NFsPrivate::WinSetCurrentWorkingDirectory(path); +#else + bool ok = !chdir(path.data()); +#endif + if (!ok) { + ythrow TSystemError() << "failed to change directory to " << path.Quote(); + } +} |
