filefn.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. #include "rar.hpp"
  2. MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
  3. {
  4. return MKDIR_SUCCESS; // OPENMPT ADDITION
  5. #ifdef _WIN_ALL
  6. // Windows automatically removes dots and spaces in the end of directory
  7. // name. So we detect such names and process them with \\?\ prefix.
  8. wchar *LastChar=PointToLastChar(Name);
  9. bool Special=*LastChar=='.' || *LastChar==' ';
  10. BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL);
  11. if (RetCode==0 && !FileExist(Name))
  12. {
  13. wchar LongName[NM];
  14. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  15. RetCode=CreateDirectory(LongName,NULL);
  16. }
  17. if (RetCode!=0) // Non-zero return code means success for CreateDirectory.
  18. {
  19. if (SetAttr)
  20. SetFileAttr(Name,Attr);
  21. return MKDIR_SUCCESS;
  22. }
  23. int ErrCode=GetLastError();
  24. if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND)
  25. return MKDIR_BADPATH;
  26. return MKDIR_ERROR;
  27. #elif defined(_UNIX)
  28. char NameA[NM];
  29. WideToChar(Name,NameA,ASIZE(NameA));
  30. mode_t uattr=SetAttr ? (mode_t)Attr:0777;
  31. int ErrCode=mkdir(NameA,uattr);
  32. if (ErrCode==-1)
  33. return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR;
  34. return MKDIR_SUCCESS;
  35. #else
  36. return MKDIR_ERROR;
  37. #endif
  38. }
  39. bool CreatePath(const wchar *Path,bool SkipLastName,bool Silent)
  40. {
  41. return true; // OPENMPT ADDITION
  42. if (Path==NULL || *Path==0)
  43. return false;
  44. #if defined(_WIN_ALL) || defined(_EMX)
  45. uint DirAttr=0;
  46. #else
  47. uint DirAttr=0777;
  48. #endif
  49. bool Success=true;
  50. for (const wchar *s=Path;*s!=0;s++)
  51. {
  52. wchar DirName[NM];
  53. if (s-Path>=ASIZE(DirName))
  54. break;
  55. // Process all kinds of path separators, so user can enter Unix style
  56. // path in Windows or Windows in Unix. s>Path check avoids attempting
  57. // creating an empty directory for paths starting from path separator.
  58. if (IsPathDiv(*s) && s>Path)
  59. {
  60. #ifdef _WIN_ALL
  61. // We must not attempt to create "D:" directory, because first
  62. // CreateDirectory will fail, so we'll use \\?\D:, which forces Wine
  63. // to create "D:" directory.
  64. if (s==Path+2 && Path[1]==':')
  65. continue;
  66. #endif
  67. wcsncpy(DirName,Path,s-Path);
  68. DirName[s-Path]=0;
  69. Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
  70. if (Success && !Silent)
  71. {
  72. mprintf(St(MCreatDir),DirName);
  73. mprintf(L" %s",St(MOk));
  74. }
  75. }
  76. }
  77. if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path)))
  78. Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS;
  79. return Success;
  80. }
  81. void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
  82. {
  83. return; // OPENMPT ADDITION
  84. #if defined(_WIN_ALL)
  85. bool sm=ftm!=NULL && ftm->IsSet();
  86. bool sc=ftc!=NULL && ftc->IsSet();
  87. bool sa=fta!=NULL && fta->IsSet();
  88. uint DirAttr=GetFileAttr(Name);
  89. bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0);
  90. if (ResetAttr)
  91. SetFileAttr(Name,0);
  92. HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
  93. NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
  94. if (hFile==INVALID_HANDLE_VALUE)
  95. {
  96. wchar LongName[NM];
  97. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  98. hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
  99. NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
  100. }
  101. if (hFile==INVALID_HANDLE_VALUE)
  102. return;
  103. FILETIME fm,fc,fa;
  104. if (sm)
  105. ftm->GetWinFT(&fm);
  106. if (sc)
  107. ftc->GetWinFT(&fc);
  108. if (sa)
  109. fta->GetWinFT(&fa);
  110. SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
  111. CloseHandle(hFile);
  112. if (ResetAttr)
  113. SetFileAttr(Name,DirAttr);
  114. #endif
  115. #if defined(_UNIX) || defined(_EMX)
  116. File::SetCloseFileTimeByName(Name,ftm,fta);
  117. #endif
  118. }
  119. bool IsRemovable(const wchar *Name)
  120. {
  121. return false; // OPENMPT ADDITION
  122. #if defined(_WIN_ALL)
  123. wchar Root[NM];
  124. GetPathRoot(Name,Root,ASIZE(Root));
  125. int Type=GetDriveType(*Root!=0 ? Root:NULL);
  126. return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM;
  127. #else
  128. return false;
  129. #endif
  130. }
  131. #ifndef SFX_MODULE
  132. int64 GetFreeDisk(const wchar *Name)
  133. {
  134. return 0; // OPENMPT ADDITION
  135. #ifdef _WIN_ALL
  136. wchar Root[NM];
  137. GetFilePath(Name,Root,ASIZE(Root));
  138. ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
  139. uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
  140. if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
  141. uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
  142. return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart);
  143. return 0;
  144. #elif defined(_UNIX)
  145. wchar Root[NM];
  146. GetFilePath(Name,Root,ASIZE(Root));
  147. char RootA[NM];
  148. WideToChar(Root,RootA,ASIZE(RootA));
  149. struct statvfs sfs;
  150. if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0)
  151. return 0;
  152. int64 FreeSize=sfs.f_bsize;
  153. FreeSize=FreeSize*sfs.f_bavail;
  154. return FreeSize;
  155. #else
  156. return 0;
  157. #endif
  158. }
  159. #endif
  160. #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
  161. // Return 'true' for FAT and FAT32, so we can adjust the maximum supported
  162. // file size to 4 GB for these file systems.
  163. bool IsFAT(const wchar *Name)
  164. {
  165. wchar Root[NM];
  166. GetPathRoot(Name,Root,ASIZE(Root));
  167. wchar FileSystem[MAX_PATH+1];
  168. if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
  169. return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0;
  170. return false;
  171. }
  172. #endif
  173. bool FileExist(const wchar *Name)
  174. {
  175. return false; // OPENMPT ADDITION
  176. #ifdef _WIN_ALL
  177. return GetFileAttr(Name)!=0xffffffff;
  178. #elif defined(ENABLE_ACCESS)
  179. char NameA[NM];
  180. WideToChar(Name,NameA,ASIZE(NameA));
  181. return access(NameA,0)==0;
  182. #else
  183. FindData FD;
  184. return FindFile::FastFind(Name,&FD);
  185. #endif
  186. }
  187. bool WildFileExist(const wchar *Name)
  188. {
  189. return false; // OPENMPT ADDITION
  190. if (IsWildcard(Name))
  191. {
  192. FindFile Find;
  193. Find.SetMask(Name);
  194. FindData fd;
  195. return Find.Next(&fd);
  196. }
  197. return FileExist(Name);
  198. }
  199. bool IsDir(uint Attr)
  200. {
  201. #ifdef _WIN_ALL
  202. return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=0;
  203. #endif
  204. #if defined(_UNIX)
  205. return (Attr & 0xF000)==0x4000;
  206. #endif
  207. }
  208. bool IsUnreadable(uint Attr)
  209. {
  210. #if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR)
  211. return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr);
  212. #endif
  213. return false;
  214. }
  215. bool IsLink(uint Attr)
  216. {
  217. #ifdef _UNIX
  218. return (Attr & 0xF000)==0xA000;
  219. #elif defined(_WIN_ALL)
  220. return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0;
  221. #else
  222. return false;
  223. #endif
  224. }
  225. bool IsDeleteAllowed(uint FileAttr)
  226. {
  227. #ifdef _WIN_ALL
  228. return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0;
  229. #else
  230. return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR);
  231. #endif
  232. }
  233. void PrepareToDelete(const wchar *Name)
  234. {
  235. return; // OPENMPT ADDITION
  236. #if defined(_WIN_ALL) || defined(_EMX)
  237. SetFileAttr(Name,0);
  238. #endif
  239. #ifdef _UNIX
  240. if (Name!=NULL)
  241. {
  242. char NameA[NM];
  243. WideToChar(Name,NameA,ASIZE(NameA));
  244. chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR);
  245. }
  246. #endif
  247. }
  248. uint GetFileAttr(const wchar *Name)
  249. {
  250. return 0; // OPENMPT ADDITION
  251. #ifdef _WIN_ALL
  252. DWORD Attr=GetFileAttributes(Name);
  253. if (Attr==0xffffffff)
  254. {
  255. wchar LongName[NM];
  256. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  257. Attr=GetFileAttributes(LongName);
  258. }
  259. return Attr;
  260. #else
  261. char NameA[NM];
  262. WideToChar(Name,NameA,ASIZE(NameA));
  263. struct stat st;
  264. if (stat(NameA,&st)!=0)
  265. return 0;
  266. return st.st_mode;
  267. #endif
  268. }
  269. bool SetFileAttr(const wchar *Name,uint Attr)
  270. {
  271. return false; // OPENMPT ADDITION
  272. #ifdef _WIN_ALL
  273. bool Success=SetFileAttributes(Name,Attr)!=0;
  274. if (!Success)
  275. {
  276. wchar LongName[NM];
  277. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  278. Success=SetFileAttributes(LongName,Attr)!=0;
  279. }
  280. return Success;
  281. #elif defined(_UNIX)
  282. char NameA[NM];
  283. WideToChar(Name,NameA,ASIZE(NameA));
  284. return chmod(NameA,(mode_t)Attr)==0;
  285. #else
  286. return false;
  287. #endif
  288. }
  289. #if 0
  290. wchar *MkTemp(wchar *Name,size_t MaxSize)
  291. {
  292. size_t Length=wcslen(Name);
  293. RarTime CurTime;
  294. CurTime.SetCurrentTime();
  295. // We cannot use CurTime.GetWin() as is, because its lowest bits can
  296. // have low informational value, like being a zero or few fixed numbers.
  297. uint Random=(uint)(CurTime.GetWin()/100000);
  298. // Using PID we guarantee that different RAR copies use different temp names
  299. // even if started in exactly the same time.
  300. uint PID=0;
  301. #ifdef _WIN_ALL
  302. PID=(uint)GetCurrentProcessId();
  303. #elif defined(_UNIX)
  304. PID=(uint)getpid();
  305. #endif
  306. for (uint Attempt=0;;Attempt++)
  307. {
  308. uint Ext=Random%50000+Attempt;
  309. wchar RndText[50];
  310. swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
  311. if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
  312. return NULL;
  313. wcsncpyz(Name+Length,RndText,MaxSize-Length);
  314. if (!FileExist(Name))
  315. break;
  316. }
  317. return Name;
  318. }
  319. #endif
  320. #if !defined(SFX_MODULE)
  321. void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
  322. {
  323. int64 SavePos=SrcFile->Tell();
  324. #ifndef SILENT
  325. int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size;
  326. #endif
  327. if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWPERCENT))!=0)
  328. uiMsg(UIEVENT_FILESUMSTART);
  329. if ((Flags & CALCFSUM_CURPOS)==0)
  330. SrcFile->Seek(0,SEEK_SET);
  331. const size_t BufSize=0x100000;
  332. Array<byte> Data(BufSize);
  333. DataHash HashCRC,HashBlake2;
  334. HashCRC.Init(HASH_CRC32,Threads);
  335. HashBlake2.Init(HASH_BLAKE2,Threads);
  336. int64 BlockCount=0;
  337. int64 TotalRead=0;
  338. while (true)
  339. {
  340. size_t SizeToRead;
  341. if (Size==INT64NDF) // If we process the entire file.
  342. SizeToRead=BufSize; // Then always attempt to read the entire buffer.
  343. else
  344. SizeToRead=(size_t)Min((int64)BufSize,Size);
  345. int ReadSize=SrcFile->Read(&Data[0],SizeToRead);
  346. if (ReadSize==0)
  347. break;
  348. TotalRead+=ReadSize;
  349. if ((++BlockCount & 0xf)==0)
  350. {
  351. #ifndef SILENT
  352. if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
  353. {
  354. // Update only the current file progress in WinRAR, set the total to 0
  355. // to keep it as is. It looks better for WinRAR,
  356. uiExtractProgress(TotalRead,FileLength,0,0);
  357. }
  358. else
  359. {
  360. if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
  361. uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(TotalRead,FileLength));
  362. }
  363. #endif
  364. Wait();
  365. }
  366. if (CRC32!=NULL)
  367. HashCRC.Update(&Data[0],ReadSize);
  368. if (Blake2!=NULL)
  369. HashBlake2.Update(&Data[0],ReadSize);
  370. if (Size!=INT64NDF)
  371. Size-=ReadSize;
  372. }
  373. SrcFile->Seek(SavePos,SEEK_SET);
  374. if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
  375. uiMsg(UIEVENT_FILESUMEND);
  376. if (CRC32!=NULL)
  377. *CRC32=HashCRC.GetCRC32();
  378. if (Blake2!=NULL)
  379. {
  380. HashValue Result;
  381. HashBlake2.Result(&Result);
  382. memcpy(Blake2,Result.Digest,sizeof(Result.Digest));
  383. }
  384. }
  385. #endif
  386. bool RenameFile(const wchar *SrcName,const wchar *DestName)
  387. {
  388. return true; // OPENMPT ADDITION
  389. #ifdef _WIN_ALL
  390. bool Success=MoveFile(SrcName,DestName)!=0;
  391. if (!Success)
  392. {
  393. wchar LongName1[NM],LongName2[NM];
  394. if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) &&
  395. GetWinLongPath(DestName,LongName2,ASIZE(LongName2)))
  396. Success=MoveFile(LongName1,LongName2)!=0;
  397. }
  398. return Success;
  399. #else
  400. char SrcNameA[NM],DestNameA[NM];
  401. WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA));
  402. WideToChar(DestName,DestNameA,ASIZE(DestNameA));
  403. bool Success=rename(SrcNameA,DestNameA)==0;
  404. return Success;
  405. #endif
  406. }
  407. bool DelFile(const wchar *Name)
  408. {
  409. return true; // OPENMPT ADDITION
  410. #ifdef _WIN_ALL
  411. bool Success=DeleteFile(Name)!=0;
  412. if (!Success)
  413. {
  414. wchar LongName[NM];
  415. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  416. Success=DeleteFile(LongName)!=0;
  417. }
  418. return Success;
  419. #else
  420. char NameA[NM];
  421. WideToChar(Name,NameA,ASIZE(NameA));
  422. bool Success=remove(NameA)==0;
  423. return Success;
  424. #endif
  425. }
  426. bool DelDir(const wchar *Name)
  427. {
  428. return true; // OPENMPT ADDITION
  429. #ifdef _WIN_ALL
  430. bool Success=RemoveDirectory(Name)!=0;
  431. if (!Success)
  432. {
  433. wchar LongName[NM];
  434. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  435. Success=RemoveDirectory(LongName)!=0;
  436. }
  437. return Success;
  438. #else
  439. char NameA[NM];
  440. WideToChar(Name,NameA,ASIZE(NameA));
  441. bool Success=rmdir(NameA)==0;
  442. return Success;
  443. #endif
  444. }
  445. #if defined(_WIN_ALL) && !defined(SFX_MODULE)
  446. bool SetFileCompression(const wchar *Name,bool State)
  447. {
  448. return true; // OPENMPT ADDITION
  449. HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA,
  450. FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
  451. FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
  452. if (hFile==INVALID_HANDLE_VALUE)
  453. {
  454. wchar LongName[NM];
  455. if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
  456. hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA,
  457. FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
  458. FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
  459. }
  460. if (hFile==INVALID_HANDLE_VALUE)
  461. return false;
  462. SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE;
  463. DWORD Result;
  464. int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState,
  465. sizeof(NewState),NULL,0,&Result,NULL);
  466. CloseHandle(hFile);
  467. return RetCode!=0;
  468. }
  469. void ResetFileCache(const wchar *Name)
  470. {
  471. // To reset file cache in Windows it is enough to open it with
  472. // FILE_FLAG_NO_BUFFERING and then close it.
  473. HANDLE hSrc=CreateFile(Name,GENERIC_READ,
  474. FILE_SHARE_READ|FILE_SHARE_WRITE,
  475. NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,NULL);
  476. if (hSrc!=INVALID_HANDLE_VALUE)
  477. CloseHandle(hSrc);
  478. }
  479. #endif