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"?> <?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> <dependencies>
<deployment identifier="macosx"/> <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"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
@ -13,7 +13,7 @@
</connections> </connections>
</customObject> </customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="1"> <customView id="1">
<rect key="frame" x="0.0" y="0.0" width="273" height="22"/> <rect key="frame" x="0.0" y="0.0" width="273" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -27,10 +27,10 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </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"/> <rect key="frame" x="66" y="0.0" width="207" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <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"/> <font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" 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" #pragma mark "Main"
- (BOOL) extractRarWith:(NSString *) filename { - (BOOL) extractRarWith:(NSString *) filename {
quietUnrar = (__bridge QuietUnrarAppDelegate *)((__bridge void *) self);
char commentBuffer[BUF_LEN]; char commentBuffer[BUF_LEN];
BOOL extractionSuccessful = YES; BOOL extractionSuccessful = YES;
struct RARHeaderData headerData; struct RARHeaderData headerData;
@ -219,7 +220,9 @@ int callbackFunction(UINT message, LPARAM userData, LPARAM parameterOne, LPARAM
NSBundle* bundle = [NSBundle bundleForClass:[self class]]; NSBundle* bundle = [NSBundle bundleForClass:[self class]];
[bundle loadNibNamed:@"PasswordView" owner:self topLevelObjects: nil]; [bundle loadNibNamed:@"PasswordView" owner:self topLevelObjects: nil];
} } else {
[passwordField setStringValue:@""];
}
NSString * password = nil; NSString * password = nil;

View File

@ -51,7 +51,7 @@
* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm. * RAR uses CRC32 function based on Intel Slicing-by-8 algorithm.
Original Intel Slicing-by-8 code is available here: 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 Original Intel Slicing-by-8 code is licensed under BSD License
available at http://www.opensource.org/licenses/bsd-license.html available at http://www.opensource.org/licenses/bsd-license.html

View File

@ -785,7 +785,7 @@ size_t Archive::ReadHeader50()
case HEAD_SERVICE: case HEAD_SERVICE:
{ {
FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead; FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
hd->Reset(); hd->Reset(); // Clear hash, time fields and other stuff like flags.
*(BaseBlock *)hd=ShortBlock; *(BaseBlock *)hd=ShortBlock;
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; 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 // In Windows we may prefer to implement our own command line parser
// to avoid replacing \" by " in standard parser. Such replacing corrupts // to avoid replacing \" by " in standard parser. Such replacing corrupts
// destination paths like "dest path\" in extraction commands. // destination paths like "dest path\" in extraction commands.
// Also our own parser is Unicode compatible.
const wchar *CmdLine=GetCommandLine(); const wchar *CmdLine=GetCommandLine();
wchar *Par; wchar *Par;
@ -288,7 +287,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AppendArcNameToPath=APPENDARCNAME_DESTPATH; AppendArcNameToPath=APPENDARCNAME_DESTPATH;
else else
if (Switch[2]=='1') if (Switch[2]=='1')
AppendArcNameToPath=APPENDARCNAME_OWNDIR; AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR;
else
if (Switch[2]=='2')
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
break; break;
#ifndef SFX_MODULE #ifndef SFX_MODULE
case 'G': case 'G':
@ -436,9 +438,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo)); wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
break; 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; break;
} }
if (wcsicomp(Switch+1,L"NUL")==0) if (wcsicomp(Switch+1,L"NUL")==0)
@ -465,6 +467,12 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'P': case 'P':
DisablePercentage=true; DisablePercentage=true;
break; break;
case 'N':
DisableNames=true;
break;
case 'V':
VerboseOutput=true;
break;
} }
break; break;
} }
@ -539,7 +547,6 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'D': Type=FILTER_DELTA; break; case 'D': Type=FILTER_DELTA; break;
case 'A': Type=FILTER_AUDIO; break; case 'A': Type=FILTER_AUDIO; break;
case 'C': Type=FILTER_RGB; break; case 'C': Type=FILTER_RGB; break;
case 'I': Type=FILTER_ITANIUM; break;
case 'R': Type=FILTER_ARM; break; case 'R': Type=FILTER_ARM; break;
} }
if (*Str=='+' || *Str=='-') if (*Str=='+' || *Str=='-')

View File

@ -11,7 +11,6 @@ enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1};
class CommandData:public RAROptions class CommandData:public RAROptions
{ {
private: private:
void ProcessSwitchesString(const wchar *Str);
void ProcessSwitch(const wchar *Switch); void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch); void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str,bool &Dir); uint GetExclAttr(const wchar *Str,bool &Dir);
@ -34,6 +33,7 @@ class CommandData:public RAROptions
void ParseEnvVar(); void ParseEnvVar();
void ReadConfig(); void ReadConfig();
void PreprocessArg(const wchar *Arg); void PreprocessArg(const wchar *Arg);
void ProcessSwitchesString(const wchar *Str);
void OutTitle(); void OutTitle();
void OutHelp(RAR_EXIT ExitCode); void OutHelp(RAR_EXIT ExitCode);
bool IsSwitch(int Ch); bool IsSwitch(int Ch);

View File

@ -164,7 +164,7 @@ static void GetPasswordText(wchar *Str,uint MaxLength)
SetConsoleMode(hConIn,ConInMode); SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode); SetConsoleMode(hConOut,ConOutMode);
#else #else
char StrA[MAXPASSWORD]; char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
#if defined(_EMX) || defined (__VMS) #if defined(_EMX) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin); fgets(StrA,ASIZE(StrA)-1,stdin);
#elif defined(__sun) #elif defined(__sun)
@ -248,6 +248,12 @@ bool getwstr(wchar *str,size_t n)
ErrHandler.Exit(RARX_USERBREAK); ErrHandler.Exit(RARX_USERBREAK);
} }
StrA[ReadSize]=0; 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); CharToWide(&StrA[0],str,n);
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords. 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++) 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]; int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++) for (int J=0;J<KeyPos;J++)
eprintf(L"%c",Item[I][J]); eprintf(L"%c",Item[I][J]);

View File

@ -474,6 +474,7 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
switch(ErrCode) switch(ErrCode)
{ {
case RARX_FATAL: case RARX_FATAL:
case RARX_READ:
return ERAR_EREAD; return ERAR_EREAD;
case RARX_CRC: case RARX_CRC:
return ERAR_BAD_DATA; 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 RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc);
void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc);
void PASCAL RARSetPassword(HANDLE hArcData,char *Password); void PASCAL RARSetPassword(HANDLE hArcData,char *Password);
int PASCAL RARGetDllVersion(void); int PASCAL RARGetDllVersion();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -2,8 +2,8 @@
#include <commctrl.h> #include <commctrl.h>
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 91, 100, 3470 FILEVERSION 6, 2, 1, 3796
PRODUCTVERSION 5, 91, 100, 3470 PRODUCTVERSION 6, 2, 1, 3796
FILEOS VOS__WINDOWS32 FILEOS VOS__WINDOWS32
FILETYPE VFT_APP FILETYPE VFT_APP
{ {
@ -14,9 +14,9 @@ FILETYPE VFT_APP
VALUE "CompanyName", "Alexander Roshal\0" VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0" VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0" VALUE "FileDescription", "RAR decompression library\0"
VALUE "FileVersion", "5.91.0\0" VALUE "FileVersion", "6.2.1\0"
VALUE "ProductVersion", "5.91.0\0" VALUE "ProductVersion", "6.2.1\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0" VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2021\0"
VALUE "OriginalFilename", "Unrar.dll\0" VALUE "OriginalFilename", "Unrar.dll\0"
} }
} }

View File

@ -15,6 +15,7 @@ void ErrorHandler::Clean()
UserBreak=false; UserBreak=false;
MainExit=false; MainExit=false;
DisableShutdown=false; DisableShutdown=false;
ReadErrIgnoreAll=false;
} }
@ -56,24 +57,34 @@ void ErrorHandler::ReadError(const wchar *FileName)
ReadErrorMsg(FileName); ReadErrorMsg(FileName);
#endif #endif
#if !defined(SILENT) || defined(RARDLL) #if !defined(SILENT) || defined(RARDLL)
Exit(RARX_FATAL); Exit(RARX_READ);
#endif #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 !defined(SILENT) && !defined(SFX_MODULE)
if (!Silent) if (!Silent)
{ {
uiMsg(UIERROR_FILEREAD,UINULL,FileName);
SysErrMsg(); SysErrMsg();
bool Repeat=uiAskRepeatRead(FileName); if (ReadErrIgnoreAll)
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog. Ignore=true;
DisableShutdown=true; else
return Repeat; {
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 #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); uiMsg(UIERROR_FILEREAD,ArcName,FileName);
SysErrMsg(); SysErrMsg();
SetErrorCode(RARX_FATAL); SetErrorCode(RARX_READ);
} }
@ -356,7 +367,7 @@ bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
void ErrorHandler::SysErrMsg() void ErrorHandler::SysErrMsg()
{ {
#if !defined(SFX_MODULE) && !defined(SILENT) #ifndef SILENT
wchar Msg[1024]; wchar Msg[1024];
if (!GetSysErrMsg(Msg,ASIZE(Msg))) if (!GetSysErrMsg(Msg,ASIZE(Msg)))
return; return;

View File

@ -15,9 +15,11 @@ enum RAR_EXIT // RAR exit code.
RARX_CREATE = 9, RARX_CREATE = 9,
RARX_NOFILES = 10, RARX_NOFILES = 10,
RARX_BADPWD = 11, RARX_BADPWD = 11,
RARX_READ = 12,
RARX_USERBREAK = 255 RARX_USERBREAK = 255
}; };
class ErrorHandler class ErrorHandler
{ {
private: private:
@ -26,6 +28,7 @@ class ErrorHandler
bool EnableBreak; bool EnableBreak;
bool Silent; bool Silent;
bool DisableShutdown; // Shutdown is not suitable after last error. bool DisableShutdown; // Shutdown is not suitable after last error.
bool ReadErrIgnoreAll;
public: public:
ErrorHandler(); ErrorHandler();
void Clean(); void Clean();
@ -33,7 +36,7 @@ class ErrorHandler
void OpenError(const wchar *FileName); void OpenError(const wchar *FileName);
void CloseError(const wchar *FileName); void CloseError(const wchar *FileName);
void ReadError(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 WriteError(const wchar *ArcName,const wchar *FileName);
void WriteErrorFAT(const wchar *FileName); void WriteErrorFAT(const wchar *FileName);
bool AskRepeatWrite(const wchar *FileName,bool DiskFull); 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); void SetUnixOwner(Archive &Arc,const wchar *FileName);
#endif #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); 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. Cmd->Password.Clean(); // Clean user entered password before processing next archive.
ReconstructDone=false; // Must be reset here, not in ExtractArchiveInit(). ReconstructDone=false; // Must be reset here, not in ExtractArchiveInit().
UseExactVolName=false; // Must be reset here, not in ExtractArchiveInit().
while (true) while (true)
{ {
EXTRACT_ARC_CODE Code=ExtractArchive(); EXTRACT_ARC_CODE Code=ExtractArchive();
@ -140,7 +141,7 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
return EXTRACT_ARC_NEXT; return EXTRACT_ARC_NEXT;
#ifndef SFX_MODULE #ifndef SFX_MODULE
if (Arc.Volume && !Arc.FirstVolume) if (Arc.Volume && !Arc.FirstVolume && !UseExactVolName)
{ {
wchar FirstVolName[NM]; wchar FirstVolName[NM];
VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),Arc.NewNumbering); VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),Arc.NewNumbering);
@ -158,6 +159,16 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
if (Arc.Volume) 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. // Calculate the total size of all accessible volumes.
// This size is necessary to display the correct total progress indicator. // 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(); Arc.ConvertAttributes();
#if !defined(SFX_MODULE) && !defined(RARDLL) #if !defined(SFX_MODULE) && !defined(RARDLL)
if (Arc.FileHead.SplitBefore && FirstFile) if (Arc.FileHead.SplitBefore && FirstFile && !UseExactVolName)
{ {
wchar CurVolName[NM]; wchar CurVolName[NM];
wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); 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)) if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
{ {
@ -575,7 +586,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
TotalFileCount++; TotalFileCount++;
} }
FileCount++; FileCount++;
if (Command!='I') if (Command!='I' && !Cmd->DisableNames)
if (SkipSolid) if (SkipSolid)
mprintf(St(MExtrSkipFile),ArcFileName); mprintf(St(MExtrSkipFile),ArcFileName);
else else
@ -594,8 +605,10 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
mprintf(St(MExtrFile),DestFileName); mprintf(St(MExtrFile),DestFileName);
break; break;
} }
if (!Cmd->DisablePercentage) if (!Cmd->DisablePercentage && !Cmd->DisableNames)
mprintf(L" "); mprintf(L" ");
if (Cmd->DisableNames)
uiEolAfterMsg(); // Avoid erasing preceding messages by percentage indicator in -idn mode.
DataIO.CurUnpRead=0; DataIO.CurUnpRead=0;
DataIO.CurUnpWrite=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)); ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting));
if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch.
if (Type==FSREDIR_HARDLINK) if (Type==FSREDIR_HARDLINK)
LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting)); LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting));
else else
LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting));
} }
@ -653,7 +666,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
} }
else else
{ {
uiMsg(UIERROR_UNKNOWNEXTRA, Arc.FileName, DestFileName); uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,DestFileName);
LinkSuccess=false; LinkSuccess=false;
} }
@ -711,7 +724,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
{ {
if (ValidCRC) 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 ", mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ",
Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk));
} }
@ -734,7 +747,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
} }
} }
else 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 // If we successfully unpacked a hard link, we wish to set its file
// attributes. Hard link shares file metadata with link target, // 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; Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif #endif
if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,Arc.FileHead.FileAttr)) if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,Arc.FileHead.FileAttr))
{
uiMsg(UIERROR_FILEATTR,Arc.FileName,DestFileName); 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; PrevProcessed=true;
} }
@ -863,6 +888,8 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
wchar LastChar=*PointToLastChar(Cmd->ExtrPath); wchar LastChar=*PointToLastChar(Cmd->ExtrPath);
// We need IsPathDiv check here to correctly handle Unix forward slash // We need IsPathDiv check here to correctly handle Unix forward slash
// in the end of destination path in Windows: rar x arc dest/ // 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: // IsDriveDiv is needed for current drive dir: rar x arc d:
if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar)) if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar))
{ {
@ -874,11 +901,21 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
#ifndef SFX_MODULE #ifndef SFX_MODULE
if (Cmd->AppendArcNameToPath!=APPENDARCNAME_NONE) if (Cmd->AppendArcNameToPath!=APPENDARCNAME_NONE)
{ {
if (Cmd->AppendArcNameToPath==APPENDARCNAME_DESTPATH) switch(Cmd->AppendArcNameToPath)
wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); {
else case APPENDARCNAME_DESTPATH: // To subdir of destination path.
wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); // To archive own dir. wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
SetExt(DestName,NULL,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); AddEndSlash(DestName,DestSize);
} }
#endif #endif
@ -1048,8 +1085,11 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
{ {
if (Cmd->Test) if (Cmd->Test)
{ {
mprintf(St(MExtrTestFile),ArcFileName); if (!Cmd->DisableNames)
mprintf(L" %s",St(MOk)); {
mprintf(St(MExtrTestFile),ArcFileName);
mprintf(L" %s",St(MOk));
}
return; return;
} }
@ -1068,26 +1108,33 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
} }
if (!DirExist) if (!DirExist)
{ {
CreatePath(DestFileName,true); CreatePath(DestFileName,true,Cmd->DisableNames);
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); 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)]; wchar OrigName[ASIZE(DestFileName)];
wcsncpyz(OrigName,DestFileName,ASIZE(OrigName)); wcsncpyz(OrigName,DestFileName,ASIZE(OrigName));
MakeNameUsable(DestFileName,true); MakeNameUsable(DestFileName,true);
CreatePath(DestFileName,true);
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
#ifndef SFX_MODULE #ifndef SFX_MODULE
if (MDCode==MKDIR_SUCCESS) uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName);
uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName);
#endif #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) if (MDCode==MKDIR_SUCCESS)
{ {
mprintf(St(MCreatDir),DestFileName); if (!Cmd->DisableNames)
mprintf(L" %s",St(MOk)); {
mprintf(St(MCreatDir),DestFileName);
mprintf(L" %s",St(MOk));
}
PrevProcessed=true; PrevProcessed=true;
} }
else else
@ -1141,6 +1188,9 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile)
if (!UserReject) if (!UserReject)
{ {
ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName); ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
if (FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName)))
uiMsg(UIERROR_DIRNAMEEXISTS);
#ifdef RARDLL #ifdef RARDLL
Cmd->DllError=ERAR_ECREATE; Cmd->DllError=ERAR_ECREATE;
#endif #endif
@ -1153,7 +1203,7 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile)
MakeNameUsable(DestFileName,true); 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)) if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true))
{ {
#ifndef SFX_MODULE #ifndef SFX_MODULE
@ -1196,3 +1246,104 @@ bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName)
} }
return !WrongVer; 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); void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName);
bool ExtrCreateFile(Archive &Arc,File &CurFile); bool ExtrCreateFile(Archive &Arc,File &CurFile);
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName); 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; CommandData *Cmd;
@ -34,6 +38,7 @@ class CmdExtract
bool FirstFile; bool FirstFile;
bool AllMatchesExact; bool AllMatchesExact;
bool ReconstructDone; bool ReconstructDone;
bool UseExactVolName;
// If any non-zero solid file was successfully unpacked before current. // If any non-zero solid file was successfully unpacked before current.
// If true and if current encrypted file is broken, obviously // 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)) if (NewFile!=NULL && NewFile->Create(Name,FileMode))
return true; return true;
CreatePath(Name,true); CreatePath(Name,true,Cmd->DisableNames);
return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name); return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
} }

View File

@ -8,7 +8,6 @@ File::File()
LastWrite=false; LastWrite=false;
HandleType=FILE_HANDLENORMAL; HandleType=FILE_HANDLENORMAL;
SkipClose=false; SkipClose=false;
IgnoreReadErrors=false;
ErrorType=FILE_SUCCESS; ErrorType=FILE_SUCCESS;
OpenShared=false; OpenShared=false;
AllowDelete=true; AllowDelete=true;
@ -18,6 +17,8 @@ File::File()
NoSequentialRead=false; NoSequentialRead=false;
CreateMode=FMF_UNDEFINED; CreateMode=FMF_UNDEFINED;
#endif #endif
ReadErrorMode=FREM_ASK;
TruncatedAfterReadError=false;
} }
@ -37,6 +38,7 @@ void File::operator = (File &SrcFile)
NewFile=SrcFile.NewFile; NewFile=SrcFile.NewFile;
LastWrite=SrcFile.LastWrite; LastWrite=SrcFile.LastWrite;
HandleType=SrcFile.HandleType; HandleType=SrcFile.HandleType;
TruncatedAfterReadError=SrcFile.TruncatedAfterReadError;
wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName)); wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
SrcFile.SkipClose=true; SrcFile.SkipClose=true;
} }
@ -118,12 +120,12 @@ bool File::Open(const wchar *Name,uint Mode)
#ifdef _OSF_SOURCE #ifdef _OSF_SOURCE
extern "C" int flock(int, int); extern "C" int flock(int, int);
#endif #endif
if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1) if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
{ {
close(handle); close(handle);
return false; return false;
} }
#endif #endif
if (handle==-1) if (handle==-1)
hNewFile=FILE_BAD_HANDLE; hNewFile=FILE_BAD_HANDLE;
@ -146,6 +148,7 @@ bool File::Open(const wchar *Name,uint Mode)
{ {
hFile=hNewFile; hFile=hNewFile;
wcsncpyz(FileName,Name,ASIZE(FileName)); wcsncpyz(FileName,Name,ASIZE(FileName));
TruncatedAfterReadError=false;
} }
return Success; return Success;
} }
@ -369,9 +372,12 @@ bool File::Write(const void *Data,size_t Size)
int File::Read(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. int64 FilePos=0; // Initialized only to suppress some compilers warning.
if (IgnoreReadErrors) if (ReadErrorMode==FREM_IGNORE)
FilePos=Tell(); FilePos=Tell();
int ReadSize; int ReadSize;
while (true) while (true)
@ -381,7 +387,7 @@ int File::Read(void *Data,size_t Size)
{ {
ErrorType=FILE_READERROR; ErrorType=FILE_READERROR;
if (AllowExceptions) if (AllowExceptions)
if (IgnoreReadErrors) if (ReadErrorMode==FREM_IGNORE)
{ {
ReadSize=0; ReadSize=0;
for (size_t I=0;I<Size;I+=512) for (size_t I=0;I<Size;I+=512)
@ -394,8 +400,18 @@ int File::Read(void *Data,size_t Size)
} }
else else
{ {
if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName)) bool Ignore=false,Retry=false,Quit=false;
continue; 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); ErrHandler.ReadError(FileName);
} }
} }

View File

@ -46,6 +46,12 @@ enum FILE_MODE_FLAGS {
FMF_UNDEFINED=256 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 class File
{ {
@ -54,7 +60,7 @@ class File
bool LastWrite; bool LastWrite;
FILE_HANDLETYPE HandleType; FILE_HANDLETYPE HandleType;
bool SkipClose; bool SkipClose;
bool IgnoreReadErrors; FILE_READ_ERROR_MODE ReadErrorMode;
bool NewFile; bool NewFile;
bool AllowDelete; bool AllowDelete;
bool AllowExceptions; bool AllowExceptions;
@ -63,6 +69,7 @@ class File
uint CreateMode; uint CreateMode;
#endif #endif
bool PreserveAtime; bool PreserveAtime;
bool TruncatedAfterReadError;
protected: protected:
bool OpenShared; // Set by 'Archive' class. bool OpenShared; // Set by 'Archive' class.
public: public:
@ -108,7 +115,7 @@ class File
static bool RemoveCreated(); static bool RemoveCreated();
FileHandle GetHandle() {return hFile;} FileHandle GetHandle() {return hFile;}
void SetHandle(FileHandle Handle) {Close();hFile=Handle;} 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); int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;} void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;} void SetExceptions(bool Allow) {AllowExceptions=Allow;}
@ -116,6 +123,7 @@ class File
void RemoveSequentialFlag() {NoSequentialRead=true;} void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif #endif
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;} void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;}
#ifdef _UNIX #ifdef _UNIX
int GetFD() 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) if (Path==NULL || *Path==0)
return false; return false;
@ -73,7 +73,7 @@ bool CreatePath(const wchar *Path,bool SkipLastName)
DirName[s-Path]=0; DirName[s-Path]=0;
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS; Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
if (Success) if (Success && !Silent)
{ {
mprintf(St(MCreatDir),DirName); mprintf(St(MCreatDir),DirName);
mprintf(L" %s",St(MOk)); 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) #if defined(_WIN_ALL) && !defined(SFX_MODULE)

View File

@ -4,7 +4,7 @@
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH}; enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr); 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); void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
bool IsRemovable(const wchar *Name); 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. 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); ErrHandler.SetErrorCode(RARX_CREATE);
return false; return false;
} }
CreatePath(NameNew,true); CreatePath(NameNew,true,Cmd->DisableNames);
#ifdef _WIN_ALL #ifdef _WIN_ALL
bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0; bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0;

View File

@ -1,6 +1,6 @@
#include "rar.hpp" #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 ListSymLink(Archive &Arc);
static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);
static void ListOldSubHeader(Archive &Arc); static void ListOldSubHeader(Archive &Arc);
@ -28,7 +28,7 @@ void ListArchive(CommandData *Cmd)
if (!Arc.WOpen(ArcName)) if (!Arc.WOpen(ArcName))
continue; continue;
bool FileMatched=true; bool FileMatched=true;
while (1) while (true)
{ {
int64 TotalPackSize=0,TotalUnpSize=0; int64 TotalPackSize=0,TotalUnpSize=0;
uint FileCount=0; uint FileCount=0;
@ -69,7 +69,7 @@ void ListArchive(CommandData *Cmd)
wchar VolNumText[50]; wchar VolNumText[50];
*VolNumText=0; *VolNumText=0;
while(Arc.ReadHeader()>0) while (Arc.ReadHeader()>0)
{ {
Wait(); // Allow quit listing with Ctrl+C. Wait(); // Allow quit listing with Ctrl+C.
HEADER_TYPE HeaderType=Arc.GetHeaderType(); 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; FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
if (FileMatched) if (FileMatched)
{ {
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare,Cmd->DisableNames);
if (!Arc.FileHead.SplitBefore) if (!Arc.FileHead.SplitBefore)
{ {
TotalUnpSize+=Arc.FileHead.UnpSize; TotalUnpSize+=Arc.FileHead.UnpSize;
@ -108,7 +108,7 @@ void ListArchive(CommandData *Cmd)
if (FileMatched && !Bare) if (FileMatched && !Bare)
{ {
if (Technical && ShowService) if (Technical && ShowService)
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,Cmd->DisableNames);
} }
break; 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; wchar *Name=hd.FileName;
RARFORMAT Format=Arc.Format; RARFORMAT Format=Arc.Format;
@ -199,21 +220,6 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
return; 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]; wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF) if (hd.UnpSize==INT64NDF)
wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText)); wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));

View File

@ -4,6 +4,7 @@
#define MYesNoAllRenQ L"_Yes_No_All_nEver_Rename_Quit" #define MYesNoAllRenQ L"_Yes_No_All_nEver_Rename_Quit"
#define MContinueQuit L"_Continue_Quit" #define MContinueQuit L"_Continue_Quit"
#define MRetryAbort L"_Retry_Abort" #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 MCopyright L"\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %s %d"
#define MRegTo L"\nRegistered to %s\n" #define MRegTo L"\nRegistered to %s\n"
#define MShare L"\nTrial version Type 'rar -?' for help\n" #define MShare L"\nTrial version Type 'rar -?' for help\n"
@ -54,7 +55,7 @@
#define MCHelpSwm L"\n - Stop switches scanning" #define MCHelpSwm L"\n - Stop switches scanning"
#define MCHelpSwAT L"\n @[+] Disable [enable] file lists" #define MCHelpSwAT L"\n @[+] Disable [enable] file lists"
#define MCHelpSwAC L"\n ac Clear Archive attribute after compression or extraction" #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 MCHelpSwAG L"\n ag[format] Generate archive name using the current date"
#define MCHelpSwAI L"\n ai Ignore file attributes" #define MCHelpSwAI L"\n ai Ignore file attributes"
#define MCHelpSwAO L"\n ao Add files with Archive attribute set" #define MCHelpSwAO L"\n ao Add files with Archive attribute set"
@ -79,7 +80,7 @@
#define MCHelpSwF L"\n f Freshen files" #define MCHelpSwF L"\n f Freshen files"
#define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers" #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 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 MCHelpSwIEML L"\n ieml[addr] Send archive by email"
#define MCHelpSwIERR L"\n ierr Send all messages to stderr" #define MCHelpSwIERR L"\n ierr Send all messages to stderr"
#define MCHelpSwILOG L"\n ilog[name] Log errors to file" #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 MStreamUnknown L"\nWARNING: Unknown format of %s stream data\n"
#define MInvalidName L"\nERROR: Invalid file name %s" #define MInvalidName L"\nERROR: Invalid file name %s"
#define MProcessArc L"\n\nProcessing archive %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 MUnpCannotMerge L"\nWARNING: You need to start extraction from a previous volume to unpack %s"
#define MUnknownOption L"\nERROR: Unknown option: %s" #define MUnknownOption L"\nERROR: Unknown option: %s"
#define MSubHeadCorrupt L"\nERROR: Corrupt data header found, ignored" #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 MRecVolLimit L"\nTotal number of usual and recovery volumes must not exceed %d"
#define MVolumeNumber L"volume %d" #define MVolumeNumber L"volume %d"
#define MCannotDelete L"\nCannot delete %s" #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 MCalcCRC L"\nCalculating the checksum"
#define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB." #define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB."
#define MCalcCRCAllVol L"\nCalculating checksums of all volumes." #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 MDictOutMem L"\nNot enough memory for %d MB compression dictionary, changed to %d MB."
#define MUseSmalllerDict L"\nPlease use a smaller compression dictionary." #define MUseSmalllerDict L"\nPlease use a smaller compression dictionary."
#define MOpenErrAtime L"\nYou may need to remove -tsp switch to open this file." #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 enum APPENDARCNAME_MODE
{ {
APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNSUBDIR,
APPENDARCNAME_OWNDIR
}; };
enum POWER_MODE { enum POWER_MODE {
@ -132,6 +133,7 @@ class RAROptions
bool DisablePercentage; bool DisablePercentage;
bool DisableCopyright; bool DisableCopyright;
bool DisableDone; bool DisableDone;
bool DisableNames;
bool PrintVersion; bool PrintVersion;
int Solid; int Solid;
int SolidCount; int SolidCount;
@ -146,7 +148,7 @@ class RAROptions
Array<int64> NextVolSizes; Array<int64> NextVolSizes;
uint CurVolNum; uint CurVolNum;
bool AllYes; 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; bool DisableSortSolid;
int ArcTime; int ArcTime;
int ConvertNames; 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'. // the temporary buffer instead of constructing the name in 'Pathname'.
wchar OutName[NM]; wchar OutName[NM];
wcsncpyz(OutName,Path,ASIZE(OutName)); 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)); wcsncatz(OutName,Name,ASIZE(OutName));
wcsncpyz(Pathname,OutName,MaxSize); wcsncpyz(Pathname,OutName,MaxSize);
} }
@ -655,7 +657,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,b
} }
if (!FileExist(FirstName)) 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. // check if volume with same name and any other extension is available.
// It can help in case of *.exe or *.sfx first volume. // It can help in case of *.exe or *.sfx first volume.
wchar Mask[NM]; wchar Mask[NM];

View File

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

View File

@ -38,7 +38,8 @@ enum UIMESSAGE_CODE {
UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET, UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET,
UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID,
UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST, UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIERROR_OPENPRESERVEATIME, UIERROR_OPENPRESERVEATIME, UIERROR_READERRTRUNCATED, UIERROR_READERRCOUNT,
UIERROR_DIRNAMEEXISTS,
UIMSG_FIRST, UIMSG_FIRST,
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA, UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA,
@ -92,16 +93,18 @@ bool uiIsGlobalPasswordSet();
enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION}; enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION};
void uiAlarm(UIALARM_TYPE Type); void uiAlarm(UIALARM_TYPE Type);
void uiEolAfterMsg();
bool uiAskNextVolume(wchar *VolName,size_t MaxSize); 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); bool uiAskRepeatWrite(const wchar *FileName,bool DiskFull);
#ifndef SFX_MODULE #ifndef SFX_MODULE
const wchar *uiGetMonthName(int Month); const wchar *uiGetMonthName(int Month);
#endif #endif
class uiMsgStore class uiMsgStore
{ {
private: private:

View File

@ -1,3 +1,5 @@
static bool AnyMessageDisplayed=false; // For console -idn switch.
// Purely user interface function. Gets and returns user input. // Purely user interface function. Gets and returns user input.
UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags) 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() 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) switch(Code)
{ {
case UIERROR_SYSERRMSG: case UIERROR_SYSERRMSG:
@ -121,6 +136,7 @@ void uiMsgStore::Msg()
Log(NULL,St(MErrSeek),Str[0]); Log(NULL,St(MErrSeek),Str[0]);
break; break;
case UIERROR_FILEREAD: case UIERROR_FILEREAD:
mprintf(L"\n");
Log(Str[0],St(MErrRead),Str[1]); Log(Str[0],St(MErrRead),Str[1]);
break; break;
case UIERROR_FILEWRITE: case UIERROR_FILEWRITE:
@ -304,7 +320,15 @@ void uiMsgStore::Msg()
case UIERROR_ULINKEXIST: case UIERROR_ULINKEXIST:
Log(NULL,St(MSymLinkExists),Str[0]); Log(NULL,St(MSymLinkExists),Str[0]);
break; 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 #ifndef SFX_MODULE
case UIMSG_STRING: 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"); eprintf(St(MErrReadInfo));
Log(NULL,St(MErrRead),FileName); int Code=Ask(St(MIgnoreAllRetryQuit));
return Ask(St(MRetryAbort))==1;
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]); return St(MonthID[Month]);
} }
#endif #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""; return L"";
} }
#endif #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); DelFile(LinkName);
char LinkNameA[NM]; char LinkNameA[NM];
WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA)); WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA));
if (symlink(Target,LinkNameA)==-1) // Error. 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) || if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) ||
!IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW))) !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
return false; 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; return false;
} }
@ -101,5 +106,5 @@ bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
if (!Cmd->AbsoluteLinks && (IsFullPath(Target) || if (!Cmd->AbsoluteLinks && (IsFullPath(Target) ||
!IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName))) !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
return false; 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) const wchar_t* wcscasestr(const wchar_t *str, const wchar_t *search)
{ {
for (size_t i=0;str[i]!=0;i++) for (size_t i=0;str[i]!=0;i++)

View File

@ -1,6 +1,6 @@
#define RARVER_MAJOR 5 #define RARVER_MAJOR 6
#define RARVER_MINOR 91 #define RARVER_MINOR 2
#define RARVER_BETA 0 #define RARVER_BETA 1
#define RARVER_DAY 25 #define RARVER_DAY 17
#define RARVER_MONTH 6 #define RARVER_MONTH 5
#define RARVER_YEAR 2020 #define RARVER_YEAR 2021

View File

@ -136,7 +136,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
Arc.ConvertAttributes(); Arc.ConvertAttributes();
Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
} }
if (ShowFileName) if (ShowFileName && !Cmd->DisableNames)
{ {
mprintf(St(MExtrPoints),Arc.FileHead.FileName); mprintf(St(MExtrPoints),Arc.FileHead.FileName);
if (!Cmd->DisablePercentage) 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))) !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
return false; 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. // 'DirTarget' check is important for Unix symlinks to directories.
// Unix symlinks do not have their own 'directory' attribute. // Unix symlinks do not have their own 'directory' attribute.
if (hd->Dir || hd->DirTarget) if (hd->Dir || hd->DirTarget)
{ {
if (!CreateDirectory(Name,NULL)) if (!CreateDirectory(Name,NULL))
{
uiMsg(UIERROR_DIRCREATE,UINULL,Name);
ErrHandler.SetErrorCode(RARX_CREATE);
return false; return false;
}
} }
else else
{ {
HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE) if (hFile == INVALID_HANDLE_VALUE)
{
ErrHandler.CreateErrorMsg(Name);
return false; return false;
}
CloseHandle(hFile); CloseHandle(hFile);
} }
@ -138,7 +154,11 @@ bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd)
OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT| OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT|
FILE_FLAG_BACKUP_SEMANTICS,NULL); FILE_FLAG_BACKUP_SEMANTICS,NULL);
if (hFile==INVALID_HANDLE_VALUE) if (hFile==INVALID_HANDLE_VALUE)
{
ErrHandler.CreateErrorMsg(Name);
ErrHandler.SetErrorCode(RARX_CREATE);
return false; return false;
}
DWORD Returned; DWORD Returned;
if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb, if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb,