Updated packages from Carthage

This commit is contained in:
Robert McGovern 2022-04-18 05:14:03 +01:00
parent d46c9ee32a
commit bc011c0cbf
139 changed files with 2007 additions and 1868 deletions

View File

@ -1,3 +1,3 @@
github "abbeycode/UnrarKit" "2.9"
github "abbeycode/UnrarKit" "2.10"
github "abbeycode/UnzipKit" "1.9"
github "sindresorhus/DockProgress" "v3.2.0"

View File

@ -2,10 +2,10 @@
"commitish" : "v3.2.0",
"Mac" : [
{
"hash" : "13e7fe07ca491fe900ae7c858e66797a66d0a2e1dffde3a2c0b64188b211012e",
"hash" : "19676367de93b3ec3bc61b60e454d565ca1c47fe32c4116ef78955c7ecdfcd1e",
"name" : "DockProgress",
"linking" : "dynamic",
"swiftToolchainVersion" : "5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)"
"swiftToolchainVersion" : "5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)"
}
]
}

6
Carthage/Build/.UnrarKit.version generated vendored
View File

@ -2,7 +2,7 @@
"Mac" : [
{
"name" : "UnrarKit",
"hash" : "0ee8db439c431777277ec76976faa8a1d19ba93d3f6977094746350e942215d3",
"hash" : "e18e69a1e9f0344776a442bf542e0a45be0427977b765897399058bb766e83db",
"linking" : "dynamic"
}
],
@ -12,11 +12,11 @@
"tvOS" : [
],
"commitish" : "2.9",
"commitish" : "2.10",
"iOS" : [
{
"name" : "UnrarKit",
"hash" : "2c752a88c360be277b938f55190d07bc6688ce0452932b4fbf52a12e9bfcf5d0",
"hash" : "308b414f23c29d8599f7b214fb8ef39ea574ac8117b21b6946a7c969b9cf38b4",
"linking" : "dynamic"
}
]

View File

@ -1,6 +1,6 @@
#if 0
#elif defined(__arm64__) && __arm64__
// Generated by Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)
// Generated by Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)
#ifndef DOCKPROGRESS_SWIFT_H
#define DOCKPROGRESS_SWIFT_H
#pragma clang diagnostic push
@ -186,6 +186,13 @@ typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#if !defined(IBSegueAction)
# define IBSegueAction
#endif
#if !defined(SWIFT_EXTERN)
# if defined(__cplusplus)
# define SWIFT_EXTERN extern "C"
# else
# define SWIFT_EXTERN extern
# endif
#endif
#if __has_feature(modules)
#if __has_warning("-Watimport-in-framework-header")
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
@ -221,7 +228,7 @@ typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#endif
#elif defined(__x86_64__) && __x86_64__
// Generated by Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)
// Generated by Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)
#ifndef DOCKPROGRESS_SWIFT_H
#define DOCKPROGRESS_SWIFT_H
#pragma clang diagnostic push
@ -407,6 +414,13 @@ typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#if !defined(IBSegueAction)
# define IBSegueAction
#endif
#if !defined(SWIFT_EXTERN)
# if defined(__cplusplus)
# define SWIFT_EXTERN extern "C"
# else
# define SWIFT_EXTERN extern
# endif
#endif
#if __has_feature(modules)
#if __has_warning("-Watimport-in-framework-header")
#pragma clang diagnostic ignored "-Watimport-in-framework-header"

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>20E241</string>
<string>21F5048e</string>
<key>CFBundleExecutable</key>
<string>DockProgress</string>
<key>CFBundleIdentifier</key>
@ -23,19 +23,19 @@
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>12E262</string>
<string>13E500a</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>11.3</string>
<string>12.3</string>
<key>DTSDKBuild</key>
<string>20E214</string>
<string>21E226</string>
<key>DTSDKName</key>
<string>macosx11.3</string>
<string>macosx12.3</string>
<key>DTXcode</key>
<string>1250</string>
<string>1331</string>
<key>DTXcodeBuild</key>
<string>12E262</string>
<string>13E500a</string>
<key>LSMinimumSystemVersion</key>
<string>10.12</string>
</dict>

View File

@ -13,8 +13,8 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>2.9</string>
<string>2.10-beta8</string>
<key>CFBundleVersion</key>
<string>2.9</string>
<string>2.10-beta8</string>
</dict>
</plist>

View File

@ -6,14 +6,14 @@
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#import "UnrarKitMacros.h"
#import <UnrarKit/UnrarKitMacros.h>
RarosHppIgnore
#import "raros.hpp"
#import <UnrarKit/raros.hpp>
#pragma clang diagnostic pop
DllHppIgnore
#import "dll.hpp"
#import <UnrarKit/dll.hpp>
#pragma clang diagnostic pop
@class URKFileInfo;
@ -25,7 +25,7 @@ DllHppIgnore
typedef NS_ENUM(NSInteger, URKErrorCode) {
/**
* The archive's header is empty
* The last file of the archive has been read
*/
URKErrorCodeEndOfArchive = ERAR_END_ARCHIVE,
@ -35,7 +35,7 @@ typedef NS_ENUM(NSInteger, URKErrorCode) {
URKErrorCodeNoMemory = ERAR_NO_MEMORY,
/**
* The header is broken
* The header's CRC doesn't match the decompressed data's CRC
*/
URKErrorCodeBadData = ERAR_BAD_DATA,
@ -173,6 +173,17 @@ extern NSString *URKErrorDomain;
*/
@property(nullable, strong) NSProgress *progress;
/**
* When performing operations on a RAR archive, the contents of compressed files are checked
* against the record of what they were when the archive was created. If there's a mismatch,
* either the metadata (header) or archive contents have become corrupted. You can defeat this check by
* setting this property to YES, though there may be security implications to turning the
* warnings off, as it may indicate a maliciously crafted archive intended to exploit a vulnerability.
*
* It's recommended to leave the decision of how to treat archives with mismatched CRCs to the user
*/
@property (assign) BOOL ignoreCRCMismatches;
/**
* **DEPRECATED:** Creates and returns an archive at the given path
@ -475,15 +486,34 @@ extern NSString *URKErrorDomain;
- (BOOL)validatePassword;
/**
Extract each file in the archive, checking whether the data matches the CRC checksum
stored at the time it was written
Iterate through the archive, checking for any errors, including CRC mismatches between
the archived file and its header
@return YES if the data is all correct, false if any check failed
@return YES if the data is all correct, false if any check failed (_even if ignoreCRCMismatches is YES_)
*/
- (BOOL)checkDataIntegrity;
/**
Extract a particular file, to determine if its data matches the CRC
Iterate through the archive, checking for any errors, including CRC mismatches between
the archived file and its header. If any file's CRC doesn't match, run the given block
to allow the API consumer to decide whether to ignore mismatches. NOTE: This may be a
security risk. The block is intended to prompt the user, which is why it's forced onto
the main thread, rather than making a design-time decision
@param ignoreCRCMismatches This block, called on the main thread, allows a consuming API to
prompt the user whether or not he'd like to ignore CRC mismatches.
This block is called the first time a CRC mismatch is detected, if
at all. It won't be called if all CRCs match. If this returns YES,
then all further CRC mismatches will be ignored for the
archive instance
@return YES if the data is all correct and/or the block returns YES; returns false if
any check failed and the given block also returns NO
*/
- (BOOL)checkDataIntegrityIgnoringCRCMismatches:(BOOL(^)(void))ignoreCRCMismatches;
/**
Check a particular file, to determine if its data matches the CRC
checksum stored at the time it written
@param filePath The file in the archive to check

View File

@ -4,14 +4,14 @@
//
#import <Foundation/Foundation.h>
#import "UnrarKitMacros.h"
#import <UnrarKit/UnrarKitMacros.h>
RarosHppIgnore
#import "raros.hpp"
#import <UnrarKit/raros.hpp>
#pragma clang diagnostic pop
DllHppIgnore
#import "dll.hpp"
#import <UnrarKit/dll.hpp>
#pragma clang diagnostic pop
/* See http://www.forensicswiki.org/wiki/RAR and

View File

@ -15,5 +15,5 @@ FOUNDATION_EXPORT double UnrarKitVersionNumber;
FOUNDATION_EXPORT const unsigned char UnrarKitVersionString[];
#import "URKArchive.h"
#import "URKFileInfo.h"
#import <UnrarKit/URKArchive.h>
#import <UnrarKit/URKFileInfo.h>

View File

@ -60,7 +60,7 @@ __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \
#import <os/activity.h>
// Called from +[UnrarKit initialize] and +[URKArchiveTestCase setUp]
extern os_log_t unrarkit_log; // Declared in URKArchive.m
extern os_log_t unrarkit_log; // Declared in URKArchive.mm
extern BOOL unrarkitIsAtLeast10_13SDK; // Declared in URKArchive.m
#define URKLogInit() \
unrarkit_log = os_log_create("com.abbey-code.UnrarKit", "General"); \

View File

@ -1,7 +1,7 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#pragma pack(push, 1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
@ -135,6 +135,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
#define ROADOF_KEEPBROKEN 0x0001
struct RAROpenArchiveDataEx
{
char *ArcName;
@ -148,7 +150,9 @@ struct RAROpenArchiveDataEx
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int Reserved[28];
unsigned int OpFlags;
wchar_t *CmtBufW;
unsigned int Reserved[25];
};
enum UNRARCALLBACK_MESSAGES {
@ -180,6 +184,6 @@ int PASCAL RARGetDllVersion();
}
#endif
#pragma pack()
#pragma pack(pop)
#endif

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>17D47</string>
<string>19H2</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.9</string>
<string>2.10-beta8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
@ -25,20 +25,24 @@
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>2.9</string>
<string>2.10-beta8</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>9E145</string>
<string>12A7300</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<string>10.15.6</string>
<key>DTSDKBuild</key>
<string>17E189</string>
<string>19G68</string>
<key>DTSDKName</key>
<string>macosx10.13</string>
<string>macosx10.15</string>
<key>DTXcode</key>
<string>0930</string>
<string>1201</string>
<key>DTXcodeBuild</key>
<string>9E145</string>
<string>12A7300</string>
<key>LSMinimumSystemVersion</key>
<string>10.15</string>
</dict>
</plist>

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>17D47</string>
<string>19H2</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>2.9</string>
<string>2.10-beta8</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
@ -23,21 +23,25 @@
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>2.9</string>
<string>2.10-beta8</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>9E145</string>
<string>12A7300</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<string>10.15.6</string>
<key>DTSDKBuild</key>
<string>17E189</string>
<string>19G68</string>
<key>DTSDKName</key>
<string>macosx10.13</string>
<string>macosx10.15</string>
<key>DTXcode</key>
<string>0930</string>
<string>1201</string>
<key>DTXcodeBuild</key>
<string>9E145</string>
<string>12A7300</string>
<key>LSMinimumSystemVersion</key>
<string>10.15</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2017 Abbey Code. All rights reserved.</string>
</dict>

Binary file not shown.

View File

@ -13,8 +13,8 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>2.9</string>
<string>2.10-beta8</string>
<key>CFBundleVersion</key>
<string>2.9</string>
<string>2.10-beta8</string>
</dict>
</plist>

View File

@ -6,14 +6,14 @@
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#import "UnrarKitMacros.h"
#import <UnrarKit/UnrarKitMacros.h>
RarosHppIgnore
#import "raros.hpp"
#import <UnrarKit/raros.hpp>
#pragma clang diagnostic pop
DllHppIgnore
#import "dll.hpp"
#import <UnrarKit/dll.hpp>
#pragma clang diagnostic pop
@class URKFileInfo;
@ -25,7 +25,7 @@ DllHppIgnore
typedef NS_ENUM(NSInteger, URKErrorCode) {
/**
* The archive's header is empty
* The last file of the archive has been read
*/
URKErrorCodeEndOfArchive = ERAR_END_ARCHIVE,
@ -35,7 +35,7 @@ typedef NS_ENUM(NSInteger, URKErrorCode) {
URKErrorCodeNoMemory = ERAR_NO_MEMORY,
/**
* The header is broken
* The header's CRC doesn't match the decompressed data's CRC
*/
URKErrorCodeBadData = ERAR_BAD_DATA,
@ -173,6 +173,17 @@ extern NSString *URKErrorDomain;
*/
@property(nullable, strong) NSProgress *progress;
/**
* When performing operations on a RAR archive, the contents of compressed files are checked
* against the record of what they were when the archive was created. If there's a mismatch,
* either the metadata (header) or archive contents have become corrupted. You can defeat this check by
* setting this property to YES, though there may be security implications to turning the
* warnings off, as it may indicate a maliciously crafted archive intended to exploit a vulnerability.
*
* It's recommended to leave the decision of how to treat archives with mismatched CRCs to the user
*/
@property (assign) BOOL ignoreCRCMismatches;
/**
* **DEPRECATED:** Creates and returns an archive at the given path
@ -475,15 +486,34 @@ extern NSString *URKErrorDomain;
- (BOOL)validatePassword;
/**
Extract each file in the archive, checking whether the data matches the CRC checksum
stored at the time it was written
Iterate through the archive, checking for any errors, including CRC mismatches between
the archived file and its header
@return YES if the data is all correct, false if any check failed
@return YES if the data is all correct, false if any check failed (_even if ignoreCRCMismatches is YES_)
*/
- (BOOL)checkDataIntegrity;
/**
Extract a particular file, to determine if its data matches the CRC
Iterate through the archive, checking for any errors, including CRC mismatches between
the archived file and its header. If any file's CRC doesn't match, run the given block
to allow the API consumer to decide whether to ignore mismatches. NOTE: This may be a
security risk. The block is intended to prompt the user, which is why it's forced onto
the main thread, rather than making a design-time decision
@param ignoreCRCMismatches This block, called on the main thread, allows a consuming API to
prompt the user whether or not he'd like to ignore CRC mismatches.
This block is called the first time a CRC mismatch is detected, if
at all. It won't be called if all CRCs match. If this returns YES,
then all further CRC mismatches will be ignored for the
archive instance
@return YES if the data is all correct and/or the block returns YES; returns false if
any check failed and the given block also returns NO
*/
- (BOOL)checkDataIntegrityIgnoringCRCMismatches:(BOOL(^)(void))ignoreCRCMismatches;
/**
Check a particular file, to determine if its data matches the CRC
checksum stored at the time it written
@param filePath The file in the archive to check

View File

@ -4,14 +4,14 @@
//
#import <Foundation/Foundation.h>
#import "UnrarKitMacros.h"
#import <UnrarKit/UnrarKitMacros.h>
RarosHppIgnore
#import "raros.hpp"
#import <UnrarKit/raros.hpp>
#pragma clang diagnostic pop
DllHppIgnore
#import "dll.hpp"
#import <UnrarKit/dll.hpp>
#pragma clang diagnostic pop
/* See http://www.forensicswiki.org/wiki/RAR and

View File

@ -15,5 +15,5 @@ FOUNDATION_EXPORT double UnrarKitVersionNumber;
FOUNDATION_EXPORT const unsigned char UnrarKitVersionString[];
#import "URKArchive.h"
#import "URKFileInfo.h"
#import <UnrarKit/URKArchive.h>
#import <UnrarKit/URKFileInfo.h>

View File

@ -60,7 +60,7 @@ __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \
#import <os/activity.h>
// Called from +[UnrarKit initialize] and +[URKArchiveTestCase setUp]
extern os_log_t unrarkit_log; // Declared in URKArchive.m
extern os_log_t unrarkit_log; // Declared in URKArchive.mm
extern BOOL unrarkitIsAtLeast10_13SDK; // Declared in URKArchive.m
#define URKLogInit() \
unrarkit_log = os_log_create("com.abbey-code.UnrarKit", "General"); \

View File

@ -1,7 +1,7 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#pragma pack(push, 1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
@ -135,6 +135,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
#define ROADOF_KEEPBROKEN 0x0001
struct RAROpenArchiveDataEx
{
char *ArcName;
@ -148,7 +150,9 @@ struct RAROpenArchiveDataEx
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int Reserved[28];
unsigned int OpFlags;
wchar_t *CmtBufW;
unsigned int Reserved[25];
};
enum UNRARCALLBACK_MESSAGES {
@ -180,6 +184,6 @@ int PASCAL RARGetDllVersion();
}
#endif
#pragma pack()
#pragma pack(pop)
#endif

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,12 @@
language: objective-c
osx_image: xcode9.3
osx_image: xcode12
branches:
except:
- circle-ci
before_script:
- pod --version
# Make log level less verbose. Temporarily undo if more info is needed
- sudo log config --mode "level:default"
@ -15,7 +20,7 @@ matrix:
- stage: Test
env: Name=iOS
# The CLANG arguments and find command fail the build on analyzer errors
script: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarKit -destination 'platform=iOS Simulator,name=iPhone 7,OS=latest' -configuration Release analyze test CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]]
script: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarKit -destination 'platform=iOS Simulator,name=iPhone 11,OS=latest' -configuration Release analyze test CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]]
- stage: Test
env: Name=ExampleAppBuild
@ -32,5 +37,4 @@ matrix:
- stage: Release
if: tag IS present
before_install: brew upgrade python # Needs Python 3
script: ./Scripts/push-output.sh

View File

@ -1,5 +1,14 @@
# UnrarKit CHANGELOG
## 2.10
* Added method (`checkDataIntegrityIgnoringCRCMismatches:`) to prompt user for a decision on whether or not to ignore CRC mismatches (Issue #82)
* Fixed crash in `+pathIsARAR:` when a file is unreadable (Issue #85)
* Fixed crash in `-_unrarOpenFile:inMode:withPassword:error:` (PR #97)
* Updated to v5.9.4 of UnRAR library
* Xcode 12 compatibility in Carthage
## 2.9
* Added support for `NSProgress` and `NSProgressReporting` in all extraction and iteration methods (Issue #34)

View File

@ -6,14 +6,14 @@
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#import "UnrarKitMacros.h"
#import <UnrarKit/UnrarKitMacros.h>
RarosHppIgnore
#import "raros.hpp"
#import <UnrarKit/raros.hpp>
#pragma clang diagnostic pop
DllHppIgnore
#import "dll.hpp"
#import <UnrarKit/dll.hpp>
#pragma clang diagnostic pop
@class URKFileInfo;
@ -25,7 +25,7 @@ DllHppIgnore
typedef NS_ENUM(NSInteger, URKErrorCode) {
/**
* The archive's header is empty
* The last file of the archive has been read
*/
URKErrorCodeEndOfArchive = ERAR_END_ARCHIVE,
@ -35,7 +35,7 @@ typedef NS_ENUM(NSInteger, URKErrorCode) {
URKErrorCodeNoMemory = ERAR_NO_MEMORY,
/**
* The header is broken
* The header's CRC doesn't match the decompressed data's CRC
*/
URKErrorCodeBadData = ERAR_BAD_DATA,
@ -173,6 +173,17 @@ extern NSString *URKErrorDomain;
*/
@property(nullable, strong) NSProgress *progress;
/**
* When performing operations on a RAR archive, the contents of compressed files are checked
* against the record of what they were when the archive was created. If there's a mismatch,
* either the metadata (header) or archive contents have become corrupted. You can defeat this check by
* setting this property to YES, though there may be security implications to turning the
* warnings off, as it may indicate a maliciously crafted archive intended to exploit a vulnerability.
*
* It's recommended to leave the decision of how to treat archives with mismatched CRCs to the user
*/
@property (assign) BOOL ignoreCRCMismatches;
/**
* **DEPRECATED:** Creates and returns an archive at the given path
@ -475,15 +486,34 @@ extern NSString *URKErrorDomain;
- (BOOL)validatePassword;
/**
Extract each file in the archive, checking whether the data matches the CRC checksum
stored at the time it was written
Iterate through the archive, checking for any errors, including CRC mismatches between
the archived file and its header
@return YES if the data is all correct, false if any check failed
@return YES if the data is all correct, false if any check failed (_even if ignoreCRCMismatches is YES_)
*/
- (BOOL)checkDataIntegrity;
/**
Extract a particular file, to determine if its data matches the CRC
Iterate through the archive, checking for any errors, including CRC mismatches between
the archived file and its header. If any file's CRC doesn't match, run the given block
to allow the API consumer to decide whether to ignore mismatches. NOTE: This may be a
security risk. The block is intended to prompt the user, which is why it's forced onto
the main thread, rather than making a design-time decision
@param ignoreCRCMismatches This block, called on the main thread, allows a consuming API to
prompt the user whether or not he'd like to ignore CRC mismatches.
This block is called the first time a CRC mismatch is detected, if
at all. It won't be called if all CRCs match. If this returns YES,
then all further CRC mismatches will be ignored for the
archive instance
@return YES if the data is all correct and/or the block returns YES; returns false if
any check failed and the given block also returns NO
*/
- (BOOL)checkDataIntegrityIgnoringCRCMismatches:(BOOL(^)(void))ignoreCRCMismatches;
/**
Check a particular file, to determine if its data matches the CRC
checksum stored at the time it written
@param filePath The file in the archive to check

View File

@ -28,6 +28,11 @@ BOOL unrarkitIsAtLeast10_13SDK;
static NSBundle *_resources = nil;
typedef enum : NSUInteger {
URKReadHeaderLoopActionStopReading,
URKReadHeaderLoopActionContinueReading,
} URKReadHeaderLoopAction;
@interface URKArchive ()
@ -46,6 +51,9 @@ NS_DESIGNATED_INITIALIZER
@property (strong) NSObject *threadLock;
@property (copy) NSString *lastArchivePath;
@property (copy) NSString *lastFilepath;
@end
@ -161,6 +169,10 @@ NS_DESIGNATED_INITIALIZER
_password = password;
_threadLock = [[NSObject alloc] init];
_lastArchivePath = nil;
_lastFilepath = nil;
_ignoreCRCMismatches = NO;
if (bookmarkError) {
URKLogFault("Error creating bookmark to RAR archive: %{public}@", bookmarkError);
@ -336,6 +348,9 @@ NS_DESIGNATED_INITIALIZER
URKLogDebug("File is not a RAR. Unknown contents in 7th and 8th bytes (%02X %02X)", dataBytes[6], dataBytes[7]);
}
@catch (NSException *e) {
URKLogError("Error checking if %{public}@ is a RAR archive: %{public}@", filePath, e);
}
@finally {
[handle closeFile];
}
@ -508,8 +523,7 @@ NS_DESIGNATED_INITIALIZER
URKLogInfo("Extracting to %{public}@", filePath);
URKLogDebug("Reading through RAR header looking for files...");
while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == ERAR_SUCCESS) {
fileInfo = [URKFileInfo fileInfo:welf.header];
while ([welf readHeader:&RHCode info:&fileInfo] == URKReadHeaderLoopActionContinueReading) {
URKLogDebug("Extracting %{public}@ (%{iec-bytes}lld)", fileInfo.filename, fileInfo.uncompressedSize);
NSURL *extractedURL = [[NSURL fileURLWithPath:filePath] URLByAppendingPathComponent:fileInfo.filename];
[progress setUserInfoObject:extractedURL
@ -517,7 +531,7 @@ NS_DESIGNATED_INITIALIZER
[progress setUserInfoObject:fileInfo
forKey:URKProgressInfoKeyFileInfoExtracting];
if ([self headerContainsErrors:innerError]) {
if ([welf headerContainsErrors:innerError]) {
URKLogError("Header contains an error")
result = NO;
return;
@ -525,7 +539,7 @@ NS_DESIGNATED_INITIALIZER
if (progress.isCancelled) {
NSString *errorName = nil;
[self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
[welf assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
URKLogInfo("Halted file extraction due to user cancellation: %{public}@", errorName);
result = NO;
return;
@ -537,7 +551,7 @@ NS_DESIGNATED_INITIALIZER
encoding:NSUTF8StringEncoding];
if (!utf8ConversionSucceeded) {
NSString *errorName = nil;
[self assignError:innerError code:URKErrorCodeStringConversion errorName:&errorName];
[welf assignError:innerError code:URKErrorCodeStringConversion errorName:&errorName];
URKLogError("Error converting file to UTF-8 (buffer too short?)");
result = NO;
return;
@ -550,12 +564,13 @@ NS_DESIGNATED_INITIALIZER
};
RARSetCallback(welf.rarFile, AllowCancellationCallbackProc, (long)shouldCancelBlock);
if ((PFCode = RARProcessFile(welf.rarFile, RAR_EXTRACT, cFilePath, NULL)) != 0) {
PFCode = RARProcessFile(welf.rarFile, RAR_EXTRACT, cFilePath, NULL);
if (![welf didReturnSuccessfully:PFCode]) {
RARSetCallback(welf.rarFile, NULL, NULL);
NSString *errorName = nil;
NSInteger errorCode = progress.isCancelled ? URKErrorCodeUserCancelled : PFCode;
[self assignError:innerError code:errorCode errorName:&errorName];
[welf assignError:innerError code:errorCode errorName:&errorName];
URKLogError("Error extracting file: %{public}@ (%ld)", errorName, (long)errorCode);
result = NO;
return;
@ -583,9 +598,9 @@ NS_DESIGNATED_INITIALIZER
RARSetCallback(welf.rarFile, NULL, NULL);
if (RHCode != ERAR_SUCCESS && RHCode != ERAR_END_ARCHIVE) {
if (![welf didReturnSuccessfully:RHCode]) {
NSString *errorName = nil;
[self assignError:innerError code:RHCode errorName:&errorName];
[welf assignError:innerError code:RHCode errorName:&errorName];
URKLogError("Error reading file header: %{public}@ (%d)", errorName, RHCode);
result = NO;
}
@ -642,14 +657,12 @@ NS_DESIGNATED_INITIALIZER
URKFileInfo *fileInfo;
URKLogDebug("Reading through RAR header looking for files...");
while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == ERAR_SUCCESS) {
if ([self headerContainsErrors:innerError]) {
while ([welf readHeader:&RHCode info:&fileInfo] == URKReadHeaderLoopActionContinueReading) {
if ([welf headerContainsErrors:innerError]) {
URKLogError("Header contains an error")
return;
}
fileInfo = [URKFileInfo fileInfo:welf.header];
if ([fileInfo.filename isEqualToString:filePath]) {
URKLogDebug("Extracting %{public}@", fileInfo.filename);
break;
@ -658,7 +671,7 @@ NS_DESIGNATED_INITIALIZER
URKLogDebug("Skipping %{public}@", fileInfo.filename);
if ((PFCode = RARProcessFileW(welf.rarFile, RAR_SKIP, NULL, NULL)) != 0) {
NSString *errorName = nil;
[self assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Error skipping file: %{public}@ (%d)", errorName, PFCode);
return;
}
@ -667,7 +680,7 @@ NS_DESIGNATED_INITIALIZER
if (RHCode != ERAR_SUCCESS) {
NSString *errorName = nil;
[self assignError:innerError code:RHCode errorName:&errorName];
[welf assignError:innerError code:RHCode errorName:&errorName];
URKLogError("Error reading file header: %{public}@ (%d)", errorName, RHCode);
return;
}
@ -715,14 +728,14 @@ NS_DESIGNATED_INITIALIZER
if (progress.isCancelled) {
NSString *errorName = nil;
[self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
[welf assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
URKLogInfo("Returning nil data from extraction due to user cancellation: %{public}@", errorName);
return;
}
if (PFCode != 0) {
if (![welf didReturnSuccessfully:PFCode]) {
NSString *errorName = nil;
[self assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Error extracting file data: %{public}@ (%d)", errorName, PFCode);
return;
}
@ -813,27 +826,36 @@ NS_DESIGNATED_INITIALIZER
BOOL stop = NO;
NSProgress *progress = [self beginProgressOperation:totalSize.longLongValue];
NSProgress *progress = [welf beginProgressOperation:totalSize.longLongValue];
URKLogDebug("Reading through RAR header looking for files...");
while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == 0) {
URKFileInfo *info = nil;
while ([welf readHeader:&RHCode info:&info] == URKReadHeaderLoopActionContinueReading) {
if (stop || progress.isCancelled) {
URKLogDebug("Action dictated an early stop");
return;
}
if ([self headerContainsErrors:innerError]) {
if ([welf headerContainsErrors:innerError]) {
URKLogError("Header contains an error")
return;
}
URKFileInfo *info = [URKFileInfo fileInfo:welf.header];
URKLogDebug("Performing action on %{public}@", info.filename);
// Empty file, or a directory
if (info.uncompressedSize == 0) {
if (info.isDirectory || info.uncompressedSize == 0) {
URKLogDebug("%{public}@ is an empty file, or a directory", info.filename);
action(info, [NSData data], &stop);
PFCode = RARProcessFile(welf.rarFile, RAR_SKIP, NULL, NULL);
if (PFCode != 0) {
NSString *errorName = nil;
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Error skipping directory: %{public}@ (%d)", errorName, PFCode);
return;
}
continue;
}
@ -845,9 +867,9 @@ NS_DESIGNATED_INITIALIZER
URKLogInfo("Processing file...");
PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL);
if (PFCode != 0) {
if (![welf didReturnSuccessfully:PFCode]) {
NSString *errorName = nil;
[self assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Error processing file: %{public}@ (%d)", errorName, PFCode);
return;
}
@ -861,14 +883,14 @@ NS_DESIGNATED_INITIALIZER
if (progress.isCancelled) {
NSString *errorName = nil;
[self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
[welf assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
URKLogInfo("Returning NO from performOnData:error: due to user cancellation: %{public}@", errorName);
return;
}
if (RHCode != ERAR_SUCCESS && RHCode != ERAR_END_ARCHIVE) {
if (![welf didReturnSuccessfully:RHCode]) {
NSString *errorName = nil;
[self assignError:innerError code:RHCode errorName:&errorName];
[welf assignError:innerError code:RHCode errorName:&errorName];
URKLogError("Error reading file header: %{public}@ (%d)", errorName, RHCode);
return;
}
@ -897,24 +919,22 @@ NS_DESIGNATED_INITIALIZER
URKLogInfo("Looping through files, looking for %{public}@...", filePath);
while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == ERAR_SUCCESS) {
if ([self headerContainsErrors:innerError]) {
while ([welf readHeader:&RHCode info:&fileInfo] == URKReadHeaderLoopActionContinueReading) {
if ([welf headerContainsErrors:innerError]) {
URKLogDebug("Header contains error")
return;
}
URKLogDebug("Getting file info from header");
fileInfo = [URKFileInfo fileInfo:welf.header];
if ([fileInfo.filename isEqualToString:filePath]) {
URKLogDebug("Found desired file");
break;
}
else {
URKLogDebug("Skipping file...");
if ((PFCode = RARProcessFile(welf.rarFile, RAR_SKIP, NULL, NULL)) != 0) {
PFCode = RARProcessFile(welf.rarFile, RAR_SKIP, NULL, NULL);
if (![welf didReturnSuccessfully:PFCode]) {
NSString *errorName = nil;
[self assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Failed to skip file: %{public}@ (%d)", errorName, PFCode);
return;
}
@ -924,9 +944,9 @@ NS_DESIGNATED_INITIALIZER
long long totalBytes = fileInfo.uncompressedSize;
progress.totalUnitCount = totalBytes;
if (RHCode != ERAR_SUCCESS) {
if (![welf didReturnSuccessfully:RHCode]) {
NSString *errorName = nil;
[self assignError:innerError code:RHCode errorName:&errorName];
[welf assignError:innerError code:RHCode errorName:&errorName];
URKLogError("Header read yielded error: %{public}@ (%d)", errorName, RHCode);
return;
}
@ -965,14 +985,14 @@ NS_DESIGNATED_INITIALIZER
if (progress.isCancelled) {
NSString *errorName = nil;
[self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
[welf assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName];
URKLogError("Buffered data extraction has been cancelled: %{public}@", errorName);
return;
}
if (PFCode != 0) {
if (![welf didReturnSuccessfully:PFCode]) {
NSString *errorName = nil;
[self assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Error processing file: %{public}@ (%d)", errorName, PFCode);
}
} inMode:RAR_OM_EXTRACT error:&actionError];
@ -1049,7 +1069,7 @@ NS_DESIGNATED_INITIALIZER
int RHCode = RARReadHeaderEx(welf.rarFile, welf.header);
int PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL);
if ([self headerContainsErrors:innerError]) {
if ([welf headerContainsErrors:innerError]) {
if (error.code == ERAR_MISSING_PASSWORD) {
URKLogDebug("Password invalidated by header");
passwordIsGood = NO;
@ -1062,13 +1082,18 @@ NS_DESIGNATED_INITIALIZER
}
if (RHCode == ERAR_MISSING_PASSWORD || PFCode == ERAR_MISSING_PASSWORD
|| RHCode == ERAR_BAD_DATA || PFCode == ERAR_BAD_DATA
|| RHCode == ERAR_BAD_PASSWORD || PFCode == ERAR_BAD_PASSWORD)
{
URKLogDebug("Missing/bad password indicated by RHCode (%d) or PFCode (%d)", RHCode, PFCode);
passwordIsGood = NO;
return;
}
if ([welf hasBadCRC:RHCode] || [welf hasBadCRC:PFCode]) {
URKLogDebug("Missing/bad password indicated via CRC mismatch by RHCode (%d) or PFCode (%d)", RHCode, PFCode);
passwordIsGood = NO;
return;
}
} inMode:RAR_OM_EXTRACT error:&error];
if (!success) {
@ -1084,47 +1109,96 @@ NS_DESIGNATED_INITIALIZER
return [self checkDataIntegrityOfFile:(NSString *_Nonnull)nil];
}
- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath
- (BOOL)checkDataIntegrityIgnoringCRCMismatches:(BOOL(^)())ignoreCRCMismatches
{
int rhCode = [self dataIntegrityCodeOfFile:nil];
if (rhCode == ERAR_SUCCESS) {
return YES;
}
if (rhCode == ERAR_BAD_DATA) {
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
__block BOOL blockResult;
if ([NSOperationQueue currentQueue] == mainQueue) {
blockResult = ignoreCRCMismatches();
} else {
[mainQueue addOperations:@[[NSBlockOperation blockOperationWithBlock:^{
blockResult = ignoreCRCMismatches();
}]]
waitUntilFinished:YES];
}
self.ignoreCRCMismatches = blockResult;
return self.ignoreCRCMismatches;
}
return NO;
}
- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath {
return [self dataIntegrityCodeOfFile:filePath] == ERAR_SUCCESS;
}
- (int)dataIntegrityCodeOfFile:(NSString *)filePath
{
URKCreateActivity("Checking Data Integrity");
URKLogInfo("Checking integrity of %{public}@", filePath ? filePath : @"whole archive");
__block BOOL corruptDataFound = YES;
__block int RHCode = 0;
__block int PFCode = 0;
__weak URKArchive *welf = self;
NSError *performOnFilesError = nil;
[self performOnFilesInArchive:^(URKFileInfo *fileInfo, BOOL *stop) {
BOOL wasSuccessful = [self performActionWithArchiveOpen:^(NSError **innerError) {
URKCreateActivity("Iterating through each file");
corruptDataFound = NO; // Set inside here so invalid archives are marked as corrupt
if (filePath && ![fileInfo.filename isEqualToString:filePath]) return;
while (true) {
URKFileInfo *fileInfo = nil;
[welf readHeader:&RHCode info:&fileInfo];
welf.lastFilepath = nil;
welf.lastArchivePath = nil;
URKLogDebug("Extracting '%{public}@ to check its CRC...", fileInfo.filename);
NSError *extractError = nil;
NSData *fileData = [self extractData:fileInfo error:&extractError];
if (!fileData) {
URKLogError("Error extracting %{public}@: %{public}@", fileInfo.filename, extractError);
*stop = YES;
return;
if (RHCode == ERAR_END_ARCHIVE) {
RHCode = ERAR_SUCCESS;
break;
}
uLong expectedCRC = fileInfo.CRC;
uLong actualCRC = crc32((uLong)0, (const Bytef*)fileData.bytes, (uint)fileData.length);
URKLogDebug("Checking integrity of %{public}@. Expected CRC: %010lu vs. Actual: %010lu",
fileInfo.filename, expectedCRC, actualCRC);
if (expectedCRC != actualCRC) {
corruptDataFound = YES;
URKLogError("Corrupt data found (filename: %{public}@, expected CRC: %010lu, actual CRC: %010lu",
fileInfo.filename, expectedCRC, actualCRC);
if (filePath && ![fileInfo.filename isEqualToString:filePath]) continue;
if (RHCode != ERAR_SUCCESS) {
break;
}
if (filePath) *stop = YES;
} error:&performOnFilesError];
if ((PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL)) != ERAR_SUCCESS) {
RHCode = PFCode;
break;
}
if (filePath) {
break;
}
}
} inMode:RAR_OM_EXTRACT error:&performOnFilesError];
if (RHCode == ERAR_END_ARCHIVE) {
RHCode = ERAR_SUCCESS;
}
if (performOnFilesError) {
URKLogError("Error checking data integrity: %{public}@", performOnFilesError);
}
return !corruptDataFound;
if (!wasSuccessful) {
URKLogError("Error checking data integrity");
if (RHCode == ERAR_SUCCESS) {
RHCode = ERAR_UNKNOWN;
}
}
return RHCode;
}
@ -1269,10 +1343,9 @@ int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, lon
URKLogDebug("Setting archive name...");
const char *filenameData = (const char *) [rarFile UTF8String];
self.flags->ArcName = new char[strlen(filenameData) + 1];
strcpy(self.flags->ArcName, filenameData);
self.flags->ArcName = strdup(rarFile.UTF8String);
self.flags->OpenMode = (uint)mode;
self.flags->OpFlags = self.ignoreCRCMismatches ? ROADOF_KEEPBROKEN : 0;
URKLogDebug("Opening archive %{public}@...", rarFile);
@ -1284,6 +1357,9 @@ int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, lon
return NO;
}
self.lastFilepath = nil;
self.lastArchivePath = nil;
if (aPassword != nil) {
URKLogDebug("Setting password...");
@ -1339,10 +1415,10 @@ int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, lon
URKLogDebug("Reading through RAR header looking for files...");
while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == 0) {
URKFileInfo *info = nil;
while ([welf readHeader:&RHCode info:&info] == URKReadHeaderLoopActionContinueReading) {
URKLogDebug("Calling iterateAllFileInfo handler");
BOOL shouldStop = NO;
URKFileInfo *info = [URKFileInfo fileInfo:welf.header];
action(info, &shouldStop);
if (shouldStop) {
@ -1353,15 +1429,15 @@ int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, lon
URKLogDebug("Skipping to next file...");
if ((PFCode = RARProcessFile(welf.rarFile, RAR_SKIP, NULL, NULL)) != 0) {
NSString *errorName = nil;
[self assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
[welf assignError:innerError code:(NSInteger)PFCode errorName:&errorName];
URKLogError("Error skipping to next header file: %{public}@ (%d)", errorName, PFCode);
return;
}
}
if (RHCode != ERAR_SUCCESS && RHCode != ERAR_END_ARCHIVE) {
if (![welf didReturnSuccessfully:RHCode]) {
NSString *errorName = nil;
[self assignError:innerError code:RHCode errorName:&errorName];
[welf assignError:innerError code:RHCode errorName:&errorName];
URKLogError("Error reading RAR header: %{public}@ (%d)", errorName, RHCode);
}
} inMode:RAR_OM_LIST_INCSPLIT error:error];
@ -1485,7 +1561,7 @@ int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, lon
default:
errorName = [NSString stringWithFormat:@"Unknown (%ld)", (long)errorCode];
detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Unknown error encountered (code %ld)", @"UnrarKit", _resources, @"Error detail string"), errorCode];
detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Unknown error encountered (code %ld)", @"UnrarKit", _resources, @"Error detail string"), (long)errorCode];
break;
}
@ -1641,4 +1717,71 @@ int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, lon
return volumeURL;
}
- (URKReadHeaderLoopAction) readHeader:(int *)returnCode
info:(URKFileInfo *__autoreleasing *)info
{
NSAssert(returnCode != NULL, @"otherReturnCode argument is required");
NSAssert(info != NULL, @"info argument is required");
URKLogDebug("Reading RAR header");
*returnCode = RARReadHeaderEx(self.rarFile, self.header);
URKLogDebug("Reading file info from RAR header");
*info = [URKFileInfo fileInfo:self.header];
URKLogDebug("RARReadHeaderEx returned %d", *returnCode);
URKReadHeaderLoopAction result;
switch (*returnCode) {
case ERAR_SUCCESS:
result = URKReadHeaderLoopActionContinueReading;
break;
case ERAR_END_ARCHIVE:
URKLogDebug("Successful return code from RARReadHeaderEx");
result = URKReadHeaderLoopActionStopReading;
break;
case ERAR_BAD_DATA:
if (self.ignoreCRCMismatches) {
URKLogError("Ignoring CRC mismatch in %{public}@", (*info).filename);
result = URKReadHeaderLoopActionContinueReading;
} else {
URKLogError("CRC mismatch when reading %{public}@. To read the archive and ignore CRC mismatches, use -checkDataIntegrityIgnoringCRCMismatches:", (*info).filename);
result = URKReadHeaderLoopActionStopReading;
}
break;
default:
result = URKReadHeaderLoopActionStopReading;
break;
}
if (result == URKReadHeaderLoopActionContinueReading
&& [self.lastFilepath isEqualToString:(*info).filename]
&& [self.lastArchivePath isEqualToString:(*info).archiveName])
{
URKLogInfo("Same header returned twice. Presuming archive done being read. Probably a bad CRC")
result = URKReadHeaderLoopActionStopReading;
}
self.lastFilepath = (result == URKReadHeaderLoopActionStopReading
? nil
: (*info).filename);
self.lastArchivePath = (result == URKReadHeaderLoopActionStopReading
? nil
: (*info).archiveName);
return result;
}
- (BOOL)didReturnSuccessfully:(int)returnCode {
return (returnCode == ERAR_SUCCESS
|| returnCode == ERAR_END_ARCHIVE
|| (returnCode == ERAR_BAD_DATA && self.ignoreCRCMismatches));
}
- (BOOL)hasBadCRC:(int)returnCode {
return returnCode == ERAR_BAD_DATA && !self.ignoreCRCMismatches;
}
@end

View File

@ -4,14 +4,14 @@
//
#import <Foundation/Foundation.h>
#import "UnrarKitMacros.h"
#import <UnrarKit/UnrarKitMacros.h>
RarosHppIgnore
#import "raros.hpp"
#import <UnrarKit/raros.hpp>
#pragma clang diagnostic pop
DllHppIgnore
#import "dll.hpp"
#import <UnrarKit/dll.hpp>
#pragma clang diagnostic pop
/* See http://www.forensicswiki.org/wiki/RAR and

View File

@ -40,7 +40,7 @@
_isEncryptedWithPassword = fileHeader->Flags & (1 << 2);
//_fileHasComment = fileHeader->Flags & (1 << 3)
_isDirectory = fileHeader->Flags & RHDF_DIRECTORY;
_isDirectory = (fileHeader->Flags & RHDF_DIRECTORY) ? YES : NO;
}
return self;

View File

@ -15,5 +15,5 @@ FOUNDATION_EXPORT double UnrarKitVersionNumber;
FOUNDATION_EXPORT const unsigned char UnrarKitVersionString[];
#import "URKArchive.h"
#import "URKFileInfo.h"
#import <UnrarKit/URKArchive.h>
#import <UnrarKit/URKFileInfo.h>

View File

@ -60,7 +60,7 @@ __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \
#import <os/activity.h>
// Called from +[UnrarKit initialize] and +[URKArchiveTestCase setUp]
extern os_log_t unrarkit_log; // Declared in URKArchive.m
extern os_log_t unrarkit_log; // Declared in URKArchive.mm
extern BOOL unrarkitIsAtLeast10_13SDK; // Declared in URKArchive.m
#define URKLogInit() \
unrarkit_log = os_log_create("com.abbey-code.UnrarKit", "General"); \

View File

@ -143,17 +143,15 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0930;
LastUpgradeCheck = 1200;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "UnrarExample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
en,
Base,
);
mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
projectDirPath = "";
@ -257,6 +255,7 @@
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -272,14 +271,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
ONLY_ACTIVE_ARCH = YES;
OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-lc++",
"-all_load",
);
PREBINDING = NO;
SDKROOT = iphoneos;
};
name = Debug;
@ -301,6 +299,7 @@
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -316,13 +315,12 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
OTHER_LDFLAGS = (
"-lc++",
"-all_load",
);
PREBINDING = NO;
SDKROOT = iphoneos;
WARNING_CFLAGS = "-Wno-error=unused-command-line-argument";
};

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
LastUpgradeVersion = "1200"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@ -38,8 +36,8 @@
ReferencedContainer = "container:UnrarExample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -61,8 +59,6 @@
ReferencedContainer = "container:UnrarExample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -4,8 +4,15 @@ bool Archive::GetComment(Array<wchar> *CmtData)
{
if (!MainComment)
return false;
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
bool Success=DoGetComment(CmtData);
Seek(SavePos,SEEK_SET);
return Success;
}
bool Archive::DoGetComment(Array<wchar> *CmtData)
{
#ifndef SFX_MODULE
uint CmtLength;
if (Format==RARFMT14)
@ -34,7 +41,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader)
if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
@ -57,6 +64,8 @@ bool Archive::GetComment(Array<wchar> *CmtData)
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
if (CmtLength<2)
return false;
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
@ -85,6 +94,8 @@ bool Archive::GetComment(Array<wchar> *CmtData)
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
if (UnpDataSize>0)
{
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
@ -96,6 +107,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
}
else
{
if (CmtLength==0)
@ -131,7 +143,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
bool Archive::ReadCommentData(Array<wchar> *CmtData)
{
Array<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL))
if (!ReadSubData(&CmtRaw,NULL,false))
return false;
size_t CmtSize=CmtRaw.Size();
CmtRaw.Push(0);

View File

@ -208,14 +208,15 @@ bool Archive::IsArchive(bool EnableBroken)
break;
}
// This check allows to make RS based recovery even if password is incorrect.
// But we should not do it for EnableBroken or we'll get 'not RAR archive'
// We should not do it for EnableBroken or we'll get 'not RAR archive'
// messages when extracting encrypted archives with wrong password.
if (FailedHeaderDecryption && !EnableBroken)
return false;
if (BrokenHeader || !StartFound) // Main archive header is corrupt or missing.
{
if (!FailedHeaderDecryption) // If not reported a wrong password already.
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!EnableBroken)
return false;
@ -232,7 +233,7 @@ bool Archive::IsArchive(bool EnableBroken)
// immediately after IsArchive call.
if (HeadersLeft && (!SilentOpen || !Encrypted))
{
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
@ -261,6 +262,7 @@ bool Archive::IsArchive(bool EnableBroken)
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
CurHeaderType=SaveCurHeaderType;
Seek(SavePos,SEEK_SET);
}
if (!Volume || FirstVolume)
wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName));

View File

@ -20,13 +20,15 @@ enum ADDSUBDATA_FLAGS
ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
};
// RAR5 headers must not exceed 2 MB.
#define MAX_HEADER_SIZE_RAR5 0x200000
class Archive:public File
{
private:
void UpdateLatestTime(FileHeader *CurBlock);
void ConvertNameCase(wchar *Name);
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
size_t ReadHeader14();
size_t ReadHeader15();
size_t ReadHeader50();
@ -34,8 +36,8 @@ class Archive:public File
void RequestArcPassword();
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
void UnkEncVerMsg(const wchar *Name,const wchar *Info);
bool DoGetComment(Array<wchar> *CmtData);
bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(RAR_NOCRYPT)
@ -63,8 +65,6 @@ class Archive:public File
size_t SearchBlock(HEADER_TYPE HeaderType);
size_t SearchSubBlock(const wchar *Type);
size_t SearchRR();
void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false);
void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);}
size_t ReadHeader();
void CheckArc(bool EnableBroken);
void CheckOpen(const wchar *Name);
@ -81,8 +81,8 @@ class Archive:public File
int64 GetStartPos();
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
RAROptions* GetRAROptions() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0

View File

@ -10,7 +10,10 @@ size_t Archive::ReadHeader()
CurBlockPos=Tell();
size_t ReadSize;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
size_t ReadSize=0;
switch(Format)
{
#ifndef SFX_MODULE
@ -113,9 +116,9 @@ void Archive::BrokenHeaderMsg()
}
void Archive::UnkEncVerMsg(const wchar *Name)
void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
{
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name);
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
ErrHandler.SetErrorCode(RARX_WARNING);
}
@ -265,14 +268,14 @@ size_t Archive::ReadHeader15()
uint FileTime=Raw.Get4();
hd->UnpVer=Raw.Get1();
// RAR15 did not use the special dictionary size to mark dirs.
if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
hd->Dir=true;
hd->Method=Raw.Get1()-0x30;
size_t NameSize=Raw.Get2();
hd->FileAttr=Raw.Get4();
// RAR15 did not use the special dictionary size to mark dirs.
if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
hd->Dir=true;
hd->CryptMethod=CRYPT_NONE;
if (hd->Encrypted)
switch(hd->UnpVer)
@ -399,8 +402,8 @@ size_t Archive::ReadHeader15()
if (rmode & 4)
rlt.Second++;
rlt.Reminder=0;
int count=rmode&3;
for (int J=0;J<count;J++)
uint count=rmode&3;
for (uint J=0;J<count;J++)
{
byte CurByte=Raw.Get1();
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
@ -518,7 +521,6 @@ size_t Archive::ReadHeader15()
{
// Last 7 bytes of recovered volume can contain zeroes, because
// REV files store its own information (volume number, etc.) here.
SaveFilePos SavePos(*this);
int64 Length=Tell();
Seek(Length-7,SEEK_SET);
Recovered=true;
@ -563,6 +565,11 @@ size_t Archive::ReadHeader50()
return 0;
}
// We repeat the password request only for manually entered passwords
// and not for -p<pwd>. Wrong password can be intentionally provided
// in -p<pwd> to not stop batch processing for encrypted archives.
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
while (true) // Repeat the password prompt for wrong passwords.
{
RequestArcPassword();
@ -571,12 +578,24 @@ size_t Archive::ReadHeader50()
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
// Verify password validity.
if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
{
if (GlobalPassword) // For -p<pwd> or Ctrl+P.
{
// This message is used by Android GUI to reset cached passwords.
// Update appropriate code if changed.
uiMsg(UIERROR_BADPSW,FileName,FileName);
FailedHeaderDecryption=true;
ErrHandler.SetErrorCode(RARX_BADPWD);
return 0;
}
else // For passwords entered manually.
{
// This message is used by Android GUI and Windows GUI and SFX to
// reset cached passwords. Update appropriate code if changed.
uiMsg(UIWAIT_BADPSW,FileName);
uiMsg(UIWAIT_BADPSW,FileName,FileName);
Cmd->Password.Clean();
}
#ifdef RARDLL
// Avoid new requests for unrar.dll to prevent the infinite loop
// if app always returns the same password.
@ -595,8 +614,8 @@ size_t Archive::ReadHeader50()
}
// Header size must not occupy more than 3 variable length integer bytes
// resulting in 2 MB maximum header size, so here we read 4 byte CRC32
// followed by 3 bytes or less of header size.
// resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
// so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
const size_t FirstReadSize=7; // Smallest possible block size.
if (Raw.Read(FirstReadSize)<FirstReadSize)
{
@ -685,7 +704,9 @@ size_t Archive::ReadHeader50()
uint CryptVersion=(uint)Raw.GetV();
if (CryptVersion>CRYPT_VERSION)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
UnkEncVerMsg(FileName,Info);
return 0;
}
uint EncFlags=(uint)Raw.GetV();
@ -693,9 +714,12 @@ size_t Archive::ReadHeader50()
CryptHead.Lg2Count=Raw.Get1();
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
UnkEncVerMsg(FileName,Info);
return 0;
}
Raw.GetB(CryptHead.Salt,SIZE_SALT50);
if (CryptHead.UsePswCheck)
{
@ -798,6 +822,8 @@ size_t Archive::ReadHeader50()
// but it was already used in RAR 1.5 and Unpack needs to distinguish
// them.
hd->UnpVer=(CompInfo & 0x3f) + 50;
if (hd->UnpVer!=50) // Only 5.0 compression is known now.
hd->UnpVer=VER_UNKNOWN;
hd->HostOS=(byte)Raw.GetV();
size_t NameSize=(size_t)Raw.GetV();
@ -973,7 +999,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
FileHeader *hd=(FileHeader *)bb;
uint EncVersion=(uint)Raw->GetV();
if (EncVersion>CRYPT_VERSION)
UnkEncVerMsg(hd->FileName);
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
UnkEncVerMsg(hd->FileName,Info);
}
else
{
uint Flags=(uint)Raw->GetV();
@ -981,7 +1011,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
hd->Lg2Count=Raw->Get1();
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
UnkEncVerMsg(hd->FileName);
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
UnkEncVerMsg(hd->FileName,Info);
}
Raw->GetB(hd->Salt,SIZE_SALT50);
Raw->GetB(hd->InitV,SIZE_INITV);
if (hd->UsePswCheck)
@ -1222,11 +1256,13 @@ size_t Archive::ReadHeader14()
Raw.Read(NameSize);
char FileName[NM];
Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
FileName[NameSize]=0;
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize);
FileName[ReadNameSize]=0;
IntToExt(FileName,FileName,ASIZE(FileName));
CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
ConvertNameCase(FileHead.FileName);
ConvertFileHeader(&FileHead);
if (Raw.Size()!=0)
NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
@ -1380,7 +1416,7 @@ int64 Archive::GetStartPos()
}
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
{
if (BrokenHeader)
{
@ -1428,6 +1464,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
SubDataIO.EnableShowProgress(false);
SubDataIO.SetFiles(this,DestFile);
SubDataIO.SetTestMode(TestMode);
SubDataIO.UnpVolume=SubHead.SplitAfter;
SubDataIO.SetSubHeader(&SubHead,NULL);
Unpack.SetDestSize(SubHead.UnpSize);

View File

@ -3,6 +3,7 @@
#define _RAR_BLAKE2_
#define BLAKE2_DIGEST_SIZE 32
#define BLAKE2_THREADS_NUMBER 8
enum blake2s_constant
{

View File

@ -1,5 +1,8 @@
#include "rar.hpp"
#include "cmdfilter.cpp"
#include "cmdmix.cpp"
CommandData::CommandData()
{
Init();
@ -120,6 +123,7 @@ void CommandData::ParseArg(wchar *Arg)
wchar CmdChar=toupperw(*Command);
bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
bool Extract=CmdChar=='X' || CmdChar=='E';
bool Repair=CmdChar=='R' && Command[1]==0;
if (EndSeparator && !Add)
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
else
@ -130,15 +134,15 @@ void CommandData::ParseArg(wchar *Arg)
FindData FileData;
bool Found=FindFile::FastFind(Arg,&FileData);
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg))
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
{
FileLists=true;
ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
}
else
if (Found && FileData.IsDir && Extract && *ExtrPath==0)
else // We use 'destpath\' when extracting and reparing.
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
{
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
@ -280,12 +284,19 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ClearArc=true;
break;
case 'D':
AppendArcNameToPath=true;
if (Switch[2]==0)
AppendArcNameToPath=APPENDARCNAME_DESTPATH;
else
if (Switch[2]=='1')
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
break;
#ifndef SFX_MODULE
case 'G':
if (Switch[2]=='-' && Switch[3]==0)
GenerateArcName=0;
else
if (toupperw(Switch[2])=='F')
wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
else
{
GenerateArcName=true;
@ -302,7 +313,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AddArcOnly=true;
break;
case 'P':
wcscpy(ArcPath,Switch+2);
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
break;
case 'S':
SyncFiles=true;
@ -365,11 +376,11 @@ void CommandData::ProcessSwitch(const wchar *Switch)
default:
if (Switch[1]=='+')
{
InclFileAttr|=GetExclAttr(Switch+2);
InclFileAttr|=GetExclAttr(Switch+2,InclDir);
InclAttrSet=true;
}
else
ExclFileAttr|=GetExclAttr(Switch+1);
ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
break;
}
break;
@ -407,9 +418,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
break;
}
if (wcsicomp(Switch+1,L"SND")==0)
if (wcsnicomp(Switch+1,L"SND",3)==0)
{
Sound=true;
Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
break;
}
if (wcsicomp(Switch+1,L"ERR")==0)
@ -805,51 +816,19 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ArcTime=ARCTIME_LATEST;
break;
case 'O':
FileTimeBefore.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,true,true);
break;
case 'N':
FileTimeAfter.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,false,true);
break;
case 'B':
FileTimeBefore.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,true,false);
break;
case 'A':
FileTimeAfter.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,false,false);
break;
case 'S':
{
EXTTIME_MODE Mode=EXTTIME_HIGH3;
bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
if (CommonMode)
Mode=(EXTTIME_MODE)(Switch[2]-'0');
if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
Mode=EXTTIME_HIGH3;
if (Switch[2]=='-')
Mode=EXTTIME_NONE;
if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
xmtime=xctime=xatime=Mode;
else
{
if (Switch[3]>='0' && Switch[3]<='4')
Mode=(EXTTIME_MODE)(Switch[3]-'0');
if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
Mode=EXTTIME_HIGH3;
if (Switch[3]=='-')
Mode=EXTTIME_NONE;
switch(toupperw(Switch[2]))
{
case 'M':
xmtime=Mode;
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
}
}
}
SetStoreTimeMode(Switch+2);
break;
case '-':
Test=false;
@ -897,7 +876,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
if (Switch[1]==0)
{
// If comment file is not specified, we read data from stdin.
wcscpy(CommentFile,L"stdin");
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
}
else
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
@ -922,309 +901,6 @@ void CommandData::BadSwitch(const wchar *Switch)
#endif
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ft)
{
if (FileTimeBefore.IsSet() && ft>=FileTimeBefore)
return true;
if (FileTimeAfter.IsSet() && ft<=FileTimeAfter)
return true;
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return(true);
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return(true);
return(false);
}
#endif
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
// if (wcslen(FileHead.FileName)>=NM)
// return 0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE
@ -1255,7 +931,10 @@ void CommandData::ProcessCommand()
if (wcschr(L"AFUMD",*Command)==NULL)
{
if (GenerateArcName)
GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false);
{
const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
}
StringList ArcMasks;
ArcMasks.AddString(ArcName);
@ -1274,7 +953,6 @@ void CommandData::ProcessCommand()
case 'X':
case 'E':
case 'T':
case 'I':
{
CmdExtract Extract(this);
Extract.DoExtract();
@ -1317,7 +995,7 @@ bool CommandData::IsSwitch(int Ch)
#ifndef SFX_MODULE
uint CommandData::GetExclAttr(const wchar *Str)
uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
{
if (IsDigit(*Str))
return wcstol(Str,NULL,0);
@ -1327,10 +1005,10 @@ uint CommandData::GetExclAttr(const wchar *Str)
{
switch(toupperw(*Str))
{
#ifdef _UNIX
case 'D':
Attr|=S_IFDIR;
Dir=true;
break;
#ifdef _UNIX
case 'V':
Attr|=S_IFCHR;
break;
@ -1344,9 +1022,6 @@ uint CommandData::GetExclAttr(const wchar *Str)
case 'S':
Attr|=0x4;
break;
case 'D':
Attr|=0x10;
break;
case 'A':
Attr|=0x20;
break;

View File

@ -6,13 +6,19 @@
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
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);
uint GetExclAttr(const wchar *Str,bool &Dir);
#if !defined(SFX_MODULE)
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
void SetStoreTimeMode(const wchar *S);
#endif
bool FileLists;
bool NoMoreSwitches;
@ -34,11 +40,11 @@ class CommandData:public RAROptions
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize);
void ProcessCommand();
void AddArcName(const wchar *Name);
bool GetArcName(wchar *Name,int MaxSize);

View File

@ -28,8 +28,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
sha1_context c;
sha1_init(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
const uint HashRounds=0x40000;
for (uint I=0;I<HashRounds;I++)
{
sha1_process_rar29( &c, RawPsw, RawLength );
byte PswNum[3];
@ -47,8 +47,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
}
uint32 digest[5];
sha1_done( &c, digest );
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
for (uint I=0;I<4;I++)
for (uint J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
KDF3Cache[KDF3CachePos].Pwd=*Password;

View File

@ -42,6 +42,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
Data->Cmd.FileArgs.AddString(L"*");
Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0;
char AnsiArcName[NM];
*AnsiArcName=0;
@ -94,37 +95,51 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
r->Flags=0;
if (Data->Arc.Volume)
r->Flags|=0x01;
r->Flags|=ROADF_VOLUME;
if (Data->Arc.MainComment)
r->Flags|=ROADF_COMMENT;
if (Data->Arc.Locked)
r->Flags|=0x04;
r->Flags|=ROADF_LOCK;
if (Data->Arc.Solid)
r->Flags|=0x08;
r->Flags|=ROADF_SOLID;
if (Data->Arc.NewNumbering)
r->Flags|=0x10;
r->Flags|=ROADF_NEWNUMBERING;
if (Data->Arc.Signed)
r->Flags|=0x20;
r->Flags|=ROADF_SIGNED;
if (Data->Arc.Protected)
r->Flags|=0x40;
r->Flags|=ROADF_RECOVERY;
if (Data->Arc.Encrypted)
r->Flags|=0x80;
r->Flags|=ROADF_ENCHEADERS;
if (Data->Arc.FirstVolume)
r->Flags|=0x100;
r->Flags|=ROADF_FIRSTVOLUME;
Array<wchar> CmtDataW;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
if (r->CmtBufW!=NULL)
{
CmtDataW.Push(0);
size_t Size=wcslen(&CmtDataW[0])+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW));
r->CmtBufW[r->CmtSize-1]=0;
}
else
if (r->CmtBuf!=NULL)
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
r->Flags|=2;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
if (Size<=r->CmtBufSize)
r->CmtBuf[r->CmtSize-1]=0;
}
}
else
r->CmtState=r->CmtSize=0;
Data->Extract.ExtractArchiveInit(Data->Arc);
@ -253,9 +268,6 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
D->UnpSize=uint(hd->UnpSize & 0xffffffff);
D->UnpSizeHigh=uint(hd->UnpSize>>32);
D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
if (Data->Arc.Format==RARFMT50)
D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
else
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->FileCRC=hd->FileHash.CRC32;
D->FileTime=hd->mtime.GetDos();
@ -372,7 +384,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
if (DestNameW!=NULL)
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command));
Data->Cmd.Test=Operation!=RAR_EXTRACT;
bool Repeat=false;
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
@ -439,16 +451,16 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro
}
#ifndef RAR_NOCRYPT
void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
{
#ifndef RAR_NOCRYPT
DataSet *Data=(DataSet *)hArcData;
wchar PasswordW[MAXPASSWORD];
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
Data->Cmd.Password.Set(PasswordW);
cleandata(PasswordW,sizeof(PasswordW));
}
#endif
}
int PASCAL RARGetDllVersion()

View File

@ -5,6 +5,7 @@ EXPORTS
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARProcessFileW
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc

View File

@ -1,7 +1,7 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#pragma pack(push, 1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
@ -135,6 +135,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
#define ROADOF_KEEPBROKEN 0x0001
struct RAROpenArchiveDataEx
{
char *ArcName;
@ -148,7 +150,9 @@ struct RAROpenArchiveDataEx
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int Reserved[28];
unsigned int OpFlags;
wchar_t *CmtBufW;
unsigned int Reserved[25];
};
enum UNRARCALLBACK_MESSAGES {
@ -180,6 +184,6 @@ int PASCAL RARGetDllVersion();
}
#endif
#pragma pack()
#pragma pack(pop)
#endif

View File

@ -2,8 +2,8 @@
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 60, 3, 2672
PRODUCTVERSION 5, 60, 3, 2672
FILEVERSION 5, 91, 100, 3470
PRODUCTVERSION 5, 91, 100, 3470
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.60.3\0"
VALUE "ProductVersion", "5.60.3\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2018\0"
VALUE "FileVersion", "5.91.0\0"
VALUE "ProductVersion", "5.91.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}

View File

@ -158,6 +158,7 @@ void ErrorHandler::OpenErrorMsg(const wchar *FileName)
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
{
Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
SysErrMsg();
SetErrorCode(RARX_OPEN);
@ -270,6 +271,7 @@ void _stdfunction ProcessSignal(int SigType)
#endif
ErrHandler.UserBreak=true;
ErrHandler.SetDisableShutdown();
mprintf(St(MBreak));
#ifdef _WIN_ALL
@ -293,7 +295,7 @@ void _stdfunction ProcessSignal(int SigType)
#endif
#if defined(_WIN_ALL) && !defined(_MSC_VER)
// never reached, just to avoid a compiler warning
// Never reached, just to avoid a compiler warning
return TRUE;
#endif
}
@ -327,7 +329,7 @@ void ErrorHandler::Throw(RAR_EXIT Code)
bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
{
#if !defined(SFX_MODULE) && !defined(SILENT)
#ifndef SILENT
#ifdef _WIN_ALL
int ErrType=GetLastError();
if (ErrType!=0)
@ -360,7 +362,7 @@ void ErrorHandler::SysErrMsg()
return;
#ifdef _WIN_ALL
wchar *CurMsg=Msg;
while (CurMsg!=NULL)
while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
{
while (*CurMsg=='\r' || *CurMsg=='\n')
CurMsg++;

View File

@ -56,11 +56,12 @@ class ErrorHandler
uint GetErrorCount() {return ErrCount;}
void SetSignalHandlers(bool Enable);
void Throw(RAR_EXIT Code);
void SetSilent(bool Mode) {Silent=Mode;};
void SetSilent(bool Mode) {Silent=Mode;}
bool GetSysErrMsg(wchar *Msg,size_t Size);
void SysErrMsg();
int GetSystemErrorCode();
void SetSystemErrorCode(int Code);
void SetDisableShutdown() {DisableShutdown=true;}
bool IsShutdownEnabled() {return !DisableShutdown;}
bool UserBreak; // Ctrl+Break is pressed.

View File

@ -40,6 +40,8 @@ void CmdExtract::DoExtract()
{
if (Cmd->ManualPassword)
Cmd->Password.Clean(); // Clean user entered password before processing next archive.
ReconstructDone=false; // Must be reset here, not in ExtractArchiveInit().
while (true)
{
EXTRACT_ARC_CODE Code=ExtractArchive();
@ -59,6 +61,10 @@ void CmdExtract::DoExtract()
{
if (!PasswordCancelled)
uiMsg(UIERROR_NOFILESTOEXTRACT,ArcName);
// Other error codes may explain a reason of "no files extracted" clearer,
// so set it only if no other errors found (wrong mask set by user).
if (ErrHandler.GetErrorCode()==RARX_SUCCESS)
ErrHandler.SetErrorCode(RARX_NOFILES);
}
else
@ -83,13 +89,12 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
FirstFile=true;
#endif
PasswordAll=(Cmd->Password.IsSet());
GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
DataIO.UnpVolume=false;
PrevProcessed=false;
AllMatchesExact=true;
ReconstructDone=false;
AnySolidDataUnpackedWell=false;
StartTime.SetCurrentTime();
@ -157,7 +162,7 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
// This size is necessary to display the correct total progress indicator.
wchar NextName[NM];
wcscpy(NextName,Arc.FileName);
wcsncpyz(NextName,Arc.FileName,ASIZE(NextName));
while (true)
{
@ -257,15 +262,17 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (HeaderType==HEAD_ENDARC)
if (Arc.EndArcHead.NextVolume)
{
#ifndef NOVOLUME
#ifdef NOVOLUME
return false;
#else
if (!MergeArchive(Arc,&DataIO,false,Command))
{
ErrHandler.SetErrorCode(RARX_WARNING);
return false;
}
#endif
Arc.Seek(Arc.CurBlockPos,SEEK_SET);
return true;
#endif
}
else
return false;
@ -294,7 +301,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
bool EqualNames=false;
wchar MatchedArg[NM];
int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg));
int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,0,MatchedArg,ASIZE(MatchedArg));
bool MatchFound=MatchNumber!=0;
#ifndef SFX_MODULE
if (Cmd->ExclPath==EXCL_BASEPATH)
@ -319,6 +326,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
{
wcsncpyz(Cmd->ArcName,ArcName,ASIZE(ArcName)); // For GUI "Delete archive after extraction".
// If first volume name does not match the current name and if such
// volume name really exists, let's unpack from this first volume.
Repeat=true;
@ -340,7 +348,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
#endif
wchar ArcFileName[NM];
ConvertPath(Arc.FileHead.FileName,ArcFileName);
ConvertPath(Arc.FileHead.FileName,ArcFileName,ASIZE(ArcFileName));
if (Arc.FileHead.Version)
{
@ -468,17 +476,17 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
!Arc.BrokenHeader)
{
if (PasswordAll) // For -p<pwd> or Ctrl+P.
if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
{
// This message is used by Android GUI to reset cached passwords.
// Update appropriate code if changed.
uiMsg(UIERROR_BADPSW,ArcFileName);
uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName);
}
else // For passwords entered manually.
{
// This message is used by Android GUI and Windows GUI and SFX to
// reset cached passwords. Update appropriate code if changed.
uiMsg(UIWAIT_BADPSW,ArcFileName);
uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName);
Cmd->Password.Clean();
// Avoid new requests for unrar.dll to prevent the infinite loop
@ -609,11 +617,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
}
#endif
if (!TestMode && !Arc.BrokenHeader &&
(Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
uint64 Preallocated=0;
if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 &&
Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize &&
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
{
CurFile.Prealloc(Arc.FileHead.UnpSize);
Preallocated=Arc.FileHead.UnpSize;
}
CurFile.SetAllowDelete(!Cmd->KeepBroken);
bool FileCreateMode=!TestMode && !SkipSolid && Command!='P';
@ -725,18 +736,28 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
else
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,
// so we do not need to set link time or owner. But when we overwrite
// an existing link, we can call PrepareToDelete(), which affects
// link target attributes as well. So we set link attributes to restore
// both target and link attributes if PrepareToDelete() changed them.
bool SetAttrOnly=LinkEntry && Arc.FileHead.RedirType==FSREDIR_HARDLINK && LinkSuccess;
if (!TestMode && (Command=='X' || Command=='E') &&
(!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) &&
(!LinkEntry || SetAttrOnly || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) &&
(!BrokenFile || Cmd->KeepBroken))
{
// We could preallocate more space that really written to broken file.
if (BrokenFile)
CurFile.Truncate();
// Below we use DestFileName instead of CurFile.FileName,
// so we can set file attributes also for hard links, which do not
// have the open CurFile. These strings are the same for other items.
#if defined(_WIN_ALL) || defined(_EMX)
if (Cmd->ClearArc)
Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif
if (!SetAttrOnly)
{
// We could preallocate more space that really written to broken file
// or file with crafted header.
if (Preallocated>0 && (BrokenFile || DataIO.CurUnpWrite!=Preallocated))
CurFile.Truncate();
CurFile.SetOpenFileTime(
@ -744,18 +765,23 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
CurFile.Close();
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
SetFileCompression(CurFile.FileName,true);
#endif
SetFileHeaderExtra(Cmd,Arc,CurFile.FileName);
SetFileHeaderExtra(Cmd,Arc,DestFileName);
CurFile.SetCloseFileTime(
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr))
uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName);
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
SetFileCompression(DestFileName,true);
if (Cmd->ClearArc)
Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif
if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,Arc.FileHead.FileAttr))
uiMsg(UIERROR_FILEATTR,Arc.FileName,DestFileName);
PrevProcessed=true;
}
@ -846,9 +872,12 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
}
#ifndef SFX_MODULE
if (Cmd->AppendArcNameToPath)
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);
AddEndSlash(DestName,DestSize);
}
@ -961,14 +990,18 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/)
{
// Suppress "test is ok" message if user cancelled the password prompt.
uiMsg(UIERROR_INCERRCOUNT);
// 2019.03.23: If some archives are tested ok and prompt is cancelled for others,
// do we really need to suppress "test is ok"? Also if we set an empty password
// and "Use for all archives" in WinRAR Ctrl+P and skip some encrypted archives.
// We commented out this UIERROR_INCERRCOUNT for now.
// uiMsg(UIERROR_INCERRCOUNT);
return false;
}
Cmd->ManualPassword=true;
}
#if !defined(SILENT)
else
if (!PasswordAll && !Arc.FileHead.Solid)
if (!GlobalPassword && !Arc.FileHead.Solid)
{
eprintf(St(MUseCurPsw),ArcFileName);
switch(Cmd->AllYes ? 1 : Ask(St(MYesNoAll)))
@ -980,7 +1013,7 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
return false;
break;
case 3:
PasswordAll=true;
GlobalPassword=true;
break;
}
}
@ -1077,7 +1110,7 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()!=WNT_NONE)
SetFileCompression(DestFileName,true);
#endif
SetFileHeaderExtra(Cmd,Arc,DestFileName);

View File

@ -43,7 +43,7 @@ class CmdExtract
wchar ArcName[NM];
bool PasswordAll;
bool GlobalPassword;
bool PrevProcessed; // If previous file was successfully extracted or tested.
wchar DestFileName[NM];
bool PasswordCancelled;

View File

@ -13,6 +13,7 @@ File::File()
OpenShared=false;
AllowDelete=true;
AllowExceptions=true;
PreserveAtime=false;
#ifdef _WIN_ALL
NoSequentialRead=false;
CreateMode=FMF_UNDEFINED;
@ -56,6 +57,9 @@ bool File::Open(const wchar *Name,uint Mode)
if (OpenShared)
ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
FindData FD;
if (PreserveAtime)
Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
DWORD LastError;
@ -86,6 +90,11 @@ bool File::Open(const wchar *Name,uint Mode)
}
if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
ErrorType=FILE_NOTFOUND;
if (PreserveAtime && hNewFile!=FILE_BAD_HANDLE)
{
FILETIME ft={0xffffffff,0xffffffff}; // This value prevents atime modification.
SetFileTime(hNewFile,NULL,&ft,NULL);
}
#else
int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
@ -94,6 +103,11 @@ bool File::Open(const wchar *Name,uint Mode)
#if defined(_AIX) && defined(_LARGE_FILE_API)
flags|=O_LARGEFILE;
#endif
#endif
// NDK r20 has O_NOATIME, but fails to create files with it in Android 7+.
#if defined(O_NOATIME)
if (PreserveAtime)
flags|=O_NOATIME;
#endif
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
@ -271,7 +285,7 @@ bool File::Rename(const wchar *NewName)
Success=RenameFile(FileName,NewName);
if (Success)
wcscpy(FileName,NewName);
wcsncpyz(FileName,NewName,ASIZE(FileName));
return Success;
}
@ -387,7 +401,7 @@ int File::Read(void *Data,size_t Size)
}
break;
}
return ReadSize;
return ReadSize; // It can return -1 only if AllowExceptions is disabled.
}
@ -670,9 +684,11 @@ void File::GetOpenFileTime(RarTime *ft)
int64 File::FileLength()
{
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
Seek(0,SEEK_END);
return Tell();
int64 Length=Tell();
Seek(SavePos,SEEK_SET);
return Length;
}

View File

@ -62,6 +62,7 @@ class File
bool NoSequentialRead;
uint CreateMode;
#endif
bool PreserveAtime;
protected:
bool OpenShared; // Set by 'Archive' class.
public:
@ -99,7 +100,7 @@ class File
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft);
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;}; // 'virtual' for MultiFile class.
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
FILE_HANDLETYPE GetHandleType() {return HandleType;}
@ -114,6 +115,7 @@ class File
#ifdef _WIN_ALL
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
#ifdef _UNIX
int GetFD()
{

View File

@ -348,7 +348,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
return NULL;
wcscpy(Name+Length,RndText);
wcsncpyz(Name+Length,RndText,MaxSize-Length);
if (!FileExist(Name))
break;
}
@ -360,7 +360,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
#if !defined(SFX_MODULE)
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
{
SaveFilePos SavePos(*SrcFile);
int64 SavePos=SrcFile->Tell();
#ifndef SILENT
int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size;
#endif
@ -415,6 +415,8 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
if (Size!=INT64NDF)
Size-=ReadSize;
}
SrcFile->Seek(SavePos,SEEK_SET);
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
uiMsg(UIEVENT_FILESUMEND);

View File

@ -26,7 +26,7 @@ FindFile::~FindFile()
void FindFile::SetMask(const wchar *Mask)
{
wcscpy(FindMask,Mask);
wcsncpyz(FindMask,Mask,ASIZE(FindMask));
FirstCall=true;
}
@ -52,7 +52,7 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
wcsncpyz(DirName,FindMask,ASIZE(DirName));
RemoveNameFromPath(DirName);
if (*DirName==0)
wcscpy(DirName,L".");
wcsncpyz(DirName,L".",ASIZE(DirName));
char DirNameA[NM];
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
if ((dirp=opendir(DirNameA))==NULL)
@ -63,32 +63,32 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
}
while (1)
{
wchar Name[NM];
struct dirent *ent=readdir(dirp);
if (ent==NULL)
return false;
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
continue;
wchar Name[NM];
if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
if (CmpName(FindMask,Name,MATCH_NAMES))
{
wchar FullName[NM];
wcscpy(FullName,FindMask);
wcsncpyz(FullName,FindMask,ASIZE(FullName));
*PointToName(FullName)=0;
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
{
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
return false;
}
wcscat(FullName,Name);
wcsncatz(FullName,Name,ASIZE(FullName));
if (!FastFind(FullName,fd,GetSymLink))
{
ErrHandler.OpenErrorMsg(FullName);
continue;
}
wcscpy(fd->Name,FullName);
wcsncpyz(fd->Name,FullName,ASIZE(fd->Name));
break;
}
}

View File

@ -3,7 +3,12 @@ bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
if (!FileExist(NameExisting))
{
uiMsg(UIERROR_HLINKCREATE,NameNew);
uiMsg(UIERROR_NOLINKTARGET);
ErrHandler.SetErrorCode(RARX_CREATE);
return false;
}
CreatePath(NameNew,true);
#ifdef _WIN_ALL

View File

@ -53,7 +53,7 @@ DataHash::DataHash()
DataHash::~DataHash()
{
#ifdef RAR_SMP
DestroyThreadPool(ThPool);
delete ThPool;
#endif
cleandata(&CurCRC32, sizeof(CurCRC32));
if (blake2ctx!=NULL)
@ -94,7 +94,7 @@ void DataHash::Update(const void *Data,size_t DataSize)
{
#ifdef RAR_SMP
if (MaxThreads>1 && ThPool==NULL)
ThPool=CreateThreadPool();
ThPool=new ThreadPool(BLAKE2_THREADS_NUMBER);
blake2ctx->ThPool=ThPool;
blake2ctx->MaxThreads=MaxThreads;
#endif

View File

@ -14,10 +14,11 @@
#define SIZEOF_UOHEAD 18
#define SIZEOF_STREAMHEAD 26
#define VER_PACK 29
#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29
#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive.
#define VER_PACK 29U
#define VER_PACK5 50U // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29U
#define VER_UNPACK5 50U // It is stored as 0, but we add 50 when reading an archive.
#define VER_UNKNOWN 9999U // Just some large value.
#define MHD_VOLUME 0x0001U
@ -174,7 +175,7 @@ struct MainHeader:BaseBlock
struct FileHeader:BlockHeader
{
byte HostOS;
byte UnpVer;
uint UnpVer; // It is 1 byte in RAR29 and bit field in RAR5.
byte Method;
union {
uint FileAttr;
@ -190,7 +191,7 @@ struct FileHeader:BlockHeader
int64 PackSize;
int64 UnpSize;
int64 MaxSize; // Reserve size bytes for vint of this size.
int64 MaxSize; // Reserve packed and unpacked size bytes for vint of this size.
HashValue FileHash;

View File

@ -71,6 +71,7 @@ void ListArchive(CommandData *Cmd)
*VolNumText=0;
while(Arc.ReadHeader()>0)
{
Wait(); // Allow quit listing with Ctrl+C.
HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType==HEAD_ENDARC)
{
@ -91,7 +92,7 @@ void ListArchive(CommandData *Cmd)
switch(HeaderType)
{
case HEAD_FILE:
FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0;
FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
if (FileMatched)
{
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare);
@ -215,7 +216,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF)
wcscpy(UnpSizeText,L"?");
wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));
else
itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));
itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));
@ -229,13 +230,13 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
wchar RatioStr[10];
if (hd.SplitBefore && hd.SplitAfter)
wcscpy(RatioStr,L"<->");
wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr));
else
if (hd.SplitBefore)
wcscpy(RatioStr,L"<--");
wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr));
else
if (hd.SplitAfter)
wcscpy(RatioStr,L"-->");
wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));
else
swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
@ -344,7 +345,8 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method,
Format==RARFMT15 ? L"1.5":L"5.0",
hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
hd.WinSize>=0x100000 ? L"M":L"K");
@ -466,7 +468,7 @@ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSiz
(A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');
break;
case HSYS_UNKNOWN:
wcscpy(AttrStr,L"?");
wcsncpyz(AttrStr,L"?",AttrSize);
break;
}
}

View File

@ -85,7 +85,7 @@
#define MCHelpSwILOG L"\n ilog[name] Log errors to file"
#define MCHelpSwINUL L"\n inul Disable all messages"
#define MCHelpSwIOFF L"\n ioff[n] Turn PC off after completing an operation"
#define MCHelpSwISND L"\n isnd Enable sound"
#define MCHelpSwISND L"\n isnd[-] Control notification sounds"
#define MCHelpSwIVER L"\n iver Display the version number"
#define MCHelpSwK L"\n k Lock archive"
#define MCHelpSwKB L"\n kb Keep broken extracted files"
@ -127,11 +127,11 @@
#define MCHelpSwT L"\n t Test files after archiving"
#define MCHelpSwTK L"\n tk Keep original archive time"
#define MCHelpSwTL L"\n tl Set archive time to latest file"
#define MCHelpSwTN L"\n tn<time> Process files newer than <time>"
#define MCHelpSwTO L"\n to<time> Process files older than <time>"
#define MCHelpSwTA L"\n ta<date> Process files modified after <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTB L"\n tb<date> Process files modified before <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTS L"\n ts[m|c|a] Save or restore file time (modification, creation, access)"
#define MCHelpSwTN L"\n tn[mcao]<t> Process files newer than <t> time"
#define MCHelpSwTO L"\n to[mcao]<t> Process files older than <t> time"
#define MCHelpSwTA L"\n ta[mcao]<d> Process files modified after <d> YYYYMMDDHHMMSS date"
#define MCHelpSwTB L"\n tb[mcao]<d> Process files modified before <d> YYYYMMDDHHMMSS date"
#define MCHelpSwTS L"\n ts[m,c,a,p] Save or restore time (modification, creation, access, preserve)"
#define MCHelpSwU L"\n u Update files"
#define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes"
#define MCHelpSwVUnr L"\n v List all volumes"
@ -203,7 +203,6 @@
#define MErrOpenFile L"file"
#define MAddNoFiles L"\nWARNING: No files"
#define MMdfEncrSol L"\n%s: encrypted"
#define MCannotMdfEncrSol L"\nCannot modify solid archive containing encrypted files"
#define MAddAnalyze L"\nAnalyzing archived files: "
#define MRepacking L"\nRepacking archived files: "
#define MCRCFailed L"\n%-20s - checksum error"
@ -342,7 +341,7 @@
#define MFAT32Size L"\nWARNING: FAT32 file system does not support 4 GB or larger files"
#define MErrChangeAttr L"\nWARNING: Cannot change attributes of %s"
#define MWrongSFXVer L"\nERROR: default SFX module does not support RAR %d.%d archives"
#define MCannotEncName L"\nCannot encrypt archive already containing encrypted files"
#define MHeadEncMismatch L"\nCannot change the header encryption mode in already encrypted archive"
#define MCannotEmail L"\nCannot email the file %s"
#define MCopyrightS L"\nRAR SFX archive"
#define MSHelpCmd L"\n\n<Commands>"
@ -354,12 +353,13 @@
#define MCannotDelete L"\nCannot delete %s"
#define MRecycleFailed L"\nCannot move some files and folders to Recycle Bin"
#define MCalcCRC L"\nCalculating the checksum"
#define MTooLargeSFXArc L"\nWARNING: Too 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 MNotEnoughDisk L"\nERROR: Not enough disk space for %s."
#define MNewerRAR L"\nYou may need a newer version of RAR."
#define MUnkEncMethod L"\nUnknown encryption method in %s"
#define MWrongPassword L"\nThe specified password is incorrect."
#define MWrongFilePassword L"\nIncorrect password for %s"
#define MAreaDamaged L"\nCorrupt %d bytes at %08x %08x"
#define MBlocksRecovered L"\n%u blocks are recovered, %u blocks are relocated"
#define MRRDamaged L"\nRecovery record is corrupt."
@ -375,6 +375,8 @@
#define MCopyingData L"\nCopying data"
#define MErrCreateLnkS L"\nCannot create symbolic link %s"
#define MErrCreateLnkH L"\nCannot create hard link %s"
#define MErrLnkTarget L"\nYou need to unpack the link target first"
#define MNeedAdmin L"\nYou may need to run RAR as administrator"
#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."

View File

@ -138,7 +138,9 @@ install: install-unrar
uninstall: uninstall-unrar
clean:
@rm -f *.o *.bak *~
@rm -f *.bak *~
@rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ)
@rm -f unrar libunrar.*
unrar: clean $(OBJECTS) $(UNRAR_OBJ)
@rm -f unrar
@ -154,8 +156,7 @@ sfx: clean $(OBJECTS)
lib: WHAT=RARDLL
lib: CXXFLAGS+=$(LIBFLAGS)
lib: clean $(OBJECTS) $(LIB_OBJ)
@rm -f libunrar.so
@rm -f libunrar.a
@rm -f libunrar.*
$(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
$(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ)

View File

@ -25,10 +25,10 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
if (CmpMode!=MATCH_NAMES)
{
size_t WildLength=wcslen(Wildcard);
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && CmpMode!=MATCH_ALLWILD &&
mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0)
{
// For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
// For all modes except MATCH_NAMES, MATCH_EXACT, MATCH_EXACTPATH, MATCH_ALLWILD,
// "path1" mask must match "path1\path2\filename.ext" and "path1" names.
wchar NextCh=Name[WildLength];
if (NextCh==L'\\' || NextCh==L'/' || NextCh==0)
@ -46,6 +46,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
mwcsicompc(Path1,Path2,ForceCase)!=0)
return(false);
if (CmpMode==MATCH_ALLWILD)
return match(Wildcard,Name,ForceCase);
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
if (IsWildcard(Path1))
return(match(Wildcard,Name,ForceCase));
@ -64,8 +66,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
// Always return false for RAR temporary files to exclude them
// from archiving operations.
if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
return(false);
// if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
// return(false);
if (CmpMode==MATCH_EXACT)
return(mwcsicompc(Name1,Name2,ForceCase)==0);

View File

@ -14,6 +14,10 @@ enum {
MATCH_EXACT, // Paths must match exactly.
// Names must match exactly.
MATCH_ALLWILD, // Paths and names are compared using wildcards.
// Unlike MATCH_SUBPATH, paths do not match subdirs
// unless a wildcard tells so.
MATCH_EXACTPATH, // Paths must match exactly.
// Names are compared using wildcards.

View File

@ -22,7 +22,7 @@ void RAROptions::Init()
Method=3;
MsgStream=MSG_STDOUT;
ConvertNames=NAMES_ORIGINALCASE;
xmtime=EXTTIME_HIGH3;
xmtime=EXTTIME_MAX;
FileSizeLess=INT64NDF;
FileSizeMore=INT64NDF;
HashType=HASH_CRC32;

View File

@ -12,11 +12,7 @@ enum PATH_EXCL_MODE {
EXCL_SKIPWHOLEPATH, // -ep (exclude the path completely)
EXCL_BASEPATH, // -ep1 (exclude the base part of path)
EXCL_SAVEFULLPATH, // -ep2 (the full path without the disk letter)
EXCL_ABSPATH, // -ep3 (the full path with the disk letter)
EXCL_SKIPABSPATH // Works as EXCL_BASEPATH for fully qualified paths
// and as EXCL_UNCHANGED for relative paths.
// Used by WinRAR GUI only.
EXCL_ABSPATH // -ep3 (the full path with the disk letter)
};
enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
@ -25,7 +21,7 @@ enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST};
enum EXTTIME_MODE {
EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_HIGH1,EXTTIME_HIGH2,EXTTIME_HIGH3
EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_MAX
};
enum {NAMES_ORIGINALCASE=0,NAMES_UPPERCASE,NAMES_LOWERCASE};
@ -63,11 +59,20 @@ enum SAVECOPY_MODE {
SAVECOPY_DUPLISTEXIT
};
enum APPENDARCNAME_MODE
{
APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR
};
enum POWER_MODE {
POWERMODE_KEEP=0,POWERMODE_OFF,POWERMODE_HIBERNATE,POWERMODE_SLEEP,
POWERMODE_RESTART
};
// Need "forced off" state to turn off sound in GUI command line.
enum SOUND_NOTIFY_MODE {SOUND_NOTIFY_DEFAULT=0,SOUND_NOTIFY_ON,SOUND_NOTIFY_OFF};
struct FilterMode
{
FilterState State;
@ -87,6 +92,12 @@ class RAROptions
uint ExclFileAttr;
uint InclFileAttr;
// We handle -ed and -e+d with special flags instead of attribute mask,
// so it works with both Windows and Unix archives.
bool ExclDir;
bool InclDir;
bool InclAttrSet;
size_t WinSize;
wchar TempPath[NM];
@ -112,7 +123,7 @@ class RAROptions
wchar LogName[NM];
MESSAGE_TYPE MsgStream;
bool Sound;
SOUND_NOTIFY_MODE Sound;
OVERWRITE_MODE Overwrite;
int Method;
HASH_TYPE HashType;
@ -157,14 +168,17 @@ class RAROptions
#ifndef SFX_MODULE
bool GenerateArcName;
wchar GenerateMask[MAX_GENERATE_MASK];
wchar DefGenerateMask[MAX_GENERATE_MASK];
#endif
bool SyncFiles;
bool ProcessEA;
bool SaveStreams;
bool SetCompressedAttr;
bool IgnoreGeneralAttr;
RarTime FileTimeBefore;
RarTime FileTimeAfter;
RarTime FileMtimeBefore,FileCtimeBefore,FileAtimeBefore;
bool FileMtimeBeforeOR,FileCtimeBeforeOR,FileAtimeBeforeOR;
RarTime FileMtimeAfter,FileCtimeAfter,FileAtimeAfter;
bool FileMtimeAfterOR,FileCtimeAfterOR,FileAtimeAfterOR;
int64 FileSizeLess;
int64 FileSizeMore;
bool Lock;
@ -173,11 +187,12 @@ class RAROptions
FilterMode FilterModes[MAX_FILTER_TYPES];
wchar EmailTo[NM];
uint VersionControl;
bool AppendArcNameToPath;
APPENDARCNAME_MODE AppendArcNameToPath;
POWER_MODE Shutdown;
EXTTIME_MODE xmtime;
EXTTIME_MODE xmtime; // Extended time modes (time precision to store).
EXTTIME_MODE xctime;
EXTTIME_MODE xatime;
bool PreserveAtime;
wchar CompressStdin[NM];
uint Threads; // We use it to init hash even if RAR_SMP is not defined.

View File

@ -22,8 +22,22 @@
#ifdef _WIN_ALL
#define STRICT
// We got a report that just "#define STRICT" is incompatible with
// "#define STRICT 1" in Windows 10 SDK minwindef.h and depending on the order
// in which these statements are reached this may cause a compiler warning
// and build break for other projects incorporating this source.
// So we changed it to "#define STRICT 1".
#ifndef STRICT
#define STRICT 1
#endif
// 'ifndef' check here is needed for unrar.dll header to avoid macro
// re-definition warnings in third party projects.
#ifndef UNICODE
#define UNICODE
#endif
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0501

View File

@ -16,7 +16,7 @@ wchar* PointToLastChar(const wchar *Path)
}
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize)
{
const wchar *DestPtr=SrcPath;
@ -25,7 +25,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
DestPtr=s+4;
// Remove <d>:\ and any sequence of . and \ in the beginning of path string.
// Remove any amount of <d>:\ and any sequence of . and \ in the beginning of path string.
while (*DestPtr!=0)
{
const wchar *s=DestPtr;
@ -58,7 +58,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
// so we use the temporary buffer for copying.
wchar TmpStr[NM];
wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
wcscpy(DestPath,TmpStr);
wcsncpyz(DestPath,TmpStr,DestSize);
}
return (wchar *)DestPtr;
}
@ -120,7 +120,14 @@ bool CmpExt(const wchar *Name,const wchar *Ext)
bool IsWildcard(const wchar *Str)
{
return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL;
if (Str==NULL)
return false;
#ifdef _WIN_ALL
// Not treat the special NTFS \\?\d: path prefix as a wildcard.
if (Str[0]=='\\' && Str[1]=='\\' && Str[2]=='?' && Str[3]=='\\')
Str+=4;
#endif
return wcspbrk(Str,L"*?")!=NULL;
}
@ -164,13 +171,16 @@ void AddEndSlash(wchar *Path,size_t MaxLength)
{
size_t Length=wcslen(Path);
if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength)
wcscat(Path,SPATHDIVIDER);
{
Path[Length]=CPATHDIVIDER;
Path[Length+1]=0;
}
}
void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize)
{
// 'Name' and 'Pathname' can point to same memory area. This is why we use
// 'Path', 'Name' and 'Pathname' can point to same memory area. So we use
// the temporary buffer instead of constructing the name in 'Pathname'.
wchar OutName[NM];
wcsncpyz(OutName,Path,ASIZE(OutName));
@ -303,9 +313,13 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
#endif
// Returns a pointer to rightmost digit of volume number.
// Returns a pointer to rightmost digit of volume number or to beginning
// of file name if numeric part is missing.
wchar* GetVolNumPart(const wchar *ArcName)
{
if (*ArcName==0)
return (wchar *)ArcName;
// Pointing to last name character.
const wchar *ChPtr=ArcName+wcslen(ArcName)-1;
@ -346,18 +360,33 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
ChPtr=GetExt(ArcName);
}
else
if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
wcscpy(ChPtr+1,L"rar");
if (ChPtr[1]==0 || wcsicomp(ChPtr,L".exe")==0 || wcsicomp(ChPtr,L".sfx")==0)
wcsncpyz(ChPtr,L".rar",MaxLength-(ChPtr-ArcName));
if (ChPtr==NULL || *ChPtr!='.' || ChPtr[1]==0)
{
// Normally we shall have some extension here. If we don't, it means
// the name has no extension and buffer has no free space to append one.
// Let's clear the name to prevent a new call with same name and return.
*ArcName=0;
return;
}
if (!OldNumbering)
{
ChPtr=GetVolNumPart(ArcName);
// We should not check for IsDigit(*ChPtr) here and should increment
// even non-digits. If we got a corrupt archive with volume flag,
// but without numeric part, we still need to modify its name somehow,
// so while (exist(name)) {NextVolumeName()} loops do not run infinitely.
while ((++(*ChPtr))=='9'+1)
{
*ChPtr='0';
ChPtr--;
if (ChPtr<ArcName || !IsDigit(*ChPtr))
{
// Convert .part:.rar (.part9.rar after increment) to part10.rar.
for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--)
*(EndPtr+1)=*EndPtr;
*(ChPtr+1)='1';
@ -366,15 +395,15 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
}
}
else
if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
wcscpy(ChPtr+2,L"00");
if (!IsDigit(ChPtr[2]) || !IsDigit(ChPtr[3]))
wcsncpyz(ChPtr+2,L"00",MaxLength-(ChPtr-ArcName)-2); // From .rar to .r00.
else
{
ChPtr+=3;
while ((++(*ChPtr))=='9'+1)
if (*(ChPtr-1)=='.')
ChPtr+=wcslen(ChPtr)-1; // Set to last character.
while (++(*ChPtr)=='9'+1)
if (ChPtr<=ArcName || *(ChPtr-1)=='.')
{
*ChPtr='A';
*ChPtr='a'; // From .999 to .a00 if started from .001 or for too short names.
break;
}
else
@ -585,7 +614,6 @@ int ParseVersionFileName(wchar *Name,bool Truncate)
wchar *VerText=wcsrchr(Name,';');
if (VerText!=NULL)
{
if (Version==0)
Version=atoiw(VerText+1);
if (Truncate)
*VerText=0;
@ -652,7 +680,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,b
#ifndef SFX_MODULE
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
{
bool Prefix=false;
if (*GenerateMask=='+')
@ -713,7 +741,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
wchar Ext[NM],*Dot=GetExt(ArcName);
*Ext=0;
if (Dot==NULL)
wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L"");
wcsncpyz(Ext,*PointToName(ArcName)==0 ? L".rar":L"",ASIZE(Ext));
else
{
wcsncpyz(Ext,Dot,ASIZE(Ext));
@ -749,7 +777,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField));
QuoteMode=false;
for (int I=0;Mask[I]!=0;I++)
for (uint I=0;Mask[I]!=0;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
{
@ -810,21 +838,17 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
AddEndSlash(NewName,ASIZE(NewName));
wcsncatz(NewName,DateText,ASIZE(NewName));
wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName));
wcscpy(ArcName,NewName);
wcsncpyz(ArcName,NewName,MaxSize);
}
else
wcscat(ArcName,DateText);
wcscat(ArcName,Ext);
wcsncatz(ArcName,DateText,MaxSize);
wcsncatz(ArcName,Ext,MaxSize);
}
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving)
{
// Must be enough space for archive name plus all stuff in mask plus
// extra overhead produced by mask 'N' (archive number) characters.
// One 'N' character can result in several numbers if we process more
// than 9 archives.
wchar NewName[NM+MAX_GENERATE_MASK+20];
wchar NewName[NM];
uint ArcNumber=1;
while (true) // Loop for 'N' (archive number) processing.
@ -833,7 +857,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
bool ArcNumPresent=false;
GenArcName(NewName,GenerateMask,ArcNumber,ArcNumPresent);
GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber,ArcNumPresent);
if (!ArcNumPresent)
break;
@ -845,7 +869,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
// existing archive before the first unused name. So we generate
// the name for (ArcNumber-1) below.
wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent);
GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber-1,ArcNumPresent);
}
break;
}
@ -895,8 +919,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,Src);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,Src,MaxSize); // "\\?\D:\very long path".
return true;
}
else
@ -904,9 +928,9 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,L"UNC");
wcscpy(Dest+PrefixLength+3,Src+1);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,L"UNC",MaxSize);
wcsncatz(Dest,Src+1,MaxSize); // "\\?\UNC\server\share".
return true;
}
// We may be here only if we modify IsFullPath in the future.
@ -923,9 +947,10 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'.
wcscpy(Dest+PrefixLength+2,Src);
wcsncpyz(Dest,Prefix,MaxSize);
CurDir[2]=0;
wcsncatz(Dest,CurDir,MaxSize); // Copy drive letter 'd:'.
wcsncatz(Dest,Src,MaxSize);
return true;
}
else // Paths in path\name format.
@ -933,8 +958,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
AddEndSlash(CurDir,ASIZE(CurDir));
if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,CurDir);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,CurDir,MaxSize);
if (Src[0]=='.' && IsPathDiv(Src[1])) // Remove leading .\ in pathname.
Src+=2;

View File

@ -3,7 +3,7 @@
wchar* PointToName(const wchar *Path);
wchar* PointToLastChar(const wchar *Path);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize);
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize);
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize);
void SetSFXExt(wchar *SFXName,size_t MaxSize);

View File

@ -67,7 +67,7 @@ void QuickOpen::Load(uint64 BlockPos)
SeekPos=Arc->Tell();
UnsyncSeekPos=false;
SaveFilePos SavePos(*Arc);
int64 SavePos=SeekPos;
Arc->Seek(BlockPos,SEEK_SET);
// If BlockPos points to original main header, we'll have the infinite
@ -83,10 +83,14 @@ void QuickOpen::Load(uint64 BlockPos)
if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
!Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
{
Arc->Seek(SavePos,SEEK_SET);
return;
QLHeaderPos=Arc->CurBlockPos;
}
QOHeaderPos=Arc->CurBlockPos;
RawDataStart=Arc->Tell();
RawDataSize=Arc->SubHead.UnpSize;
Arc->Seek(SavePos,SEEK_SET);
Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
}
@ -172,7 +176,7 @@ bool QuickOpen::Seek(int64 Offset,int Method)
// archive updating involve several passes. So if we detect that file
// pointer is moved back, we reload quick open data from beginning.
if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
Load(QLHeaderPos);
Load(QOHeaderPos);
if (Method==SEEK_SET)
SeekPos=Offset;
@ -201,22 +205,28 @@ bool QuickOpen::Tell(int64 *Pos)
uint QuickOpen::ReadBuffer()
{
SaveFilePos SavePos(*Arc);
int64 SavePos=Arc->Tell();
Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
if (Arc->SubHead.Encrypted)
SizeToRead &= ~CRYPT_BLOCK_MASK;
if (SizeToRead==0)
return 0;
int ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
int ReadSize=0;
if (SizeToRead!=0)
{
ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
if (ReadSize<=0)
return 0;
ReadSize=0;
else
{
#ifndef RAR_NOCRYPT
if (Arc->SubHead.Encrypted)
Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
#endif
RawDataPos+=ReadSize;
ReadBufSize+=ReadSize;
}
}
Arc->Seek(SavePos,SEEK_SET);
return ReadSize;
}
@ -250,10 +260,10 @@ bool QuickOpen::ReadRaw(RawRead &Raw)
return false;
}
// If rest of block data crosses buffer boundary, read it in loop.
size_t DataLeft=ReadBufSize-ReadBufPos;
// If rest of block data crosses Buf boundary, read it in loop.
while (SizeToRead>0)
{
size_t DataLeft=ReadBufSize-ReadBufPos;
size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
Raw.Read(Buf+ReadBufPos,CurSizeToRead);
ReadBufPos+=CurSizeToRead;
@ -280,9 +290,11 @@ bool QuickOpen::ReadNext()
uint Flags=(uint)Raw.GetV();
uint64 Offset=Raw.GetV();
size_t HeaderSize=(size_t)Raw.GetV();
if (HeaderSize>MAX_HEADER_SIZE_RAR5)
return false;
LastReadHeader.Alloc(HeaderSize);
Raw.GetB(&LastReadHeader[0],HeaderSize);
// Calculate the absolute position as offset from quick open service header.
LastReadHeaderPos=QLHeaderPos-Offset;
LastReadHeaderPos=QOHeaderPos-Offset;
return true;
}

View File

@ -29,20 +29,20 @@ class QuickOpen
QuickOpenItem *ListStart;
QuickOpenItem *ListEnd;
byte *Buf;
static const size_t MaxBufSize=0x10000; // Must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize;
byte *Buf; // Read quick open data here.
static const size_t MaxBufSize=0x10000; // Buf size, must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize; // Current size of buffered data in write mode.
#ifndef RAR_NOCRYPT // For shell extension.
CryptData Crypt;
#endif
bool Loaded;
uint64 QLHeaderPos;
uint64 RawDataStart;
uint64 RawDataSize;
uint64 RawDataPos;
size_t ReadBufSize;
size_t ReadBufPos;
uint64 QOHeaderPos; // Main QO header position.
uint64 RawDataStart; // Start of QO data, just after the main header.
uint64 RawDataSize; // Size of entire QO data.
uint64 RawDataPos; // Current read position in QO data.
size_t ReadBufSize; // Size of Buf data currently read from QO.
size_t ReadBufPos; // Current read position in Buf data.
Array<byte> LastReadHeader;
uint64 LastReadHeaderPos;
uint64 SeekPos;

View File

@ -37,7 +37,7 @@ int main(int argc, char *argv[])
CommandData *Cmd=new CommandData;
#ifdef SFX_MODULE
wcscpy(Cmd->Command,L"X");
wcsncpyz(Cmd->Command,L"X",ASIZE(Cmd->Command));
char *Switch=argc>1 ? argv[1]:NULL;
if (Switch!=NULL && Cmd->IsSwitch(Switch[0]))
{
@ -68,6 +68,8 @@ int main(int argc, char *argv[])
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ShutdownOnClose=Cmd->Shutdown;
if (ShutdownOnClose)
ShutdownCheckAnother(true);
#endif
uiInit(Cmd->Sound);
@ -75,13 +77,6 @@ int main(int argc, char *argv[])
ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL);
Cmd->OutTitle();
/*
byte Buf[10000];
File Src;
Src.TOpen(L"123.rar");
int Size=Src.Read(Buf,sizeof(Buf));
Cmd->SetArcInMem(Buf,Size);
*/
Cmd->ProcessCommand();
delete Cmd;
}
@ -100,7 +95,8 @@ int main(int argc, char *argv[])
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled())
if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled() &&
!ShutdownCheckAnother(false))
Shutdown(ShutdownOnClose);
#endif
ErrHandler.MainExit=true;

View File

@ -39,7 +39,6 @@
#include "filestr.hpp"
#include "find.hpp"
#include "scantree.hpp"
#include "savepos.hpp"
#include "getbits.hpp"
#include "rdwrfn.hpp"
#ifdef USE_QOPEN
@ -77,6 +76,9 @@
#include "rs.hpp"
#include "rs16.hpp"
#include "recvol.hpp"
#include "volume.hpp"
#include "smallfn.hpp"

View File

@ -21,15 +21,12 @@ typedef wchar_t wchar; // Unicode character
// Maximum int64 value.
#define MAX_INT64 int64(INT32TO64(0x7fffffff,0xffffffff))
// Special int64 value, large enough to never be found in real life.
// Special int64 value, large enough to never be found in real life
// and small enough to fit to both signed and unsigned 64-bit ints.
// We use it in situations, when we need to indicate that parameter
// is not defined and probably should be calculated inside of function.
// Lower part is intentionally 0x7fffffff, not 0xffffffff, to make it
// compatible with 32 bit int64.
// compatible with 32 bit int64 if 64 bit type is not supported.
#define INT64NDF INT32TO64(0x7fffffff,0x7fffffff)
// Maximum uint64 value.
#define MAX_UINT64 INT32TO64(0xffffffff,0xffffffff)
#define UINT64NDF MAX_UINT64
#endif

View File

@ -25,6 +25,7 @@ void ComprDataIO::Init()
NextVolumeMissing=false;
SrcFile=NULL;
DestFile=NULL;
UnpWrAddr=NULL;
UnpWrSize=0;
Command=NULL;
Encryption=false;

View File

@ -3,6 +3,7 @@
class CmdAdd;
class Unpack;
class ArcFileSearch;
#if 0
// We use external i/o calls for Benchmark command.

View File

@ -31,12 +31,12 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
// handling exceptions. So it can close and delete files on Cancel.
if (Fmt==RARFMT15)
{
RecVolumes3 RecVol(false);
RecVolumes3 RecVol(Cmd,false);
return RecVol.Restore(Cmd,Name,Silent);
}
else
{
RecVolumes5 RecVol(false);
RecVolumes5 RecVol(Cmd,false);
return RecVol.Restore(Cmd,Name,Silent);
}
}
@ -100,12 +100,12 @@ void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
RevFile.Close();
if (Rev5)
{
RecVolumes5 RecVol(true);
RecVolumes5 RecVol(Cmd,true);
RecVol.Test(Cmd,Name);
}
else
{
RecVolumes3 RecVol(true);
RecVolumes3 RecVol(Cmd,true);
RecVol.Test(Cmd,Name);
}
}

View File

@ -14,7 +14,7 @@ class RecVolumes3
ThreadPool *RSThreadPool;
#endif
public:
RecVolumes3(bool TestOnly);
RecVolumes3(RAROptions *Cmd,bool TestOnly);
~RecVolumes3();
void Make(RAROptions *Cmd,wchar *ArcName);
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
@ -71,11 +71,12 @@ class RecVolumes5
#ifdef RAR_SMP
ThreadPool *RecThreadPool;
#endif
RecRSThreadData ThreadData[MaxPoolThreads]; // Store thread parameters.
uint MaxUserThreads; // Maximum number of threads defined by user.
RecRSThreadData *ThreadData; // Array to store thread parameters.
public: // 'public' only because called from thread functions.
void ProcessAreaRS(RecRSThreadData *td);
public:
RecVolumes5(bool TestOnly);
RecVolumes5(RAROptions *Cmd,bool TestOnly);
~RecVolumes5();
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
void Test(RAROptions *Cmd,const wchar *Name);

View File

@ -36,7 +36,7 @@ THREAD_PROC(RSDecodeThread)
}
#endif
RecVolumes3::RecVolumes3(bool TestOnly)
RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
{
memset(SrcFile,0,sizeof(SrcFile));
if (TestOnly)
@ -50,7 +50,7 @@ RecVolumes3::RecVolumes3(bool TestOnly)
Buf.Alloc(TotalBufferSize);
memset(SrcFile,0,sizeof(SrcFile));
#ifdef RAR_SMP
RSThreadPool=CreateThreadPool();
RSThreadPool=new ThreadPool(Cmd->Threads);
#endif
}
}
@ -61,7 +61,7 @@ RecVolumes3::~RecVolumes3()
for (size_t I=0;I<ASIZE(SrcFile);I++)
delete SrcFile[I];
#ifdef RAR_SMP
DestroyThreadPool(RSThreadPool);
delete RSThreadPool;
#endif
}
@ -111,7 +111,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
NewStyle=IsNewStyleRev(ArcName);
while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_'))
Ext--;
wcscpy(Ext,L"*.*");
wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName));
FindFile Find;
Find.SetMask(ArcName);
@ -235,7 +235,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
}
RecVolNumber=P[1];
FileNumber=P[2];
wcscpy(PrevName,CurName);
wcsncpyz(PrevName,CurName,ASIZE(PrevName));
File *NewFile=new File;
NewFile->TOpen(CurName);
SrcFile[FileNumber+P[0]-1]=NewFile;
@ -247,7 +247,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (!Silent || FoundRecVolumes!=0)
uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
if (FoundRecVolumes==0)
return(false);
return false;
bool WriteFlags[256];
memset(WriteFlags,0,sizeof(WriteFlags));
@ -290,8 +290,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
{
NewFile->Close();
wchar NewName[NM];
wcscpy(NewName,ArcName);
wcscat(NewName,L".bad");
wcsncpyz(NewName,ArcName,ASIZE(NewName));
wcsncatz(NewName,L".bad",ASIZE(NewName));
uiMsg(UIMSG_BADARCHIVE,ArcName);
uiMsg(UIMSG_RENAMING,ArcName,NewName);
@ -322,7 +322,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
MissingVolumes++;
if (CurArcNum==FileNumber-1)
wcscpy(LastVolName,ArcName);
wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName));
uiMsg(UIMSG_MISSINGVOL,ArcName);
uiMsg(UIEVENT_NEWARCHIVE,ArcName);
@ -363,11 +363,10 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
#ifdef RAR_SMP
uint ThreadNumber=Cmd->Threads;
RSEncode rse[MaxPoolThreads];
#else
uint ThreadNumber=1;
RSEncode rse[1];
#endif
RSEncode *rse=new RSEncode[ThreadNumber];
for (uint I=0;I<ThreadNumber;I++)
rse[I].Init(RecVolNumber);
@ -438,6 +437,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (WriteFlags[I])
SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
}
delete[] rse;
for (int I=0;I<RecVolNumber+FileNumber;I++)
if (SrcFile[I]!=NULL)
{

View File

@ -1,6 +1,6 @@
static const uint MaxVolumes=65535;
RecVolumes5::RecVolumes5(bool TestOnly)
RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly)
{
RealBuf=NULL;
RealReadBuffer=NULL;
@ -10,7 +10,14 @@ RecVolumes5::RecVolumes5(bool TestOnly)
TotalCount=0;
RecBufferSize=0;
for (uint I=0;I<ASIZE(ThreadData);I++)
#ifdef RAR_SMP
MaxUserThreads=Cmd->Threads;
#else
MaxUserThreads=1;
#endif
ThreadData=new RecRSThreadData[MaxUserThreads];
for (uint I=0;I<MaxUserThreads;I++)
{
ThreadData[I].RecRSPtr=this;
ThreadData[I].RS=NULL;
@ -25,7 +32,7 @@ RecVolumes5::RecVolumes5(bool TestOnly)
else
{
#ifdef RAR_SMP
RecThreadPool=CreateThreadPool();
RecThreadPool=new ThreadPool(MaxUserThreads);
#endif
RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT];
Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT);
@ -39,10 +46,11 @@ RecVolumes5::~RecVolumes5()
delete[] RealReadBuffer;
for (uint I=0;I<RecItems.Size();I++)
delete RecItems[I].f;
for (uint I=0;I<ASIZE(ThreadData);I++)
for (uint I=0;I<MaxUserThreads;I++)
delete ThreadData[I].RS;
delete[] ThreadData;
#ifdef RAR_SMP
DestroyThreadPool(RecThreadPool);
delete RecThreadPool;
#endif
}
@ -68,11 +76,7 @@ void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint M
RS.UpdateECC(DataNum, I, Data, Buf+I*RecBufferSize, MaxRead);
*/
#ifdef RAR_SMP
uint ThreadNumber=Cmd->Threads;
#else
uint ThreadNumber=1;
#endif
uint ThreadNumber=MaxUserThreads;
const uint MinThreadBlock=0x1000;
ThreadNumber=Min(ThreadNumber,MaxRead/MinThreadBlock);
@ -139,12 +143,10 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
wcsncpyz(ArcName,Name,ASIZE(ArcName));
wchar *Num=GetVolNumPart(ArcName);
if (Num==ArcName)
return false; // Number part is missing in the name.
while (Num>ArcName && IsDigit(*(Num-1)))
Num--;
if (Num==ArcName)
return false; // Entire volume name is numeric, not possible for REV file.
return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume.
wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
wchar FirstVolName[NM];
@ -240,7 +242,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
uiMsg(UIMSG_STRING,Item->Name);
uint RevCRC;
CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS);
CalcFileSum(Item->f,&RevCRC,NULL,MaxUserThreads,INT64NDF,CALCFSUM_CURPOS);
Item->Valid=RevCRC==Item->CRC;
if (!Item->Valid)
{
@ -289,8 +291,8 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Item->f->Close();
wchar NewName[NM];
wcscpy(NewName,Item->Name);
wcscat(NewName,L".bad");
wcsncpyz(NewName,Item->Name,ASIZE(NewName));
wcsncatz(NewName,L".bad",ASIZE(NewName));
uiMsg(UIMSG_BADARCHIVE,Item->Name);
uiMsg(UIMSG_RENAMING,Item->Name,NewName);

View File

@ -2,6 +2,8 @@
#ifndef RARDLL
const wchar* St(MSGID StringId)
{

View File

@ -75,11 +75,20 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
// Check SSE here instead of constructor, so if object is a part of some
// structure memset'ed before use, this variable is not lost.
int CPUInfo[4];
__cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function.
if ((CPUInfo[0] & 0x7fffffff)>=1)
{
__cpuid(CPUInfo, 1);
AES_NI=(CPUInfo[2] & 0x2000000)!=0;
}
else
AES_NI=0;
#endif
uint uKeyLenInBytes;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
uint uKeyLenInBytes=0;
switch(keyLen)
{
case 128:

View File

@ -14,14 +14,27 @@ class SaveFilePos
}
~SaveFilePos()
{
// If file is already closed by current exception processing,
// we would get uneeded error messages and an exception inside of
// exception and terminate if we try to seek without checking
// if file is still opened. We should not also restore the position
// if external code closed the file on purpose.
// Unless the file is already closed either by current exception
// processing or intentionally by external code.
if (SaveFile->IsOpened())
{
try
{
SaveFile->Seek(SavePos,SEEK_SET);
}
catch(RAR_EXIT)
{
// Seek() can throw an exception and it terminates process
// if we are already processing another exception. Also in C++ 11
// an exception in destructor always terminates process unless
// we mark destructor with noexcept(false). So we do not want to
// throw here. To prevent data loss we do not want to continue
// execution after seek error, so we close the file.
// Any next access to this file will return an error.
SaveFile->Close();
}
}
}
};
#endif

View File

@ -142,7 +142,12 @@ bool ScanTree::GetFilteredMask()
bool WildcardFound=false;
uint FolderWildcardCount=0;
uint SlashPos=0;
for (int I=0;CurMask[I]!=0;I++)
uint StartPos=0;
#ifdef _WIN_ALL // Not treat the special NTFS \\?\d: path prefix as a wildcard.
if (CurMask[0]=='\\' && CurMask[1]=='\\' && CurMask[2]=='?' && CurMask[3]=='\\')
StartPos=4;
#endif
for (uint I=StartPos;CurMask[I]!=0;I++)
{
if (CurMask[I]=='?' || CurMask[I]=='*')
WildcardFound=true;
@ -171,7 +176,7 @@ bool ScanTree::GetFilteredMask()
wchar Filter[NM];
// Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders.
wcscpy(Filter,L"*");
wcsncpyz(Filter,L"*",ASIZE(Filter));
AddEndSlash(Filter,ASIZE(Filter));
// SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*'
wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos;
@ -360,7 +365,7 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
wcsncpyz(CurMask,Mask+1,ASIZE(CurMask));
else
{
*(PrevSlash+1)=0;
*PrevSlash=0;
wcsncatz(CurMask,Mask,ASIZE(CurMask));
}
}

View File

@ -64,7 +64,7 @@ class ScanTree
ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs);
~ScanTree();
SCAN_CODE GetNext(FindData *FindData);
size_t GetSpecPathLength() {return SpecPathLength;};
size_t GetSpecPathLength() {return SpecPathLength;}
int GetErrors() {return Errors;};
void SetErrArcName(const wchar *Name) {wcsncpyz(ErrArcName,Name,ASIZE(ErrArcName));}
void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;}

View File

@ -241,8 +241,8 @@ uint GetDigits(uint Number)
bool LowAscii(const char *Str)
{
for (int I=0;Str[I]!=0;I++)
if ((byte)Str[I]<32 || (byte)Str[I]>127)
for (size_t I=0;Str[I]!=0;I++)
if (/*(byte)Str[I]<32 || */(byte)Str[I]>127)
return false;
return true;
}
@ -250,11 +250,11 @@ bool LowAscii(const char *Str)
bool LowAscii(const wchar *Str)
{
for (int I=0;Str[I]!=0;I++)
for (size_t I=0;Str[I]!=0;I++)
{
// We convert wchar_t to uint just in case if some compiler
// uses signed wchar_t.
if ((uint)Str[I]<32 || (uint)Str[I]>127)
if (/*(uint)Str[I]<32 || */(uint)Str[I]>127)
return false;
}
return true;
@ -281,53 +281,49 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n)
}
// Safe strncpy: copies maxlen-1 max and always returns zero terminated dest.
char* strncpyz(char *dest, const char *src, size_t maxlen)
// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest.
void strncpyz(char *dest, const char *src, size_t maxlen)
{
if (maxlen>0)
{
strncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
while (--maxlen>0 && *src!=0)
*dest++=*src++;
*dest=0;
}
return dest;
}
// Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest.
wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest.
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
{
if (maxlen>0)
{
wcsncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
while (--maxlen>0 && *src!=0)
*dest++=*src++;
*dest=0;
}
return dest;
}
// Safe strncat: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. Note that 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with standard strncat.
char* strncatz(char* dest, const char* src, size_t maxlen)
// Safe append: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with wcsncat.
void strncatz(char* dest, const char* src, size_t maxlen)
{
size_t Length = strlen(dest);
int avail=int(maxlen - Length - 1);
if (avail > 0)
strncat(dest, src, avail);
return dest;
size_t length = strlen(dest);
if (maxlen > length)
strncpyz(dest + length, src, maxlen - length);
}
// Safe wcsncat: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. Note that 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with standard wcsncat.
wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen)
// Safe append: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with wcsncat.
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen)
{
size_t Length = wcslen(dest);
int avail=int(maxlen - Length - 1);
if (avail > 0)
wcsncat(dest, src, avail);
return dest;
size_t length = wcslen(dest);
if (maxlen > length)
wcsncpyz(dest + length, src, maxlen - length);
}

View File

@ -16,10 +16,10 @@ wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
char* strncpyz(char *dest, const char *src, size_t maxlen);
wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
char* strncatz(char* dest, const char* src, size_t maxlen);
wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
void strncpyz(char *dest, const char *src, size_t maxlen);
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
void strncatz(char* dest, const char* src, size_t maxlen);
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
unsigned char etoupper(unsigned char ch);
wchar etoupperw(wchar ch);

View File

@ -80,7 +80,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
{
uint t=SASize << 20;
if (SubAllocatorSize == t)
return TRUE;
return true;
StopSubAllocator();
// Original algorithm expects FIXED_UNIT_SIZE, but actual structure size
@ -91,7 +91,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
{
ErrHandler.MemoryError();
return FALSE;
return false;
}
// HeapEnd did not present in original algorithm. We added it to control
@ -99,7 +99,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
SubAllocatorSize=t;
return TRUE;
return true;
}

View File

@ -77,7 +77,7 @@ class SubAllocator
inline void* ExpandUnits(void* ptr,int OldNU);
inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU);
inline void FreeUnits(void* ptr,int OldNU);
long GetAllocatedMemory() {return(SubAllocatorSize);};
long GetAllocatedMemory() {return(SubAllocatorSize);}
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
};

View File

@ -123,6 +123,28 @@ void Shutdown(POWER_MODE Mode)
if (Mode==POWERMODE_RESTART)
ExitWindowsEx(EWX_REBOOT|EWX_FORCE,SHTDN_REASON_FLAG_PLANNED);
}
bool ShutdownCheckAnother(bool Open)
{
const wchar *EventName=L"rar -ioff";
static HANDLE hEvent=NULL;
bool Result=false; // Return false if no other RAR -ioff are running.
if (Open) // Create or open the event.
hEvent=CreateEvent(NULL,FALSE,FALSE,EventName);
else
{
if (hEvent!=NULL)
CloseHandle(hEvent); // Close our event.
// Check if other copies still own the event. While race conditions
// are possible, they are improbable and their harm is minimal.
hEvent=CreateEvent(NULL,FALSE,FALSE,EventName);
Result=GetLastError()==ERROR_ALREADY_EXISTS;
if (hEvent!=NULL)
CloseHandle(hEvent);
}
return Result;
}
#endif
@ -165,9 +187,19 @@ SSE_VERSION _SSE_Version=GetSSEVersion();
SSE_VERSION GetSSEVersion()
{
int CPUInfo[4];
__cpuid(CPUInfo, 0x80000000);
// Maximum supported cpuid function. For example, Pentium M 755 returns 4 here.
uint MaxSupported=CPUInfo[0] & 0x7fffffff;
if (MaxSupported>=7)
{
__cpuid(CPUInfo, 7);
if ((CPUInfo[1] & 0x20)!=0)
return SSE_AVX2;
}
if (MaxSupported>=1)
{
__cpuid(CPUInfo, 1);
if ((CPUInfo[2] & 0x80000)!=0)
return SSE_SSE41;
@ -177,6 +209,7 @@ SSE_VERSION GetSSEVersion()
return SSE_SSE2;
if ((CPUInfo[3] & 0x2000000)!=0)
return SSE_SSE;
}
return SSE_NONE;
}
#endif

View File

@ -23,6 +23,7 @@ clock_t MonoClock();
void Wait();
bool EmailFile(const wchar *FileName,const wchar *MailToW);
void Shutdown(POWER_MODE Mode);
bool ShutdownCheckAnother(bool Open);
#ifdef _WIN_ALL
HMODULE WINAPI LoadSysLibrary(const wchar *Name);

View File

@ -1,7 +1,3 @@
// Typically we use the same global thread pool for all RAR modules.
static ThreadPool *GlobalPool=NULL;
static uint GlobalPoolUseCount=0;
static inline bool CriticalSectionCreate(CRITSECT_HANDLE *CritSection)
{
#ifdef _WIN_ALL
@ -43,57 +39,6 @@ static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection)
}
static struct GlobalPoolCreateSync
{
CRITSECT_HANDLE CritSection;
GlobalPoolCreateSync() { CriticalSectionCreate(&CritSection); }
~GlobalPoolCreateSync() { CriticalSectionDelete(&CritSection); }
} PoolCreateSync;
ThreadPool* CreateThreadPool()
{
CriticalSectionStart(&PoolCreateSync.CritSection);
if (GlobalPoolUseCount++ == 0)
GlobalPool=new ThreadPool(MaxPoolThreads);
// We use a simple thread pool, which does not allow to add tasks from
// different functions and threads in the same time. It is ok for RAR,
// but UnRAR.dll can be used in multithreaded environment. So if one of
// threads requests a copy of global pool and another copy is already
// in use, we create and return a new pool instead of existing global.
if (GlobalPoolUseCount > 1)
{
ThreadPool *Pool = new ThreadPool(MaxPoolThreads);
CriticalSectionEnd(&PoolCreateSync.CritSection);
return Pool;
}
CriticalSectionEnd(&PoolCreateSync.CritSection);
return GlobalPool;
}
void DestroyThreadPool(ThreadPool *Pool)
{
if (Pool!=NULL)
{
CriticalSectionStart(&PoolCreateSync.CritSection);
if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0)
delete GlobalPool;
// To correctly work in multithreaded environment UnRAR.dll creates
// new pools if global pool is already in use. We delete such pools here.
if (Pool!=GlobalPool)
delete Pool;
CriticalSectionEnd(&PoolCreateSync.CritSection);
}
}
static THREAD_HANDLE ThreadCreate(NATIVE_THREAD_PTR Proc,void *Data)
{
#ifdef _UNIX

View File

@ -170,12 +170,13 @@ void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
CreateThreads();
// If queue is full, wait until it is empty.
if ((QueueTop + 1) % ASIZE(TaskQueue) == QueueBottom)
if (ActiveThreads>=ASIZE(TaskQueue))
WaitDone();
TaskQueue[QueueTop].Proc = Proc;
TaskQueue[QueueTop].Param = Data;
QueueTop = (QueueTop + 1) % ASIZE(TaskQueue);
ActiveThreads++;
}
@ -184,9 +185,6 @@ void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
// are sleeping yet.
void ThreadPool::WaitDone()
{
// We add ASIZE(TaskQueue) for case if TaskQueue array size is not
// a power of two. Negative numbers would not suit our purpose here.
ActiveThreads=(QueueTop+ASIZE(TaskQueue)-QueueBottom) % ASIZE(TaskQueue);
if (ActiveThreads==0)
return;
#ifdef _WIN_ALL

View File

@ -4,7 +4,10 @@
#ifndef RAR_SMP
const uint MaxPoolThreads=1; // For single threaded version.
#else
const uint MaxPoolThreads=32;
// We need to use the processor groups API to increase it beyond 64.
// Also be sure to check and adjust if needed per thread and total block size
// when compressing if going above 64.
const uint MaxPoolThreads=64;
#ifdef _UNIX
@ -98,9 +101,6 @@ class ThreadPool
#endif
};
ThreadPool* CreateThreadPool();
void DestroyThreadPool(ThreadPool *Pool);
#endif // RAR_SMP
#endif // _RAR_THREADPOOL_

View File

@ -236,7 +236,7 @@ void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS)
else
{
// We use escape before '?' to avoid weird C trigraph characters.
wcscpy(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?");
wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize);
}
}
@ -271,7 +271,7 @@ void RarTime::SetIsoText(const wchar *TimeText)
void RarTime::SetAgeText(const wchar *TimeText)
{
uint Seconds=0,Value=0;
for (int I=0;TimeText[I]!=0;I++)
for (uint I=0;TimeText[I]!=0;I++)
{
int Ch=TimeText[I];
if (IsDigit(Ch))

Some files were not shown because too many files have changed in this diff Show More