fs.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include "fs.h"
  2. #include "defaults.h"
  3. #if defined(_win_)
  4. #include "fs_win.h"
  5. #else
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #endif
  9. #include <util/generic/yexception.h>
  10. #include <util/memory/tempbuf.h>
  11. #include <util/stream/file.h>
  12. #include <util/charset/wide.h>
  13. #include <util/folder/iterator.h>
  14. #include <util/system/fstat.h>
  15. #include <util/folder/path.h>
  16. bool NFs::Remove(const TString& path) {
  17. #if defined(_win_)
  18. return NFsPrivate::WinRemove(path);
  19. #else
  20. return ::remove(path.data()) == 0;
  21. #endif
  22. }
  23. void NFs::RemoveRecursive(const TString& path) {
  24. static const TStringBuf errStr = "error while removing ";
  25. if (!NFs::Exists(path)) {
  26. return;
  27. }
  28. if (!TFileStat(path).IsDir()) {
  29. if (!NFs::Remove(path)) {
  30. ythrow TSystemError() << errStr << path << " with cwd (" << NFs::CurrentWorkingDirectory() << ")";
  31. }
  32. }
  33. TDirIterator dir(path);
  34. for (auto it = dir.begin(); it != dir.end(); ++it) {
  35. switch (it->fts_info) {
  36. case FTS_DOT:
  37. case FTS_D:
  38. break;
  39. default:
  40. if (!NFs::Remove(it->fts_path)) {
  41. ythrow TSystemError() << errStr << it->fts_path << " with cwd (" << NFs::CurrentWorkingDirectory() << ")";
  42. }
  43. break;
  44. }
  45. }
  46. }
  47. bool NFs::MakeDirectory(const TString& path, EFilePermissions mode) {
  48. #if defined(_win_)
  49. Y_UNUSED(mode);
  50. return NFsPrivate::WinMakeDirectory(path);
  51. #else
  52. return mkdir(path.data(), mode) == 0;
  53. #endif
  54. }
  55. bool NFs::MakeDirectoryRecursive(const TString& path, EFilePermissions mode, bool alwaysCreate) {
  56. if (NFs::Exists(path) && TFileStat(path).IsDir()) {
  57. if (alwaysCreate) {
  58. ythrow TIoException() << "path " << path << " already exists"
  59. << " with cwd (" << NFs::CurrentWorkingDirectory() << ")";
  60. }
  61. return true;
  62. } else {
  63. //NOTE: recursion is finite due to existence of "." and "/"
  64. if (!NFs::MakeDirectoryRecursive(TFsPath(path).Parent(), mode, false)) {
  65. return false;
  66. }
  67. bool isDirMade = NFs::MakeDirectory(path, mode);
  68. if (!isDirMade && alwaysCreate) {
  69. ythrow TIoException() << "failed to create " << path << " with cwd (" << NFs::CurrentWorkingDirectory() << ")";
  70. }
  71. return TFileStat(path).IsDir();
  72. }
  73. }
  74. bool NFs::Rename(const TString& oldPath, const TString& newPath) {
  75. #if defined(_win_)
  76. return NFsPrivate::WinRename(oldPath, newPath);
  77. #else
  78. return ::rename(oldPath.data(), newPath.data()) == 0;
  79. #endif
  80. }
  81. void NFs::HardLinkOrCopy(const TString& existingPath, const TString& newPath) {
  82. if (!NFs::HardLink(existingPath, newPath)) {
  83. Copy(existingPath, newPath);
  84. }
  85. }
  86. bool NFs::HardLink(const TString& existingPath, const TString& newPath) {
  87. #if defined(_win_)
  88. return NFsPrivate::WinHardLink(existingPath, newPath);
  89. #elif defined(_unix_)
  90. return (0 == link(existingPath.data(), newPath.data()));
  91. #endif
  92. }
  93. bool NFs::SymLink(const TString& targetPath, const TString& linkPath) {
  94. #if defined(_win_)
  95. return NFsPrivate::WinSymLink(targetPath, linkPath);
  96. #elif defined(_unix_)
  97. return 0 == symlink(targetPath.data(), linkPath.data());
  98. #endif
  99. }
  100. TString NFs::ReadLink(const TString& path) {
  101. #if defined(_win_)
  102. return NFsPrivate::WinReadLink(path);
  103. #elif defined(_unix_)
  104. TTempBuf buf;
  105. while (true) {
  106. ssize_t r = readlink(path.data(), buf.Data(), buf.Size());
  107. if (r < 0) {
  108. ythrow yexception() << "can't read link " << path << ", errno = " << errno;
  109. }
  110. if (r < (ssize_t)buf.Size()) {
  111. return TString(buf.Data(), r);
  112. }
  113. buf = TTempBuf(buf.Size() * 2);
  114. }
  115. #endif
  116. }
  117. void NFs::Cat(const TString& dstPath, const TString& srcPath) {
  118. TUnbufferedFileInput src(srcPath);
  119. TUnbufferedFileOutput dst(TFile(dstPath, ForAppend | WrOnly | Seq));
  120. TransferData(&src, &dst);
  121. }
  122. void NFs::Copy(const TString& existingPath, const TString& newPath) {
  123. TUnbufferedFileInput src(existingPath);
  124. TUnbufferedFileOutput dst(TFile(newPath, CreateAlways | WrOnly | Seq));
  125. TransferData(&src, &dst);
  126. }
  127. bool NFs::Exists(const TString& path) {
  128. #if defined(_win_)
  129. return NFsPrivate::WinExists(path);
  130. #elif defined(_unix_)
  131. return access(path.data(), F_OK) == 0;
  132. #endif
  133. }
  134. TString NFs::CurrentWorkingDirectory() {
  135. #if defined(_win_)
  136. return NFsPrivate::WinCurrentWorkingDirectory();
  137. #elif defined(_unix_)
  138. TTempBuf result;
  139. char* r = getcwd(result.Data(), result.Size());
  140. if (r == nullptr) {
  141. throw TIoSystemError() << "failed to getcwd";
  142. }
  143. return result.Data();
  144. #endif
  145. }
  146. void NFs::SetCurrentWorkingDirectory(TString path) {
  147. #ifdef _win_
  148. bool ok = NFsPrivate::WinSetCurrentWorkingDirectory(path);
  149. #else
  150. bool ok = !chdir(path.data());
  151. #endif
  152. if (!ok) {
  153. ythrow TSystemError() << "failed to change directory to " << path.Quote();
  154. }
  155. }