1 #include "rar.hpp"
2
ReadHeader()3 size_t Archive::ReadHeader()
4 {
5 // Once we failed to decrypt an encrypted block, there is no reason to
6 // attempt to do it further. We'll never be successful and only generate
7 // endless errors.
8 if (FailedHeaderDecryption)
9 return 0;
10
11 CurBlockPos=Tell();
12
13 // Other developers asked us to initialize it to suppress "may be used
14 // uninitialized" warning in code below in some compilers.
15 size_t ReadSize=0;
16
17 switch(Format)
18 {
19 #ifndef SFX_MODULE
20 case RARFMT14:
21 ReadSize=ReadHeader14();
22 break;
23 #endif
24 case RARFMT15:
25 ReadSize=ReadHeader15();
26 break;
27 case RARFMT50:
28 ReadSize=ReadHeader50();
29 break;
30 }
31
32 // It is important to check ReadSize>0 here, because it is normal
33 // for RAR2 and RAR3 archives without end of archive block to have
34 // NextBlockPos==CurBlockPos after the end of archive has reached.
35 if (ReadSize>0 && NextBlockPos<=CurBlockPos)
36 {
37 BrokenHeaderMsg();
38 ReadSize=0;
39 }
40
41 if (ReadSize==0)
42 CurHeaderType=HEAD_UNKNOWN;
43
44 return ReadSize;
45 }
46
47
SearchBlock(HEADER_TYPE HeaderType)48 size_t Archive::SearchBlock(HEADER_TYPE HeaderType)
49 {
50 size_t Size,Count=0;
51 while ((Size=ReadHeader())!=0 &&
52 (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC))
53 {
54 if ((++Count & 127)==0)
55 Wait();
56 if (GetHeaderType()==HeaderType)
57 return Size;
58 SeekToNext();
59 }
60 return 0;
61 }
62
63
SearchSubBlock(const wchar * Type)64 size_t Archive::SearchSubBlock(const wchar *Type)
65 {
66 size_t Size,Count=0;
67 while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC)
68 {
69 if ((++Count & 127)==0)
70 Wait();
71 if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type))
72 return Size;
73 SeekToNext();
74 }
75 return 0;
76 }
77
78
SearchRR()79 size_t Archive::SearchRR()
80 {
81 // If locator extra field is available for recovery record, let's utilize it.
82 if (MainHead.Locator && MainHead.RROffset!=0)
83 {
84 uint64 CurPos=Tell();
85 Seek(MainHead.RROffset,SEEK_SET);
86 size_t Size=ReadHeader();
87 if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR))
88 return Size;
89 Seek(CurPos,SEEK_SET);
90 }
91 // Otherwise scan the entire archive to find the recovery record.
92 return SearchSubBlock(SUBHEAD_TYPE_RR);
93 }
94
95
UnexpEndArcMsg()96 void Archive::UnexpEndArcMsg()
97 {
98 int64 ArcSize=FileLength();
99
100 // If block positions are equal to file size, this is not an error.
101 // It can happen when we reached the end of older RAR 1.5 archive,
102 // which did not have the end of archive block.
103 if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
104 {
105 uiMsg(UIERROR_UNEXPEOF,FileName);
106 ErrHandler.SetErrorCode(RARX_WARNING);
107 }
108 }
109
110
BrokenHeaderMsg()111 void Archive::BrokenHeaderMsg()
112 {
113 uiMsg(UIERROR_HEADERBROKEN,FileName);
114 BrokenHeader=true;
115 ErrHandler.SetErrorCode(RARX_CRC);
116 }
117
118
UnkEncVerMsg(const wchar * Name,const wchar * Info)119 void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
120 {
121 uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
122 ErrHandler.SetErrorCode(RARX_WARNING);
123 }
124
125
126 // Return f in case of signed integer overflow or negative parameters
127 // or v1+v2 otherwise. We use it for file offsets, which are signed
128 // for compatibility with off_t in POSIX file functions and third party code.
129 // Signed integer overflow is the undefined behavior according to
130 // C++ standard and it causes fuzzers to complain.
SafeAdd(int64 v1,int64 v2,int64 f)131 inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
132 {
133 return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
134 }
135
136
ReadHeader15()137 size_t Archive::ReadHeader15()
138 {
139 RawRead Raw(this);
140
141 bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3;
142
143 if (Decrypt)
144 {
145 #if defined(RAR_NOCRYPT) || \
146 defined(CHROMIUM_UNRAR) // For rarext.dll and unrar_nocrypt.dll.
147 return 0;
148 #else
149 RequestArcPassword();
150
151 byte Salt[SIZE_SALT30];
152 if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
153 {
154 UnexpEndArcMsg();
155 return 0;
156 }
157 HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL);
158 Raw.SetCrypt(&HeadersCrypt);
159 #endif
160 }
161
162 Raw.Read(SIZEOF_SHORTBLOCKHEAD);
163 if (Raw.Size()==0)
164 {
165 UnexpEndArcMsg();
166 return 0;
167 }
168
169 ShortBlock.HeadCRC=Raw.Get2();
170
171 ShortBlock.Reset();
172
173 uint HeaderType=Raw.Get1();
174 ShortBlock.Flags=Raw.Get2();
175 ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
176 ShortBlock.HeadSize=Raw.Get2();
177
178 ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
179 if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
180 {
181 BrokenHeaderMsg();
182 return 0;
183 }
184
185 // For simpler further processing we map header types common
186 // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
187 // header types specific for RAR 1.5 - 4.x only.
188 switch(ShortBlock.HeaderType)
189 {
190 case HEAD3_MAIN: ShortBlock.HeaderType=HEAD_MAIN; break;
191 case HEAD3_FILE: ShortBlock.HeaderType=HEAD_FILE; break;
192 case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE; break;
193 case HEAD3_ENDARC: ShortBlock.HeaderType=HEAD_ENDARC; break;
194 }
195 CurHeaderType=ShortBlock.HeaderType;
196
197 if (ShortBlock.HeaderType==HEAD3_CMT)
198 {
199 // Old style (up to RAR 2.9) comment header embedded into main
200 // or file header. We must not read the entire ShortBlock.HeadSize here
201 // to not break the comment processing logic later.
202 Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
203 }
204 else
205 if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
206 {
207 // Old style (up to RAR 2.9) main archive comment embedded into
208 // the main archive header found. While we can read the entire
209 // ShortBlock.HeadSize here and remove this part of "if", it would be
210 // waste of memory, because we'll read and process this comment data
211 // in other function anyway and we do not need them here now.
212 Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
213 }
214 else
215 Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
216
217 NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
218
219 switch(ShortBlock.HeaderType)
220 {
221 case HEAD_MAIN:
222 MainHead.Reset();
223 *(BaseBlock *)&MainHead=ShortBlock;
224 MainHead.HighPosAV=Raw.Get2();
225 MainHead.PosAV=Raw.Get4();
226
227 Volume=(MainHead.Flags & MHD_VOLUME)!=0;
228 Solid=(MainHead.Flags & MHD_SOLID)!=0;
229 Locked=(MainHead.Flags & MHD_LOCK)!=0;
230 Protected=(MainHead.Flags & MHD_PROTECT)!=0;
231 Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
232 Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
233 MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
234
235 // Only for encrypted 3.0+ archives. 2.x archives did not have this
236 // flag, so for non-encrypted archives, we'll set it later based on
237 // file attributes.
238 FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0;
239
240 NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0;
241 break;
242 case HEAD_FILE:
243 case HEAD_SERVICE:
244 {
245 bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
246 FileHeader *hd=FileBlock ? &FileHead:&SubHead;
247 hd->Reset();
248
249 *(BaseBlock *)hd=ShortBlock;
250
251 hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
252 hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
253 hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
254 hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
255 hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
256 hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
257 hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
258 hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
259 hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
260 hd->Version=(hd->Flags & LHD_VERSION)!=0;
261
262 hd->DataSize=Raw.Get4();
263 uint LowUnpSize=Raw.Get4();
264 hd->HostOS=Raw.Get1();
265
266 hd->FileHash.Type=HASH_CRC32;
267 hd->FileHash.CRC32=Raw.Get4();
268
269 uint FileTime=Raw.Get4();
270 hd->UnpVer=Raw.Get1();
271
272 // RAR15 did not use the special dictionary size to mark dirs.
273 if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
274 hd->Dir=true;
275
276 hd->Method=Raw.Get1()-0x30;
277 size_t NameSize=Raw.Get2();
278 hd->FileAttr=Raw.Get4();
279
280 hd->CryptMethod=CRYPT_NONE;
281 if (hd->Encrypted)
282 switch(hd->UnpVer)
283 {
284 case 13: hd->CryptMethod=CRYPT_RAR13; break;
285 case 15: hd->CryptMethod=CRYPT_RAR15; break;
286 case 20:
287 case 26: hd->CryptMethod=CRYPT_RAR20; break;
288 default: hd->CryptMethod=CRYPT_RAR30; break;
289 }
290
291 hd->HSType=HSYS_UNKNOWN;
292 if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
293 hd->HSType=HSYS_UNIX;
294 else
295 if (hd->HostOS<HOST_MAX)
296 hd->HSType=HSYS_WINDOWS;
297
298 hd->RedirType=FSREDIR_NONE;
299
300 // RAR 4.x Unix symlink.
301 if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
302 {
303 hd->RedirType=FSREDIR_UNIXSYMLINK;
304 *hd->RedirName=0;
305 }
306
307 hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
308
309 hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
310
311 uint HighPackSize,HighUnpSize;
312 if (hd->LargeFile)
313 {
314 HighPackSize=Raw.Get4();
315 HighUnpSize=Raw.Get4();
316 hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
317 }
318 else
319 {
320 HighPackSize=HighUnpSize=0;
321 // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
322 // that we do not know the unpacked file size and must unpack it
323 // until we find the end of file marker in compressed data.
324 hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
325 }
326 hd->PackSize=INT32TO64(HighPackSize,hd->DataSize);
327 hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize);
328 if (hd->UnknownUnpSize)
329 hd->UnpSize=INT64NDF;
330
331 char FileName[NM*4];
332 size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
333 Raw.GetB((byte *)FileName,ReadNameSize);
334 FileName[ReadNameSize]=0;
335
336 if (FileBlock)
337 {
338 *hd->FileName=0;
339 if ((hd->Flags & LHD_UNICODE)!=0)
340 {
341 EncodeFileName NameCoder;
342 size_t Length=strlen(FileName);
343 Length++;
344 if (ReadNameSize>Length)
345 NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
346 ReadNameSize-Length,hd->FileName,
347 ASIZE(hd->FileName));
348 }
349
350 if (*hd->FileName==0)
351 ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
352
353 #ifndef SFX_MODULE
354 ConvertNameCase(hd->FileName);
355 #endif
356 ConvertFileHeader(hd);
357 }
358 else
359 {
360 CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
361
362 // Calculate the size of optional data.
363 int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
364 if ((hd->Flags & LHD_SALT)!=0)
365 DataSize-=SIZE_SALT30;
366
367 if (DataSize>0)
368 {
369 // Here we read optional additional fields for subheaders.
370 // They are stored after the file name and before salt.
371 hd->SubData.Alloc(DataSize);
372 Raw.GetB(&hd->SubData[0],DataSize);
373
374 }
375
376 if (hd->CmpName(SUBHEAD_TYPE_CMT))
377 MainComment=true;
378 }
379 if ((hd->Flags & LHD_SALT)!=0)
380 Raw.GetB(hd->Salt,SIZE_SALT30);
381 hd->mtime.SetDos(FileTime);
382 if ((hd->Flags & LHD_EXTTIME)!=0)
383 {
384 ushort Flags=Raw.Get2();
385 RarTime *tbl[4];
386 tbl[0]=&FileHead.mtime;
387 tbl[1]=&FileHead.ctime;
388 tbl[2]=&FileHead.atime;
389 tbl[3]=NULL; // Archive time is not used now.
390 for (int I=0;I<4;I++)
391 {
392 RarTime *CurTime=tbl[I];
393 uint rmode=Flags>>(3-I)*4;
394 if ((rmode & 8)==0 || CurTime==NULL)
395 continue;
396 if (I!=0)
397 {
398 uint DosTime=Raw.Get4();
399 CurTime->SetDos(DosTime);
400 }
401 RarLocalTime rlt;
402 CurTime->GetLocal(&rlt);
403 if (rmode & 4)
404 rlt.Second++;
405 rlt.Reminder=0;
406 int count=rmode&3;
407 for (int J=0;J<count;J++)
408 {
409 byte CurByte=Raw.Get1();
410 rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
411 }
412 // Convert from 100ns RAR precision to REMINDER_PRECISION.
413 rlt.Reminder*=RarTime::REMINDER_PRECISION/10000000;
414 CurTime->SetLocal(&rlt);
415 }
416 }
417 // Set to 0 in case of overflow, so end of ReadHeader cares about it.
418 NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
419
420 bool CRCProcessedOnly=hd->CommentInHeader;
421 ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
422 if (hd->HeadCRC!=HeaderCRC)
423 {
424 BrokenHeader=true;
425 ErrHandler.SetErrorCode(RARX_WARNING);
426
427 // If we have a broken encrypted header, we do not need to display
428 // the error message here, because it will be displayed for such
429 // headers later in this function. Also such headers are unlikely
430 // to have anything sensible in file name field, so it is useless
431 // to display the file name.
432 if (!Decrypt)
433 uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
434 }
435 }
436 break;
437 case HEAD_ENDARC:
438 *(BaseBlock *)&EndArcHead=ShortBlock;
439 EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
440 EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
441 EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
442 EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
443 if (EndArcHead.DataCRC)
444 EndArcHead.ArcDataCRC=Raw.Get4();
445 if (EndArcHead.StoreVolNumber)
446 VolNumber=EndArcHead.VolNumber=Raw.Get2();
447 break;
448 #ifndef SFX_MODULE
449 case HEAD3_CMT:
450 *(BaseBlock *)&CommHead=ShortBlock;
451 CommHead.UnpSize=Raw.Get2();
452 CommHead.UnpVer=Raw.Get1();
453 CommHead.Method=Raw.Get1();
454 CommHead.CommCRC=Raw.Get2();
455 break;
456 case HEAD3_PROTECT:
457 *(BaseBlock *)&ProtectHead=ShortBlock;
458 ProtectHead.DataSize=Raw.Get4();
459 ProtectHead.Version=Raw.Get1();
460 ProtectHead.RecSectors=Raw.Get2();
461 ProtectHead.TotalBlocks=Raw.Get4();
462 Raw.GetB(ProtectHead.Mark,8);
463 NextBlockPos+=ProtectHead.DataSize;
464 break;
465 case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
466 *(BaseBlock *)&SubBlockHead=ShortBlock;
467 SubBlockHead.DataSize=Raw.Get4();
468 NextBlockPos+=SubBlockHead.DataSize;
469 SubBlockHead.SubType=Raw.Get2();
470 SubBlockHead.Level=Raw.Get1();
471 switch(SubBlockHead.SubType)
472 {
473 case UO_HEAD:
474 *(SubBlockHeader *)&UOHead=SubBlockHead;
475 UOHead.OwnerNameSize=Raw.Get2();
476 UOHead.GroupNameSize=Raw.Get2();
477 if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
478 UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
479 if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
480 UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
481 Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
482 Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
483 UOHead.OwnerName[UOHead.OwnerNameSize]=0;
484 UOHead.GroupName[UOHead.GroupNameSize]=0;
485 break;
486 case NTACL_HEAD:
487 *(SubBlockHeader *)&EAHead=SubBlockHead;
488 EAHead.UnpSize=Raw.Get4();
489 EAHead.UnpVer=Raw.Get1();
490 EAHead.Method=Raw.Get1();
491 EAHead.EACRC=Raw.Get4();
492 break;
493 case STREAM_HEAD:
494 *(SubBlockHeader *)&StreamHead=SubBlockHead;
495 StreamHead.UnpSize=Raw.Get4();
496 StreamHead.UnpVer=Raw.Get1();
497 StreamHead.Method=Raw.Get1();
498 StreamHead.StreamCRC=Raw.Get4();
499 StreamHead.StreamNameSize=Raw.Get2();
500 if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
501 StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
502 Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
503 StreamHead.StreamName[StreamHead.StreamNameSize]=0;
504 break;
505 }
506 break;
507 #endif
508 default:
509 if (ShortBlock.Flags & LONG_BLOCK)
510 NextBlockPos+=Raw.Get4();
511 break;
512 }
513
514 ushort HeaderCRC=Raw.GetCRC15(false);
515
516 // Old AV header does not have header CRC properly set.
517 if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
518 ShortBlock.HeaderType!=HEAD3_AV)
519 {
520 bool Recovered=false;
521 if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
522 {
523 // Last 7 bytes of recovered volume can contain zeroes, because
524 // REV files store its own information (volume number, etc.) here.
525 SaveFilePos SavePos(*this);
526 int64 Length=Tell();
527 Seek(Length-7,SEEK_SET);
528 Recovered=true;
529 for (int J=0;J<7;J++)
530 if (GetByte()!=0)
531 Recovered=false;
532 }
533 if (!Recovered)
534 {
535 BrokenHeader=true;
536 ErrHandler.SetErrorCode(RARX_CRC);
537
538 if (Decrypt)
539 {
540 uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
541 FailedHeaderDecryption=true;
542 return 0;
543 }
544 }
545 }
546
547 return Raw.Size();
548 }
549
550
ReadHeader50()551 size_t Archive::ReadHeader50()
552 {
553 RawRead Raw(this);
554
555 bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5;
556
557 if (Decrypt)
558 {
559 #if defined(RAR_NOCRYPT) || defined(CHROMIUM_UNRAR)
560 return 0;
561 #else
562
563 byte HeadersInitV[SIZE_INITV];
564 if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
565 {
566 UnexpEndArcMsg();
567 return 0;
568 }
569
570 // We repeat the password request only for manually entered passwords
571 // and not for -p<pwd>. Wrong password can be intentionally provided
572 // in -p<pwd> to not stop batch processing for encrypted archives.
573 bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
574
575 while (true) // Repeat the password prompt for wrong passwords.
576 {
577 RequestArcPassword();
578
579 byte PswCheck[SIZE_PSWCHECK];
580 HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
581 // Verify password validity.
582 if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
583 {
584 if (GlobalPassword) // For -p<pwd> or Ctrl+P.
585 {
586 // This message is used by Android GUI to reset cached passwords.
587 // Update appropriate code if changed.
588 uiMsg(UIERROR_BADPSW,FileName);
589 FailedHeaderDecryption=true;
590 ErrHandler.SetErrorCode(RARX_BADPWD);
591 return 0;
592 }
593 else // For passwords entered manually.
594 {
595 // This message is used by Android GUI and Windows GUI and SFX to
596 // reset cached passwords. Update appropriate code if changed.
597 uiMsg(UIWAIT_BADPSW,FileName);
598 Cmd->Password.Clean();
599 }
600
601 #ifdef RARDLL
602 // Avoid new requests for unrar.dll to prevent the infinite loop
603 // if app always returns the same password.
604 ErrHandler.SetErrorCode(RARX_BADPWD);
605 Cmd->DllError=ERAR_BAD_PASSWORD;
606 ErrHandler.Exit(RARX_BADPWD);
607 #else
608 continue; // Request a password again.
609 #endif
610 }
611 break;
612 }
613
614 Raw.SetCrypt(&HeadersCrypt);
615 #endif
616 }
617
618 // Header size must not occupy more than 3 variable length integer bytes
619 // resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
620 // so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
621 const size_t FirstReadSize=7; // Smallest possible block size.
622 if (Raw.Read(FirstReadSize)<FirstReadSize)
623 {
624 UnexpEndArcMsg();
625 return 0;
626 }
627
628 ShortBlock.Reset();
629 ShortBlock.HeadCRC=Raw.Get4();
630 uint SizeBytes=Raw.GetVSize(4);
631 uint64 BlockSize=Raw.GetV();
632
633 if (BlockSize==0 || SizeBytes==0)
634 {
635 BrokenHeaderMsg();
636 return 0;
637 }
638
639 int SizeToRead=int(BlockSize);
640 SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
641 uint HeaderSize=4+SizeBytes+(uint)BlockSize;
642
643 if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
644 {
645 BrokenHeaderMsg();
646 return 0;
647 }
648
649 Raw.Read(SizeToRead);
650
651 if (Raw.Size()<HeaderSize)
652 {
653 UnexpEndArcMsg();
654 return 0;
655 }
656
657 uint HeaderCRC=Raw.GetCRC50();
658
659 ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
660 ShortBlock.Flags=(uint)Raw.GetV();
661 ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
662 ShortBlock.HeadSize=HeaderSize;
663
664 CurHeaderType=ShortBlock.HeaderType;
665
666 bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
667 if (BadCRC)
668 {
669 BrokenHeaderMsg(); // Report, but attempt to process.
670
671 BrokenHeader=true;
672 ErrHandler.SetErrorCode(RARX_CRC);
673
674 if (Decrypt)
675 {
676 uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
677 FailedHeaderDecryption=true;
678 return 0;
679 }
680 }
681
682 uint64 ExtraSize=0;
683 if ((ShortBlock.Flags & HFL_EXTRA)!=0)
684 {
685 ExtraSize=Raw.GetV();
686 if (ExtraSize>=ShortBlock.HeadSize)
687 {
688 BrokenHeaderMsg();
689 return 0;
690 }
691 }
692
693 uint64 DataSize=0;
694 if ((ShortBlock.Flags & HFL_DATA)!=0)
695 DataSize=Raw.GetV();
696
697 NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
698 // Set to 0 in case of overflow, so end of ReadHeader cares about it.
699 NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
700
701 switch(ShortBlock.HeaderType)
702 {
703 case HEAD_CRYPT:
704 {
705 *(BaseBlock *)&CryptHead=ShortBlock;
706 uint CryptVersion=(uint)Raw.GetV();
707 if (CryptVersion>CRYPT_VERSION)
708 {
709 wchar Info[20];
710 swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
711 UnkEncVerMsg(FileName,Info);
712 return 0;
713 }
714 uint EncFlags=(uint)Raw.GetV();
715 CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0;
716 CryptHead.Lg2Count=Raw.Get1();
717 if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
718 {
719 wchar Info[20];
720 swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
721 UnkEncVerMsg(FileName,Info);
722 return 0;
723 }
724 Raw.GetB(CryptHead.Salt,SIZE_SALT50);
725 if (CryptHead.UsePswCheck)
726 {
727 Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK);
728
729 byte csum[SIZE_PSWCHECK_CSUM];
730 Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
731
732 sha256_context ctx;
733 sha256_init(&ctx);
734 sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK);
735
736 byte Digest[SHA256_DIGEST_SIZE];
737 sha256_done(&ctx, Digest);
738
739 CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
740 }
741 Encrypted=true;
742 }
743 break;
744 case HEAD_MAIN:
745 {
746 MainHead.Reset();
747 *(BaseBlock *)&MainHead=ShortBlock;
748 uint ArcFlags=(uint)Raw.GetV();
749
750 Volume=(ArcFlags & MHFL_VOLUME)!=0;
751 Solid=(ArcFlags & MHFL_SOLID)!=0;
752 Locked=(ArcFlags & MHFL_LOCK)!=0;
753 Protected=(ArcFlags & MHFL_PROTECT)!=0;
754 Signed=false;
755 NewNumbering=true;
756
757 if ((ArcFlags & MHFL_VOLNUMBER)!=0)
758 VolNumber=(uint)Raw.GetV();
759 else
760 VolNumber=0;
761 FirstVolume=Volume && VolNumber==0;
762
763 if (ExtraSize!=0)
764 ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
765
766 #ifdef USE_QOPEN
767 if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
768 {
769 // We seek to QO block in the end of archive when processing
770 // QOpen.Load, so we need to preserve current block positions
771 // to not break normal archive processing by calling function.
772 int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
773 HEADER_TYPE SaveCurHeaderType=CurHeaderType;
774
775 QOpen.Init(this,false);
776 QOpen.Load(MainHead.QOpenOffset);
777
778 CurBlockPos=SaveCurBlockPos;
779 NextBlockPos=SaveNextBlockPos;
780 CurHeaderType=SaveCurHeaderType;
781 }
782 #endif
783 }
784 break;
785 case HEAD_FILE:
786 case HEAD_SERVICE:
787 {
788 FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
789 hd->Reset();
790 *(BaseBlock *)hd=ShortBlock;
791
792 bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
793
794 hd->LargeFile=true;
795
796 hd->PackSize=DataSize;
797 hd->FileFlags=(uint)Raw.GetV();
798 hd->UnpSize=Raw.GetV();
799
800 hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
801 if (hd->UnknownUnpSize)
802 hd->UnpSize=INT64NDF;
803
804 hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
805 hd->FileAttr=(uint)Raw.GetV();
806 if ((hd->FileFlags & FHFL_UTIME)!=0)
807 hd->mtime.SetUnix((time_t)Raw.Get4());
808
809 hd->FileHash.Type=HASH_NONE;
810 if ((hd->FileFlags & FHFL_CRC32)!=0)
811 {
812 hd->FileHash.Type=HASH_CRC32;
813 hd->FileHash.CRC32=Raw.Get4();
814 }
815
816 hd->RedirType=FSREDIR_NONE;
817
818 uint CompInfo=(uint)Raw.GetV();
819 hd->Method=(CompInfo>>7) & 7;
820
821 // "+ 50" to not mix with old RAR format algorithms. For example,
822 // we may need to use the compression algorithm 15 in the future,
823 // but it was already used in RAR 1.5 and Unpack needs to distinguish
824 // them.
825 hd->UnpVer=(CompInfo & 0x3f) + 50;
826 if (hd->UnpVer!=50) // Only 5.0 compression is known now.
827 hd->UnpVer=VER_UNKNOWN;
828
829 hd->HostOS=(byte)Raw.GetV();
830 size_t NameSize=(size_t)Raw.GetV();
831 hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
832
833 hd->HSType=HSYS_UNKNOWN;
834 if (hd->HostOS==HOST5_UNIX)
835 hd->HSType=HSYS_UNIX;
836 else
837 if (hd->HostOS==HOST5_WINDOWS)
838 hd->HSType=HSYS_WINDOWS;
839
840 hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
841 hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
842 hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
843 hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
844 hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
845 hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
846
847 hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
848
849 char FileName[NM*4];
850 size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
851 Raw.GetB((byte *)FileName,ReadNameSize);
852 FileName[ReadNameSize]=0;
853
854 UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName));
855
856 // Should do it before converting names, because extra fields can
857 // affect name processing, like in case of NTFS streams.
858 if (ExtraSize!=0)
859 ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
860
861 if (FileBlock)
862 {
863 #ifndef SFX_MODULE
864 ConvertNameCase(hd->FileName);
865 #endif
866 ConvertFileHeader(hd);
867 }
868
869 if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
870 MainComment=true;
871
872 #if 0
873 // For RAR5 format we read the user specified recovery percent here.
874 // It would be useful to do it for shell extension too, so we display
875 // the correct recovery record size in archive properties. But then
876 // we would need to include the entire recovery record processing
877 // code to shell extension, which is not done now.
878 if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
879 {
880 RecoveryPercent=hd->SubData[0];
881 RSBlockHeader Header;
882 GetRRInfo(this,&Header);
883 RecoverySize=Header.RecSectionSize*Header.RecCount;
884 }
885 #endif
886
887 if (BadCRC) // Add the file name to broken header message displayed above.
888 uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
889 }
890 break;
891 case HEAD_ENDARC:
892 {
893 *(BaseBlock *)&EndArcHead=ShortBlock;
894 uint ArcFlags=(uint)Raw.GetV();
895 EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
896 EndArcHead.StoreVolNumber=false;
897 EndArcHead.DataCRC=false;
898 EndArcHead.RevSpace=false;
899 }
900 break;
901 }
902
903 return Raw.Size();
904 }
905
906
907 #if !defined(RAR_NOCRYPT)
RequestArcPassword()908 void Archive::RequestArcPassword()
909 {
910 if (!Cmd->Password.IsSet())
911 {
912 #ifdef RARDLL
913 if (Cmd->Callback!=NULL)
914 {
915 wchar PasswordW[MAXPASSWORD];
916 *PasswordW=0;
917 if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
918 *PasswordW=0;
919 if (*PasswordW==0)
920 {
921 char PasswordA[MAXPASSWORD];
922 *PasswordA=0;
923 if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
924 *PasswordA=0;
925 GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
926 cleandata(PasswordA,sizeof(PasswordA));
927 }
928 Cmd->Password.Set(PasswordW);
929 cleandata(PasswordW,sizeof(PasswordW));
930 }
931 if (!Cmd->Password.IsSet())
932 {
933 Close();
934 Cmd->DllError=ERAR_MISSING_PASSWORD;
935 ErrHandler.Exit(RARX_USERBREAK);
936 }
937 #else
938 if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password))
939 {
940 Close();
941 uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
942 ErrHandler.Exit(RARX_USERBREAK);
943 }
944 #endif
945 Cmd->ManualPassword=true;
946 }
947 }
948 #endif
949
950
ProcessExtra50(RawRead * Raw,size_t ExtraSize,BaseBlock * bb)951 void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
952 {
953 // Read extra data from the end of block skipping any fields before it.
954 size_t ExtraStart=Raw->Size()-ExtraSize;
955 if (ExtraStart<Raw->GetPos())
956 return;
957 Raw->SetPos(ExtraStart);
958 while (Raw->DataLeft()>=2)
959 {
960 int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
961 if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
962 break;
963 size_t NextPos=size_t(Raw->GetPos()+FieldSize);
964 uint64 FieldType=Raw->GetV();
965
966 FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
967
968 if (FieldSize<0) // FieldType is longer than expected extra field size.
969 break;
970
971 if (bb->HeaderType==HEAD_MAIN)
972 {
973 MainHeader *hd=(MainHeader *)bb;
974 if (FieldType==MHEXTRA_LOCATOR)
975 {
976 hd->Locator=true;
977 uint Flags=(uint)Raw->GetV();
978 if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
979 {
980 uint64 Offset=Raw->GetV();
981 if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
982 hd->QOpenOffset=Offset+CurBlockPos;
983 }
984 if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
985 {
986 uint64 Offset=Raw->GetV();
987 if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
988 hd->RROffset=Offset+CurBlockPos;
989 }
990 }
991 }
992
993 if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
994 {
995 FileHeader *hd=(FileHeader *)bb;
996 switch(FieldType)
997 {
998 case FHEXTRA_CRYPT:
999 {
1000 FileHeader *hd=(FileHeader *)bb;
1001 uint EncVersion=(uint)Raw->GetV();
1002 if (EncVersion>CRYPT_VERSION)
1003 {
1004 wchar Info[20];
1005 swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
1006 UnkEncVerMsg(hd->FileName,Info);
1007 }
1008 else
1009 {
1010 uint Flags=(uint)Raw->GetV();
1011 hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
1012 hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
1013 hd->Lg2Count=Raw->Get1();
1014 if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
1015 {
1016 wchar Info[20];
1017 swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
1018 UnkEncVerMsg(hd->FileName,Info);
1019 }
1020 Raw->GetB(hd->Salt,SIZE_SALT50);
1021 Raw->GetB(hd->InitV,SIZE_INITV);
1022 if (hd->UsePswCheck)
1023 {
1024 Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
1025
1026 // It is important to know if password check data is valid.
1027 // If it is damaged and header CRC32 fails to detect it,
1028 // archiver would refuse to decompress a possibly valid file.
1029 // Since we want to be sure distinguishing a wrong password
1030 // or corrupt file data, we use 64-bit password check data
1031 // and to control its validity we use 32 bits of password
1032 // check data SHA-256 additionally to 32-bit header CRC32.
1033 byte csum[SIZE_PSWCHECK_CSUM];
1034 Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
1035
1036 sha256_context ctx;
1037 sha256_init(&ctx);
1038 sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK);
1039
1040 byte Digest[SHA256_DIGEST_SIZE];
1041 sha256_done(&ctx, Digest);
1042
1043 hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
1044
1045 // RAR 5.21 and earlier set PswCheck field in service records to 0
1046 // even if UsePswCheck was present.
1047 if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
1048 hd->UsePswCheck=0;
1049 }
1050 hd->SaltSet=true;
1051 hd->CryptMethod=CRYPT_RAR50;
1052 hd->Encrypted=true;
1053 }
1054 }
1055 break;
1056 case FHEXTRA_HASH:
1057 {
1058 FileHeader *hd=(FileHeader *)bb;
1059 uint Type=(uint)Raw->GetV();
1060 if (Type==FHEXTRA_HASH_BLAKE2)
1061 {
1062 hd->FileHash.Type=HASH_BLAKE2;
1063 Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
1064 }
1065 }
1066 break;
1067 case FHEXTRA_HTIME:
1068 if (FieldSize>=5)
1069 {
1070 byte Flags=(byte)Raw->GetV();
1071 bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
1072 if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
1073 if (UnixTime)
1074 hd->mtime.SetUnix(Raw->Get4());
1075 else
1076 hd->mtime.SetWin(Raw->Get8());
1077 if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
1078 if (UnixTime)
1079 hd->ctime.SetUnix(Raw->Get4());
1080 else
1081 hd->ctime.SetWin(Raw->Get8());
1082 if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
1083 if (UnixTime)
1084 hd->atime.SetUnix((time_t)Raw->Get4());
1085 else
1086 hd->atime.SetWin(Raw->Get8());
1087 if (UnixTime && (Flags & FHEXTRA_HTIME_UNIX_NS)!=0) // Add nanoseconds.
1088 {
1089 uint ns;
1090 if ((Flags & FHEXTRA_HTIME_MTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1091 hd->mtime.Adjust(ns);
1092 if ((Flags & FHEXTRA_HTIME_CTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1093 hd->ctime.Adjust(ns);
1094 if ((Flags & FHEXTRA_HTIME_ATIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1095 hd->atime.Adjust(ns);
1096 }
1097 }
1098 break;
1099 case FHEXTRA_VERSION:
1100 if (FieldSize>=1)
1101 {
1102 Raw->GetV(); // Skip flags field.
1103 uint Version=(uint)Raw->GetV();
1104 if (Version!=0)
1105 {
1106 hd->Version=true;
1107
1108 wchar VerText[20];
1109 swprintf(VerText,ASIZE(VerText),L";%u",Version);
1110 wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
1111 }
1112 }
1113 break;
1114 case FHEXTRA_REDIR:
1115 {
1116 hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
1117 uint Flags=(uint)Raw->GetV();
1118 hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
1119 size_t NameSize=(size_t)Raw->GetV();
1120
1121 char UtfName[NM*4];
1122 *UtfName=0;
1123 if (NameSize<ASIZE(UtfName)-1)
1124 {
1125 Raw->GetB(UtfName,NameSize);
1126 UtfName[NameSize]=0;
1127 }
1128 #ifdef _WIN_ALL
1129 UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName));
1130 #endif
1131 UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
1132 }
1133 break;
1134 case FHEXTRA_UOWNER:
1135 {
1136 uint Flags=(uint)Raw->GetV();
1137 hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
1138 hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
1139 *hd->UnixOwnerName=*hd->UnixGroupName=0;
1140 if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
1141 {
1142 size_t Length=(size_t)Raw->GetV();
1143 Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
1144 Raw->GetB(hd->UnixOwnerName,Length);
1145 hd->UnixOwnerName[Length]=0;
1146 }
1147 if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
1148 {
1149 size_t Length=(size_t)Raw->GetV();
1150 Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
1151 Raw->GetB(hd->UnixGroupName,Length);
1152 hd->UnixGroupName[Length]=0;
1153 }
1154 #ifdef _UNIX
1155 if (hd->UnixOwnerNumeric)
1156 hd->UnixOwnerID=(uid_t)Raw->GetV();
1157 if (hd->UnixGroupNumeric)
1158 hd->UnixGroupID=(gid_t)Raw->GetV();
1159 #else
1160 // Need these fields in Windows too for 'list' command,
1161 // but uid_t and gid_t are not defined.
1162 if (hd->UnixOwnerNumeric)
1163 hd->UnixOwnerID=(uint)Raw->GetV();
1164 if (hd->UnixGroupNumeric)
1165 hd->UnixGroupID=(uint)Raw->GetV();
1166 #endif
1167 hd->UnixOwnerSet=true;
1168 }
1169 break;
1170 case FHEXTRA_SUBDATA:
1171 {
1172 // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than
1173 // required. It did not hurt extraction, because UnRAR 5.21
1174 // and earlier ignored this field and set FieldSize as data left
1175 // in entire extra area. But now we set the correct field size
1176 // and set FieldSize based on the actual extra record size,
1177 // so we need to adjust it for those older archives here.
1178 // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
1179 // and always is last in extra area. So since its size is by 1
1180 // less than needed, we always have 1 byte left in extra area,
1181 // which fact we use here to detect such archives.
1182 if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
1183 FieldSize++;
1184
1185 // We cannot allocate too much memory here, because above
1186 // we check FieldSize againt Raw size and we control that Raw size
1187 // is sensible when reading headers.
1188 hd->SubData.Alloc((size_t)FieldSize);
1189 Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
1190 }
1191 break;
1192 }
1193 }
1194
1195 Raw->SetPos(NextPos);
1196 }
1197 }
1198
1199
1200 #ifndef SFX_MODULE
ReadHeader14()1201 size_t Archive::ReadHeader14()
1202 {
1203 RawRead Raw(this);
1204 if (CurBlockPos<=(int64)SFXSize)
1205 {
1206 Raw.Read(SIZEOF_MAINHEAD14);
1207 MainHead.Reset();
1208 byte Mark[4];
1209 Raw.GetB(Mark,4);
1210 uint HeadSize=Raw.Get2();
1211 if (HeadSize<7)
1212 return false;
1213 byte Flags=Raw.Get1();
1214 NextBlockPos=CurBlockPos+HeadSize;
1215 CurHeaderType=HEAD_MAIN;
1216
1217 Volume=(Flags & MHD_VOLUME)!=0;
1218 Solid=(Flags & MHD_SOLID)!=0;
1219 Locked=(Flags & MHD_LOCK)!=0;
1220 MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
1221 MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
1222 }
1223 else
1224 {
1225 Raw.Read(SIZEOF_FILEHEAD14);
1226 FileHead.Reset();
1227
1228 FileHead.HeaderType=HEAD_FILE;
1229 FileHead.DataSize=Raw.Get4();
1230 FileHead.UnpSize=Raw.Get4();
1231 FileHead.FileHash.Type=HASH_RAR14;
1232 FileHead.FileHash.CRC32=Raw.Get2();
1233 FileHead.HeadSize=Raw.Get2();
1234 if (FileHead.HeadSize<21)
1235 return false;
1236 uint FileTime=Raw.Get4();
1237 FileHead.FileAttr=Raw.Get1();
1238 FileHead.Flags=Raw.Get1()|LONG_BLOCK;
1239 FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
1240 size_t NameSize=Raw.Get1();
1241 FileHead.Method=Raw.Get1();
1242
1243 FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
1244 FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
1245 FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
1246 FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE;
1247
1248 FileHead.PackSize=FileHead.DataSize;
1249 FileHead.WinSize=0x10000;
1250 FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
1251
1252 FileHead.HostOS=HOST_MSDOS;
1253 FileHead.HSType=HSYS_WINDOWS;
1254
1255 FileHead.mtime.SetDos(FileTime);
1256
1257 Raw.Read(NameSize);
1258
1259 char FileName[NM];
1260 Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
1261 FileName[NameSize]=0;
1262 IntToExt(FileName,FileName,ASIZE(FileName));
1263 CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
1264 ConvertNameCase(FileHead.FileName);
1265
1266 if (Raw.Size()!=0)
1267 NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
1268 CurHeaderType=HEAD_FILE;
1269 }
1270 return NextBlockPos>CurBlockPos ? Raw.Size() : 0;
1271 }
1272 #endif
1273
1274
1275 #ifndef SFX_MODULE
ConvertNameCase(wchar * Name)1276 void Archive::ConvertNameCase(wchar *Name)
1277 {
1278 if (Cmd->ConvertNames==NAMES_UPPERCASE)
1279 wcsupper(Name);
1280 if (Cmd->ConvertNames==NAMES_LOWERCASE)
1281 wcslower(Name);
1282 }
1283 #endif
1284
1285
IsArcDir()1286 bool Archive::IsArcDir()
1287 {
1288 return FileHead.Dir;
1289 }
1290
1291
ConvertAttributes()1292 void Archive::ConvertAttributes()
1293 {
1294 #if defined(_WIN_ALL) || defined(_EMX)
1295 if (FileHead.HSType!=HSYS_WINDOWS)
1296 FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
1297 #endif
1298 #ifdef _UNIX
1299 // umask defines which permission bits must not be set by default
1300 // when creating a file or directory. The typical default value
1301 // for the process umask is S_IWGRP | S_IWOTH (octal 022),
1302 // resulting in 0644 mode for new files.
1303 // Normally umask is applied automatically when creating a file,
1304 // but we set attributes with chmod later, so we need to calculate
1305 // resulting attributes here. We do it only for non-Unix archives.
1306 // We restore native Unix attributes as is, because it can be backup.
1307 static mode_t mask = (mode_t) -1;
1308
1309 if (mask == (mode_t) -1)
1310 {
1311 // umask call returns the current umask value. Argument (022) is not
1312 // really important here.
1313 mask = umask(022);
1314
1315 // Restore the original umask value, which was changed to 022 above.
1316 umask(mask);
1317 }
1318
1319 switch(FileHead.HSType)
1320 {
1321 case HSYS_WINDOWS:
1322 {
1323 // Mapping MSDOS, OS/2 and Windows file attributes to Unix.
1324
1325 if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
1326 {
1327 // For directories we use 0777 mask.
1328 FileHead.FileAttr=0777 & ~mask;
1329 }
1330 else
1331 if (FileHead.FileAttr & 1) // FILE_ATTRIBUTE_READONLY
1332 {
1333 // For read only files we use 0444 mask with 'w' bits turned off.
1334 FileHead.FileAttr=0444 & ~mask;
1335 }
1336 else
1337 {
1338 // umask does not set +x for regular files, so we use 0666
1339 // instead of 0777 as for directories.
1340 FileHead.FileAttr=0666 & ~mask;
1341 }
1342 }
1343 break;
1344 case HSYS_UNIX:
1345 break;
1346 default:
1347 if (FileHead.Dir)
1348 FileHead.FileAttr=0x41ff & ~mask;
1349 else
1350 FileHead.FileAttr=0x81b6 & ~mask;
1351 break;
1352 }
1353 #endif
1354 }
1355
1356
ConvertFileHeader(FileHeader * hd)1357 void Archive::ConvertFileHeader(FileHeader *hd)
1358 {
1359 if (hd->HSType==HSYS_UNKNOWN)
1360 if (hd->Dir)
1361 hd->FileAttr=0x10;
1362 else
1363 hd->FileAttr=0x20;
1364
1365 #ifdef _WIN_ALL
1366 if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
1367 ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName));
1368 #endif
1369
1370 for (wchar *s=hd->FileName;*s!=0;s++)
1371 {
1372 #ifdef _UNIX
1373 // Backslash is the invalid character for Windows file headers,
1374 // but it can present in Unix file names extracted in Unix.
1375 if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS)
1376 *s='_';
1377 #endif
1378
1379 #if defined(_WIN_ALL) || defined(_EMX)
1380 // RAR 5.0 archives do not use '\' as path separator, so if we see it,
1381 // it means that it is a part of Unix file name, which we cannot
1382 // extract in Windows.
1383 if (*s=='\\' && Format==RARFMT50)
1384 *s='_';
1385
1386 // ':' in file names is allowed in Unix, but not in Windows.
1387 // Even worse, file data will be written to NTFS stream on NTFS,
1388 // so automatic name correction on file create error in extraction
1389 // routine does not work. In Windows and DOS versions we better
1390 // replace ':' now.
1391 if (*s==':')
1392 *s='_';
1393 #endif
1394
1395 // This code must be performed only after other path separator checks,
1396 // because it produces backslashes illegal for some of checks above.
1397 // Backslash is allowed in file names in Unix, but not in Windows.
1398 // Still, RAR 4.x uses backslashes as path separator even in Unix.
1399 // Forward slash is not allowed in both systems. In RAR 5.0 we use
1400 // the forward slash as universal path separator.
1401 if (*s=='/' || *s=='\\' && Format!=RARFMT50)
1402 *s=CPATHDIVIDER;
1403 }
1404 }
1405
1406
GetStartPos()1407 int64 Archive::GetStartPos()
1408 {
1409 int64 StartPos=SFXSize+MarkHead.HeadSize;
1410 if (Format==RARFMT15)
1411 StartPos+=MainHead.HeadSize;
1412 else // RAR 5.0.
1413 StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize);
1414 return StartPos;
1415 }
1416
1417
ReadSubData(Array<byte> * UnpData,File * DestFile)1418 bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
1419 {
1420 if (BrokenHeader)
1421 {
1422 uiMsg(UIERROR_SUBHEADERBROKEN,FileName);
1423 ErrHandler.SetErrorCode(RARX_CRC);
1424 return false;
1425 }
1426 if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK))
1427 {
1428 uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1429 return false;
1430 }
1431
1432 if (SubHead.PackSize==0 && !SubHead.SplitAfter)
1433 return true;
1434
1435 SubDataIO.Init();
1436 Unpack Unpack(&SubDataIO);
1437 Unpack.Init(SubHead.WinSize,false);
1438
1439 if (DestFile==NULL)
1440 {
1441 if (SubHead.UnpSize>0x1000000)
1442 {
1443 // So huge allocation must never happen in valid archives.
1444 uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1445 return false;
1446 }
1447 if (UnpData==NULL)
1448 SubDataIO.SetTestMode(true);
1449 else
1450 {
1451 UnpData->Alloc((size_t)SubHead.UnpSize);
1452 SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
1453 }
1454 }
1455 if (SubHead.Encrypted)
1456 if (Cmd->Password.IsSet())
1457 SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password,
1458 SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV,
1459 SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck);
1460 else
1461 return false;
1462 SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
1463 SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
1464 SubDataIO.EnableShowProgress(false);
1465 SubDataIO.SetFiles(this,DestFile);
1466 SubDataIO.UnpVolume=SubHead.SplitAfter;
1467 SubDataIO.SetSubHeader(&SubHead,NULL);
1468 Unpack.SetDestSize(SubHead.UnpSize);
1469 if (SubHead.Method==0)
1470 CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
1471 else
1472 Unpack.DoUnpack(SubHead.UnpVer,false);
1473
1474 if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL))
1475 {
1476 uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
1477 ErrHandler.SetErrorCode(RARX_CRC);
1478 if (UnpData!=NULL)
1479 UnpData->Reset();
1480 return false;
1481 }
1482 return true;
1483 }
1484