file.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. #include "rar.hpp"
  2. File::File()
  3. {
  4. hFile=FILE_BAD_HANDLE;
  5. *FileName=0;
  6. NewFile=false;
  7. LastWrite=false;
  8. HandleType=FILE_HANDLENORMAL;
  9. LineInput=false;
  10. SkipClose=false;
  11. ErrorType=FILE_SUCCESS;
  12. OpenShared=false;
  13. AllowDelete=true;
  14. AllowExceptions=true;
  15. PreserveAtime=false;
  16. #ifdef _WIN_ALL
  17. CreateMode=FMF_UNDEFINED;
  18. #endif
  19. ReadErrorMode=FREM_ASK;
  20. TruncatedAfterReadError=false;
  21. CurFilePos=0;
  22. }
  23. File::~File()
  24. {
  25. if (hFile!=FILE_BAD_HANDLE && !SkipClose)
  26. if (NewFile)
  27. Delete();
  28. else
  29. Close();
  30. }
  31. void File::operator = (File &SrcFile)
  32. {
  33. hFile=SrcFile.hFile;
  34. NewFile=SrcFile.NewFile;
  35. LastWrite=SrcFile.LastWrite;
  36. HandleType=SrcFile.HandleType;
  37. TruncatedAfterReadError=SrcFile.TruncatedAfterReadError;
  38. wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
  39. SrcFile.SkipClose=true;
  40. }
  41. bool File::Open(const wchar *Name,uint Mode)
  42. {
  43. ErrorType=FILE_SUCCESS;
  44. FileHandle hNewFile;
  45. bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0;
  46. bool UpdateMode=(Mode & FMF_UPDATE)!=0;
  47. bool WriteMode=(Mode & FMF_WRITE)!=0;
  48. #ifdef _WIN_ALL
  49. uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ;
  50. if (UpdateMode)
  51. Access|=GENERIC_WRITE;
  52. uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
  53. if (OpenShared)
  54. ShareMode|=FILE_SHARE_WRITE;
  55. uint Flags=FILE_FLAG_SEQUENTIAL_SCAN;
  56. FindData FD;
  57. if (PreserveAtime)
  58. Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
  59. hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
  60. DWORD LastError;
  61. if (hNewFile==FILE_BAD_HANDLE)
  62. {
  63. LastError=GetLastError();
  64. wchar LongName[NM];
  65. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  66. {
  67. hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
  68. // For archive names longer than 260 characters first CreateFile
  69. // (without \\?\) fails and sets LastError to 3 (access denied).
  70. // We need the correct "file not found" error code to decide
  71. // if we create a new archive or quit with "cannot create" error.
  72. // So we need to check the error code after \\?\ CreateFile again,
  73. // otherwise we'll fail to create new archives with long names.
  74. // But we cannot simply assign the new code to LastError,
  75. // because it would break "..\arcname.rar" relative names processing.
  76. // First CreateFile returns the correct "file not found" code for such
  77. // names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating
  78. // dots as a directory name. So we check only for "file not found"
  79. // error here and for other errors use the first CreateFile result.
  80. if (GetLastError()==ERROR_FILE_NOT_FOUND)
  81. LastError=ERROR_FILE_NOT_FOUND;
  82. }
  83. }
  84. if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
  85. ErrorType=FILE_NOTFOUND;
  86. if (PreserveAtime && hNewFile!=FILE_BAD_HANDLE)
  87. {
  88. FILETIME ft={0xffffffff,0xffffffff}; // This value prevents atime modification.
  89. SetFileTime(hNewFile,NULL,&ft,NULL);
  90. }
  91. #else
  92. int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
  93. #ifdef O_BINARY
  94. flags|=O_BINARY;
  95. #if defined(_AIX) && defined(_LARGE_FILE_API)
  96. flags|=O_LARGEFILE;
  97. #endif
  98. #endif
  99. // NDK r20 has O_NOATIME, but fails to create files with it in Android 7+.
  100. #if defined(O_NOATIME)
  101. if (PreserveAtime)
  102. flags|=O_NOATIME;
  103. #endif
  104. char NameA[NM];
  105. WideToChar(Name,NameA,ASIZE(NameA));
  106. int handle=open(NameA,flags);
  107. #ifdef LOCK_EX
  108. #ifdef _OSF_SOURCE
  109. extern "C" int flock(int, int);
  110. #endif
  111. if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
  112. {
  113. close(handle);
  114. return false;
  115. }
  116. #endif
  117. if (handle==-1)
  118. hNewFile=FILE_BAD_HANDLE;
  119. else
  120. {
  121. #ifdef FILE_USE_OPEN
  122. hNewFile=handle;
  123. #else
  124. hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
  125. #endif
  126. }
  127. if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT)
  128. ErrorType=FILE_NOTFOUND;
  129. #endif
  130. NewFile=false;
  131. HandleType=FILE_HANDLENORMAL;
  132. SkipClose=false;
  133. bool Success=hNewFile!=FILE_BAD_HANDLE;
  134. if (Success)
  135. {
  136. hFile=hNewFile;
  137. wcsncpyz(FileName,Name,ASIZE(FileName));
  138. TruncatedAfterReadError=false;
  139. }
  140. return Success;
  141. }
  142. #if !defined(SFX_MODULE)
  143. void File::TOpen(const wchar *Name)
  144. {
  145. if (!WOpen(Name))
  146. ErrHandler.Exit(RARX_OPEN);
  147. }
  148. #endif
  149. bool File::WOpen(const wchar *Name)
  150. {
  151. if (Open(Name))
  152. return true;
  153. ErrHandler.OpenErrorMsg(Name);
  154. return false;
  155. }
  156. bool File::Create(const wchar *Name,uint Mode)
  157. {
  158. return false; /* // OPENMPT ADDITION
  159. // OpenIndiana based NAS and CIFS shares fail to set the file time if file
  160. // was created in read+write mode and some data was written and not flushed
  161. // before SetFileTime call. So we should use the write only mode if we plan
  162. // SetFileTime call and do not need to read from file.
  163. bool WriteMode=(Mode & FMF_WRITE)!=0;
  164. bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared;
  165. #ifdef _WIN_ALL
  166. CreateMode=Mode;
  167. uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
  168. DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
  169. // Windows automatically removes dots and spaces in the end of file name,
  170. // So we detect such names and process them with \\?\ prefix.
  171. wchar *LastChar=PointToLastChar(Name);
  172. bool Special=*LastChar=='.' || *LastChar==' ';
  173. if (Special && (Mode & FMF_STANDARDNAMES)==0)
  174. hFile=FILE_BAD_HANDLE;
  175. else
  176. hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
  177. if (hFile==FILE_BAD_HANDLE)
  178. {
  179. wchar LongName[NM];
  180. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  181. hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
  182. }
  183. #else
  184. char NameA[NM];
  185. WideToChar(Name,NameA,ASIZE(NameA));
  186. #ifdef FILE_USE_OPEN
  187. hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
  188. #else
  189. hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
  190. #endif
  191. #endif
  192. NewFile=true;
  193. HandleType=FILE_HANDLENORMAL;
  194. SkipClose=false;
  195. wcsncpyz(FileName,Name,ASIZE(FileName));
  196. return hFile!=FILE_BAD_HANDLE;
  197. */ // OPENMPT ADDITION
  198. }
  199. #if !defined(SFX_MODULE)
  200. void File::TCreate(const wchar *Name,uint Mode)
  201. {
  202. if (!WCreate(Name,Mode))
  203. ErrHandler.Exit(RARX_FATAL);
  204. }
  205. #endif
  206. bool File::WCreate(const wchar *Name,uint Mode)
  207. {
  208. if (Create(Name,Mode))
  209. return true;
  210. ErrHandler.CreateErrorMsg(Name);
  211. return false;
  212. }
  213. bool File::Close()
  214. {
  215. bool Success=true;
  216. if (hFile!=FILE_BAD_HANDLE)
  217. {
  218. if (!SkipClose)
  219. {
  220. #ifdef _WIN_ALL
  221. // We use the standard system handle for stdout in Windows
  222. // and it must not be closed here.
  223. if (HandleType==FILE_HANDLENORMAL)
  224. Success=CloseHandle(hFile)==TRUE;
  225. #else
  226. #ifdef FILE_USE_OPEN
  227. Success=close(hFile)!=-1;
  228. #else
  229. Success=fclose(hFile)!=EOF;
  230. #endif
  231. #endif
  232. }
  233. hFile=FILE_BAD_HANDLE;
  234. }
  235. HandleType=FILE_HANDLENORMAL;
  236. if (!Success && AllowExceptions)
  237. ErrHandler.CloseError(FileName);
  238. return Success;
  239. }
  240. bool File::Delete()
  241. {
  242. if (HandleType!=FILE_HANDLENORMAL)
  243. return false;
  244. if (hFile!=FILE_BAD_HANDLE)
  245. Close();
  246. if (!AllowDelete)
  247. return false;
  248. return DelFile(FileName);
  249. }
  250. bool File::Rename(const wchar *NewName)
  251. {
  252. // No need to rename if names are already same.
  253. bool Success=wcscmp(FileName,NewName)==0;
  254. if (!Success)
  255. Success=RenameFile(FileName,NewName);
  256. if (Success)
  257. wcsncpyz(FileName,NewName,ASIZE(FileName));
  258. return Success;
  259. }
  260. bool File::Write(const void *Data,size_t Size)
  261. {
  262. return true; /* // OPENMPT ADDITION
  263. if (Size==0)
  264. return true;
  265. if (HandleType==FILE_HANDLESTD)
  266. {
  267. #ifdef _WIN_ALL
  268. hFile=GetStdHandle(STD_OUTPUT_HANDLE);
  269. #else
  270. // Cannot use the standard stdout here, because it already has wide orientation.
  271. if (hFile==FILE_BAD_HANDLE)
  272. {
  273. #ifdef FILE_USE_OPEN
  274. hFile=dup(STDOUT_FILENO); // Open new stdout stream.
  275. #else
  276. hFile=fdopen(dup(STDOUT_FILENO),"w"); // Open new stdout stream.
  277. #endif
  278. }
  279. #endif
  280. }
  281. bool Success;
  282. while (1)
  283. {
  284. Success=false;
  285. #ifdef _WIN_ALL
  286. DWORD Written=0;
  287. if (HandleType!=FILE_HANDLENORMAL)
  288. {
  289. // writing to stdout can fail in old Windows if data block is too large
  290. const size_t MaxSize=0x4000;
  291. for (size_t I=0;I<Size;I+=MaxSize)
  292. {
  293. Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)==TRUE;
  294. if (!Success)
  295. break;
  296. }
  297. }
  298. else
  299. Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
  300. #else
  301. #ifdef FILE_USE_OPEN
  302. ssize_t Written=write(hFile,Data,Size);
  303. Success=Written==Size;
  304. #else
  305. int Written=fwrite(Data,1,Size,hFile);
  306. Success=Written==Size && !ferror(hFile);
  307. #endif
  308. #endif
  309. if (!Success && AllowExceptions && HandleType==FILE_HANDLENORMAL)
  310. {
  311. #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(RARDLL)
  312. int ErrCode=GetLastError();
  313. int64 FilePos=Tell();
  314. uint64 FreeSize=GetFreeDisk(FileName);
  315. SetLastError(ErrCode);
  316. if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff)
  317. ErrHandler.WriteErrorFAT(FileName);
  318. #endif
  319. if (ErrHandler.AskRepeatWrite(FileName,false))
  320. {
  321. #if !defined(_WIN_ALL) && !defined(FILE_USE_OPEN)
  322. clearerr(hFile);
  323. #endif
  324. if (Written<Size && Written>0)
  325. Seek(Tell()-Written,SEEK_SET);
  326. continue;
  327. }
  328. ErrHandler.WriteError(NULL,FileName);
  329. }
  330. break;
  331. }
  332. LastWrite=true;
  333. return Success; // It can return false only if AllowExceptions is disabled.
  334. */ // OPENMPT ADDITION
  335. }
  336. int File::Read(void *Data,size_t Size)
  337. {
  338. if (TruncatedAfterReadError)
  339. return 0;
  340. int64 FilePos=0; // Initialized only to suppress some compilers warning.
  341. if (ReadErrorMode==FREM_IGNORE)
  342. FilePos=Tell();
  343. int TotalRead=0;
  344. while (true)
  345. {
  346. int ReadSize=DirectRead(Data,Size);
  347. if (ReadSize==-1)
  348. {
  349. ErrorType=FILE_READERROR;
  350. if (AllowExceptions)
  351. if (ReadErrorMode==FREM_IGNORE)
  352. {
  353. ReadSize=0;
  354. for (size_t I=0;I<Size;I+=512)
  355. {
  356. Seek(FilePos+I,SEEK_SET);
  357. size_t SizeToRead=Min(Size-I,512);
  358. int ReadCode=DirectRead(Data,SizeToRead);
  359. ReadSize+=(ReadCode==-1) ? 512:ReadCode;
  360. if (ReadSize!=-1)
  361. TotalRead+=ReadSize;
  362. }
  363. }
  364. else
  365. {
  366. bool Ignore=false,Retry=false,Quit=false;
  367. if (ReadErrorMode==FREM_ASK && HandleType==FILE_HANDLENORMAL)
  368. {
  369. ErrHandler.AskRepeatRead(FileName,Ignore,Retry,Quit);
  370. if (Retry)
  371. continue;
  372. }
  373. if (Ignore || ReadErrorMode==FREM_TRUNCATE)
  374. {
  375. TruncatedAfterReadError=true;
  376. return 0;
  377. }
  378. ErrHandler.ReadError(FileName);
  379. }
  380. }
  381. TotalRead+=ReadSize; // If ReadSize is -1, TotalRead is also set to -1 here.
  382. if (HandleType==FILE_HANDLESTD && !LineInput && ReadSize>0 && (uint)ReadSize<Size)
  383. {
  384. // Unlike regular files, for pipe we can read only as much as was
  385. // written at the other end of pipe. We had seen data coming in small
  386. // ~80 byte chunks when piping from 'type arc.rar'. Extraction code
  387. // would fail if we read an incomplete archive header from stdin.
  388. // So here we ensure that requested size is completely read.
  389. // But we return the available data immediately in "line input" mode,
  390. // when processing user's input in console prompts. Otherwise apps
  391. // piping user responses to multiple Ask() prompts can hang if no more
  392. // data is available yet and pipe isn't closed.
  393. Data=(byte*)Data+ReadSize;
  394. Size-=ReadSize;
  395. continue;
  396. }
  397. break;
  398. }
  399. if (TotalRead>0) // Can be -1 for error and AllowExceptions disabled.
  400. CurFilePos+=TotalRead;
  401. return TotalRead; // It can return -1 only if AllowExceptions is disabled.
  402. }
  403. // Returns -1 in case of error.
  404. int File::DirectRead(void *Data,size_t Size)
  405. {
  406. #ifdef _WIN_ALL
  407. const size_t MaxDeviceRead=20000;
  408. const size_t MaxLockedRead=32768;
  409. #endif
  410. if (HandleType==FILE_HANDLESTD)
  411. {
  412. #ifdef _WIN_ALL
  413. // if (Size>MaxDeviceRead)
  414. // Size=MaxDeviceRead;
  415. hFile=GetStdHandle(STD_INPUT_HANDLE);
  416. #else
  417. #ifdef FILE_USE_OPEN
  418. hFile=STDIN_FILENO;
  419. #else
  420. hFile=stdin;
  421. #endif
  422. #endif
  423. }
  424. #ifdef _WIN_ALL
  425. // For pipes like 'type file.txt | rar -si arcname' ReadFile may return
  426. // data in small ~4KB blocks. It may slightly reduce the compression ratio.
  427. DWORD Read;
  428. if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL))
  429. {
  430. if (IsDevice() && Size>MaxDeviceRead)
  431. return DirectRead(Data,MaxDeviceRead);
  432. if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE)
  433. return 0;
  434. // We had a bug report about failure to archive 1C database lock file
  435. // 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB
  436. // permanently locked. If our first read request uses too large buffer
  437. // and if we are in -dh mode, so we were able to open the file,
  438. // we'll fail with "Read error". So now we use try a smaller buffer size
  439. // in case of lock error.
  440. if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead &&
  441. GetLastError()==ERROR_LOCK_VIOLATION)
  442. return DirectRead(Data,MaxLockedRead);
  443. return -1;
  444. }
  445. return Read;
  446. #else
  447. #ifdef FILE_USE_OPEN
  448. ssize_t ReadSize=read(hFile,Data,Size);
  449. if (ReadSize==-1)
  450. return -1;
  451. return (int)ReadSize;
  452. #else
  453. if (LastWrite)
  454. {
  455. fflush(hFile);
  456. LastWrite=false;
  457. }
  458. clearerr(hFile);
  459. size_t ReadSize=fread(Data,1,Size,hFile);
  460. if (ferror(hFile))
  461. return -1;
  462. return (int)ReadSize;
  463. #endif
  464. #endif
  465. }
  466. void File::Seek(int64 Offset,int Method)
  467. {
  468. if (!RawSeek(Offset,Method) && AllowExceptions)
  469. ErrHandler.SeekError(FileName);
  470. }
  471. bool File::RawSeek(int64 Offset,int Method)
  472. {
  473. if (hFile==FILE_BAD_HANDLE)
  474. return true;
  475. if (!IsSeekable())
  476. {
  477. if (Method==SEEK_CUR)
  478. {
  479. Offset+=CurFilePos;
  480. Method=SEEK_SET;
  481. }
  482. if (Method==SEEK_SET && Offset>=CurFilePos) // Reading for seek forward.
  483. {
  484. uint64 SkipSize=Offset-CurFilePos;
  485. while (SkipSize>0)
  486. {
  487. byte Buf[4096];
  488. int ReadSize=Read(Buf,(size_t)Min(SkipSize,ASIZE(Buf)));
  489. if (ReadSize<=0)
  490. return false;
  491. SkipSize-=ReadSize;
  492. }
  493. CurFilePos=Offset;
  494. return true;
  495. }
  496. return false; // Backward or end of file seek on unseekable file.
  497. }
  498. if (Offset<0 && Method!=SEEK_SET)
  499. {
  500. Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
  501. Method=SEEK_SET;
  502. }
  503. #ifdef _WIN_ALL
  504. LONG HighDist=(LONG)(Offset>>32);
  505. if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff &&
  506. GetLastError()!=NO_ERROR)
  507. return false;
  508. #else
  509. LastWrite=false;
  510. #ifdef FILE_USE_OPEN
  511. if (lseek(hFile,(off_t)Offset,Method)==-1)
  512. return false;
  513. #elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
  514. if (fseeko(hFile,Offset,Method)!=0)
  515. return false;
  516. #else
  517. if (fseek(hFile,(long)Offset,Method)!=0)
  518. return false;
  519. #endif
  520. #endif
  521. return true;
  522. }
  523. int64 File::Tell()
  524. {
  525. if (hFile==FILE_BAD_HANDLE)
  526. if (AllowExceptions)
  527. ErrHandler.SeekError(FileName);
  528. else
  529. return -1;
  530. if (!IsSeekable())
  531. return CurFilePos;
  532. #ifdef _WIN_ALL
  533. LONG HighDist=0;
  534. uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
  535. if (LowDist==0xffffffff && GetLastError()!=NO_ERROR)
  536. if (AllowExceptions)
  537. ErrHandler.SeekError(FileName);
  538. else
  539. return -1;
  540. return INT32TO64(HighDist,LowDist);
  541. #else
  542. #ifdef FILE_USE_OPEN
  543. return lseek(hFile,0,SEEK_CUR);
  544. #elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
  545. return ftello(hFile);
  546. #else
  547. return ftell(hFile);
  548. #endif
  549. #endif
  550. }
  551. void File::Prealloc(int64 Size)
  552. {
  553. /* // OPENMPT ADDITION
  554. #ifdef _WIN_ALL
  555. if (RawSeek(Size,SEEK_SET))
  556. {
  557. Truncate();
  558. Seek(0,SEEK_SET);
  559. }
  560. #endif
  561. #if defined(_UNIX) && defined(USE_FALLOCATE)
  562. // fallocate is rather new call. Only latest kernels support it.
  563. // So we are not using it by default yet.
  564. int fd = GetFD();
  565. if (fd >= 0)
  566. fallocate(fd, 0, 0, Size);
  567. #endif
  568. */ // OPENMPT ADDITION
  569. }
  570. byte File::GetByte()
  571. {
  572. byte Byte=0;
  573. Read(&Byte,1);
  574. return Byte;
  575. }
  576. void File::PutByte(byte Byte)
  577. {
  578. Write(&Byte,1);
  579. }
  580. bool File::Truncate()
  581. {
  582. return false; /* // OPENMPT ADDITION
  583. #ifdef _WIN_ALL
  584. return SetEndOfFile(hFile)==TRUE;
  585. #else
  586. return ftruncate(GetFD(),(off_t)Tell())==0;
  587. #endif
  588. */ // OPENMPT ADDITION
  589. }
  590. void File::Flush()
  591. {
  592. return; /* // OPENMPT ADDITION
  593. #ifdef _WIN_ALL
  594. FlushFileBuffers(hFile);
  595. #else
  596. #ifndef FILE_USE_OPEN
  597. fflush(hFile);
  598. #endif
  599. fsync(GetFD());
  600. #endif
  601. */ // OPENMPT EDDITION
  602. }
  603. void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
  604. {
  605. /* // OPENMPT ADDITION
  606. #ifdef _WIN_ALL
  607. // Workaround for OpenIndiana NAS time bug. If we cannot create a file
  608. // in write only mode, we need to flush the write buffer before calling
  609. // SetFileTime or file time will not be changed.
  610. if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
  611. FlushFileBuffers(hFile);
  612. bool sm=ftm!=NULL && ftm->IsSet();
  613. bool sc=ftc!=NULL && ftc->IsSet();
  614. bool sa=fta!=NULL && fta->IsSet();
  615. FILETIME fm,fc,fa;
  616. if (sm)
  617. ftm->GetWinFT(&fm);
  618. if (sc)
  619. ftc->GetWinFT(&fc);
  620. if (sa)
  621. fta->GetWinFT(&fa);
  622. SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
  623. #endif
  624. */ // OPENMPT ADDITION
  625. }
  626. void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
  627. {
  628. /* // OPENMPT ADDITION
  629. // Android APP_PLATFORM := android-14 does not support futimens and futimes.
  630. // Newer platforms support futimens, but fail on Android 4.2.
  631. // We have to use utime for Android.
  632. // Also we noticed futimens fail to set timestamps on NTFS partition
  633. // mounted to virtual Linux x86 machine, but utimensat worked correctly.
  634. // So we set timestamps for already closed files in Unix.
  635. #ifdef _UNIX
  636. SetCloseFileTimeByName(FileName,ftm,fta);
  637. #endif
  638. */ // OPENMPT ADDITION
  639. }
  640. void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
  641. {
  642. /* // OPENMPT ADDITION
  643. #ifdef _UNIX
  644. bool setm=ftm!=NULL && ftm->IsSet();
  645. bool seta=fta!=NULL && fta->IsSet();
  646. if (setm || seta)
  647. {
  648. char NameA[NM];
  649. WideToChar(Name,NameA,ASIZE(NameA));
  650. #ifdef UNIX_TIME_NS
  651. timespec times[2];
  652. times[0].tv_sec=seta ? fta->GetUnix() : 0;
  653. times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
  654. times[1].tv_sec=setm ? ftm->GetUnix() : 0;
  655. times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
  656. utimensat(AT_FDCWD,NameA,times,0);
  657. #else
  658. utimbuf ut;
  659. if (setm)
  660. ut.modtime=ftm->GetUnix();
  661. else
  662. ut.modtime=fta->GetUnix(); // Need to set something, cannot left it 0.
  663. if (seta)
  664. ut.actime=fta->GetUnix();
  665. else
  666. ut.actime=ut.modtime; // Need to set something, cannot left it 0.
  667. utime(NameA,&ut);
  668. #endif
  669. }
  670. #endif
  671. */ // OPENMPT ADDITION
  672. }
  673. void File::GetOpenFileTime(RarTime *ft)
  674. {
  675. /* // OPENMPT ADDITION
  676. #ifdef _WIN_ALL
  677. FILETIME FileTime;
  678. GetFileTime(hFile,NULL,NULL,&FileTime);
  679. ft->SetWinFT(&FileTime);
  680. #endif
  681. #if defined(_UNIX) || defined(_EMX)
  682. struct stat st;
  683. fstat(GetFD(),&st);
  684. ft->SetUnix(st.st_mtime);
  685. #endif
  686. */ // OPENMPT ADDITION
  687. }
  688. int64 File::FileLength()
  689. {
  690. int64 SavePos=Tell();
  691. Seek(0,SEEK_END);
  692. int64 Length=Tell();
  693. Seek(SavePos,SEEK_SET);
  694. return Length;
  695. }
  696. bool File::IsDevice()
  697. {
  698. if (hFile==FILE_BAD_HANDLE)
  699. return false;
  700. #ifdef _WIN_ALL
  701. uint Type=GetFileType(hFile);
  702. return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE;
  703. #else
  704. return isatty(GetFD());
  705. #endif
  706. }
  707. #ifndef SFX_MODULE
  708. int64 File::Copy(File &Dest,int64 Length)
  709. {
  710. Array<byte> Buffer(File::CopyBufferSize());
  711. int64 CopySize=0;
  712. bool CopyAll=(Length==INT64NDF);
  713. while (CopyAll || Length>0)
  714. {
  715. Wait();
  716. size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
  717. byte *Buf=&Buffer[0];
  718. int ReadSize=Read(Buf,SizeToRead);
  719. if (ReadSize==0)
  720. break;
  721. size_t WriteSize=ReadSize;
  722. #ifdef _WIN_ALL
  723. // For FAT32 USB flash drives in Windows if first write is 4 KB or more,
  724. // write caching is disabled and "write through" is enabled, resulting
  725. // in bad performance, especially for many small files. It happens when
  726. // we create SFX archive on USB drive, because SFX module is written first.
  727. // So we split the first write to small 1 KB followed by rest of data.
  728. if (CopySize==0 && WriteSize>=4096)
  729. {
  730. const size_t FirstWrite=1024;
  731. Dest.Write(Buf,FirstWrite);
  732. Buf+=FirstWrite;
  733. WriteSize-=FirstWrite;
  734. }
  735. #endif
  736. Dest.Write(Buf,WriteSize);
  737. CopySize+=ReadSize;
  738. if (!CopyAll)
  739. Length-=ReadSize;
  740. }
  741. return CopySize;
  742. }
  743. #endif