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