fstat_ut.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. #include "fstat.h"
  2. #include "file.h"
  3. #include "sysstat.h"
  4. #include "fs.h"
  5. #include <library/cpp/testing/unittest/registar.h>
  6. #include <library/cpp/testing/unittest/tests_data.h>
  7. #include <util/folder/path.h>
  8. Y_UNIT_TEST_SUITE(TestFileStat) {
  9. Y_UNIT_TEST(FileTest) {
  10. TString fileName = "f1.txt";
  11. TFileStat oFs;
  12. {
  13. TFile file(fileName.data(), OpenAlways | WrOnly);
  14. file.Write("1234567", 7);
  15. {
  16. TFileStat fs(file);
  17. UNIT_ASSERT(fs.IsFile());
  18. UNIT_ASSERT(!fs.IsDir());
  19. UNIT_ASSERT(!fs.IsSymlink());
  20. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), (i64)fs.Size);
  21. UNIT_ASSERT(fs.MTime >= fs.CTime);
  22. UNIT_ASSERT(fs.NLinks == 1);
  23. oFs = fs;
  24. }
  25. UNIT_ASSERT(file.IsOpen());
  26. UNIT_ASSERT_VALUES_EQUAL(file.GetLength(), 7);
  27. file.Close();
  28. }
  29. TFileStat cFs(fileName);
  30. UNIT_ASSERT(cFs.IsFile());
  31. UNIT_ASSERT(!cFs.IsDir());
  32. UNIT_ASSERT(!cFs.IsSymlink());
  33. UNIT_ASSERT_VALUES_EQUAL(cFs.Size, oFs.Size);
  34. UNIT_ASSERT(cFs.MTime >= oFs.MTime);
  35. UNIT_ASSERT_VALUES_EQUAL(cFs.CTime, oFs.CTime);
  36. UNIT_ASSERT_VALUES_EQUAL(cFs.NLinks, oFs.NLinks);
  37. UNIT_ASSERT_VALUES_EQUAL(cFs.Mode, oFs.Mode);
  38. UNIT_ASSERT_VALUES_EQUAL(cFs.Uid, oFs.Uid);
  39. UNIT_ASSERT_VALUES_EQUAL(cFs.Gid, oFs.Gid);
  40. UNIT_ASSERT_VALUES_EQUAL(cFs.INode, oFs.INode);
  41. UNIT_ASSERT(unlink(fileName.data()) == 0);
  42. }
  43. Y_UNIT_TEST(DirTest) {
  44. Mkdir("tmpd", MODE0777);
  45. TFileStat fs("tmpd");
  46. UNIT_ASSERT(!fs.IsFile());
  47. UNIT_ASSERT(fs.IsDir());
  48. UNIT_ASSERT(!fs.IsSymlink());
  49. // UNIT_ASSERT(fs.Size == 0); // it fails under unix
  50. UNIT_ASSERT(NFs::Remove("tmpd"));
  51. fs = TFileStat("tmpd");
  52. UNIT_ASSERT(!fs.IsFile());
  53. UNIT_ASSERT(!fs.IsDir());
  54. UNIT_ASSERT(!fs.IsSymlink());
  55. UNIT_ASSERT(fs.Size == 0);
  56. UNIT_ASSERT(fs.CTime == 0);
  57. }
  58. #ifdef _win_
  59. // Symlinks require additional privileges on windows.
  60. // Skip test if we are not allowed to create one.
  61. // Wine returns true from NFs::SymLink, but actually does nothing
  62. #define SAFE_SYMLINK(target, link) \
  63. do { \
  64. auto res = NFs::SymLink(target, link); \
  65. if (!res) { \
  66. auto err = LastSystemError(); \
  67. Cerr << "can't create symlink: " << LastSystemErrorText(err) << Endl; \
  68. UNIT_ASSERT(err == ERROR_PRIVILEGE_NOT_HELD); \
  69. return; \
  70. } \
  71. if (!NFs::Exists(link) && IsWine()) { \
  72. Cerr << "wine does not support symlinks" << Endl; \
  73. return; \
  74. } \
  75. } while (false)
  76. bool IsWine() {
  77. HKEY subKey = nullptr;
  78. LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Wine", 0, KEY_READ, &subKey);
  79. if (result == ERROR_SUCCESS) {
  80. return true;
  81. }
  82. result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_READ, &subKey);
  83. if (result == ERROR_SUCCESS) {
  84. return true;
  85. }
  86. HMODULE hntdll = GetModuleHandle("ntdll.dll");
  87. if (!hntdll) {
  88. return false;
  89. }
  90. auto func = GetProcAddress(hntdll, "wine_get_version");
  91. return func != nullptr;
  92. }
  93. #else
  94. #define SAFE_SYMLINK(target, link) UNIT_ASSERT(NFs::SymLink(target, link))
  95. #endif
  96. Y_UNIT_TEST(SymlinkToExistingFileTest) {
  97. const auto path = GetOutputPath() / "file_1";
  98. const auto link = GetOutputPath() / "symlink_1";
  99. TFile(path, EOpenModeFlag::CreateNew | EOpenModeFlag::RdWr);
  100. SAFE_SYMLINK(path, link);
  101. const TFileStat statNoFollow(link, false);
  102. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsNull(), ToString(statNoFollow.Mode));
  103. UNIT_ASSERT_VALUES_EQUAL_C(true, statNoFollow.IsFile(), ToString(statNoFollow.Mode));
  104. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsSymlink(), ToString(statNoFollow.Mode));
  105. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsDir(), ToString(statNoFollow.Mode));
  106. const TFileStat statFollow(link, true);
  107. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsNull(), ToString(statFollow.Mode));
  108. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsFile(), ToString(statFollow.Mode));
  109. UNIT_ASSERT_VALUES_EQUAL_C(true, statFollow.IsSymlink(), ToString(statFollow.Mode));
  110. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsDir(), ToString(statFollow.Mode));
  111. }
  112. Y_UNIT_TEST(SymlinkToNonExistingFileTest) {
  113. const auto path = GetOutputPath() / "file_2";
  114. const auto link = GetOutputPath() / "symlink_2";
  115. SAFE_SYMLINK(path, link);
  116. const TFileStat statNoFollow(link, false);
  117. UNIT_ASSERT_VALUES_EQUAL_C(true, statNoFollow.IsNull(), ToString(statNoFollow.Mode));
  118. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsFile(), ToString(statNoFollow.Mode));
  119. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsSymlink(), ToString(statNoFollow.Mode));
  120. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsDir(), ToString(statNoFollow.Mode));
  121. const TFileStat statFollow(link, true);
  122. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsNull(), ToString(statFollow.Mode));
  123. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsFile(), ToString(statFollow.Mode));
  124. UNIT_ASSERT_VALUES_EQUAL_C(true, statFollow.IsSymlink(), ToString(statFollow.Mode));
  125. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsDir(), ToString(statFollow.Mode));
  126. }
  127. Y_UNIT_TEST(SymlinkToFileThatCantExistTest) {
  128. const auto path = TFsPath("/path") / "that" / "does" / "not" / "exists";
  129. const auto link = GetOutputPath() / "symlink_3";
  130. SAFE_SYMLINK(path, link);
  131. const TFileStat statNoFollow(link, false);
  132. UNIT_ASSERT_VALUES_EQUAL_C(true, statNoFollow.IsNull(), ToString(statNoFollow.Mode));
  133. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsFile(), ToString(statNoFollow.Mode));
  134. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsSymlink(), ToString(statNoFollow.Mode));
  135. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsDir(), ToString(statNoFollow.Mode));
  136. const TFileStat statFollow(link, true);
  137. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsNull(), ToString(statFollow.Mode));
  138. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsFile(), ToString(statFollow.Mode));
  139. UNIT_ASSERT_VALUES_EQUAL_C(true, statFollow.IsSymlink(), ToString(statFollow.Mode));
  140. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsDir(), ToString(statFollow.Mode));
  141. }
  142. Y_UNIT_TEST(FileDoesNotExistTest) {
  143. const auto path = TFsPath("/path") / "that" / "does" / "not" / "exists";
  144. const TFileStat statNoFollow(path, false);
  145. UNIT_ASSERT_VALUES_EQUAL_C(true, statNoFollow.IsNull(), ToString(statNoFollow.Mode));
  146. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsFile(), ToString(statNoFollow.Mode));
  147. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsSymlink(), ToString(statNoFollow.Mode));
  148. UNIT_ASSERT_VALUES_EQUAL_C(false, statNoFollow.IsDir(), ToString(statNoFollow.Mode));
  149. const TFileStat statFollow(path, true);
  150. UNIT_ASSERT_VALUES_EQUAL_C(true, statFollow.IsNull(), ToString(statFollow.Mode));
  151. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsFile(), ToString(statFollow.Mode));
  152. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsSymlink(), ToString(statFollow.Mode));
  153. UNIT_ASSERT_VALUES_EQUAL_C(false, statFollow.IsDir(), ToString(statFollow.Mode));
  154. }
  155. Y_UNIT_TEST(ChmodTest) {
  156. const TString fileName = "m.txt";
  157. TFile file(fileName.c_str(), OpenAlways | WrOnly);
  158. file.Write("1", 1);
  159. file.Close();
  160. const TFileStat statDefault(fileName);
  161. UNIT_ASSERT(Chmod(fileName.c_str(), statDefault.Mode) == 0);
  162. const TFileStat statUnchanged(fileName);
  163. UNIT_ASSERT_VALUES_EQUAL(statDefault.Mode, statUnchanged.Mode);
  164. UNIT_ASSERT(Chmod(fileName.c_str(), S_IRUSR | S_IRGRP | S_IROTH) == 0);
  165. const TFileStat statReadOnly(fileName);
  166. UNIT_ASSERT_VALUES_UNEQUAL(statDefault.Mode, statReadOnly.Mode);
  167. UNIT_ASSERT(Chmod(fileName.c_str(), statReadOnly.Mode) == 0);
  168. UNIT_ASSERT_VALUES_EQUAL(statReadOnly.Mode, TFileStat(fileName).Mode);
  169. UNIT_ASSERT(Chmod(fileName.c_str(), statDefault.Mode) == 0);
  170. UNIT_ASSERT(unlink(fileName.c_str()) == 0);
  171. }
  172. #ifdef _win_
  173. Y_UNIT_TEST(WinArchiveDirectoryTest) {
  174. TFsPath dir = "archive_dir";
  175. dir.MkDirs();
  176. SetFileAttributesA(dir.c_str(), FILE_ATTRIBUTE_ARCHIVE);
  177. const TFileStat stat(dir);
  178. UNIT_ASSERT(stat.IsDir());
  179. UNIT_ASSERT(!stat.IsSymlink());
  180. UNIT_ASSERT(!stat.IsFile());
  181. UNIT_ASSERT(!stat.IsNull());
  182. }
  183. Y_UNIT_TEST(WinArchiveFileTest) {
  184. TFsPath filename = "archive_file";
  185. TFile file(filename, OpenAlways | WrOnly);
  186. file.Write("1", 1);
  187. file.Close();
  188. SetFileAttributesA(filename.c_str(), FILE_ATTRIBUTE_ARCHIVE);
  189. const TFileStat stat(filename);
  190. UNIT_ASSERT(!stat.IsDir());
  191. UNIT_ASSERT(!stat.IsSymlink());
  192. UNIT_ASSERT(stat.IsFile());
  193. UNIT_ASSERT(!stat.IsNull());
  194. }
  195. #endif
  196. } // Y_UNIT_TEST_SUITE(TestFileStat)