summaryrefslogtreecommitdiffstats
path: root/util/system/fs.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/fs.cpp
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/fs.cpp')
-rw-r--r--util/system/fs.cpp179
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();
+ }
+}