// Extra data stored directly in file header. void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name) { #ifdef _UNIX if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet) SetUnixOwner(Arc,Name); #endif }
bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) { wchar Command=Cmd->Command[0]; if (HeaderSize==0) { if (DataIO.UnpVolume) { #ifdef NOVOLUME return false; #else // Supposing we unpack an old RAR volume without end of archive record // and last file is not split between volumes. if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif } else return false; } HEADER_TYPE HeaderType=Arc.GetHeaderType(); if (HeaderType!=HEAD_FILE) { #ifndef SFX_MODULE if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted) SetExtraInfo20(Cmd,Arc,DestFileName); #endif if (HeaderType==HEAD_SERVICE && PrevExtracted) SetExtraInfo(Cmd,Arc,DestFileName); if (HeaderType==HEAD_ENDARC) { if (Arc.EndArcHead.NextVolume) { #ifndef NOVOLUME if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif Arc.Seek(Arc.CurBlockPos,SEEK_SET); return true; } else return false; } Arc.SeekToNext(); return true; } PrevExtracted=false; if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) return false; int MatchType=MATCH_WILDSUBPATH; bool EqualNames=false; wchar MatchedArg[NM]; int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg)); bool MatchFound=MatchNumber!=0; #ifndef SFX_MODULE if (Cmd->ExclPath==EXCL_BASEPATH) { wcsncpyz(Cmd->ArcPath,MatchedArg,ASIZE(Cmd->ArcPath)); *PointToName(Cmd->ArcPath)=0; if (IsWildcard(Cmd->ArcPath)) // Cannot correctly process path*\* masks here. *Cmd->ArcPath=0; } #endif if (MatchFound && !EqualNames) AllMatchesExact=false; Arc.ConvertAttributes(); #if !defined(SFX_MODULE) && !defined(RARDLL) if (Arc.FileHead.SplitBefore && FirstFile) { wchar CurVolName[NM]; wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering); if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) { // If first volume name does not match the current name and if such // volume name really exists, let's unpack from this first volume. Repeat=true; return false; } #ifndef RARDLL if (!ReconstructDone) { ReconstructDone=true; if (RecVolumesRestore(Cmd,Arc.FileName,true)) { Repeat=true; return false; } } #endif wcsncpyz(ArcName,CurVolName,ASIZE(ArcName)); } #endif wchar ArcFileName[NM]; ConvertPath(Arc.FileHead.FileName,ArcFileName); if (Arc.FileHead.Version) { if (Cmd->VersionControl!=1 && !EqualNames) { if (Cmd->VersionControl==0) MatchFound=false; int Version=ParseVersionFileName(ArcFileName,false); if (Cmd->VersionControl-1==Version) ParseVersionFileName(ArcFileName,true); else MatchFound=false; } } else if (!Arc.IsArcDir() && Cmd->VersionControl>1) MatchFound=false; DataIO.UnpVolume=Arc.FileHead.SplitAfter; DataIO.NextVolumeMissing=false; Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); bool ExtrFile=false; bool SkipSolid=false; #ifndef SFX_MODULE if (FirstFile && (MatchFound || Arc.Solid) && Arc.FileHead.SplitBefore) { if (MatchFound) { uiMsg(UIERROR_NEEDPREVVOL,Arc.FileName,ArcFileName); #ifdef RARDLL Cmd->DllError=ERAR_BAD_DATA; #endif ErrHandler.SetErrorCode(RARX_OPEN); } MatchFound=false; } FirstFile=false; #endif if (MatchFound || (SkipSolid=Arc.Solid)!=0) { // First common call of uiStartFileExtract. It is done before overwrite // prompts, so if SkipSolid state is changed below, we'll need to make // additional uiStartFileExtract calls with updated parameters. if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid)) return false; ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); // DestFileName can be set empty in case of excessive -ap switch. ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X')) { FindData FD; if (FindFile::FastFind(DestFileName,&FD)) { if (FD.mtime >= Arc.FileHead.mtime) { // If directory already exists and its modification time is newer // than start of extraction, it is likely it was created // when creating a path to one of already extracted items. // In such case we'll better update its time even if archived // directory is older. if (!FD.IsDir || FD.mtime<StartTime) ExtrFile=false; } } else if (Cmd->FreshFiles) ExtrFile=false; } if (Arc.FileHead.Encrypted) { #ifdef RARDLL if (!ExtrDllGetPassword()) return false; #else if (!ExtrGetPassword(Arc,ArcFileName)) { PasswordCancelled=true; return false; } #endif // Skip only the current encrypted file if empty password is entered. if (!Cmd->Password.IsSet()) { ErrHandler.SetErrorCode(RARX_WARNING); #ifdef RARDLL Cmd->DllError=ERAR_MISSING_PASSWORD; #endif ExtrFile=false; } } #ifdef RARDLL if (*Cmd->DllDestName!=0) wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); #endif if (!CheckUnpVer(Arc,ArcFileName)) { ExtrFile=false; ErrHandler.SetErrorCode(RARX_FATAL); #ifdef RARDLL Cmd->DllError=ERAR_UNKNOWN_FORMAT; #endif } File CurFile; bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) { if (ExtrFile && Command!='P' && !Cmd->Test) { // Overwrite prompt for symbolic and hard links. bool UserReject=false; if (FileExist(DestFileName) && !UserReject) FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); if (UserReject) ExtrFile=false; } } else if (Arc.IsArcDir()) { if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) return true; TotalFileCount++; ExtrCreateDir(Arc,ArcFileName); return true; } else if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY). ExtrFile=ExtrCreateFile(Arc,CurFile); if (!ExtrFile && Arc.Solid) { SkipSolid=true; ExtrFile=true; // We changed SkipSolid, so we need to call uiStartFileExtract // with "Skip" parameter to change the operation status // from "extracting" to "skipping". For example, it can be necessary // if user answered "No" to overwrite prompt when unpacking // a solid archive. if (!uiStartFileExtract(ArcFileName,false,false,true)) return false; } if (ExtrFile) { bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk. if (!SkipSolid) { if (!TestMode && Command!='P' && CurFile.IsDevice()) { uiMsg(UIERROR_INVALIDNAME,Arc.FileName,DestFileName); ErrHandler.WriteError(Arc.FileName,DestFileName); } TotalFileCount++; } FileCount++; #ifndef GUI if (Command!='I') { if (SkipSolid) mprintf(St(MExtrSkipFile),ArcFileName); else switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch. { case 'T': mprintf(St(MExtrTestFile),ArcFileName); break; #ifndef SFX_MODULE case 'P': mprintf(St(MExtrPrinting),ArcFileName); break; #endif case 'X': case 'E': mprintf(St(MExtrFile),DestFileName); break; } } if (!Cmd->DisablePercentage) mprintf(L" "); #endif SecPassword FilePassword=Cmd->Password; #if defined(_WIN_ALL) && !defined(SFX_MODULE) ConvertDosPassword(Arc,FilePassword); #endif byte PswCheck[SIZE_PSWCHECK]; DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, Arc.FileHead.InitV,Arc.FileHead.Lg2Count, PswCheck,Arc.FileHead.HashKey); bool WrongPassword=false; // If header is damaged, we cannot rely on password check value, // because it can be damaged too. if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && !Arc.BrokenHeader) { uiMsg(UIERROR_BADPSW,Arc.FileName); ErrHandler.SetErrorCode(RARX_BADPWD); WrongPassword=true; } DataIO.CurUnpRead=0; DataIO.CurUnpWrite=0; DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize); DataIO.SetFiles(&Arc,&CurFile); DataIO.SetTestMode(TestMode); DataIO.SetSkipUnpCRC(SkipSolid); #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) if (!TestMode && !WrongPassword && !Arc.BrokenHeader && Arc.FileHead.UnpSize>0xffffffff && (Fat32 || !NotFat32)) { if (!Fat32) // Not detected yet. NotFat32=!(Fat32=IsFAT(Cmd->ExtrPath)); if (Fat32) uiMsg(UIMSG_FAT32SIZE); // Inform user about FAT32 size limit. } #endif if (!TestMode && !WrongPassword && !Arc.BrokenHeader && (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize && (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) CurFile.Prealloc(Arc.FileHead.UnpSize); CurFile.SetAllowDelete(!Cmd->KeepBroken); bool FileCreateMode=!TestMode && !SkipSolid && Command!='P'; bool ShowChecksum=true; // Display checksum verification result. bool LinkSuccess=true; // Assume success for test mode. if (LinkEntry) { FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType; if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) { wchar NameExisting[NM]; ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. { if (Type==FSREDIR_HARDLINK) LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting)); else LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); } } else if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) { if (FileCreateMode) LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); } else { uiMsg(UIERROR_UNKNOWNEXTRA, Arc.FileName, DestFileName); LinkSuccess=false; } if (!LinkSuccess || (Arc.Format==RARFMT15 && !FileCreateMode)) { // RAR 5.x links have a valid data checksum even in case of // failure, because they do not store any data. // We do not want to display "OK" in this case. // For 4.x symlinks we verify the checksum only when extracting, // but not when testing an archive. ShowChecksum=false; } PrevExtracted=FileCreateMode && LinkSuccess; } else if (!Arc.FileHead.SplitBefore && !WrongPassword) { if (Arc.FileHead.Method==0) UnstoreFile(DataIO,Arc.FileHead.UnpSize); else { #ifdef _ANDROID // malloc and new do not report memory allocation errors // in Android, so if free memory is set, check it here // trying to prevent crash. if (Cmd->FreeMem!=0 && Cmd->FreeMem < Arc.FileHead.WinSize) throw std::bad_alloc(); #endif Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); Unp->SetDestSize(Arc.FileHead.UnpSize); #ifndef SFX_MODULE if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) Unp->DoUnpack(15,FileCount>1 && Arc.Solid); else #endif Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid); } } Arc.SeekToNext(); // We check for "split after" flag to detect partially extracted files // from incomplete volume sets. For them file header contains packed // data hash, which must not be compared against unpacked data hash // to prevent accidental match. Moreover, for -m0 volumes packed data // hash would match truncated unpacked data hash and lead to fake "OK" // in incomplete volume set. bool ValidCRC=!Arc.FileHead.SplitAfter && DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL); // We set AnySolidDataUnpackedWell to true if we found at least one // valid non-zero solid file in preceding solid stream. If it is true // and if current encrypted file is broken, we do not need to hint // about a wrong password and can report CRC error only. if (!Arc.FileHead.Solid) AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found. else if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC) AnySolidDataUnpackedWell=true; bool BrokenFile=false; // Checksum is not calculated in skip solid mode for performance reason. if (!SkipSolid && ShowChecksum) { if (!WrongPassword && ValidCRC) { #ifndef GUI if (Command!='P' && Command!='I') mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ", Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); #endif } else { if (!WrongPassword) { if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck || Arc.BrokenHeader) && !AnySolidDataUnpackedWell) uiMsg(UIERROR_CHECKSUMENC,Arc.FileName,ArcFileName); else uiMsg(UIERROR_CHECKSUM,Arc.FileName,ArcFileName); } BrokenFile=true; ErrHandler.SetErrorCode(RARX_CRC); #ifdef RARDLL // If we already have ERAR_EOPEN as result of missing volume, // we should not replace it with less precise ERAR_BAD_DATA. if (Cmd->DllError!=ERAR_EOPEN) Cmd->DllError=WrongPassword ? ERAR_BAD_PASSWORD : ERAR_BAD_DATA; #endif } } #ifndef GUI else mprintf(L"\b\b\b\b\b "); #endif if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') && (!LinkEntry || (Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess)) && (!BrokenFile || Cmd->KeepBroken)) { // We could preallocate more space that really written to broken file. if (BrokenFile) CurFile.Truncate(); #if defined(_WIN_ALL) || defined(_EMX) if (Cmd->ClearArc) Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE; #endif CurFile.SetOpenFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); CurFile.Close(); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0) SetFileCompression(CurFile.FileName,true); #endif #ifdef _UNIX if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet) SetUnixOwner(Arc,CurFile.FileName); #endif CurFile.SetCloseFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr)) uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName); PrevExtracted=true; } } } if (MatchFound) MatchedArgs++; if (DataIO.NextVolumeMissing) return false; if (!ExtrFile) { if (!Arc.Solid) Arc.SeekToNext(); else if (!SkipSolid) return false; } return true; }
bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat) { wchar Command=Cmd->Command[0]; if (HeaderSize==0) if (DataIO.UnpVolume) { #ifdef NOVOLUME return false; #else if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif } else return false; HEADER_TYPE HeaderType=Arc.GetHeaderType(); if (HeaderType!=HEAD_FILE) { #ifndef SFX_MODULE if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted) SetExtraInfo20(Cmd,Arc,DestFileName); #endif if (HeaderType==HEAD_SERVICE && PrevExtracted) SetExtraInfo(Cmd,Arc,DestFileName); if (HeaderType==HEAD_ENDARC) if (Arc.EndArcHead.NextVolume) { #ifndef NOVOLUME if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif Arc.Seek(Arc.CurBlockPos,SEEK_SET); return true; } else return false; Arc.SeekToNext(); return true; } PrevExtracted=false; if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) return false; int MatchType=MATCH_WILDSUBPATH; bool EqualNames=false; int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType); bool ExactMatch=MatchNumber!=0; #ifndef SFX_MODULE if (Cmd->ExclPath==EXCL_BASEPATH) { *Cmd->ArcPath=0; if (ExactMatch) { Cmd->FileArgs.Rewind(); if (Cmd->FileArgs.GetString(Cmd->ArcPath,ASIZE(Cmd->ArcPath),MatchNumber-1)) *PointToName(Cmd->ArcPath)=0; } } #endif if (ExactMatch && !EqualNames) AllMatchesExact=false; Arc.ConvertAttributes(); #if !defined(SFX_MODULE) && !defined(RARDLL) if (Arc.FileHead.SplitBefore && FirstFile) { wchar CurVolName[NM]; wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); VolNameToFirstName(ArcName,ArcName,Arc.NewNumbering); if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) { // If first volume name does not match the current name and if such // volume name really exists, let's unpack from this first volume. Repeat=true; return false; } #ifndef RARDLL if (!ReconstructDone) { ReconstructDone=true; if (RecVolumesRestore(Cmd,Arc.FileName,true)) { Repeat=true; return false; } } #endif wcsncpyz(ArcName,CurVolName,ASIZE(ArcName)); } #endif wchar ArcFileName[NM]; ConvertPath(Arc.FileHead.FileName,ArcFileName); if (Arc.FileHead.Version) { if (Cmd->VersionControl!=1 && !EqualNames) { if (Cmd->VersionControl==0) ExactMatch=false; int Version=ParseVersionFileName(ArcFileName,false); if (Cmd->VersionControl-1==Version) ParseVersionFileName(ArcFileName,true); else ExactMatch=false; } } else if (!Arc.IsArcDir() && Cmd->VersionControl>1) ExactMatch=false; DataIO.UnpVolume=Arc.FileHead.SplitAfter; DataIO.NextVolumeMissing=false; Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); bool ExtrFile=false; bool SkipSolid=false; #ifndef SFX_MODULE if (FirstFile && (ExactMatch || Arc.Solid) && Arc.FileHead.SplitBefore) { if (ExactMatch) { Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName); #ifdef RARDLL Cmd->DllError=ERAR_BAD_DATA; #endif ErrHandler.SetErrorCode(RARX_OPEN); } ExactMatch=false; } FirstFile=false; #endif if (ExactMatch || (SkipSolid=Arc.Solid)!=0) { ExtrPrepareName(Cmd,Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); // DestFileName can be set empty in case of excessive -ap switch. ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X')) { FindData FD; if (FindFile::FastFind(DestFileName,&FD)) { if (FD.mtime >= Arc.FileHead.mtime) { // If directory already exists and its modification time is newer // than start of extraction, it is likely it was created // when creating a path to one of already extracted items. // In such case we'll better update its time even if archived // directory is older. if (!FD.IsDir || FD.mtime<StartTime) ExtrFile=false; } } else if (Cmd->FreshFiles) ExtrFile=false; } if (Arc.FileHead.Encrypted) { #ifdef RARDLL if (!ExtrDllGetPassword(Cmd)) return false; #else if (!ExtrGetPassword(Cmd,Arc,ArcFileName)) { PasswordCancelled=true; return false; } #endif // Skip only the current encrypted file if empty password is entered. if (!Password.IsSet()) { ErrHandler.SetErrorCode(RARX_WARNING); #ifdef RARDLL Cmd->DllError=ERAR_MISSING_PASSWORD; #endif ExtrFile=false; } } #ifdef RARDLL if (*Cmd->DllDestName!=0) { wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); // Do we need this code? // if (Cmd->DllOpMode!=RAR_EXTRACT) // ExtrFile=false; } #endif if (!CheckUnpVer(Arc,ArcFileName)) { ExtrFile=false; ErrHandler.SetErrorCode(RARX_WARNING); #ifdef RARDLL Cmd->DllError=ERAR_UNKNOWN_FORMAT; #endif } File CurFile; bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) { if (ExtrFile && Command!='P' && !Cmd->Test) { // Overwrite prompt for symbolic and hard links. bool UserReject=false; if (FileExist(DestFileName) && !UserReject) FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); if (UserReject) ExtrFile=false; } } else if (Arc.IsArcDir()) { if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) return true; TotalFileCount++; ExtrCreateDir(Cmd,Arc,ArcFileName); return true; } else if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY). ExtrFile=ExtrCreateFile(Cmd,Arc,CurFile); if (!ExtrFile && Arc.Solid) { SkipSolid=true; ExtrFile=true; } if (ExtrFile) { bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk. if (!SkipSolid) { if (!TestMode && Command!='P' && CurFile.IsDevice()) { Log(Arc.FileName,St(MInvalidName),DestFileName); ErrHandler.WriteError(Arc.FileName,DestFileName); } TotalFileCount++; } FileCount++; #ifndef GUI if (Command!='I') if (SkipSolid) mprintf(St(MExtrSkipFile),ArcFileName); else switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch. { case 'T': mprintf(St(MExtrTestFile),ArcFileName); break; #ifndef SFX_MODULE case 'P': mprintf(St(MExtrPrinting),ArcFileName); break; #endif case 'X': case 'E': mprintf(St(MExtrFile),DestFileName); break; } if (!Cmd->DisablePercentage) mprintf(L" "); #endif SecPassword FilePassword=Password; #if defined(_WIN_ALL) && !defined(SFX_MODULE) ConvertDosPassword(Arc,FilePassword); #endif byte PswCheck[SIZE_PSWCHECK]; DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, Arc.FileHead.InitV,Arc.FileHead.Lg2Count, PswCheck,Arc.FileHead.HashKey); bool WrongPassword=false; // If header is damaged, we cannot rely on password check value, // because it can be damaged too. if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && !Arc.BrokenHeader) { Log(Arc.FileName,St(MWrongPassword)); ErrHandler.SetErrorCode(RARX_BADPWD); WrongPassword=true; } DataIO.CurUnpRead=0; DataIO.CurUnpWrite=0; DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize); DataIO.SetFiles(&Arc,&CurFile); DataIO.SetTestMode(TestMode); DataIO.SetSkipUnpCRC(SkipSolid); if (!TestMode && !WrongPassword && !Arc.BrokenHeader && (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize && (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) CurFile.Prealloc(Arc.FileHead.UnpSize); CurFile.SetAllowDelete(!Cmd->KeepBroken); bool FileCreateMode=!TestMode && !SkipSolid && Command!='P'; bool ShowChecksum=true; // Display checksum verification result. bool LinkSuccess=true; // Assume success for test mode. if (LinkEntry) { FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType; if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) { wchar NameExisting[NM]; ExtrPrepareName(Cmd,Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. if (Type==FSREDIR_HARDLINK) LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting)); else LinkSuccess=ExtractFileCopy(Cmd,CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); } else if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) { if (FileCreateMode) LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); } else { #ifndef SFX_MODULE Log(Arc.FileName,St(MUnknownExtra),DestFileName); #endif LinkSuccess=false; } if (!LinkSuccess || Arc.Format==RARFMT15 && !FileCreateMode) { // RAR 5.x links have a valid data checksum even in case of // failure, because they do not store any data. // We do not want to display "OK" in this case. // For 4.x symlinks we verify the checksum only when extracting, // but not when testing an archive. ShowChecksum=false; } PrevExtracted=FileCreateMode && LinkSuccess; } else if (!Arc.FileHead.SplitBefore && !WrongPassword) if (Arc.FileHead.Method==0) UnstoreFile(DataIO,Arc.FileHead.UnpSize); else { Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); Unp->SetDestSize(Arc.FileHead.UnpSize); #ifndef SFX_MODULE if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) Unp->DoUnpack(15,FileCount>1 && Arc.Solid); else #endif Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid); } Arc.SeekToNext(); bool ValidCRC=DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL); // We set AnySolidDataUnpackedWell to true if we found at least one // valid non-zero solid file in preceding solid stream. If it is true // and if current encrypted file is broken, we do not need to hint // about a wrong password and can report CRC error only. if (!Arc.FileHead.Solid) AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found. else if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC) AnySolidDataUnpackedWell=true; bool BrokenFile=false; // Checksum is not calculated in skip solid mode for performance reason. if (!SkipSolid && ShowChecksum) { if (!WrongPassword && ValidCRC) { #ifndef GUI if (Command!='P' && Command!='I') mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ", Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); #endif } else { if (!WrongPassword) if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck || Arc.BrokenHeader) && !AnySolidDataUnpackedWell) { Log(Arc.FileName,St(MEncrBadCRC),ArcFileName); } else { Log(Arc.FileName,St(MCRCFailed),ArcFileName); } BrokenFile=true; ErrHandler.SetErrorCode(RARX_CRC); #ifdef RARDLL // If we already have ERAR_EOPEN as result of missing volume, // we should not replace it with less precise ERAR_BAD_DATA. if (Cmd->DllError!=ERAR_EOPEN) Cmd->DllError=ERAR_BAD_DATA; #endif } } #ifndef GUI else mprintf(L"\b\b\b\b\b "); #endif if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') && (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && (!BrokenFile || Cmd->KeepBroken)) { // We could preallocate more space that really written to broken file. if (BrokenFile) CurFile.Truncate(); #if defined(_WIN_ALL) || defined(_EMX) if (Cmd->ClearArc) Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE; #endif CurFile.SetOpenFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); CurFile.Close(); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0) SetFileCompression(CurFile.FileName,true); #endif #ifdef _UNIX if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet) SetUnixOwner(Arc,CurFile.FileName); #endif CurFile.SetCloseFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); if (!Cmd->IgnoreGeneralAttr) SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr); PrevExtracted=true; } } } if (ExactMatch) MatchedArgs++; if (DataIO.NextVolumeMissing) return false; if (!ExtrFile) if (!Arc.Solid) Arc.SeekToNext(); else if (!SkipSolid) return false; return true; }