diff --git a/PasswordView.xib b/PasswordView.xib index c8ff849..db80b76 100644 --- a/PasswordView.xib +++ b/PasswordView.xib @@ -1,8 +1,8 @@ - + - + @@ -13,7 +13,7 @@ - + @@ -27,10 +27,10 @@ - + - + diff --git a/QuietUnrarAppDelegate.m b/QuietUnrarAppDelegate.m index 7780c9c..95178e1 100644 --- a/QuietUnrarAppDelegate.m +++ b/QuietUnrarAppDelegate.m @@ -107,6 +107,7 @@ int callbackFunction(UINT message, LPARAM userData, LPARAM parameterOne, LPARAM #pragma mark "Main" - (BOOL) extractRarWith:(NSString *) filename { + quietUnrar = (__bridge QuietUnrarAppDelegate *)((__bridge void *) self); char commentBuffer[BUF_LEN]; BOOL extractionSuccessful = YES; struct RARHeaderData headerData; @@ -219,7 +220,9 @@ int callbackFunction(UINT message, LPARAM userData, LPARAM parameterOne, LPARAM NSBundle* bundle = [NSBundle bundleForClass:[self class]]; [bundle loadNibNamed:@"PasswordView" owner:self topLevelObjects: nil]; - } + } else { + [passwordField setStringValue:@""]; + } NSString * password = nil; diff --git a/libunrar/acknow.txt b/libunrar/acknow.txt index a68b672..60a772f 100644 --- a/libunrar/acknow.txt +++ b/libunrar/acknow.txt @@ -51,7 +51,7 @@ * RAR uses CRC32 function based on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code is available here: - http://sourceforge.net/projects/slicing-by-8/ + https://sourceforge.net/projects/slicing-by-8/ Original Intel Slicing-by-8 code is licensed under BSD License available at http://www.opensource.org/licenses/bsd-license.html diff --git a/libunrar/arcread.cpp b/libunrar/arcread.cpp index b0cf39f..d1df6c0 100644 --- a/libunrar/arcread.cpp +++ b/libunrar/arcread.cpp @@ -785,7 +785,7 @@ size_t Archive::ReadHeader50() case HEAD_SERVICE: { FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead; - hd->Reset(); + hd->Reset(); // Clear hash, time fields and other stuff like flags. *(BaseBlock *)hd=ShortBlock; bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; diff --git a/libunrar/cmddata.cpp b/libunrar/cmddata.cpp index 74e565a..455a07b 100644 --- a/libunrar/cmddata.cpp +++ b/libunrar/cmddata.cpp @@ -56,7 +56,6 @@ void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[]) // In Windows we may prefer to implement our own command line parser // to avoid replacing \" by " in standard parser. Such replacing corrupts // destination paths like "dest path\" in extraction commands. - // Also our own parser is Unicode compatible. const wchar *CmdLine=GetCommandLine(); wchar *Par; @@ -288,7 +287,10 @@ void CommandData::ProcessSwitch(const wchar *Switch) AppendArcNameToPath=APPENDARCNAME_DESTPATH; else if (Switch[2]=='1') - AppendArcNameToPath=APPENDARCNAME_OWNDIR; + AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR; + else + if (Switch[2]=='2') + AppendArcNameToPath=APPENDARCNAME_OWNDIR; break; #ifndef SFX_MODULE case 'G': @@ -436,9 +438,9 @@ void CommandData::ProcessSwitch(const wchar *Switch) wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo)); break; } - if (wcsicomp(Switch+1,L"M")==0) + if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv. { - MoreInfo=true; + VerboseOutput=true; break; } if (wcsicomp(Switch+1,L"NUL")==0) @@ -465,6 +467,12 @@ void CommandData::ProcessSwitch(const wchar *Switch) case 'P': DisablePercentage=true; break; + case 'N': + DisableNames=true; + break; + case 'V': + VerboseOutput=true; + break; } break; } @@ -539,7 +547,6 @@ void CommandData::ProcessSwitch(const wchar *Switch) case 'D': Type=FILTER_DELTA; break; case 'A': Type=FILTER_AUDIO; break; case 'C': Type=FILTER_RGB; break; - case 'I': Type=FILTER_ITANIUM; break; case 'R': Type=FILTER_ARM; break; } if (*Str=='+' || *Str=='-') diff --git a/libunrar/cmddata.hpp b/libunrar/cmddata.hpp index 0c6d148..719b400 100644 --- a/libunrar/cmddata.hpp +++ b/libunrar/cmddata.hpp @@ -11,7 +11,6 @@ enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1}; class CommandData:public RAROptions { private: - void ProcessSwitchesString(const wchar *Str); void ProcessSwitch(const wchar *Switch); void BadSwitch(const wchar *Switch); uint GetExclAttr(const wchar *Str,bool &Dir); @@ -34,6 +33,7 @@ class CommandData:public RAROptions void ParseEnvVar(); void ReadConfig(); void PreprocessArg(const wchar *Arg); + void ProcessSwitchesString(const wchar *Str); void OutTitle(); void OutHelp(RAR_EXIT ExitCode); bool IsSwitch(int Ch); diff --git a/libunrar/consio.cpp b/libunrar/consio.cpp index 196066e..fedd5c0 100644 --- a/libunrar/consio.cpp +++ b/libunrar/consio.cpp @@ -164,7 +164,7 @@ static void GetPasswordText(wchar *Str,uint MaxLength) SetConsoleMode(hConIn,ConInMode); SetConsoleMode(hConOut,ConOutMode); #else - char StrA[MAXPASSWORD]; + char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters. #if defined(_EMX) || defined (__VMS) fgets(StrA,ASIZE(StrA)-1,stdin); #elif defined(__sun) @@ -248,6 +248,12 @@ bool getwstr(wchar *str,size_t n) ErrHandler.Exit(RARX_USERBREAK); } StrA[ReadSize]=0; + + // We expect ANSI encoding here, but "echo text|rar ..." to pipe to RAR, + // such as send passwords, we get OEM encoding by default, unless we + // use "chcp" in console. But we avoid OEM to ANSI conversion, + // because we also want to handle ANSI files redirection correctly, + // like "rar ... < ansifile.txt". CharToWide(&StrA[0],str,n); cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords. } @@ -305,7 +311,7 @@ int Ask(const wchar *AskStr) for (int I=0;I4 ? L"\n":L" "):L", "); + eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", "); int KeyPos=ItemKeyPos[I]; for (int J=0;J VS_VERSION_INFO VERSIONINFO -FILEVERSION 5, 91, 100, 3470 -PRODUCTVERSION 5, 91, 100, 3470 +FILEVERSION 6, 2, 1, 3796 +PRODUCTVERSION 6, 2, 1, 3796 FILEOS VOS__WINDOWS32 FILETYPE VFT_APP { @@ -14,9 +14,9 @@ FILETYPE VFT_APP VALUE "CompanyName", "Alexander Roshal\0" VALUE "ProductName", "RAR decompression library\0" VALUE "FileDescription", "RAR decompression library\0" - VALUE "FileVersion", "5.91.0\0" - VALUE "ProductVersion", "5.91.0\0" - VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0" + VALUE "FileVersion", "6.2.1\0" + VALUE "ProductVersion", "6.2.1\0" + VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2021\0" VALUE "OriginalFilename", "Unrar.dll\0" } } diff --git a/libunrar/errhnd.cpp b/libunrar/errhnd.cpp index c86d176..d473b1f 100644 --- a/libunrar/errhnd.cpp +++ b/libunrar/errhnd.cpp @@ -15,6 +15,7 @@ void ErrorHandler::Clean() UserBreak=false; MainExit=false; DisableShutdown=false; + ReadErrIgnoreAll=false; } @@ -56,24 +57,34 @@ void ErrorHandler::ReadError(const wchar *FileName) ReadErrorMsg(FileName); #endif #if !defined(SILENT) || defined(RARDLL) - Exit(RARX_FATAL); + Exit(RARX_READ); #endif } -bool ErrorHandler::AskRepeatRead(const wchar *FileName) +void ErrorHandler::AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit) { + SetErrorCode(RARX_READ); #if !defined(SILENT) && !defined(SFX_MODULE) if (!Silent) { + uiMsg(UIERROR_FILEREAD,UINULL,FileName); SysErrMsg(); - bool Repeat=uiAskRepeatRead(FileName); - if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog. - DisableShutdown=true; - return Repeat; + if (ReadErrIgnoreAll) + Ignore=true; + else + { + bool All=false; + uiAskRepeatRead(FileName,Ignore,All,Retry,Quit); + if (All) + ReadErrIgnoreAll=Ignore=true; + if (Quit) // Disable shutdown if user select Quit in read error prompt. + DisableShutdown=true; + } + return; } #endif - return false; + Ignore=true; // Saving the file part for -y or -inul or "Ignore all" choice. } @@ -189,7 +200,7 @@ void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName) { uiMsg(UIERROR_FILEREAD,ArcName,FileName); SysErrMsg(); - SetErrorCode(RARX_FATAL); + SetErrorCode(RARX_READ); } @@ -356,7 +367,7 @@ bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size) void ErrorHandler::SysErrMsg() { -#if !defined(SFX_MODULE) && !defined(SILENT) +#ifndef SILENT wchar Msg[1024]; if (!GetSysErrMsg(Msg,ASIZE(Msg))) return; diff --git a/libunrar/errhnd.hpp b/libunrar/errhnd.hpp index 3455dac..06f4f61 100644 --- a/libunrar/errhnd.hpp +++ b/libunrar/errhnd.hpp @@ -15,9 +15,11 @@ enum RAR_EXIT // RAR exit code. RARX_CREATE = 9, RARX_NOFILES = 10, RARX_BADPWD = 11, + RARX_READ = 12, RARX_USERBREAK = 255 }; + class ErrorHandler { private: @@ -26,6 +28,7 @@ class ErrorHandler bool EnableBreak; bool Silent; bool DisableShutdown; // Shutdown is not suitable after last error. + bool ReadErrIgnoreAll; public: ErrorHandler(); void Clean(); @@ -33,7 +36,7 @@ class ErrorHandler void OpenError(const wchar *FileName); void CloseError(const wchar *FileName); void ReadError(const wchar *FileName); - bool AskRepeatRead(const wchar *FileName); + void AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit); void WriteError(const wchar *ArcName,const wchar *FileName); void WriteErrorFAT(const wchar *FileName); bool AskRepeatWrite(const wchar *FileName,bool DiskFull); diff --git a/libunrar/extinfo.hpp b/libunrar/extinfo.hpp index 2b0005d..f3c7511 100644 --- a/libunrar/extinfo.hpp +++ b/libunrar/extinfo.hpp @@ -7,7 +7,7 @@ bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wcha void SetUnixOwner(Archive &Arc,const wchar *FileName); #endif -bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); +bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize); diff --git a/libunrar/extract.cpp b/libunrar/extract.cpp index 76ee2d4..6c3e214 100644 --- a/libunrar/extract.cpp +++ b/libunrar/extract.cpp @@ -42,6 +42,7 @@ void CmdExtract::DoExtract() Cmd->Password.Clean(); // Clean user entered password before processing next archive. ReconstructDone=false; // Must be reset here, not in ExtractArchiveInit(). + UseExactVolName=false; // Must be reset here, not in ExtractArchiveInit(). while (true) { EXTRACT_ARC_CODE Code=ExtractArchive(); @@ -140,7 +141,7 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() return EXTRACT_ARC_NEXT; #ifndef SFX_MODULE - if (Arc.Volume && !Arc.FirstVolume) + if (Arc.Volume && !Arc.FirstVolume && !UseExactVolName) { wchar FirstVolName[NM]; VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),Arc.NewNumbering); @@ -158,6 +159,16 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() if (Arc.Volume) { +#ifndef SFX_MODULE + // Try to speed up extraction for independent solid volumes by starting + // extraction from non-first volume if we can. + if (!UseExactVolName && Arc.Solid && DetectStartVolume(Arc.FileName,Arc.NewNumbering)) + { + UseExactVolName=true; + return EXTRACT_ARC_REPEAT; + } +#endif + // Calculate the total size of all accessible volumes. // This size is necessary to display the correct total progress indicator. @@ -318,11 +329,11 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) Arc.ConvertAttributes(); #if !defined(SFX_MODULE) && !defined(RARDLL) - if (Arc.FileHead.SplitBefore && FirstFile) + if (Arc.FileHead.SplitBefore && FirstFile && !UseExactVolName) { wchar CurVolName[NM]; wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); - VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering); + GetFirstVolIfFullSet(ArcName,Arc.NewNumbering,ArcName,ASIZE(ArcName)); if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) { @@ -575,7 +586,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) TotalFileCount++; } FileCount++; - if (Command!='I') + if (Command!='I' && !Cmd->DisableNames) if (SkipSolid) mprintf(St(MExtrSkipFile),ArcFileName); else @@ -594,8 +605,10 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) mprintf(St(MExtrFile),DestFileName); break; } - if (!Cmd->DisablePercentage) + if (!Cmd->DisablePercentage && !Cmd->DisableNames) mprintf(L" "); + if (Cmd->DisableNames) + uiEolAfterMsg(); // Avoid erasing preceding messages by percentage indicator in -idn mode. DataIO.CurUnpRead=0; DataIO.CurUnpWrite=0; @@ -641,7 +654,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) 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)); + LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting)); else LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); } @@ -653,7 +666,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) } else { - uiMsg(UIERROR_UNKNOWNEXTRA, Arc.FileName, DestFileName); + uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,DestFileName); LinkSuccess=false; } @@ -711,7 +724,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) { if (ValidCRC) { - if (Command!='P' && Command!='I') + if (Command!='P' && Command!='I' && !Cmd->DisableNames) mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ", Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); } @@ -734,7 +747,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) } } else - mprintf(L"\b\b\b\b\b "); + { + // We check SkipSolid to remove percent for skipped solid files only. + // We must not apply these \b to links with ShowChecksum==false + // and their possible error messages. + if (SkipSolid) + mprintf(L"\b\b\b\b\b "); + } // If we successfully unpacked a hard link, we wish to set its file // attributes. Hard link shares file metadata with link target, @@ -781,7 +800,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE; #endif if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,Arc.FileHead.FileAttr)) + { uiMsg(UIERROR_FILEATTR,Arc.FileName,DestFileName); + // Android cannot set file attributes and while UIERROR_FILEATTR + // above is handled by Android RAR silently, this call would cause + // "Operation not permitted" message for every unpacked file. + ErrHandler.SysErrMsg(); + } PrevProcessed=true; } @@ -863,6 +888,8 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De wchar LastChar=*PointToLastChar(Cmd->ExtrPath); // We need IsPathDiv check here to correctly handle Unix forward slash // in the end of destination path in Windows: rar x arc dest/ + // so we call IsPathDiv first instead of just calling AddEndSlash, + // which checks for only one type of path separator. // IsDriveDiv is needed for current drive dir: rar x arc d: if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar)) { @@ -874,11 +901,21 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De #ifndef SFX_MODULE if (Cmd->AppendArcNameToPath!=APPENDARCNAME_NONE) { - if (Cmd->AppendArcNameToPath==APPENDARCNAME_DESTPATH) - wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); - else - wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); // To archive own dir. - SetExt(DestName,NULL,DestSize); + switch(Cmd->AppendArcNameToPath) + { + case APPENDARCNAME_DESTPATH: // To subdir of destination path. + wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); + SetExt(DestName,NULL,DestSize); + break; + case APPENDARCNAME_OWNSUBDIR: // To subdir of archive own dir. + wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); + SetExt(DestName,NULL,DestSize); + break; + case APPENDARCNAME_OWNDIR: // To archive own dir. + wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); + RemoveNameFromPath(DestName); + break; + } AddEndSlash(DestName,DestSize); } #endif @@ -1048,8 +1085,11 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) { if (Cmd->Test) { - mprintf(St(MExtrTestFile),ArcFileName); - mprintf(L" %s",St(MOk)); + if (!Cmd->DisableNames) + { + mprintf(St(MExtrTestFile),ArcFileName); + mprintf(L" %s",St(MOk)); + } return; } @@ -1068,26 +1108,33 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) } if (!DirExist) { - CreatePath(DestFileName,true); + CreatePath(DestFileName,true,Cmd->DisableNames); MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); - if (MDCode!=MKDIR_SUCCESS) + if (MDCode!=MKDIR_SUCCESS && !IsNameUsable(DestFileName)) { + uiMsg(UIMSG_CORRECTINGNAME,Arc.FileName); wchar OrigName[ASIZE(DestFileName)]; wcsncpyz(OrigName,DestFileName,ASIZE(OrigName)); MakeNameUsable(DestFileName,true); - CreatePath(DestFileName,true); - MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); #ifndef SFX_MODULE - if (MDCode==MKDIR_SUCCESS) - uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName); + uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName); #endif + DirExist=FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName)); + if (!DirExist) + { + CreatePath(DestFileName,true,Cmd->DisableNames); + MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); + } } } } if (MDCode==MKDIR_SUCCESS) { - mprintf(St(MCreatDir),DestFileName); - mprintf(L" %s",St(MOk)); + if (!Cmd->DisableNames) + { + mprintf(St(MCreatDir),DestFileName); + mprintf(L" %s",St(MOk)); + } PrevProcessed=true; } else @@ -1141,6 +1188,9 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile) if (!UserReject) { ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName); + if (FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName))) + uiMsg(UIERROR_DIRNAMEEXISTS); + #ifdef RARDLL Cmd->DllError=ERAR_ECREATE; #endif @@ -1153,7 +1203,7 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile) MakeNameUsable(DestFileName,true); - CreatePath(DestFileName,true); + CreatePath(DestFileName,true,Cmd->DisableNames); if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) { #ifndef SFX_MODULE @@ -1196,3 +1246,104 @@ bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName) } return !WrongVer; } + + +#ifndef SFX_MODULE +// To speed up solid volumes extraction, try to find a non-first start volume, +// which still allows to unpack all files. It is possible for independent +// solid volumes with solid statistics reset in the beginning. +bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering) +{ + wchar *ArgName=Cmd->FileArgs.GetString(); + Cmd->FileArgs.Rewind(); + if (ArgName!=NULL && (wcscmp(ArgName,L"*")==0 || wcscmp(ArgName,L"*.*")==0)) + return false; // No need to check further for * and *.* masks. + + wchar StartName[NM]; + *StartName=0; + + // Start search from first volume if all volumes preceding current are available. + wchar NextName[NM]; + GetFirstVolIfFullSet(VolName,NewNumbering,NextName,ASIZE(NextName)); + + bool Matched=false; + while (!Matched) + { + Archive Arc(Cmd); + if (!Arc.Open(NextName) || !Arc.IsArchive(false) || !Arc.Volume) + break; + + bool OpenNext=false; + while (Arc.ReadHeader()>0) + { + Wait(); + + HEADER_TYPE HeaderType=Arc.GetHeaderType(); + if (HeaderType==HEAD_ENDARC) + { + OpenNext|=Arc.EndArcHead.NextVolume; // Allow open next volume. + break; + } + if (HeaderType==HEAD_FILE) + { + if (!Arc.FileHead.SplitBefore) + { + if (!Arc.FileHead.Solid) // Can start extraction from here. + wcsncpyz(StartName,NextName,ASIZE(StartName)); + + if (Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0) + { + Matched=true; // First matched file found, must stop further scan. + break; + } + } + if (Arc.FileHead.SplitAfter) + { + OpenNext=true; // Allow open next volume. + break; + } + } + Arc.SeekToNext(); + } + Arc.Close(); + + if (!OpenNext) + break; + + NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); + } + bool NewStartFound=wcscmp(VolName,StartName)!=0; + if (NewStartFound) // Found a new volume to start extraction. + wcsncpyz(ArcName,StartName,ASIZE(ArcName)); + + return NewStartFound; +} +#endif + + +#ifndef SFX_MODULE +// Return the first volume name if all volumes preceding the specified +// are available. Otherwise return the specified volume name. +void CmdExtract::GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize) +{ + wchar FirstVolName[NM]; + VolNameToFirstName(SrcName,FirstVolName,ASIZE(FirstVolName),NewNumbering); + wchar NextName[NM]; + wcsncpyz(NextName,FirstVolName,ASIZE(NextName)); + wchar ResultName[NM]; + wcsncpyz(ResultName,SrcName,ASIZE(ResultName)); + while (true) + { + if (wcscmp(SrcName,NextName)==0) + { + wcsncpyz(ResultName,FirstVolName,DestSize); + break; + } + if (!FileExist(NextName)) + break; + NextVolumeName(NextName,ASIZE(NextName),!NewNumbering); + } + wcsncpyz(DestName,ResultName,DestSize); +} + +#endif \ No newline at end of file diff --git a/libunrar/extract.hpp b/libunrar/extract.hpp index 325928d..159759b 100644 --- a/libunrar/extract.hpp +++ b/libunrar/extract.hpp @@ -20,8 +20,12 @@ class CmdExtract void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName); bool ExtrCreateFile(Archive &Arc,File &CurFile); bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName); +#ifndef SFX_MODULE + bool DetectStartVolume(const wchar *VolName,bool NewNumbering); + void GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize); +#endif - RarTime StartTime; // time when extraction started + RarTime StartTime; // Time when extraction started. CommandData *Cmd; @@ -34,6 +38,7 @@ class CmdExtract bool FirstFile; bool AllMatchesExact; bool ReconstructDone; + bool UseExactVolName; // If any non-zero solid file was successfully unpacked before current. // If true and if current encrypted file is broken, obviously diff --git a/libunrar/filcreat.cpp b/libunrar/filcreat.cpp index a64a7d4..620bee8 100644 --- a/libunrar/filcreat.cpp +++ b/libunrar/filcreat.cpp @@ -49,7 +49,7 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, if (NewFile!=NULL && NewFile->Create(Name,FileMode)) return true; - CreatePath(Name,true); + CreatePath(Name,true,Cmd->DisableNames); return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name); } diff --git a/libunrar/file.cpp b/libunrar/file.cpp index e506fde..5a8099e 100644 --- a/libunrar/file.cpp +++ b/libunrar/file.cpp @@ -8,7 +8,6 @@ File::File() LastWrite=false; HandleType=FILE_HANDLENORMAL; SkipClose=false; - IgnoreReadErrors=false; ErrorType=FILE_SUCCESS; OpenShared=false; AllowDelete=true; @@ -18,6 +17,8 @@ File::File() NoSequentialRead=false; CreateMode=FMF_UNDEFINED; #endif + ReadErrorMode=FREM_ASK; + TruncatedAfterReadError=false; } @@ -37,6 +38,7 @@ void File::operator = (File &SrcFile) NewFile=SrcFile.NewFile; LastWrite=SrcFile.LastWrite; HandleType=SrcFile.HandleType; + TruncatedAfterReadError=SrcFile.TruncatedAfterReadError; wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName)); SrcFile.SkipClose=true; } @@ -118,12 +120,12 @@ bool File::Open(const wchar *Name,uint Mode) #ifdef _OSF_SOURCE extern "C" int flock(int, int); #endif - if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1) { close(handle); return false; } + #endif if (handle==-1) hNewFile=FILE_BAD_HANDLE; @@ -146,6 +148,7 @@ bool File::Open(const wchar *Name,uint Mode) { hFile=hNewFile; wcsncpyz(FileName,Name,ASIZE(FileName)); + TruncatedAfterReadError=false; } return Success; } @@ -369,9 +372,12 @@ bool File::Write(const void *Data,size_t Size) int File::Read(void *Data,size_t Size) { + if (TruncatedAfterReadError) + return 0; + int64 FilePos=0; // Initialized only to suppress some compilers warning. - if (IgnoreReadErrors) + if (ReadErrorMode==FREM_IGNORE) FilePos=Tell(); int ReadSize; while (true) @@ -381,7 +387,7 @@ int File::Read(void *Data,size_t Size) { ErrorType=FILE_READERROR; if (AllowExceptions) - if (IgnoreReadErrors) + if (ReadErrorMode==FREM_IGNORE) { ReadSize=0; for (size_t I=0;IDisableNames); #ifdef _WIN_ALL bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0; diff --git a/libunrar/list.cpp b/libunrar/list.cpp index 77c1041..9b65218 100644 --- a/libunrar/list.cpp +++ b/libunrar/list.cpp @@ -1,6 +1,6 @@ #include "rar.hpp" -static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare); +static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames); static void ListSymLink(Archive &Arc); static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); static void ListOldSubHeader(Archive &Arc); @@ -28,7 +28,7 @@ void ListArchive(CommandData *Cmd) if (!Arc.WOpen(ArcName)) continue; bool FileMatched=true; - while (1) + while (true) { int64 TotalPackSize=0,TotalUnpSize=0; uint FileCount=0; @@ -69,7 +69,7 @@ void ListArchive(CommandData *Cmd) wchar VolNumText[50]; *VolNumText=0; - while(Arc.ReadHeader()>0) + while (Arc.ReadHeader()>0) { Wait(); // Allow quit listing with Ctrl+C. HEADER_TYPE HeaderType=Arc.GetHeaderType(); @@ -95,7 +95,7 @@ void ListArchive(CommandData *Cmd) FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0; if (FileMatched) { - ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); + ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare,Cmd->DisableNames); if (!Arc.FileHead.SplitBefore) { TotalUnpSize+=Arc.FileHead.UnpSize; @@ -108,7 +108,7 @@ void ListArchive(CommandData *Cmd) if (FileMatched && !Bare) { if (Technical && ShowService) - ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); + ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,Cmd->DisableNames); } break; } @@ -188,8 +188,29 @@ enum LISTCOL_TYPE { }; -void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) +void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames) { + if (!TitleShown && !Technical && !Bare) + { + if (Verbose) + { + mprintf(L"\n%ls",St(MListTitleV)); + if (!DisableNames) + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); + } + else + { + mprintf(L"\n%ls",St(MListTitleL)); + if (!DisableNames) + mprintf(L"\n----------- --------- ---------- ----- ----"); + } + // Must be set even in DisableNames mode to suppress "0 files" output + // unless no files are matched. + TitleShown=true; + } + if (DisableNames) + return; + wchar *Name=hd.FileName; RARFORMAT Format=Arc.Format; @@ -199,21 +220,6 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo return; } - if (!TitleShown && !Technical) - { - if (Verbose) - { - mprintf(L"\n%ls",St(MListTitleV)); - mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); - } - else - { - mprintf(L"\n%ls",St(MListTitleL)); - mprintf(L"\n----------- --------- ---------- ----- ----"); - } - TitleShown=true; - } - wchar UnpSizeText[30],PackSizeText[30]; if (hd.UnpSize==INT64NDF) wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText)); diff --git a/libunrar/loclang.hpp b/libunrar/loclang.hpp index a82aca5..a1cd544 100644 --- a/libunrar/loclang.hpp +++ b/libunrar/loclang.hpp @@ -4,6 +4,7 @@ #define MYesNoAllRenQ L"_Yes_No_All_nEver_Rename_Quit" #define MContinueQuit L"_Continue_Quit" #define MRetryAbort L"_Retry_Abort" +#define MIgnoreAllRetryQuit L"_Ignore_iGnore all_Retry_Quit" #define MCopyright L"\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %s %d" #define MRegTo L"\nRegistered to %s\n" #define MShare L"\nTrial version Type 'rar -?' for help\n" @@ -54,7 +55,7 @@ #define MCHelpSwm L"\n - Stop switches scanning" #define MCHelpSwAT L"\n @[+] Disable [enable] file lists" #define MCHelpSwAC L"\n ac Clear Archive attribute after compression or extraction" -#define MCHelpSwAD L"\n ad Append archive name to destination path" +#define MCHelpSwAD L"\n ad[1,2] Alternate destination path" #define MCHelpSwAG L"\n ag[format] Generate archive name using the current date" #define MCHelpSwAI L"\n ai Ignore file attributes" #define MCHelpSwAO L"\n ao Add files with Archive attribute set" @@ -79,7 +80,7 @@ #define MCHelpSwF L"\n f Freshen files" #define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers" #define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum" -#define MCHelpSwIDP L"\n id[c,d,p,q] Disable messages" +#define MCHelpSwIDP L"\n id[c,d,n,p,q] Display or disable messages" #define MCHelpSwIEML L"\n ieml[addr] Send archive by email" #define MCHelpSwIERR L"\n ierr Send all messages to stderr" #define MCHelpSwILOG L"\n ilog[name] Log errors to file" @@ -320,7 +321,7 @@ #define MStreamUnknown L"\nWARNING: Unknown format of %s stream data\n" #define MInvalidName L"\nERROR: Invalid file name %s" #define MProcessArc L"\n\nProcessing archive %s" -#define MCorrectingName L"\nWARNING: Attempting to correct the invalid file name" +#define MCorrectingName L"\nWARNING: Attempting to correct the invalid file or directory name" #define MUnpCannotMerge L"\nWARNING: You need to start extraction from a previous volume to unpack %s" #define MUnknownOption L"\nERROR: Unknown option: %s" #define MSubHeadCorrupt L"\nERROR: Corrupt data header found, ignored" @@ -351,7 +352,7 @@ #define MRecVolLimit L"\nTotal number of usual and recovery volumes must not exceed %d" #define MVolumeNumber L"volume %d" #define MCannotDelete L"\nCannot delete %s" -#define MRecycleFailed L"\nCannot move some files and folders to Recycle Bin" +#define MRecycleFailed L"\nCannot move some files and directories to Recycle Bin" #define MCalcCRC L"\nCalculating the checksum" #define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB." #define MCalcCRCAllVol L"\nCalculating checksums of all volumes." @@ -380,3 +381,7 @@ #define MDictOutMem L"\nNot enough memory for %d MB compression dictionary, changed to %d MB." #define MUseSmalllerDict L"\nPlease use a smaller compression dictionary." #define MOpenErrAtime L"\nYou may need to remove -tsp switch to open this file." +#define MErrReadInfo L"\nChoose 'Ignore' to continue with the already read file part only, 'Ignore all' to do it for all read errors, 'Retry' to repeat read and 'Quit' to abort." +#define MErrReadTrunc L"\n%s is archived incompletely because of read error.\n" +#define MErrReadCount L"\n%u files are archived incompletely because of read errors." +#define MDirNameExists L"\nDirectory with such name already exists" diff --git a/libunrar/options.hpp b/libunrar/options.hpp index fd33d3d..993b219 100644 --- a/libunrar/options.hpp +++ b/libunrar/options.hpp @@ -61,7 +61,8 @@ enum SAVECOPY_MODE { enum APPENDARCNAME_MODE { - APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR + APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNSUBDIR, + APPENDARCNAME_OWNDIR }; enum POWER_MODE { @@ -132,6 +133,7 @@ class RAROptions bool DisablePercentage; bool DisableCopyright; bool DisableDone; + bool DisableNames; bool PrintVersion; int Solid; int SolidCount; @@ -146,7 +148,7 @@ class RAROptions Array NextVolSizes; uint CurVolNum; bool AllYes; - bool MoreInfo; // -im, show more information, used only in "WinRAR t" now. + bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now. bool DisableSortSolid; int ArcTime; int ConvertNames; diff --git a/libunrar/pathfn.cpp b/libunrar/pathfn.cpp index 278863c..18f7098 100644 --- a/libunrar/pathfn.cpp +++ b/libunrar/pathfn.cpp @@ -184,7 +184,9 @@ void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize // the temporary buffer instead of constructing the name in 'Pathname'. wchar OutName[NM]; wcsncpyz(OutName,Path,ASIZE(OutName)); - AddEndSlash(OutName,ASIZE(OutName)); + // Do not add slash to d:, we want to allow relative paths like d:filename. + if (!IsDriveLetter(Path) || Path[2]!=0) + AddEndSlash(OutName,ASIZE(OutName)); wcsncatz(OutName,Name,ASIZE(OutName)); wcsncpyz(Pathname,OutName,MaxSize); } @@ -655,7 +657,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,b } if (!FileExist(FirstName)) { - // If the first volume, which name we just generated, is not exist, + // If the first volume, which name we just generated, does not exist, // check if volume with same name and any other extension is available. // It can help in case of *.exe or *.sfx first volume. wchar Mask[NM]; diff --git a/libunrar/secpassword.cpp b/libunrar/secpassword.cpp index 4865b3f..b99e53a 100644 --- a/libunrar/secpassword.cpp +++ b/libunrar/secpassword.cpp @@ -51,7 +51,7 @@ class CryptLoader }; // We need to call FreeLibrary when RAR is exiting. -CryptLoader GlobalCryptLoader; +static CryptLoader GlobalCryptLoader; #endif SecPassword::SecPassword() diff --git a/libunrar/ui.hpp b/libunrar/ui.hpp index 6bd224d..2654387 100644 --- a/libunrar/ui.hpp +++ b/libunrar/ui.hpp @@ -38,7 +38,8 @@ enum UIMESSAGE_CODE { UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET, UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST, - UIERROR_OPENPRESERVEATIME, + UIERROR_OPENPRESERVEATIME, UIERROR_READERRTRUNCATED, UIERROR_READERRCOUNT, + UIERROR_DIRNAMEEXISTS, UIMSG_FIRST, UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA, @@ -92,16 +93,18 @@ bool uiIsGlobalPasswordSet(); enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION}; void uiAlarm(UIALARM_TYPE Type); +void uiEolAfterMsg(); bool uiAskNextVolume(wchar *VolName,size_t MaxSize); -bool uiAskRepeatRead(const wchar *FileName); +#if !defined(SILENT) && !defined(SFX_MODULE) +void uiAskRepeatRead(const wchar *FileName,bool &Ignore,bool &All,bool &Retry,bool &Quit); +#endif bool uiAskRepeatWrite(const wchar *FileName,bool DiskFull); #ifndef SFX_MODULE const wchar *uiGetMonthName(int Month); #endif - class uiMsgStore { private: diff --git a/libunrar/uiconsole.cpp b/libunrar/uiconsole.cpp index 7b4998d..ceae1a7 100644 --- a/libunrar/uiconsole.cpp +++ b/libunrar/uiconsole.cpp @@ -1,3 +1,5 @@ +static bool AnyMessageDisplayed=false; // For console -idn switch. + // Purely user interface function. Gets and returns user input. UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags) { @@ -83,6 +85,19 @@ void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize) void uiMsgStore::Msg() { + // When creating volumes, AnyMessageDisplayed must be reset for UIEVENT_NEWARCHIVE, + // so it ignores this and all earlier messages like UIEVENT_PROTECTEND + // and UIEVENT_PROTECTEND, because they precede "Creating archive" message + // and do not interfere with -idn and file names. If we do not ignore them, + // uiEolAfterMsg() in uiStartFileAddit() can cause unneeded carriage return + // in archiving percent after creating a new volume with -v -idn (and -rr + // for UIEVENT_PROTECT*) switches. AnyMessageDisplayed is set for messages + // after UIEVENT_NEWARCHIVE, so archiving percent with -idn is moved to + // next line and does not delete their last characters. + // Similarly we ignore UIEVENT_RRTESTINGEND for volumes, because it is issued + // before "Testing archive" and would add an excessive \n otherwise. + AnyMessageDisplayed=(Code!=UIEVENT_NEWARCHIVE && Code!=UIEVENT_RRTESTINGEND); + switch(Code) { case UIERROR_SYSERRMSG: @@ -121,6 +136,7 @@ void uiMsgStore::Msg() Log(NULL,St(MErrSeek),Str[0]); break; case UIERROR_FILEREAD: + mprintf(L"\n"); Log(Str[0],St(MErrRead),Str[1]); break; case UIERROR_FILEWRITE: @@ -304,7 +320,15 @@ void uiMsgStore::Msg() case UIERROR_ULINKEXIST: Log(NULL,St(MSymLinkExists),Str[0]); break; - + case UIERROR_READERRTRUNCATED: + Log(NULL,St(MErrReadTrunc),Str[0]); + break; + case UIERROR_READERRCOUNT: + Log(NULL,St(MErrReadCount),Num[0]); + break; + case UIERROR_DIRNAMEEXISTS: + Log(NULL,St(MDirNameExists)); + break; #ifndef SFX_MODULE case UIMSG_STRING: @@ -397,11 +421,15 @@ bool uiAskNextVolume(wchar *VolName,size_t MaxSize) } -bool uiAskRepeatRead(const wchar *FileName) +void uiAskRepeatRead(const wchar *FileName,bool &Ignore,bool &All,bool &Retry,bool &Quit) { - mprintf(L"\n"); - Log(NULL,St(MErrRead),FileName); - return Ask(St(MRetryAbort))==1; + eprintf(St(MErrReadInfo)); + int Code=Ask(St(MIgnoreAllRetryQuit)); + + Ignore=(Code==1); + All=(Code==2); + Quit=(Code==4); + Retry=!Ignore && !All && !Quit; // Default also for invalid input, not just for 'Retry'. } @@ -423,3 +451,15 @@ const wchar *uiGetMonthName(int Month) return St(MonthID[Month]); } #endif + + +void uiEolAfterMsg() +{ + if (AnyMessageDisplayed) + { + // Avoid deleting several last characters of any previous error message + // with percentage indicator in -idn mode. + AnyMessageDisplayed=false; + mprintf(L"\n"); + } +} diff --git a/libunrar/uisilent.cpp b/libunrar/uisilent.cpp index 1b5de13..1df0975 100644 --- a/libunrar/uisilent.cpp +++ b/libunrar/uisilent.cpp @@ -67,3 +67,8 @@ const wchar *uiGetMonthName(int Month) return L""; } #endif + + +void uiEolAfterMsg() +{ +} diff --git a/libunrar/ulinks.cpp b/libunrar/ulinks.cpp index 1656824..d198f2e 100644 --- a/libunrar/ulinks.cpp +++ b/libunrar/ulinks.cpp @@ -1,9 +1,14 @@ -static bool UnixSymlink(const char *Target,const wchar *LinkName,RarTime *ftm,RarTime *fta) +static bool UnixSymlink(CommandData *Cmd,const char *Target,const wchar *LinkName,RarTime *ftm,RarTime *fta) { - CreatePath(LinkName,true); + CreatePath(LinkName,true,Cmd->DisableNames); + + // Overwrite prompt was already issued and confirmed earlier, so we can + // remove existing symlink or regular file here. PrepareToDelete was also + // called earlier inside of uiAskReplaceEx. DelFile(LinkName); + char LinkNameA[NM]; WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA)); if (symlink(Target,LinkNameA)==-1) // Error. @@ -75,7 +80,7 @@ bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const w if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) || !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW))) return false; - return UnixSymlink(Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime); + return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime); } return false; } @@ -101,5 +106,5 @@ bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd) if (!Cmd->AbsoluteLinks && (IsFullPath(Target) || !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName))) return false; - return UnixSymlink(Target,Name,&hd->mtime,&hd->atime); + return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime); } diff --git a/libunrar/unicode.cpp b/libunrar/unicode.cpp index df63608..641f6c8 100644 --- a/libunrar/unicode.cpp +++ b/libunrar/unicode.cpp @@ -471,6 +471,7 @@ int wcsnicomp(const wchar *s1,const wchar *s2,size_t n) } +// Case insensitive wcsstr(). const wchar_t* wcscasestr(const wchar_t *str, const wchar_t *search) { for (size_t i=0;str[i]!=0;i++) diff --git a/libunrar/version.hpp b/libunrar/version.hpp index 24f0f8b..f9d8ddf 100644 --- a/libunrar/version.hpp +++ b/libunrar/version.hpp @@ -1,6 +1,6 @@ -#define RARVER_MAJOR 5 -#define RARVER_MINOR 91 -#define RARVER_BETA 0 -#define RARVER_DAY 25 -#define RARVER_MONTH 6 -#define RARVER_YEAR 2020 +#define RARVER_MAJOR 6 +#define RARVER_MINOR 2 +#define RARVER_BETA 1 +#define RARVER_DAY 17 +#define RARVER_MONTH 5 +#define RARVER_YEAR 2021 diff --git a/libunrar/volume.cpp b/libunrar/volume.cpp index 6cfa772..001a967 100644 --- a/libunrar/volume.cpp +++ b/libunrar/volume.cpp @@ -136,7 +136,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma Arc.ConvertAttributes(); Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); } - if (ShowFileName) + if (ShowFileName && !Cmd->DisableNames) { mprintf(St(MExtrPoints),Arc.FileHead.FileName); if (!Cmd->DisablePercentage) diff --git a/libunrar/win32lnk.cpp b/libunrar/win32lnk.cpp index a68ed75..84ab63f 100644 --- a/libunrar/win32lnk.cpp +++ b/libunrar/win32lnk.cpp @@ -71,20 +71,36 @@ bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd) !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName))) return false; - CreatePath(Name,true); + CreatePath(Name,true,Cmd->DisableNames); + + // Overwrite prompt was already issued and confirmed earlier, so we can + // remove existing symlink or regular file here. PrepareToDelete was also + // called earlier inside of uiAskReplaceEx. + if (FileExist(Name)) + if (IsDir(GetFileAttr(Name))) + DelDir(Name); + else + DelFile(Name); // 'DirTarget' check is important for Unix symlinks to directories. // Unix symlinks do not have their own 'directory' attribute. if (hd->Dir || hd->DirTarget) { if (!CreateDirectory(Name,NULL)) + { + uiMsg(UIERROR_DIRCREATE,UINULL,Name); + ErrHandler.SetErrorCode(RARX_CREATE); return false; + } } else { HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile == INVALID_HANDLE_VALUE) + { + ErrHandler.CreateErrorMsg(Name); return false; + } CloseHandle(hFile); } @@ -138,7 +154,11 @@ bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd) OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT| FILE_FLAG_BACKUP_SEMANTICS,NULL); if (hFile==INVALID_HANDLE_VALUE) + { + ErrHandler.CreateErrorMsg(Name); + ErrHandler.SetErrorCode(RARX_CREATE); return false; + } DWORD Returned; if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb,