file.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
  1. #include "file.h"
  2. #include "flock.h"
  3. #include "fstat.h"
  4. #include "sysstat.h"
  5. #include "align.h"
  6. #include "info.h"
  7. #include <array>
  8. #include <filesystem>
  9. #include <util/string/util.h>
  10. #include <util/string/cast.h>
  11. #include <util/string/builder.h>
  12. #include <util/stream/hex.h>
  13. #include <util/stream/format.h>
  14. #include <util/random/random.h>
  15. #include <util/generic/size_literals.h>
  16. #include <util/generic/string.h>
  17. #include <util/generic/ylimits.h>
  18. #include <util/generic/yexception.h>
  19. #include <util/datetime/base.h>
  20. #include <errno.h>
  21. #if defined(_unix_)
  22. #include <fcntl.h>
  23. #if defined(_linux_) && (!defined(_android_) || __ANDROID_API__ >= 21) && !defined(FALLOC_FL_KEEP_SIZE)
  24. #include <linux/falloc.h>
  25. #endif
  26. #include <stdlib.h>
  27. #include <unistd.h>
  28. #include <sys/mman.h>
  29. #elif defined(_win_)
  30. #include "winint.h"
  31. #include "fs_win.h"
  32. #include <io.h>
  33. #endif
  34. #if defined(_bionic_)
  35. #include <sys/sendfile.h>
  36. #define HAVE_POSIX_FADVISE 0
  37. #define HAVE_SYNC_FILE_RANGE 0
  38. #elif defined(_linux_)
  39. #include <sys/sendfile.h>
  40. #define HAVE_POSIX_FADVISE 1
  41. #define HAVE_SYNC_FILE_RANGE 1
  42. #elif defined(__FreeBSD__) && !defined(WITH_VALGRIND)
  43. #include <sys/param.h>
  44. #define HAVE_POSIX_FADVISE (__FreeBSD_version >= 900501)
  45. #define HAVE_SYNC_FILE_RANGE 0
  46. #else
  47. #define HAVE_POSIX_FADVISE 0
  48. #define HAVE_SYNC_FILE_RANGE 0
  49. #endif
  50. static bool IsStupidFlagCombination(EOpenMode oMode) {
  51. // ForAppend will actually not be applied in the following combinations:
  52. return (oMode & (CreateAlways | ForAppend)) == (CreateAlways | ForAppend) || (oMode & (TruncExisting | ForAppend)) == (TruncExisting | ForAppend) || (oMode & (CreateNew | ForAppend)) == (CreateNew | ForAppend);
  53. }
  54. #if defined(_win_)
  55. static SECURITY_ATTRIBUTES ConvertToSecAttrs(EOpenMode oMode) {
  56. bool closeOnExec = (oMode & CloseOnExec);
  57. SECURITY_ATTRIBUTES secAttrs;
  58. secAttrs.bInheritHandle = closeOnExec ? FALSE : TRUE;
  59. secAttrs.lpSecurityDescriptor = nullptr;
  60. secAttrs.nLength = sizeof(secAttrs);
  61. return secAttrs;
  62. }
  63. TFileHandle::TFileHandle(const std::filesystem::path& path, EOpenMode oMode) noexcept {
  64. ui32 fcMode = 0;
  65. EOpenMode createMode = oMode & MaskCreation;
  66. Y_ABORT_UNLESS(!IsStupidFlagCombination(oMode), "oMode %d makes no sense", static_cast<int>(oMode));
  67. if (!(oMode & MaskRW)) {
  68. oMode |= RdWr;
  69. }
  70. if (!(oMode & AMask)) {
  71. oMode |= ARW;
  72. }
  73. switch (createMode) {
  74. case OpenExisting:
  75. fcMode = OPEN_EXISTING;
  76. break;
  77. case TruncExisting:
  78. fcMode = TRUNCATE_EXISTING;
  79. break;
  80. case OpenAlways:
  81. fcMode = OPEN_ALWAYS;
  82. break;
  83. case CreateNew:
  84. fcMode = CREATE_NEW;
  85. break;
  86. case CreateAlways:
  87. fcMode = CREATE_ALWAYS;
  88. break;
  89. default:
  90. abort();
  91. break;
  92. }
  93. ui32 faMode = 0;
  94. if (oMode & RdOnly) {
  95. faMode |= GENERIC_READ;
  96. }
  97. if (oMode & WrOnly) {
  98. // WrOnly or RdWr
  99. faMode |= GENERIC_WRITE;
  100. }
  101. if (oMode & ::ForAppend) {
  102. faMode |= GENERIC_WRITE;
  103. faMode |= FILE_APPEND_DATA;
  104. faMode &= ~FILE_WRITE_DATA;
  105. }
  106. ui32 shMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  107. ui32 attrMode = FILE_ATTRIBUTE_NORMAL;
  108. if ((createMode == OpenExisting || createMode == OpenAlways) && ((oMode & AMask) == (oMode & AR))) {
  109. attrMode |= FILE_ATTRIBUTE_READONLY;
  110. }
  111. if (oMode & Seq) {
  112. attrMode |= FILE_FLAG_SEQUENTIAL_SCAN;
  113. }
  114. if (oMode & Temp) {
  115. // we use TTempFile instead of FILE_FLAG_DELETE_ON_CLOSE
  116. attrMode |= FILE_ATTRIBUTE_TEMPORARY;
  117. }
  118. if (oMode & Transient) {
  119. attrMode |= FILE_FLAG_DELETE_ON_CLOSE;
  120. }
  121. if ((oMode & (Direct | DirectAligned)) && (oMode & WrOnly)) {
  122. // WrOnly or RdWr
  123. attrMode |= /*FILE_FLAG_NO_BUFFERING |*/ FILE_FLAG_WRITE_THROUGH;
  124. }
  125. SECURITY_ATTRIBUTES secAttrs = ConvertToSecAttrs(oMode);
  126. Fd_ = ::CreateFileW(
  127. path.c_str(),
  128. faMode,
  129. shMode,
  130. &secAttrs,
  131. fcMode,
  132. attrMode,
  133. /* hTemplateHandle = */ nullptr);
  134. if ((oMode & ::ForAppend) && (Fd_ != INVALID_FHANDLE)) {
  135. ::SetFilePointer(Fd_, 0, 0, FILE_END);
  136. }
  137. }
  138. TFileHandle::TFileHandle(const TString& fName, EOpenMode oMode) noexcept
  139. : TFileHandle{
  140. // clang-format: off
  141. std::filesystem::path(
  142. std::u8string_view(reinterpret_cast<const char8_t*>(fName.data()), fName.size())),
  143. // clang-format: on
  144. oMode,
  145. }
  146. {
  147. }
  148. #elif defined(_unix_)
  149. TFileHandle::TFileHandle(const std::filesystem::path& path, EOpenMode oMode) noexcept {
  150. ui32 fcMode = 0;
  151. Y_ABORT_UNLESS(!IsStupidFlagCombination(oMode), "oMode %d makes no sense", static_cast<int>(oMode));
  152. if (!(oMode & MaskRW)) {
  153. oMode |= RdWr;
  154. }
  155. if (!(oMode & AMask)) {
  156. oMode |= ARW;
  157. }
  158. EOpenMode createMode = oMode & MaskCreation;
  159. switch (createMode) {
  160. case OpenExisting:
  161. fcMode = 0;
  162. break;
  163. case TruncExisting:
  164. fcMode = O_TRUNC;
  165. break;
  166. case OpenAlways:
  167. fcMode = O_CREAT;
  168. break;
  169. case CreateNew:
  170. fcMode = O_CREAT | O_EXCL;
  171. break;
  172. case CreateAlways:
  173. fcMode = O_CREAT | O_TRUNC;
  174. break;
  175. default:
  176. abort();
  177. break;
  178. }
  179. if ((oMode & RdOnly) && (oMode & WrOnly)) {
  180. fcMode |= O_RDWR;
  181. } else if (oMode & RdOnly) {
  182. fcMode |= O_RDONLY;
  183. } else if (oMode & WrOnly) {
  184. fcMode |= O_WRONLY;
  185. }
  186. if (oMode & ::ForAppend) {
  187. fcMode |= O_APPEND;
  188. }
  189. if (oMode & CloseOnExec) {
  190. fcMode |= O_CLOEXEC;
  191. }
  192. /* I don't now about this for unix...
  193. if (oMode & Temp) {
  194. }
  195. */
  196. #if defined(_freebsd_)
  197. if (oMode & (Direct | DirectAligned)) {
  198. fcMode |= O_DIRECT;
  199. }
  200. if (oMode & Sync) {
  201. fcMode |= O_SYNC;
  202. }
  203. #elif defined(_linux_)
  204. if (oMode & DirectAligned) {
  205. /*
  206. * O_DIRECT in Linux requires aligning request size and buffer address
  207. * to size of hardware sector (see hw_sector_size or ioctl BLKSSZGET).
  208. * Usually 512 bytes, but modern hardware works better with 4096 bytes.
  209. */
  210. fcMode |= O_DIRECT;
  211. }
  212. if (oMode & Sync) {
  213. fcMode |= O_SYNC;
  214. }
  215. #endif
  216. #if defined(_linux_)
  217. fcMode |= O_LARGEFILE;
  218. #endif
  219. ui32 permMode = 0;
  220. if (oMode & AXOther) {
  221. permMode |= S_IXOTH;
  222. }
  223. if (oMode & AWOther) {
  224. permMode |= S_IWOTH;
  225. }
  226. if (oMode & AROther) {
  227. permMode |= S_IROTH;
  228. }
  229. if (oMode & AXGroup) {
  230. permMode |= S_IXGRP;
  231. }
  232. if (oMode & AWGroup) {
  233. permMode |= S_IWGRP;
  234. }
  235. if (oMode & ARGroup) {
  236. permMode |= S_IRGRP;
  237. }
  238. if (oMode & AXUser) {
  239. permMode |= S_IXUSR;
  240. }
  241. if (oMode & AWUser) {
  242. permMode |= S_IWUSR;
  243. }
  244. if (oMode & ARUser) {
  245. permMode |= S_IRUSR;
  246. }
  247. do {
  248. Fd_ = ::open(path.c_str(), fcMode, permMode);
  249. } while (Fd_ == -1 && errno == EINTR);
  250. #if HAVE_POSIX_FADVISE
  251. if (Fd_ >= 0) {
  252. if (oMode & NoReuse) {
  253. ::posix_fadvise(Fd_, 0, 0, POSIX_FADV_NOREUSE);
  254. }
  255. if (oMode & Seq) {
  256. ::posix_fadvise(Fd_, 0, 0, POSIX_FADV_SEQUENTIAL);
  257. }
  258. if (oMode & NoReadAhead) {
  259. ::posix_fadvise(Fd_, 0, 0, POSIX_FADV_RANDOM);
  260. }
  261. }
  262. #endif
  263. // temp file
  264. if (Fd_ >= 0 && (oMode & Transient)) {
  265. std::filesystem::remove(path);
  266. }
  267. }
  268. TFileHandle::TFileHandle(const TString& fName, EOpenMode oMode) noexcept
  269. : TFileHandle{
  270. std::filesystem::path(fName.ConstRef()),
  271. oMode,
  272. }
  273. {
  274. }
  275. #else
  276. #error unsupported platform
  277. #endif
  278. TFileHandle::TFileHandle(const char* fName, EOpenMode oMode) noexcept
  279. : TFileHandle(TString(fName), oMode)
  280. {
  281. }
  282. bool TFileHandle::Close() noexcept {
  283. bool isOk = true;
  284. #ifdef _win_
  285. if (Fd_ != INVALID_FHANDLE) {
  286. isOk = (::CloseHandle(Fd_) != 0);
  287. }
  288. if (!isOk) {
  289. Y_ABORT_UNLESS(GetLastError() != ERROR_INVALID_HANDLE,
  290. "must not quietly close invalid handle");
  291. }
  292. #elif defined(_unix_)
  293. if (Fd_ != INVALID_FHANDLE) {
  294. isOk = (::close(Fd_) == 0 || errno == EINTR);
  295. }
  296. if (!isOk) {
  297. // Do not quietly close bad descriptor,
  298. // because often it means double close
  299. // that is disasterous
  300. Y_ABORT_UNLESS(errno != EBADF, "must not quietly close bad descriptor: fd=%d", int(Fd_));
  301. }
  302. #else
  303. #error unsupported platform
  304. #endif
  305. Fd_ = INVALID_FHANDLE;
  306. return isOk;
  307. }
  308. static inline i64 DoSeek(FHANDLE h, i64 offset, SeekDir origin) noexcept {
  309. if (h == INVALID_FHANDLE) {
  310. return -1L;
  311. }
  312. #if defined(_win_)
  313. static ui32 dir[] = {FILE_BEGIN, FILE_CURRENT, FILE_END};
  314. LARGE_INTEGER pos;
  315. pos.QuadPart = offset;
  316. pos.LowPart = ::SetFilePointer(h, pos.LowPart, &pos.HighPart, dir[origin]);
  317. if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
  318. pos.QuadPart = -1;
  319. }
  320. return pos.QuadPart;
  321. #elif defined(_unix_)
  322. static int dir[] = {SEEK_SET, SEEK_CUR, SEEK_END};
  323. #if defined(_sun_)
  324. return ::llseek(h, (offset_t)offset, dir[origin]);
  325. #else
  326. return ::lseek(h, (off_t)offset, dir[origin]);
  327. #endif
  328. #else
  329. #error unsupported platform
  330. #endif
  331. }
  332. i64 TFileHandle::GetPosition() const noexcept {
  333. return DoSeek(Fd_, 0, sCur);
  334. }
  335. i64 TFileHandle::Seek(i64 offset, SeekDir origin) noexcept {
  336. return DoSeek(Fd_, offset, origin);
  337. }
  338. i64 TFileHandle::GetLength() const noexcept {
  339. // XXX: returns error code, but does not set errno
  340. if (!IsOpen()) {
  341. return -1L;
  342. }
  343. return GetFileLength(Fd_);
  344. }
  345. bool TFileHandle::Resize(i64 length) noexcept {
  346. if (!IsOpen()) {
  347. return false;
  348. }
  349. i64 currentLength = GetLength();
  350. if (length == currentLength) {
  351. return true;
  352. }
  353. #if defined(_win_)
  354. i64 currentPosition = GetPosition();
  355. if (currentPosition == -1L) {
  356. return false;
  357. }
  358. Seek(length, sSet);
  359. if (!::SetEndOfFile(Fd_)) {
  360. return false;
  361. }
  362. if (currentPosition < length) {
  363. Seek(currentPosition, sSet);
  364. }
  365. return true;
  366. #elif defined(_unix_)
  367. return (0 == ftruncate(Fd_, (off_t)length));
  368. #else
  369. #error unsupported platform
  370. #endif
  371. }
  372. bool TFileHandle::Reserve(i64 length) noexcept {
  373. // FIXME this should reserve disk space with fallocate
  374. if (!IsOpen()) {
  375. return false;
  376. }
  377. i64 currentLength = GetLength();
  378. if (length <= currentLength) {
  379. return true;
  380. }
  381. if (!Resize(length)) {
  382. return false;
  383. }
  384. #if defined(_win_)
  385. if (!::SetFileValidData(Fd_, length)) {
  386. Resize(currentLength);
  387. return false;
  388. }
  389. #elif defined(_unix_)
  390. // No way to implement this under FreeBSD. Just do nothing
  391. #else
  392. #error unsupported platform
  393. #endif
  394. return true;
  395. }
  396. bool TFileHandle::FallocateNoResize(i64 length) noexcept {
  397. if (!IsOpen()) {
  398. return false;
  399. }
  400. #if defined(_linux_) && (!defined(_android_) || __ANDROID_API__ >= 21)
  401. return !fallocate(Fd_, FALLOC_FL_KEEP_SIZE, 0, length);
  402. #elif defined(_win_)
  403. FILE_ALLOCATION_INFO allocInfo = {};
  404. allocInfo.AllocationSize.QuadPart = length;
  405. return SetFileInformationByHandle(Fd_, FileAllocationInfo, &allocInfo,
  406. sizeof(FILE_ALLOCATION_INFO));
  407. #else
  408. Y_UNUSED(length);
  409. return true;
  410. #endif
  411. }
  412. // Pair for FallocateNoResize
  413. bool TFileHandle::ShrinkToFit() noexcept {
  414. if (!IsOpen()) {
  415. return false;
  416. }
  417. #if defined(_linux_) && (!defined(_android_) || __ANDROID_API__ >= 21)
  418. return !ftruncate(Fd_, (off_t)GetLength());
  419. #else
  420. return true;
  421. #endif
  422. }
  423. bool TFileHandle::Flush() noexcept {
  424. if (!IsOpen()) {
  425. return false;
  426. }
  427. #if defined(_win_)
  428. bool ok = ::FlushFileBuffers(Fd_) != 0;
  429. /*
  430. * FlushFileBuffers fails if hFile is a handle to the console output.
  431. * That is because the console output is not buffered.
  432. * The function returns FALSE, and GetLastError returns ERROR_INVALID_HANDLE.
  433. */
  434. return ok || GetLastError() == ERROR_INVALID_HANDLE;
  435. #elif defined(_unix_)
  436. int ret = ::fsync(Fd_);
  437. /*
  438. * Ignore EROFS, EINVAL - fd is bound to a special file
  439. * (PIPE, FIFO, or socket) which does not support synchronization.
  440. * Fail in case of EIO, ENOSPC, EDQUOT - data might be lost.
  441. */
  442. return ret == 0 || errno == EROFS || errno == EINVAL
  443. #if defined(_darwin_)
  444. // ENOTSUP fd does not refer to a vnode
  445. || errno == ENOTSUP
  446. #endif
  447. ;
  448. #else
  449. #error unsupported platform
  450. #endif
  451. }
  452. bool TFileHandle::FlushData() noexcept {
  453. #if defined(_linux_)
  454. if (!IsOpen()) {
  455. return false;
  456. }
  457. int ret = ::fdatasync(Fd_);
  458. // Same loginc in error handling as for fsync above.
  459. return ret == 0 || errno == EROFS || errno == EINVAL;
  460. #else
  461. return Flush();
  462. #endif
  463. }
  464. i32 TFileHandle::Read(void* buffer, ui32 byteCount) noexcept {
  465. // FIXME size and return must be 64-bit
  466. if (!IsOpen()) {
  467. return -1;
  468. }
  469. #if defined(_win_)
  470. DWORD bytesRead = 0;
  471. if (::ReadFile(Fd_, buffer, byteCount, &bytesRead, nullptr)) {
  472. return bytesRead;
  473. }
  474. return -1;
  475. #elif defined(_unix_)
  476. i32 ret;
  477. do {
  478. ret = ::read(Fd_, buffer, byteCount);
  479. } while (ret == -1 && errno == EINTR);
  480. return ret;
  481. #else
  482. #error unsupported platform
  483. #endif
  484. }
  485. i32 TFileHandle::Write(const void* buffer, ui32 byteCount) noexcept {
  486. if (!IsOpen()) {
  487. return -1;
  488. }
  489. #if defined(_win_)
  490. DWORD bytesWritten = 0;
  491. if (::WriteFile(Fd_, buffer, byteCount, &bytesWritten, nullptr)) {
  492. return bytesWritten;
  493. }
  494. return -1;
  495. #elif defined(_unix_)
  496. i32 ret;
  497. do {
  498. ret = ::write(Fd_, buffer, byteCount);
  499. } while (ret == -1 && errno == EINTR);
  500. return ret;
  501. #else
  502. #error unsupported platform
  503. #endif
  504. }
  505. i32 TFileHandle::Pread(void* buffer, ui32 byteCount, i64 offset) const noexcept {
  506. #if defined(_win_)
  507. OVERLAPPED io;
  508. Zero(io);
  509. DWORD bytesRead = 0;
  510. io.Offset = (ui32)offset;
  511. io.OffsetHigh = (ui32)(offset >> 32);
  512. if (::ReadFile(Fd_, buffer, byteCount, &bytesRead, &io)) {
  513. return bytesRead;
  514. }
  515. if (::GetLastError() == ERROR_HANDLE_EOF) {
  516. return 0;
  517. }
  518. return -1;
  519. #elif defined(_unix_)
  520. i32 ret;
  521. do {
  522. ret = ::pread(Fd_, buffer, byteCount, offset);
  523. } while (ret == -1 && errno == EINTR);
  524. return ret;
  525. #else
  526. #error unsupported platform
  527. #endif
  528. }
  529. i32 TFileHandle::Pwrite(const void* buffer, ui32 byteCount, i64 offset) const noexcept {
  530. #if defined(_win_)
  531. OVERLAPPED io;
  532. Zero(io);
  533. DWORD bytesWritten = 0;
  534. io.Offset = (ui32)offset;
  535. io.OffsetHigh = (ui32)(offset >> 32);
  536. if (::WriteFile(Fd_, buffer, byteCount, &bytesWritten, &io)) {
  537. return bytesWritten;
  538. }
  539. return -1;
  540. #elif defined(_unix_)
  541. i32 ret;
  542. do {
  543. ret = ::pwrite(Fd_, buffer, byteCount, offset);
  544. } while (ret == -1 && errno == EINTR);
  545. return ret;
  546. #else
  547. #error unsupported platform
  548. #endif
  549. }
  550. FHANDLE TFileHandle::Duplicate() const noexcept {
  551. if (!IsOpen()) {
  552. return INVALID_FHANDLE;
  553. }
  554. #if defined(_win_)
  555. FHANDLE dupHandle;
  556. if (!::DuplicateHandle(GetCurrentProcess(), Fd_, GetCurrentProcess(), &dupHandle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
  557. return INVALID_FHANDLE;
  558. }
  559. return dupHandle;
  560. #elif defined(_unix_)
  561. return ::dup(Fd_);
  562. #else
  563. #error unsupported platform
  564. #endif
  565. }
  566. int TFileHandle::Duplicate2Posix(int dstHandle) const noexcept {
  567. if (!IsOpen()) {
  568. return -1;
  569. }
  570. #if defined(_win_)
  571. FHANDLE dupHandle = Duplicate();
  572. if (dupHandle == INVALID_FHANDLE) {
  573. _set_errno(EMFILE);
  574. return -1;
  575. }
  576. int posixHandle = _open_osfhandle((intptr_t)dupHandle, 0);
  577. if (posixHandle == -1) {
  578. CloseHandle(dupHandle);
  579. return -1;
  580. }
  581. if (dup2(posixHandle, dstHandle) == -1) {
  582. dstHandle = -1;
  583. }
  584. _close(posixHandle);
  585. return dstHandle;
  586. #elif defined(_unix_)
  587. while (dup2(Fd_, dstHandle) == -1) {
  588. if (errno != EINTR) {
  589. return -1;
  590. }
  591. }
  592. return dstHandle;
  593. #else
  594. #error unsupported platform
  595. #endif
  596. }
  597. bool TFileHandle::LinkTo(const TFileHandle& fh) const noexcept {
  598. #if defined(_unix_)
  599. while (dup2(fh.Fd_, Fd_) == -1) {
  600. if (errno != EINTR) {
  601. return false;
  602. }
  603. }
  604. return true;
  605. #elif defined(_win_)
  606. TFileHandle nh(fh.Duplicate());
  607. if (!nh.IsOpen()) {
  608. return false;
  609. }
  610. // not thread-safe
  611. nh.Swap(*const_cast<TFileHandle*>(this));
  612. return true;
  613. #else
  614. #error unsupported
  615. #endif
  616. }
  617. int TFileHandle::Flock(int op) noexcept {
  618. return ::Flock(Fd_, op);
  619. }
  620. bool TFileHandle::SetDirect() {
  621. #ifdef _linux_
  622. const long flags = fcntl(Fd_, F_GETFL);
  623. const int r = fcntl(Fd_, F_SETFL, flags | O_DIRECT);
  624. return !r;
  625. #endif
  626. return false;
  627. }
  628. void TFileHandle::ResetDirect() {
  629. #ifdef _linux_
  630. long flags = fcntl(Fd_, F_GETFL);
  631. fcntl(Fd_, F_SETFL, flags & ~O_DIRECT);
  632. #endif
  633. }
  634. i64 TFileHandle::CountCache(i64 offset, i64 length) const noexcept {
  635. #ifdef _linux_
  636. const i64 pageSize = NSystemInfo::GetPageSize();
  637. constexpr size_t vecSize = 512; // Fetch up to 2MiB at once
  638. const i64 batchSize = vecSize * pageSize;
  639. std::array<ui8, vecSize> vec;
  640. void* ptr = nullptr;
  641. i64 res = 0;
  642. if (!IsOpen()) {
  643. return -1;
  644. }
  645. if (!length) {
  646. length = GetLength();
  647. length -= Min(length, offset);
  648. }
  649. if (!length) {
  650. return 0;
  651. }
  652. const i64 begin = AlignDown(offset, pageSize);
  653. const i64 end = AlignUp(offset + length, pageSize);
  654. const i64 size = end - begin;
  655. /*
  656. * Since fincode is not implemented yet use mmap and mincore.
  657. * This is not so effective and scalable for frequent usage.
  658. */
  659. ptr = ::mmap(
  660. (caddr_t) nullptr,
  661. size,
  662. PROT_READ,
  663. MAP_SHARED | MAP_NORESERVE,
  664. Fd_,
  665. begin);
  666. if (MAP_FAILED == ptr) {
  667. return -1;
  668. }
  669. for (i64 base = begin; base < end; base += batchSize) {
  670. const size_t batch = Min(vecSize, size_t((end - base) / pageSize));
  671. void* batchPtr = static_cast<caddr_t>(ptr) + (base - begin);
  672. if (::mincore(batchPtr, batch * pageSize, vec.data())) {
  673. res = -1;
  674. break;
  675. }
  676. for (size_t i = 0; i < batch; i++) {
  677. // count uptodate complete pages in cache
  678. if (vec[i] & 1) {
  679. res += pageSize;
  680. }
  681. }
  682. if (base == begin && (vec[0] & 1)) {
  683. // cut head of first page
  684. res -= offset - begin;
  685. }
  686. if ((end - base) <= batchSize && (vec[batch - 1] & 1)) {
  687. // cut tail of last page
  688. res -= size - (offset - begin) - length;
  689. }
  690. }
  691. ::munmap(ptr, size);
  692. return res;
  693. #else
  694. Y_UNUSED(offset);
  695. Y_UNUSED(length);
  696. return -1;
  697. #endif
  698. }
  699. void TFileHandle::PrefetchCache(i64 offset, i64 length, bool wait) const noexcept {
  700. #ifdef _linux_
  701. #if HAVE_POSIX_FADVISE
  702. // POSIX_FADV_WILLNEED starts reading upto read_ahead_kb in background
  703. ::posix_fadvise(Fd_, offset, length, POSIX_FADV_WILLNEED);
  704. #endif
  705. if (wait) {
  706. TFileHandle devnull("/dev/null", OpenExisting | WrOnly | CloseOnExec);
  707. off_t end = length ? (offset + length) : GetLength();
  708. off_t pos = offset;
  709. ssize_t ret;
  710. do {
  711. ret = ::sendfile((FHANDLE)devnull, Fd_, &pos, end - pos);
  712. } while (pos < end && (ret > 0 || errno == EINTR));
  713. }
  714. #else
  715. Y_UNUSED(offset);
  716. Y_UNUSED(length);
  717. Y_UNUSED(wait);
  718. #endif
  719. }
  720. void TFileHandle::EvictCache(i64 offset, i64 length) const noexcept {
  721. #if HAVE_POSIX_FADVISE
  722. /*
  723. * This tries to evicts only unmaped, clean, complete pages.
  724. */
  725. ::posix_fadvise(Fd_, offset, length, POSIX_FADV_DONTNEED);
  726. #else
  727. Y_UNUSED(offset);
  728. Y_UNUSED(length);
  729. #endif
  730. }
  731. bool TFileHandle::FlushCache(i64 offset, i64 length, bool wait) noexcept {
  732. #if HAVE_SYNC_FILE_RANGE
  733. int flags = SYNC_FILE_RANGE_WRITE;
  734. if (wait) {
  735. flags |= SYNC_FILE_RANGE_WAIT_AFTER;
  736. }
  737. int ret = ::sync_file_range(Fd_, offset, length, flags);
  738. return ret == 0 || errno == EROFS;
  739. #else
  740. Y_UNUSED(offset);
  741. Y_UNUSED(length);
  742. if (wait) {
  743. return FlushData();
  744. }
  745. return true;
  746. #endif
  747. }
  748. TString DecodeOpenMode(ui32 mode0) {
  749. ui32 mode = mode0;
  750. TStringBuilder r;
  751. struct TFlagCombo {
  752. ui32 Value;
  753. TStringBuf Name;
  754. };
  755. static constexpr TFlagCombo knownFlagCombos[]{
  756. #define F(flag) {flag, #flag}
  757. F(RdWr),
  758. F(RdOnly),
  759. F(WrOnly),
  760. F(CreateAlways),
  761. F(CreateNew),
  762. F(OpenAlways),
  763. F(TruncExisting),
  764. F(ForAppend),
  765. F(Transient),
  766. F(CloseOnExec),
  767. F(Temp),
  768. F(Sync),
  769. F(Direct),
  770. F(DirectAligned),
  771. F(Seq),
  772. F(NoReuse),
  773. F(NoReadAhead),
  774. F(AX),
  775. F(AR),
  776. F(AW),
  777. F(ARW),
  778. F(AXOther),
  779. F(AWOther),
  780. F(AROther),
  781. F(AXGroup),
  782. F(AWGroup),
  783. F(ARGroup),
  784. F(AXUser),
  785. F(AWUser),
  786. F(ARUser),
  787. #undef F
  788. };
  789. for (const auto& [flag, name] : knownFlagCombos) {
  790. if ((mode & flag) == flag) {
  791. mode &= ~flag;
  792. if (r) {
  793. r << '|';
  794. }
  795. r << name;
  796. }
  797. }
  798. if (mode != 0) {
  799. if (r) {
  800. r << TStringBuf("|");
  801. }
  802. r << Hex(mode);
  803. }
  804. if (!r) {
  805. return "0";
  806. }
  807. return std::move(r);
  808. }
  809. class TFile::TImpl: public TAtomicRefCount<TImpl> {
  810. public:
  811. inline TImpl(FHANDLE fd, const TString& fname = TString())
  812. : Handle_(fd)
  813. , FileName_(fname)
  814. {
  815. }
  816. inline TImpl(const char* fName, EOpenMode oMode)
  817. : Handle_(fName, oMode)
  818. , FileName_(fName)
  819. {
  820. if (!Handle_.IsOpen()) {
  821. ythrow TFileError() << "can't open " << FileName_.Quote() << " with mode " << DecodeOpenMode(oMode) << " (" << Hex(oMode.ToBaseType()) << ")";
  822. }
  823. }
  824. inline TImpl(const TString& fName, EOpenMode oMode)
  825. : Handle_(fName, oMode)
  826. , FileName_(fName)
  827. {
  828. if (!Handle_.IsOpen()) {
  829. ythrow TFileError() << "can't open " << FileName_.Quote() << " with mode " << DecodeOpenMode(oMode) << " (" << Hex(oMode.ToBaseType()) << ")";
  830. }
  831. }
  832. inline TImpl(const std::filesystem::path& path, EOpenMode oMode)
  833. : Handle_(path, oMode)
  834. , FileName_(path.string())
  835. {
  836. if (!Handle_.IsOpen()) {
  837. ythrow TFileError() << "can't open " << FileName_.Quote() << " with mode " << DecodeOpenMode(oMode) << " (" << Hex(oMode.ToBaseType()) << ")";
  838. }
  839. }
  840. inline ~TImpl() = default;
  841. inline void Close() {
  842. if (!Handle_.Close()) {
  843. ythrow TFileError() << "can't close " << FileName_.Quote();
  844. }
  845. }
  846. const TString& GetName() const noexcept {
  847. return FileName_;
  848. }
  849. void SetName(const TString& newName) {
  850. FileName_ = newName;
  851. }
  852. const TFileHandle& GetHandle() const noexcept {
  853. return Handle_;
  854. }
  855. i64 Seek(i64 offset, SeekDir origin) {
  856. i64 pos = Handle_.Seek(offset, origin);
  857. if (pos == -1L) {
  858. ythrow TFileError() << "can't seek " << offset << " bytes in " << FileName_.Quote();
  859. }
  860. return pos;
  861. }
  862. void Resize(i64 length) {
  863. if (!Handle_.Resize(length)) {
  864. ythrow TFileError() << "can't resize " << FileName_.Quote() << " to size " << length;
  865. }
  866. }
  867. void Reserve(i64 length) {
  868. if (!Handle_.Reserve(length)) {
  869. ythrow TFileError() << "can't reserve " << length << " for file " << FileName_.Quote();
  870. }
  871. }
  872. void FallocateNoResize(i64 length) {
  873. if (!Handle_.FallocateNoResize(length)) {
  874. ythrow TFileError() << "can't allocate " << length << "bytes of space for file " << FileName_.Quote();
  875. }
  876. }
  877. void ShrinkToFit() {
  878. if (!Handle_.ShrinkToFit()) {
  879. ythrow TFileError() << "can't shrink " << FileName_.Quote() << " to logical size";
  880. }
  881. }
  882. void Flush() {
  883. if (!Handle_.Flush()) {
  884. ythrow TFileError() << "can't flush " << FileName_.Quote();
  885. }
  886. }
  887. void FlushData() {
  888. if (!Handle_.FlushData()) {
  889. ythrow TFileError() << "can't flush data " << FileName_.Quote();
  890. }
  891. }
  892. TFile Duplicate() const {
  893. TFileHandle dupH(Handle_.Duplicate());
  894. if (!dupH.IsOpen()) {
  895. ythrow TFileError() << "can't duplicate the handle of " << FileName_.Quote();
  896. }
  897. TFile res(dupH);
  898. dupH.Release();
  899. return res;
  900. }
  901. // Maximum amount of bytes to be read via single system call.
  902. // Some libraries fail when it is greater than max int.
  903. // Syscalls can cause contention if they operate on very large data blocks.
  904. static constexpr size_t MaxReadPortion = 1_GB;
  905. i32 RawRead(void* bufferIn, size_t numBytes) {
  906. const size_t toRead = Min(MaxReadPortion, numBytes);
  907. return Handle_.Read(bufferIn, toRead);
  908. }
  909. size_t ReadOrFail(void* buf, size_t numBytes) {
  910. const i32 reallyRead = RawRead(buf, numBytes);
  911. if (reallyRead < 0) {
  912. ythrow TFileError() << "can not read data from " << FileName_.Quote();
  913. }
  914. return reallyRead;
  915. }
  916. size_t Read(void* bufferIn, size_t numBytes) {
  917. ui8* buf = (ui8*)bufferIn;
  918. while (numBytes) {
  919. const size_t reallyRead = ReadOrFail(buf, numBytes);
  920. if (reallyRead == 0) {
  921. // file exhausted
  922. break;
  923. }
  924. buf += reallyRead;
  925. numBytes -= reallyRead;
  926. }
  927. return buf - (ui8*)bufferIn;
  928. }
  929. void Load(void* buf, size_t len) {
  930. if (Read(buf, len) != len) {
  931. ythrow TFileError() << "can't read " << len << " bytes from " << FileName_.Quote();
  932. }
  933. }
  934. // Maximum amount of bytes to be written via single system call.
  935. // Some libraries fail when it is greater than max int.
  936. // Syscalls can cause contention if they operate on very large data blocks.
  937. static constexpr size_t MaxWritePortion = 1_GB;
  938. void Write(const void* buffer, size_t numBytes) {
  939. const ui8* buf = (const ui8*)buffer;
  940. while (numBytes) {
  941. const i32 toWrite = (i32)Min(MaxWritePortion, numBytes);
  942. const i32 reallyWritten = Handle_.Write(buf, toWrite);
  943. if (reallyWritten < 0) {
  944. ythrow TFileError() << "can't write " << toWrite << " bytes to " << FileName_.Quote();
  945. }
  946. buf += reallyWritten;
  947. numBytes -= reallyWritten;
  948. }
  949. }
  950. size_t Pread(void* bufferIn, size_t numBytes, i64 offset) const {
  951. ui8* buf = (ui8*)bufferIn;
  952. while (numBytes) {
  953. const i32 toRead = (i32)Min(MaxReadPortion, numBytes);
  954. const i32 reallyRead = RawPread(buf, toRead, offset);
  955. if (reallyRead < 0) {
  956. ythrow TFileError() << "can not read data from " << FileName_.Quote();
  957. }
  958. if (reallyRead == 0) {
  959. // file exausted
  960. break;
  961. }
  962. buf += reallyRead;
  963. offset += reallyRead;
  964. numBytes -= reallyRead;
  965. }
  966. return buf - (ui8*)bufferIn;
  967. }
  968. i32 RawPread(void* buf, ui32 len, i64 offset) const {
  969. return Handle_.Pread(buf, len, offset);
  970. }
  971. void Pload(void* buf, size_t len, i64 offset) const {
  972. if (Pread(buf, len, offset) != len) {
  973. ythrow TFileError() << "can't read " << len << " bytes at offset " << offset << " from " << FileName_.Quote();
  974. }
  975. }
  976. void Pwrite(const void* buffer, size_t numBytes, i64 offset) const {
  977. const ui8* buf = (const ui8*)buffer;
  978. while (numBytes) {
  979. const i32 toWrite = (i32)Min(MaxWritePortion, numBytes);
  980. const i32 reallyWritten = Handle_.Pwrite(buf, toWrite, offset);
  981. if (reallyWritten < 0) {
  982. ythrow TFileError() << "can't write " << toWrite << " bytes to " << FileName_.Quote();
  983. }
  984. buf += reallyWritten;
  985. offset += reallyWritten;
  986. numBytes -= reallyWritten;
  987. }
  988. }
  989. void Flock(int op) {
  990. if (0 != Handle_.Flock(op)) {
  991. ythrow TFileError() << "can't flock " << FileName_.Quote();
  992. }
  993. }
  994. void SetDirect() {
  995. if (!Handle_.SetDirect()) {
  996. ythrow TFileError() << "can't set direct mode for " << FileName_.Quote();
  997. }
  998. }
  999. void ResetDirect() {
  1000. Handle_.ResetDirect();
  1001. }
  1002. i64 CountCache(i64 offset, i64 length) const noexcept {
  1003. return Handle_.CountCache(offset, length);
  1004. }
  1005. void PrefetchCache(i64 offset, i64 length, bool wait) const noexcept {
  1006. Handle_.PrefetchCache(offset, length, wait);
  1007. }
  1008. void EvictCache(i64 offset, i64 length) const noexcept {
  1009. Handle_.EvictCache(offset, length);
  1010. }
  1011. void FlushCache(i64 offset, i64 length, bool wait) {
  1012. if (!Handle_.FlushCache(offset, length, wait)) {
  1013. ythrow TFileError() << "can't flush data " << FileName_.Quote();
  1014. }
  1015. }
  1016. private:
  1017. TFileHandle Handle_;
  1018. TString FileName_;
  1019. };
  1020. TFile::TFile()
  1021. : Impl_(new TImpl(INVALID_FHANDLE))
  1022. {
  1023. }
  1024. TFile::TFile(FHANDLE fd)
  1025. : Impl_(new TImpl(fd))
  1026. {
  1027. }
  1028. TFile::TFile(FHANDLE fd, const TString& name)
  1029. : Impl_(new TImpl(fd, name))
  1030. {
  1031. }
  1032. TFile::TFile(const char* fName, EOpenMode oMode)
  1033. : Impl_(new TImpl(fName, oMode))
  1034. {
  1035. }
  1036. TFile::TFile(const TString& fName, EOpenMode oMode)
  1037. : Impl_(new TImpl(fName, oMode))
  1038. {
  1039. }
  1040. TFile::TFile(const std::filesystem::path& path, EOpenMode oMode)
  1041. : Impl_(new TImpl(path, oMode))
  1042. {
  1043. }
  1044. TFile::~TFile() = default;
  1045. void TFile::Close() {
  1046. Impl_->Close();
  1047. }
  1048. const TString& TFile::GetName() const noexcept {
  1049. return Impl_->GetName();
  1050. }
  1051. i64 TFile::GetPosition() const noexcept {
  1052. return Impl_->GetHandle().GetPosition();
  1053. }
  1054. i64 TFile::GetLength() const noexcept {
  1055. return Impl_->GetHandle().GetLength();
  1056. }
  1057. bool TFile::IsOpen() const noexcept {
  1058. return Impl_->GetHandle().IsOpen();
  1059. }
  1060. FHANDLE TFile::GetHandle() const noexcept {
  1061. return Impl_->GetHandle();
  1062. }
  1063. i64 TFile::Seek(i64 offset, SeekDir origin) {
  1064. return Impl_->Seek(offset, origin);
  1065. }
  1066. void TFile::Resize(i64 length) {
  1067. Impl_->Resize(length);
  1068. }
  1069. void TFile::Reserve(i64 length) {
  1070. Impl_->Reserve(length);
  1071. }
  1072. void TFile::FallocateNoResize(i64 length) {
  1073. Impl_->FallocateNoResize(length);
  1074. }
  1075. void TFile::ShrinkToFit() {
  1076. Impl_->ShrinkToFit();
  1077. }
  1078. void TFile::Flush() {
  1079. Impl_->Flush();
  1080. }
  1081. void TFile::FlushData() {
  1082. Impl_->FlushData();
  1083. }
  1084. TFile TFile::Duplicate() const {
  1085. TFile res = Impl_->Duplicate();
  1086. res.Impl_->SetName(Impl_->GetName());
  1087. return res;
  1088. }
  1089. size_t TFile::Read(void* buf, size_t len) {
  1090. return Impl_->Read(buf, len);
  1091. }
  1092. i32 TFile::RawRead(void* buf, size_t len) {
  1093. return Impl_->RawRead(buf, len);
  1094. }
  1095. size_t TFile::ReadOrFail(void* buf, size_t len) {
  1096. return Impl_->ReadOrFail(buf, len);
  1097. }
  1098. void TFile::Load(void* buf, size_t len) {
  1099. Impl_->Load(buf, len);
  1100. }
  1101. void TFile::Write(const void* buf, size_t len) {
  1102. Impl_->Write(buf, len);
  1103. }
  1104. size_t TFile::Pread(void* buf, size_t len, i64 offset) const {
  1105. return Impl_->Pread(buf, len, offset);
  1106. }
  1107. i32 TFile::RawPread(void* buf, ui32 len, i64 offset) const {
  1108. return Impl_->RawPread(buf, len, offset);
  1109. }
  1110. void TFile::Pload(void* buf, size_t len, i64 offset) const {
  1111. Impl_->Pload(buf, len, offset);
  1112. }
  1113. void TFile::Pwrite(const void* buf, size_t len, i64 offset) const {
  1114. Impl_->Pwrite(buf, len, offset);
  1115. }
  1116. void TFile::Flock(int op) {
  1117. Impl_->Flock(op);
  1118. }
  1119. void TFile::SetDirect() {
  1120. Impl_->SetDirect();
  1121. }
  1122. void TFile::ResetDirect() {
  1123. Impl_->ResetDirect();
  1124. }
  1125. i64 TFile::CountCache(i64 offset, i64 length) const noexcept {
  1126. return Impl_->CountCache(offset, length);
  1127. }
  1128. void TFile::PrefetchCache(i64 offset, i64 length, bool wait) const noexcept {
  1129. Impl_->PrefetchCache(offset, length, wait);
  1130. }
  1131. void TFile::EvictCache(i64 offset, i64 length) const noexcept {
  1132. Impl_->EvictCache(offset, length);
  1133. }
  1134. void TFile::FlushCache(i64 offset, i64 length, bool wait) {
  1135. Impl_->FlushCache(offset, length, wait);
  1136. }
  1137. void TFile::LinkTo(const TFile& f) const {
  1138. if (!Impl_->GetHandle().LinkTo(f.Impl_->GetHandle())) {
  1139. ythrow TFileError() << "can not link fd(" << GetName() << " -> " << f.GetName() << ")";
  1140. }
  1141. }
  1142. TFile TFile::Temporary(const TString& prefix) {
  1143. // TODO - handle impossible case of name collision
  1144. return TFile(prefix + ToString(MicroSeconds()) + "-" + ToString(RandomNumber<ui64>()), CreateNew | RdWr | Seq | Temp | Transient);
  1145. }
  1146. TFile TFile::ForAppend(const TString& path) {
  1147. return TFile(path, OpenAlways | WrOnly | Seq | ::ForAppend);
  1148. }
  1149. TFile Duplicate(FILE* f) {
  1150. return Duplicate(fileno(f));
  1151. }
  1152. TFile Duplicate(int fd) {
  1153. #if defined(_win_)
  1154. /* There are two options of how to duplicate a file descriptor on Windows:
  1155. *
  1156. * 1:
  1157. * - Call dup.
  1158. * - Call _get_osfhandle on the result.
  1159. * - Use returned handle.
  1160. * - Call _close on file descriptor returned by dup. This will also close
  1161. * the handle.
  1162. *
  1163. * 2:
  1164. * - Call _get_osfhandle.
  1165. * - Call DuplicateHandle on the result.
  1166. * - Use returned handle.
  1167. * - Call CloseHandle.
  1168. *
  1169. * TFileHandle calls CloseHandle when destroyed, leaving us with option #2. */
  1170. FHANDLE handle = reinterpret_cast<FHANDLE>(::_get_osfhandle(fd));
  1171. FHANDLE dupHandle;
  1172. if (!::DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), &dupHandle, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
  1173. ythrow TFileError() << "can not duplicate file descriptor " << LastSystemError() << Endl;
  1174. }
  1175. return TFile(dupHandle);
  1176. #elif defined(_unix_)
  1177. return TFile(::dup(fd));
  1178. #else
  1179. #error unsupported platform
  1180. #endif
  1181. }
  1182. bool PosixDisableReadAhead(FHANDLE fileHandle, void* addr) noexcept {
  1183. int ret = -1;
  1184. #if HAVE_POSIX_FADVISE
  1185. #if defined(_linux_)
  1186. Y_UNUSED(fileHandle);
  1187. ret = madvise(addr, 0, MADV_RANDOM); // according to klamm@ posix_fadvise does not work under linux, madvise does work
  1188. #else
  1189. Y_UNUSED(addr);
  1190. ret = ::posix_fadvise(fileHandle, 0, 0, POSIX_FADV_RANDOM);
  1191. #endif
  1192. #else
  1193. Y_UNUSED(fileHandle);
  1194. Y_UNUSED(addr);
  1195. #endif
  1196. return ret == 0;
  1197. }