fs.cpp 5.3 KB

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