Upgrade to libunrar 6.06, tweaked the PasswordView xib to have hint text, and clear the field if dialog reappears. Password unraring not working, not sure why. Cstring passed in is perfectly valid.

This commit is contained in:
Robert McGovern 2021-05-24 16:37:15 +01:00
parent c78276aeeb
commit 043a11ec6d
34 changed files with 441 additions and 123 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17132.0.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17132.0.2"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -13,7 +13,7 @@
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="1">
<rect key="frame" x="0.0" y="0.0" width="273" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -27,10 +27,10 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<secureTextField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5">
<secureTextField verticalHuggingPriority="750" fixedFrame="YES" contentType="password" translatesAutoresizingMaskIntoConstraints="NO" id="5">
<rect key="frame" x="66" y="0.0" width="207" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="8">
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Type a Password" drawsBackground="YES" usesSingleLineMode="YES" id="8">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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=='-')

View File

@ -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);

View File

@ -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;I<NumItems;I++)
{
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++)
eprintf(L"%c",Item[I][J]);

View File

@ -474,6 +474,7 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
switch(ErrCode)
{
case RARX_FATAL:
case RARX_READ:
return ERAR_EREAD;
case RARX_CRC:
return ERAR_BAD_DATA;

View File

@ -178,7 +178,7 @@ void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserD
void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc);
void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc);
void PASCAL RARSetPassword(HANDLE hArcData,char *Password);
int PASCAL RARGetDllVersion(void);
int PASCAL RARGetDllVersion();
#ifdef __cplusplus
}

View File

@ -2,8 +2,8 @@
#include <commctrl.h>
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"
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;I<Size;I+=512)
@ -394,8 +400,18 @@ int File::Read(void *Data,size_t Size)
}
else
{
if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName))
continue;
bool Ignore=false,Retry=false,Quit=false;
if (ReadErrorMode==FREM_ASK && HandleType==FILE_HANDLENORMAL)
{
ErrHandler.AskRepeatRead(FileName,Ignore,Retry,Quit);
if (Retry)
continue;
}
if (Ignore || ReadErrorMode==FREM_TRUNCATE)
{
TruncatedAfterReadError=true;
return 0;
}
ErrHandler.ReadError(FileName);
}
}

View File

@ -46,6 +46,12 @@ enum FILE_MODE_FLAGS {
FMF_UNDEFINED=256
};
enum FILE_READ_ERROR_MODE {
FREM_ASK, // Propose to use the already read part, retry or abort.
FREM_TRUNCATE, // Use the already read part without additional prompt.
FREM_IGNORE // Try to skip unreadable block and read further.
};
class File
{
@ -54,7 +60,7 @@ class File
bool LastWrite;
FILE_HANDLETYPE HandleType;
bool SkipClose;
bool IgnoreReadErrors;
FILE_READ_ERROR_MODE ReadErrorMode;
bool NewFile;
bool AllowDelete;
bool AllowExceptions;
@ -63,6 +69,7 @@ class File
uint CreateMode;
#endif
bool PreserveAtime;
bool TruncatedAfterReadError;
protected:
bool OpenShared; // Set by 'Archive' class.
public:
@ -108,7 +115,7 @@ class File
static bool RemoveCreated();
FileHandle GetHandle() {return hFile;}
void SetHandle(FileHandle Handle) {Close();hFile=Handle;}
void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;}
void SetReadErrorMode(FILE_READ_ERROR_MODE Mode) {ReadErrorMode=Mode;}
int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;}
@ -116,6 +123,7 @@ class File
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;}
#ifdef _UNIX
int GetFD()
{

View File

@ -38,7 +38,7 @@ MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
}
bool CreatePath(const wchar *Path,bool SkipLastName)
bool CreatePath(const wchar *Path,bool SkipLastName,bool Silent)
{
if (Path==NULL || *Path==0)
return false;
@ -73,7 +73,7 @@ bool CreatePath(const wchar *Path,bool SkipLastName)
DirName[s-Path]=0;
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
if (Success)
if (Success && !Silent)
{
mprintf(St(MCreatDir),DirName);
mprintf(L" %s",St(MOk));
@ -474,6 +474,24 @@ bool DelFile(const wchar *Name)
}
bool DelDir(const wchar *Name)
{
#ifdef _WIN_ALL
bool Success=RemoveDirectory(Name)!=0;
if (!Success)
{
wchar LongName[NM];
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
Success=RemoveDirectory(LongName)!=0;
}
return Success;
#else
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
bool Success=rmdir(NameA)==0;
return Success;
#endif
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)

View File

@ -4,7 +4,7 @@
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr);
bool CreatePath(const wchar *Path,bool SkipLastName);
bool CreatePath(const wchar *Path,bool SkipLastName,bool Silent);
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
bool IsRemovable(const wchar *Name);

View File

@ -1,4 +1,4 @@
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
{
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
@ -9,7 +9,7 @@ bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
ErrHandler.SetErrorCode(RARX_CREATE);
return false;
}
CreatePath(NameNew,true);
CreatePath(NameNew,true,Cmd->DisableNames);
#ifdef _WIN_ALL
bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0;

View File

@ -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));

View File

@ -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"

View File

@ -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<int64> 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;

View File

@ -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];

View File

@ -51,7 +51,7 @@ class CryptLoader
};
// We need to call FreeLibrary when RAR is exiting.
CryptLoader GlobalCryptLoader;
static CryptLoader GlobalCryptLoader;
#endif
SecPassword::SecPassword()

View File

@ -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:

View File

@ -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");
}
}

View File

@ -67,3 +67,8 @@ const wchar *uiGetMonthName(int Month)
return L"";
}
#endif
void uiEolAfterMsg()
{
}

View File

@ -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);
}

View File

@ -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++)

View File

@ -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

View File

@ -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)

View File

@ -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,