mirror of
https://github.com/php-win-ext/php-rar.git
synced 2026-03-24 13:02:06 +01:00
Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4d66343e7 | ||
|
|
2ef087bd9e | ||
|
|
d9bc8cd4c5 | ||
|
|
60eaceb6ee | ||
|
|
b6d9dc8eae | ||
|
|
d58737756c | ||
|
|
b79e6491b5 | ||
|
|
1f1baf4fc1 | ||
|
|
4e914be013 | ||
|
|
05c8e5e675 | ||
|
|
b482f2f156 | ||
|
|
4115c69fe2 | ||
|
|
ea74acb27b | ||
|
|
1b6a2a5aa4 | ||
|
|
e5b9669359 | ||
|
|
89ac57cd59 | ||
|
|
440d2a14c8 | ||
|
|
a169ed937e | ||
|
|
10e3e3222a | ||
|
|
055906e455 | ||
|
|
2d3b968d23 | ||
|
|
371536d3a8 | ||
|
|
3f536c9f9d | ||
|
|
ff2aa63dbf | ||
|
|
0cace1db4b | ||
|
|
0c05fac324 | ||
|
|
ae9a4623fe | ||
|
|
88773b47f1 | ||
|
|
5e74ad9803 | ||
|
|
f6650b4abe | ||
|
|
be202cc5b1 | ||
|
|
6a2ec1ccfc | ||
|
|
eb1a919fb9 | ||
|
|
5e063a9626 | ||
|
|
4a4e67ec33 | ||
|
|
3dcba946ab | ||
|
|
77cc02a1db | ||
|
|
0131eef66c | ||
|
|
823315f6d6 | ||
|
|
40a7872954 | ||
|
|
9babd4f983 | ||
|
|
366007b41a | ||
|
|
320f84b6ae | ||
|
|
899eb2cedd | ||
|
|
d21e05b1f7 | ||
|
|
1c76380291 | ||
|
|
55a566364a | ||
|
|
5823bb16b5 | ||
|
|
9a5d712d99 | ||
|
|
95fe328cc2 | ||
|
|
0a08604b53 | ||
|
|
9f17788011 | ||
|
|
a657432560 | ||
|
|
abb9fa4632 | ||
|
|
b810988366 | ||
|
|
294d87a695 | ||
|
|
f57721dbb3 | ||
|
|
094a536987 | ||
|
|
340695bebb | ||
|
|
e63362d16a | ||
|
|
cc7d8e8c40 | ||
|
|
d2b82835c4 | ||
|
|
571deeda60 | ||
|
|
412c7bf024 | ||
|
|
4594bd1cd1 | ||
|
|
3fcd7f12fe | ||
|
|
efddae46a9 | ||
|
|
63a7b8bbbb | ||
|
|
d7a5b2c8f0 | ||
|
|
2f979b4b64 | ||
|
|
0922854405 | ||
|
|
b7ec361367 | ||
|
|
1502c092f0 | ||
|
|
c00e9c1493 | ||
|
|
f367a22fe3 |
88
.clang-format
Normal file
88
.clang-format
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
# Formatting style for php-rar C source files.
|
||||
# Does NOT apply to unrar/ (see unrar/.clang-format).
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Indentation: real tabs, width 4 (matches vim modeline: noet sw=4 ts=4)
|
||||
UseTab: Always
|
||||
TabWidth: 4
|
||||
IndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
|
||||
# Disable line-length wrapping to preserve hand-formatted long lines
|
||||
ColumnLimit: 0
|
||||
|
||||
# Brace style:
|
||||
# - Functions: brace on its own line (Allman)
|
||||
# - Structs/unions/enums/extern "C": brace attached (K&R)
|
||||
# - Control statements: brace attached (K&R)
|
||||
# - else/else if: on its own line (after closing })
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
|
||||
# Preserve indentation of preprocessor directives (# include, # define inside #ifdef)
|
||||
IndentPPDirectives: AfterHash
|
||||
PPIndentWidth: 1
|
||||
|
||||
# Pointer star attached to variable name: char *ptr
|
||||
PointerAlignment: Right
|
||||
DerivePointerAlignment: false
|
||||
|
||||
# Spaces
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceAfterCStyleCast: true
|
||||
SpacesInParentheses: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
|
||||
# Don't align backslashes in multi-line macros (just 1 space before \)
|
||||
AlignEscapedNewlines: DontAlign
|
||||
|
||||
# ZEND_BEGIN/END_ARG_INFO_EX act as block delimiters so ZEND_ARG_INFO lines
|
||||
# inside them keep their indentation.
|
||||
MacroBlockBegin: "^ZEND_BEGIN_ARG_INFO"
|
||||
MacroBlockEnd: "^ZEND_END_ARG_INFO"
|
||||
|
||||
# Align continuation arguments after opening paren; when ( is last on the line,
|
||||
# fall back to a block indent (ContinuationIndentWidth).
|
||||
AlignAfterOpenBracket: Align
|
||||
|
||||
# Preserve existing include order
|
||||
SortIncludes: Never
|
||||
|
||||
# case labels are indented one level inside switch
|
||||
IndentCaseLabels: true
|
||||
|
||||
# Don't collapse or expand short constructs
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
|
||||
# Alignment: leave hand-aligned blocks alone
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignTrailingComments: false
|
||||
|
||||
# Blank lines
|
||||
MaxEmptyLinesToKeep: 2
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
27
.github/docker-image-shas.yml
vendored
Normal file
27
.github/docker-image-shas.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Docker image SHA lock file.
|
||||
# Maps image tags to their multi-arch OCI index digests (amd64 + arm64).
|
||||
# Regenerate with: .github/scripts/update-docker-shas.sh
|
||||
|
||||
datadog/dd-appsec-php-ci:
|
||||
php-7.0-debug: "sha256:0a9aaeaf79bd4c578eac6dedabf6ac131537266f44562158ce67fdb37c794916"
|
||||
php-7.0-release-zts: "sha256:4bb5fac6fbd3124234d062328c68f6c51027aa95f13e4e8b14afd7c8de518ec6"
|
||||
php-7.1-debug: "sha256:500007ad057d9e71b2bb9079a2f8ba3f1ecfbb26d112db69e17d6007b4e857b5"
|
||||
php-7.1-release-zts: "sha256:d997b9f99c28967872bd0949f8572b089daaadb6ceaa1e856ccc76e07e2ba6b7"
|
||||
php-7.2-debug: "sha256:4c5f111f8e84fcb7dcc9e3cc13e1277d0702b04cd33286ce33db885485d1f025"
|
||||
php-7.2-release-zts: "sha256:634b857d74c3d77b88986ceb088be2dd5bc30151bc08c2b536443984e6659d6e"
|
||||
php-7.3-debug: "sha256:efa81f79783097478a434578226fe9a3b8fe84abda33168034aaea60c197c73b"
|
||||
php-7.3-release-zts: "sha256:c713df299596a9615f88cfe73c29b0a1f9faf32e5e6fa62fa07ee839313cd57e"
|
||||
php-7.4-debug: "sha256:b8a9e982179189122d73feb896c1a1e8578a92fc9a023dabc825f45db8299c22"
|
||||
php-7.4-release-zts: "sha256:6492e3334e722b106352180ec9f0cbee8dd81f008e3537d03f4b8da3522f49e1"
|
||||
php-8.0-debug: "sha256:900ceae7487db1e3652de2880c181e572fdf053673bcda8ff47abf664ff74d39"
|
||||
php-8.0-release-zts: "sha256:b6243199f6aea0792a97583c9036f0b191ad9efb96ea337632fbaca76289a4da"
|
||||
php-8.1-debug: "sha256:1a1e5b44cf043e59768c65fd7c94aaefdacde5fa96d83102d35db11ad86f24c6"
|
||||
php-8.1-release-zts: "sha256:5b8a269b4228d9191420059daef820b660110be0aca6776557924172fd1ff0c8"
|
||||
php-8.2-debug: "sha256:52ad14560672fc8c5130f5758bbee3fa401bc1d35b412f4a230c6258143291a5"
|
||||
php-8.2-release-zts: "sha256:cb143d915b394f16a2d78018765705460f3d1b788fdd2a90ef50fad5f8f5918c"
|
||||
php-8.3-debug: "sha256:bb6df08160126374d3d9247428928aa19a9c2b2429c98356650199b85ae20212"
|
||||
php-8.3-release-zts: "sha256:e58e25a017f75df82691d408b8cb70453875ff36718e295ee8c6653a0f117331"
|
||||
php-8.4-debug: "sha256:15045688f6986f4625b1507a7f4be6104e7bbb88caf877f1611463b929f2bca2"
|
||||
php-8.4-release-zts: "sha256:8e0ac25a3306b4b9f692c593b8a509cc789c2e001ce52682928065a92c880136"
|
||||
php-8.5-debug: "sha256:bd0170331b34fb469e29d00b19b20fb88b726160f76df274a1bdc3a27ac18d30"
|
||||
php-8.5-release-zts: "sha256:e071b2095da55bd24686209422f43a01c65acfc6021f04156d9fb43fd3d4d426"
|
||||
35
.github/scripts/build-and-test.sh
vendored
Executable file
35
.github/scripts/build-and-test.sh
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# Build the extension and run the test suite.
|
||||
# Expected to run inside a datadog/dd-appsec-php-ci container from the repo root.
|
||||
set -euo pipefail
|
||||
|
||||
# Clean up artifacts from any previous build so stale objects don't survive a
|
||||
# PHP-version switch (safe in CI where the workspace is always fresh).
|
||||
if [ -f Makefile ]; then
|
||||
make -f Makefile distclean
|
||||
fi
|
||||
|
||||
phpize
|
||||
./configure --with-php-config="$(which php-config)"
|
||||
make -f Makefile -j"$(nproc)"
|
||||
|
||||
# The generated Makefile silences and ignores errors on the `if` commands;
|
||||
# undo that so test failures surface properly.
|
||||
sed -i 's/-@if/@if/' Makefile
|
||||
|
||||
ret=0
|
||||
TEST_PHP_EXECUTABLE="$(which php)" \
|
||||
TEST_PHP_JUNIT=report.xml \
|
||||
REPORT_EXIT_STATUS=1 \
|
||||
NO_INTERACTION=1 \
|
||||
TESTS="--set-timeout 300 --show-diff" \
|
||||
make -f Makefile test || ret=$?
|
||||
|
||||
found=$(find tests -name '*.mem' | wc -l)
|
||||
if [ "$found" -gt 0 ]; then
|
||||
echo "Found $found memory leak(s):"
|
||||
find tests -name '*.mem' -print -exec cat {} \;
|
||||
ret=1
|
||||
fi
|
||||
|
||||
exit "$ret"
|
||||
52
.github/scripts/update-docker-shas.sh
vendored
Executable file
52
.github/scripts/update-docker-shas.sh
vendored
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# Refresh docker-image-shas.yml with current OCI index digests.
|
||||
# The index digest covers all platforms (amd64 + arm64); Docker resolves the
|
||||
# right platform image from it at pull time.
|
||||
# Justfile and tests.yml read from docker-image-shas.yml directly — no patching needed.
|
||||
set -euo pipefail
|
||||
|
||||
IMAGE="datadog/dd-appsec-php-ci"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCK_FILE="$SCRIPT_DIR/../docker-image-shas.yml"
|
||||
|
||||
TAGS=(
|
||||
php-7.0-debug php-7.0-release-zts
|
||||
php-7.1-debug php-7.1-release-zts
|
||||
php-7.2-debug php-7.2-release-zts
|
||||
php-7.3-debug php-7.3-release-zts
|
||||
php-7.4-debug php-7.4-release-zts
|
||||
php-8.0-debug php-8.0-release-zts
|
||||
php-8.1-debug php-8.1-release-zts
|
||||
php-8.2-debug php-8.2-release-zts
|
||||
php-8.3-debug php-8.3-release-zts
|
||||
php-8.4-debug php-8.4-release-zts
|
||||
php-8.5-debug php-8.5-release-zts
|
||||
)
|
||||
|
||||
get_index_digest() {
|
||||
# The top-level "digest" field in the Hub tags API is the manifest-list
|
||||
# (OCI index) digest, not a per-platform image digest.
|
||||
curl -fsSL "https://hub.docker.com/v2/repositories/${IMAGE}/tags/$1" \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['digest'])"
|
||||
}
|
||||
|
||||
# Collect all digests first so we fail fast before touching any file.
|
||||
declare -A DIGESTS
|
||||
for tag in "${TAGS[@]}"; do
|
||||
echo "Fetching $tag ..." >&2
|
||||
DIGESTS[$tag]=$(get_index_digest "$tag")
|
||||
done
|
||||
|
||||
# ── Update docker-image-shas.yml ─────────────────────────────────────────────
|
||||
|
||||
{
|
||||
echo "# Docker image SHA lock file."
|
||||
echo "# Maps image tags to their multi-arch OCI index digests (amd64 + arm64)."
|
||||
echo "# Regenerate with: .github/scripts/update-docker-shas.sh"
|
||||
echo ""
|
||||
echo "${IMAGE}:"
|
||||
for tag in "${TAGS[@]}"; do
|
||||
printf " %-20s \"%s\"\n" "${tag}:" "${DIGESTS[$tag]}"
|
||||
done
|
||||
} > "$LOCK_FILE"
|
||||
echo "Updated $LOCK_FILE" >&2
|
||||
123
.github/workflows/release.yml
vendored
Normal file
123
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
name: Release binaries
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]*.[0-9]*.[0-9]*'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check version consistency
|
||||
run: |
|
||||
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
||||
HEADER_VERSION=$(grep -oP '(?<=#define PHP_RAR_VERSION ")[^"]+' php_rar.h)
|
||||
PACKAGE_VERSION=$(python3 -c "
|
||||
import xml.etree.ElementTree as ET
|
||||
t = ET.parse('package.xml')
|
||||
ns = {'p': 'http://pear.php.net/dtd/package-2.0'}
|
||||
print(t.find('p:version/p:release', ns).text)
|
||||
")
|
||||
|
||||
echo "Tag version: $TAG_VERSION"
|
||||
echo "Header version: $HEADER_VERSION"
|
||||
echo "Package version: $PACKAGE_VERSION"
|
||||
|
||||
if [ "$TAG_VERSION" != "$HEADER_VERSION" ]; then
|
||||
echo "ERROR: Tag version ($TAG_VERSION) does not match PHP_RAR_VERSION in php_rar.h ($HEADER_VERSION)"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
|
||||
echo "ERROR: Tag version ($TAG_VERSION) does not match version in package.xml ($PACKAGE_VERSION)"
|
||||
exit 1
|
||||
fi
|
||||
echo "All versions match: $TAG_VERSION"
|
||||
|
||||
create-draft-release:
|
||||
needs: [check-version]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: 'true'
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- name: Create draft release from tag
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh release create "${{ github.ref_name }}" --title "${{ github.ref_name }}" --draft --notes-from-tag
|
||||
|
||||
windows-extension-matrix:
|
||||
needs: [create-draft-release]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.extension-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get the extension matrix
|
||||
id: extension-matrix
|
||||
uses: php/php-windows-builder/extension-matrix@v1
|
||||
with:
|
||||
php-version-list: '8.0, 8.1, 8.2, 8.3, 8.4, 8.5'
|
||||
|
||||
windows-build:
|
||||
needs: [windows-extension-matrix]
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.windows-extension-matrix.outputs.matrix) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build the extension for Windows
|
||||
uses: php/php-windows-builder/extension@v1
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
arch: ${{ matrix.arch }}
|
||||
ts: ${{ matrix.ts }}
|
||||
args: --enable-rar=shared
|
||||
test-runner: run-tests-rar.php
|
||||
|
||||
windows-release:
|
||||
needs: [windows-build]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Upload artifacts to the release
|
||||
uses: php/php-windows-builder/release@v1
|
||||
with:
|
||||
release: ${{ github.ref_name }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
draft: 'true'
|
||||
|
||||
pecl-package:
|
||||
needs: [create-draft-release]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.3'
|
||||
tools: pecl
|
||||
|
||||
- name: Build PECL package
|
||||
run: pecl package
|
||||
|
||||
- name: Upload PECL package to release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh release upload "${{ github.ref_name }}" rar-*.tgz
|
||||
92
.github/workflows/tests.yml
vendored
Normal file
92
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-dev-version:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check PHP_RAR_VERSION ends in -dev
|
||||
run: |
|
||||
HEADER_VERSION=$(grep -oP '(?<=#define PHP_RAR_VERSION ")[^"]+' php_rar.h)
|
||||
echo "Header version: $HEADER_VERSION"
|
||||
if [[ "$HEADER_VERSION" != *-dev ]]; then
|
||||
echo "ERROR: PHP_RAR_VERSION ($HEADER_VERSION) does not end in -dev on master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
generate-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- id: set-matrix
|
||||
run: |
|
||||
python3 <<'EOF'
|
||||
import yaml, json, os
|
||||
with open('.github/docker-image-shas.yml') as f:
|
||||
data = yaml.safe_load(f)
|
||||
image = 'datadog/dd-appsec-php-ci'
|
||||
includes = []
|
||||
for tag, sha in data[image].items():
|
||||
# tag: "php-7.0-debug" or "php-7.0-release-zts"
|
||||
ver, variant = tag[len('php-'):].split('-', 1)
|
||||
includes.append({'php': ver, 'variant': variant, 'image_sha': sha})
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
|
||||
f.write('matrix=' + json.dumps({'include': includes}) + '\n')
|
||||
EOF
|
||||
|
||||
linux:
|
||||
name: PHP ${{ matrix.php }} (${{ matrix.variant }})
|
||||
needs: generate-matrix
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: datadog/dd-appsec-php-ci@${{ matrix.image_sha }}
|
||||
options: --user root
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build and test
|
||||
run: bash .github/scripts/build-and-test.sh
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: test-results-php${{ matrix.php }}-${{ matrix.variant }}
|
||||
path: report.xml
|
||||
|
||||
windows:
|
||||
name: Windows PHP 8.1 TS
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build and test
|
||||
uses: php/php-windows-builder/extension@v1
|
||||
with:
|
||||
php-version: '8.1'
|
||||
arch: x64
|
||||
ts: ts
|
||||
args: --enable-rar=shared
|
||||
test-runner: ${{ github.workspace }}/run-tests-rar.php
|
||||
test-workers: 1
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: test-results-windows-php8.1-ts
|
||||
path: '*.xml'
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
*.o
|
||||
*.lo
|
||||
/run-tests.php
|
||||
/tests/*.sh
|
||||
/tests/*.exp
|
||||
/tests/*.diff
|
||||
@@ -7,7 +8,6 @@
|
||||
/tests/*.php
|
||||
/tests/*.out
|
||||
/tests/*.mem
|
||||
/run-tests.php
|
||||
/modules
|
||||
/missing
|
||||
/.deps
|
||||
@@ -47,3 +47,8 @@
|
||||
/php-rar.creator.user
|
||||
/compile_commands.json
|
||||
/.clangd
|
||||
/report.xml
|
||||
/.worktrees
|
||||
*.dep
|
||||
/configure~
|
||||
/.cache/
|
||||
|
||||
113
Justfile
Normal file
113
Justfile
Normal file
@@ -0,0 +1,113 @@
|
||||
# Build and test inside the matching CI Docker image.
|
||||
# Image SHAs are read from .github/docker-image-shas.yml (multi-arch OCI index digests).
|
||||
# To refresh SHAs: .github/scripts/update-docker-shas.sh
|
||||
|
||||
# ── Images ────────────────────────────────────────────────────────────────────
|
||||
|
||||
_base := "datadog/dd-appsec-php-ci@"
|
||||
_shas := ".github/docker-image-shas.yml"
|
||||
|
||||
image_7_0_debug := _base + `grep 'php-7.0-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_0_release_zts := _base + `grep 'php-7.0-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_1_debug := _base + `grep 'php-7.1-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_1_release_zts := _base + `grep 'php-7.1-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_2_debug := _base + `grep 'php-7.2-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_2_release_zts := _base + `grep 'php-7.2-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_3_debug := _base + `grep 'php-7.3-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_3_release_zts := _base + `grep 'php-7.3-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_4_debug := _base + `grep 'php-7.4-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_7_4_release_zts := _base + `grep 'php-7.4-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_0_debug := _base + `grep 'php-8.0-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_0_release_zts := _base + `grep 'php-8.0-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_1_debug := _base + `grep 'php-8.1-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_1_release_zts := _base + `grep 'php-8.1-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_2_debug := _base + `grep 'php-8.2-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_2_release_zts := _base + `grep 'php-8.2-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_3_debug := _base + `grep 'php-8.3-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_3_release_zts := _base + `grep 'php-8.3-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_4_debug := _base + `grep 'php-8.4-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_4_release_zts := _base + `grep 'php-8.4-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_5_debug := _base + `grep 'php-8.5-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_8_5_release_zts := _base + `grep 'php-8.5-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
|
||||
_run := "docker run --rm --entrypoint bash -v \"$PWD:/workspace\" -w /workspace --user root"
|
||||
|
||||
# ── Default ───────────────────────────────────────────────────────────────────
|
||||
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# ── Individual targets ────────────────────────────────────────────────────────
|
||||
|
||||
test-7_0-debug:
|
||||
{{_run}} {{image_7_0_debug}} .github/scripts/build-and-test.sh
|
||||
test-7_0-release-zts:
|
||||
{{_run}} {{image_7_0_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-7_1-debug:
|
||||
{{_run}} {{image_7_1_debug}} .github/scripts/build-and-test.sh
|
||||
test-7_1-release-zts:
|
||||
{{_run}} {{image_7_1_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-7_2-debug:
|
||||
{{_run}} {{image_7_2_debug}} .github/scripts/build-and-test.sh
|
||||
test-7_2-release-zts:
|
||||
{{_run}} {{image_7_2_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-7_3-debug:
|
||||
{{_run}} {{image_7_3_debug}} .github/scripts/build-and-test.sh
|
||||
test-7_3-release-zts:
|
||||
{{_run}} {{image_7_3_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-7_4-debug:
|
||||
{{_run}} {{image_7_4_debug}} .github/scripts/build-and-test.sh
|
||||
test-7_4-release-zts:
|
||||
{{_run}} {{image_7_4_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-8_0-debug:
|
||||
{{_run}} {{image_8_0_debug}} .github/scripts/build-and-test.sh
|
||||
test-8_0-release-zts:
|
||||
{{_run}} {{image_8_0_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-8_1-debug:
|
||||
{{_run}} {{image_8_1_debug}} .github/scripts/build-and-test.sh
|
||||
test-8_1-release-zts:
|
||||
{{_run}} {{image_8_1_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-8_2-debug:
|
||||
{{_run}} {{image_8_2_debug}} .github/scripts/build-and-test.sh
|
||||
test-8_2-release-zts:
|
||||
{{_run}} {{image_8_2_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-8_3-debug:
|
||||
{{_run}} {{image_8_3_debug}} .github/scripts/build-and-test.sh
|
||||
test-8_3-release-zts:
|
||||
{{_run}} {{image_8_3_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-8_4-debug:
|
||||
{{_run}} {{image_8_4_debug}} .github/scripts/build-and-test.sh
|
||||
test-8_4-release-zts:
|
||||
{{_run}} {{image_8_4_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-8_5-debug:
|
||||
{{_run}} {{image_8_5_debug}} .github/scripts/build-and-test.sh
|
||||
test-8_5-release-zts:
|
||||
{{_run}} {{image_8_5_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
# ── Per-version aggregates (sequential to avoid workspace conflicts) ───────────
|
||||
|
||||
test-7_0: test-7_0-debug test-7_0-release-zts
|
||||
test-7_1: test-7_1-debug test-7_1-release-zts
|
||||
test-7_2: test-7_2-debug test-7_2-release-zts
|
||||
test-7_3: test-7_3-debug test-7_3-release-zts
|
||||
test-7_4: test-7_4-debug test-7_4-release-zts
|
||||
test-8_0: test-8_0-debug test-8_0-release-zts
|
||||
test-8_1: test-8_1-debug test-8_1-release-zts
|
||||
test-8_2: test-8_2-debug test-8_2-release-zts
|
||||
test-8_3: test-8_3-debug test-8_3-release-zts
|
||||
test-8_4: test-8_4-debug test-8_4-release-zts
|
||||
test-8_5: test-8_5-debug test-8_5-release-zts
|
||||
|
||||
# ── All Linux targets ─────────────────────────────────────────────────────────
|
||||
|
||||
test-linux: test-7_0 test-7_1 test-7_2 test-7_3 test-7_4 test-8_0 test-8_1 test-8_2 test-8_3 test-8_4 test-8_5
|
||||
@@ -1,6 +1,5 @@
|
||||
.PHONY: replace-run-tests
|
||||
replace-run-tests:
|
||||
@if ! grep -q 'Minimum required PHP version: 5\.3\.0' run-tests.php; then \
|
||||
cp run-tests8.php run-tests.php; \
|
||||
fi
|
||||
cp run-tests-rar.php run-tests.php
|
||||
|
||||
test: replace-run-tests
|
||||
|
||||
22
README.md
22
README.md
@@ -10,6 +10,22 @@ unrar/LICENSE.txt for details.
|
||||
Some modifications have been applied to the UnRAR library, mainly to allow
|
||||
streaming extraction of files without using threads.
|
||||
|
||||
[](https://ci.appveyor.com/project/cataphract/php-rar/branch/master)
|
||||
[](https://travis-ci.org/cataphract/php-rar)
|
||||
[](https://codecov.io/gh/cataphract/php-rar)
|
||||
## Installation
|
||||
|
||||
### With PECL
|
||||
|
||||
```sh
|
||||
pecl install rar
|
||||
```
|
||||
|
||||
Then add `extension=rar` to your `php.ini`.
|
||||
|
||||
### With PIE
|
||||
|
||||
[PIE](https://github.com/php/pie) is the modern replacement for PECL, available from PHP 8.1+.
|
||||
|
||||
```sh
|
||||
pie install rar
|
||||
```
|
||||
|
||||
PIE automatically adds the extension to your `php.ini`.
|
||||
|
||||
31
appveyor.bat
31
appveyor.bat
@@ -1,31 +0,0 @@
|
||||
echo Running appveyor.bat
|
||||
echo on
|
||||
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat"
|
||||
|
||||
IF NOT EXIST "C:\projects\php-sdk" (
|
||||
wget -nv http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip
|
||||
7z x -y php-sdk-binary-tools-20110915.zip -oC:\projects\php-sdk
|
||||
)
|
||||
IF NOT EXIST "C:\projects\php-src\Release_TS\php7ts.lib" (
|
||||
git clone --depth=1 --branch=PHP-7.1 https://github.com/php/php-src C:\projects\php-src
|
||||
wget -nv http://windows.php.net/downloads/php-sdk/deps-7.1-vc14-x86.7z
|
||||
7z x -y deps-7.1-vc14-x86.7z -oC:\projects\php-src
|
||||
CALL C:\projects\php-sdk\bin\phpsdk_setvars.bat
|
||||
cd C:\projects\php-src
|
||||
CALL buildconf.bat
|
||||
CALL configure.bat --disable-all --enable-cli --with-config-file-scan-dir=C:\projects\extension\bin\modules.d --with-prefix=%APPVEYOR_BUILD_FOLDER%\bin --with-php-build=deps
|
||||
nmake
|
||||
) ELSE (
|
||||
echo php7ts.lib already exists
|
||||
cd C:\projects\php-src
|
||||
CALL C:\projects\php-sdk\bin\phpsdk_setvars.bat
|
||||
)
|
||||
|
||||
CALL buildconf.bat --force --add-modules-dir=%APPVEYOR_BUILD_FOLDER%\..
|
||||
CALL configure.bat --disable-all --enable-cli --enable-rar=shared --with-config-file-scan-dir=C:\projects\extension\bin\modules.d --with-prefix=%APPVEYOR_BUILD_FOLDER%\bin --with-php-build=deps
|
||||
nmake || exit /b
|
||||
rmdir Release_TS\php-rar /S /Q
|
||||
del /S /Q "Release_TS\*.sbr"
|
||||
|
||||
copy %APPVEYOR_BUILD_FOLDER%\run-tests8.php C:\projects\php-src\run-tests.php
|
||||
26
appveyor.yml
26
appveyor.yml
@@ -1,26 +0,0 @@
|
||||
# Based on igbinary's appveyor config.
|
||||
|
||||
version: '{branch}.{build}'
|
||||
install:
|
||||
- cmd: choco feature enable -n=allowGlobalConfirmation
|
||||
- cmd: cinst wget
|
||||
- cmd: mkdir %APPVEYOR_BUILD_FOLDER%\bin
|
||||
|
||||
build_script:
|
||||
- cmd: "%APPVEYOR_BUILD_FOLDER%\\appveyor.bat"
|
||||
|
||||
test_script:
|
||||
- cmd: cd C:\projects\php-src
|
||||
- cmd: set NO_INTERACTION=1
|
||||
- cmd: set REPORT_EXIT_STATUS=1
|
||||
- cmd: set TZ=UTC
|
||||
- cmd: 'nmake test TESTS="--show-diff --set-timeout 30 -d extension=C:\projects\php-src\Release_TS\php_rar.dll %APPVEYOR_BUILD_FOLDER%\tests"'
|
||||
|
||||
after_test:
|
||||
# - cmd: dir /S C:\projects\php-src\Release_TS
|
||||
- cmd: 'del C:\projects\php-src\Release_TS\php_rar.*'
|
||||
|
||||
cache:
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
- C:\projects\php-src
|
||||
- C:\projects\php-sdk
|
||||
@@ -1,85 +0,0 @@
|
||||
jobs:
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_5_3_valgrind
|
||||
displayName: PHP 5.3 ZTS (valgrind, clang)
|
||||
phpVersion: '5.3'
|
||||
clang: true
|
||||
valgrind: true
|
||||
zts: true
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_5_4
|
||||
displayName: PHP 5.4
|
||||
phpVersion: '5.4'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_5_5
|
||||
displayName: PHP 5.5
|
||||
phpVersion: '5.5'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_5_6
|
||||
displayName: PHP 5.6
|
||||
phpVersion: '5.6'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_5_6_valgrind
|
||||
displayName: PHP 5.6 ZTS (valgrind, clang)
|
||||
phpVersion: '5.6'
|
||||
clang: true
|
||||
valgrind: true
|
||||
zts: true
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_7_0
|
||||
displayName: PHP 7.0
|
||||
phpVersion: '7.0'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_7_1
|
||||
displayName: PHP 7.1
|
||||
phpVersion: '7.1'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_7_2
|
||||
displayName: PHP 7.2
|
||||
phpVersion: '7.2'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_7_3
|
||||
displayName: PHP 7.3
|
||||
phpVersion: '7.3'
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_7_4
|
||||
displayName: PHP 7.4 ZTS (valgrind, clang)
|
||||
phpVersion: '7.4'
|
||||
clang: true
|
||||
valgrind: true
|
||||
zts: true
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_8_0
|
||||
displayName: PHP 8.0 ZTS
|
||||
phpVersion: '8.0'
|
||||
zts: true
|
||||
publishCoverage: true
|
||||
|
||||
- template: azure-template.yml
|
||||
parameters:
|
||||
name: php_8_0_valgrind
|
||||
displayName: PHP 8.0 (valgrind, clang)
|
||||
phpVersion: '8.0'
|
||||
clang: true
|
||||
valgrind: true
|
||||
@@ -1,65 +0,0 @@
|
||||
parameters:
|
||||
name: ~
|
||||
displayName: ~
|
||||
phpVersion: bundled
|
||||
imageName: ubuntu-20.04
|
||||
zts: false
|
||||
clang: false
|
||||
publishCoverage: false
|
||||
valgrind: false
|
||||
|
||||
jobs:
|
||||
- job: ${{ parameters.name }}
|
||||
displayName: ${{ parameters.displayName }}
|
||||
pool:
|
||||
vmImage: ${{ parameters.imageName }}
|
||||
|
||||
variables:
|
||||
${{ if eq(parameters.clang, true) }}:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: Checkout
|
||||
clean: true
|
||||
submodules: recursive
|
||||
|
||||
- bash: |
|
||||
source test_funcs.sh
|
||||
install_php ${{ parameters.phpVersion }} ${{ parameters.zts }}
|
||||
displayName: Install PHP ${{ parameters.phpVersion }}
|
||||
|
||||
- ${{ if eq(parameters.valgrind, true) }}:
|
||||
- bash: >
|
||||
sudo apt-get install valgrind
|
||||
displayName: "Install Valgrind"
|
||||
|
||||
- script: |
|
||||
source test_funcs.sh
|
||||
build_ext ${{ parameters.phpVersion }} ${{ parameters.zts }} ${{ parameters.publishCoverage }}
|
||||
displayName: Build extension
|
||||
|
||||
- script: |
|
||||
source test_funcs.sh
|
||||
run_tests ${{ parameters.phpVersion }} ${{ parameters.zts }} ${{ parameters.publishCoverage }}
|
||||
${{ if eq(parameters.valgrind, true) }}:
|
||||
env:
|
||||
RUN_TESTS_FLAGS: -m
|
||||
displayName: Run tests
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish test results
|
||||
condition: succeededOrFailed()
|
||||
inputs:
|
||||
testResultsFormat: 'JUnit'
|
||||
testResultsFiles: 'report.xml'
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)'
|
||||
mergeTestResults: true
|
||||
|
||||
- ${{ if eq(parameters.publishCoverage, true) }}:
|
||||
- bash: >
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
displayName: "Publish coverage (Codecov)"
|
||||
env:
|
||||
CODECOV_TOKEN: $(CODECOV_TOKEN)
|
||||
@@ -1,18 +1,31 @@
|
||||
{
|
||||
"name": "rar",
|
||||
"type": "extension",
|
||||
"license": [
|
||||
"PHP License"
|
||||
],
|
||||
"name": "cataphract/rar",
|
||||
"type": "php-ext",
|
||||
"description": "PHP extension for reading RAR archives using bundled unRAR library",
|
||||
"license": "PHP-3.01",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gustavo Lopes",
|
||||
"email": "cataphract@php.net"
|
||||
"email": "cataphract@php.net",
|
||||
"role": "lead"
|
||||
},
|
||||
{
|
||||
"name": "Antony Dovgal",
|
||||
"email": "tony@daylessday.org"
|
||||
"email": "tony@daylessday.org",
|
||||
"role": "developer"
|
||||
}
|
||||
],
|
||||
"description": "rar extension"
|
||||
}
|
||||
"require": {
|
||||
"php": "^7.0 || ^8.0"
|
||||
},
|
||||
"replace": {
|
||||
"ext-rar": "*"
|
||||
},
|
||||
"support": {
|
||||
"source": "https://github.com/cataphract/php-rar"
|
||||
},
|
||||
"php-ext": {
|
||||
"extension-name": "rar",
|
||||
"download-url-method": ["pre-packaged-binary", "composer-default"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ unrar_sources="unrar/sha256.cpp unrar/qopen.cpp \
|
||||
unrar/arcread.cpp unrar/filefn.cpp \
|
||||
unrar/global.cpp unrar/list.cpp \
|
||||
unrar/encname.cpp unrar/file.cpp \
|
||||
unrar/secpassword.cpp unrar/options.cpp"
|
||||
unrar/secpassword.cpp unrar/options.cpp \
|
||||
unrar/largepage.cpp"
|
||||
|
||||
|
||||
AC_LANG_PUSH([C++])
|
||||
@@ -68,6 +69,6 @@ if test "$PHP_RAR" != "no"; then
|
||||
PHP_REQUIRE_CXX()
|
||||
PHP_ADD_LIBRARY_WITH_PATH(stdc++, "", RAR_SHARED_LIBADD)
|
||||
|
||||
PHP_NEW_EXTENSION(rar, rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c rar_time.c $unrar_sources, $ext_shared,,-DRARDLL -DSILENT -Wno-write-strings -Wall -fvisibility=hidden -I@ext_srcdir@/unrar)
|
||||
PHP_NEW_EXTENSION(rar, rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c rar_time.c $unrar_sources, $ext_shared,,-DRARDLL -DSILENT -Wno-write-strings -Wall -fPIC -fvisibility=hidden -I@ext_srcdir@/unrar)
|
||||
PHP_ADD_BUILD_DIR($ext_builddir/unrar)
|
||||
fi
|
||||
|
||||
@@ -18,7 +18,7 @@ if (PHP_RAR != "no") {
|
||||
crc.cpp rijndael.cpp crypt.cpp \
|
||||
rawread.cpp \
|
||||
rs.cpp smallfn.cpp \
|
||||
isnt.cpp rar.cpp consio.cpp \
|
||||
isnt.cpp consio.cpp \
|
||||
scantree.cpp archive.cpp strfn.cpp \
|
||||
strlist.cpp \
|
||||
getbits.cpp hash.cpp \
|
||||
@@ -31,7 +31,8 @@ if (PHP_RAR != "no") {
|
||||
arcread.cpp filefn.cpp \
|
||||
global.cpp list.cpp \
|
||||
encname.cpp file.cpp \
|
||||
secpassword.cpp options.cpp", "rar");
|
||||
secpassword.cpp options.cpp \
|
||||
largepage.cpp motw.cpp", "rar");
|
||||
|
||||
AC_DEFINE("HAVE_RAR", 1, "Rar support");
|
||||
}
|
||||
|
||||
65
package.xml
65
package.xml
@@ -23,11 +23,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<active>no</active>
|
||||
</developer>
|
||||
|
||||
<date>2020-12-06</date>
|
||||
<date>2026-03-08</date>
|
||||
<time>20:00:00</time>
|
||||
<version>
|
||||
<release>4.2.0</release>
|
||||
<api>4.2.0</api>
|
||||
<release>4.3.0</release>
|
||||
<api>4.0.0</api>
|
||||
</version>
|
||||
|
||||
<stability>
|
||||
@@ -36,9 +36,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
</stability>
|
||||
|
||||
<license uri="http://www.php.net/license">PHP License</license>
|
||||
<notes>- Support PHP 8.
|
||||
- Merge unrar 6.0.2.
|
||||
- RarArchive implements IteratorAggregate (PHP 8 only).
|
||||
<notes>- Add PHP 8.1, 8.2, 8.3, 8.4, 8.5 support.
|
||||
- Drop PHP 5 support; minimum PHP version is now 7.0.
|
||||
- Update bundled unrar to 7.2.4.
|
||||
- Fix Windows bug
|
||||
</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
@@ -111,8 +112,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file role="test" name="065.phpt"/>
|
||||
<file role="test" name="066.phpt"/>
|
||||
<file role="test" name="067.phpt"/>
|
||||
<file role="test" name="068.phpt"/>
|
||||
<file role="test" name="069.phpt"/>
|
||||
<file role="test" name="070.phpt"/>
|
||||
<file role="test" name="071.phpt"/>
|
||||
<file role="test" name="072.phpt"/>
|
||||
@@ -148,7 +147,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file role="test" name="102.phpt"/>
|
||||
<file role="test" name="103.phpt"/>
|
||||
<file role="test" name="104.phpt"/>
|
||||
<file role="test" name="105.phpt"/>
|
||||
<file role="test" name="106.phpt"/>
|
||||
<file role="test" name="107.phpt"/>
|
||||
<file role="test" name="108.phpt"/>
|
||||
@@ -193,7 +191,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file name="archive.cpp" role="src" />
|
||||
<file name="archive.hpp" role="src" />
|
||||
<file name="arcread.cpp" role="src" />
|
||||
<file name="array.hpp" role="src" />
|
||||
<file name="blake2s.cpp" role="src" />
|
||||
<file name="blake2s.hpp" role="src" />
|
||||
<file name="blake2s_sse.cpp" role="src" />
|
||||
@@ -248,6 +245,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file name="headers5.hpp" role="src" />
|
||||
<file name="isnt.cpp" role="src" />
|
||||
<file name="isnt.hpp" role="src" />
|
||||
<file name="largepage.cpp" role="src" />
|
||||
<file name="largepage.hpp" role="src" />
|
||||
<file name="LICENSE.txt" role="doc" />
|
||||
<file name="list.cpp" role="src" />
|
||||
<file name="list.hpp" role="src" />
|
||||
@@ -258,6 +257,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file name="match.hpp" role="src" />
|
||||
<file name="model.cpp" role="src" />
|
||||
<file name="model.hpp" role="src" />
|
||||
<file name="motw.cpp" role="src" />
|
||||
<file name="motw.hpp" role="src" />
|
||||
<file name="options.cpp" role="src" />
|
||||
<file name="options.hpp" role="src" />
|
||||
<file name="os.hpp" role="src" />
|
||||
@@ -307,7 +308,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file name="rijndael.hpp" role="src" />
|
||||
<file name="rs.cpp" role="src" />
|
||||
<file name="rs.hpp" role="src" />
|
||||
<file name="savepos.hpp" role="src" />
|
||||
<file name="scantree.cpp" role="src" />
|
||||
<file name="scantree.hpp" role="src" />
|
||||
<file name="secpassword.cpp" role="src" />
|
||||
@@ -340,7 +340,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file name="win32acl.cpp" role="src" />
|
||||
<file name="win32stm.cpp" role="src" />
|
||||
</dir> <!-- /unrar -->
|
||||
<file name="config.m4" role="src" />
|
||||
<file name="config.m4" role="src" />
|
||||
<file name="config.w32" role="src" />
|
||||
<file name="CREDITS" role="doc" />
|
||||
@@ -356,7 +355,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<file name="rarentry.c" role="src" />
|
||||
<file name="rar_error.c" role="src" />
|
||||
<file name="rar_time.c" role="src" />
|
||||
<file name="run-tests8.php" role="test" />
|
||||
<file name="run-tests-rar.php" role="test" />
|
||||
<file role="src" name="rar_navigation.c"/>
|
||||
</dir> <!-- / -->
|
||||
</contents>
|
||||
@@ -364,7 +363,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>5.3.0</min>
|
||||
<min>7.0.0</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.4.0</min>
|
||||
@@ -376,6 +375,44 @@ http://pear.php.net/dtd/package-2.0.xsd">
|
||||
|
||||
<extsrcrelease />
|
||||
<changelog>
|
||||
<release>
|
||||
<version>
|
||||
<release>4.3.0</release>
|
||||
<api>4.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<date>2026-03-08</date>
|
||||
<notes>Changes in this version:
|
||||
- Add PHP 8.1, 8.2, 8.3 support.
|
||||
- Drop PHP 5 support; minimum PHP version is now 7.0.
|
||||
- Update bundled unrar to 7.2.4.
|
||||
- Fix segfault caused by uninitialized RARHeaderDataEx.
|
||||
- Fix dll.cpp: don't propagate non-fatal ErrHandler errors as failures.
|
||||
- Fix RAR5 chunk extraction spurious warning on Windows with multi-core CPUs.
|
||||
- Migrate CI from Azure Pipelines/Appveyor to GitHub Actions.
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>4.2.0</release>
|
||||
<api>4.0.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<date>2020-12-06</date>
|
||||
<notes>Changes in this version:
|
||||
- Support PHP 8.
|
||||
- Merge unrar 6.0.2.
|
||||
- RarArchive implements IteratorAggregate (PHP 8 only).
|
||||
</notes>
|
||||
</release>
|
||||
|
||||
<release>
|
||||
<version>
|
||||
<release>4.1.0</release>
|
||||
|
||||
18
php_compat.h
18
php_compat.h
@@ -15,7 +15,6 @@ typedef zend_object handler_this_t;
|
||||
typedef zval handler_this_t;
|
||||
#endif
|
||||
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
typedef zend_object* rar_obj_ref;
|
||||
|
||||
#define rar_zval_add_ref(ppzv) zval_add_ref(*ppzv)
|
||||
@@ -53,20 +52,3 @@ typedef size_t zpp_s_size_t;
|
||||
#define INIT_ZVAL(zv) ZVAL_UNDEF(&zv)
|
||||
|
||||
#define ZEND_ACC_FINAL_CLASS ZEND_ACC_FINAL
|
||||
|
||||
#else /* PHP 5.x */
|
||||
typedef zend_object_handle rar_obj_ref;
|
||||
|
||||
#define rar_zval_add_ref zval_add_ref
|
||||
#define ZVAL_ALLOC_DUP(dst, src) \
|
||||
do { \
|
||||
zval *z_src = src; \
|
||||
dst = z_src; \
|
||||
zval_add_ref(&dst); \
|
||||
SEPARATE_ZVAL(&dst); \
|
||||
} while (0)
|
||||
#define RAR_ZVAL_STRING ZVAL_STRING
|
||||
#define RAR_RETURN_STRINGL(s, l, duplicate) RETURN_STRINGL(s, l, duplicate)
|
||||
typedef int zpp_s_size_t;
|
||||
#define zend_hash_str_del zend_hash_del
|
||||
#endif
|
||||
|
||||
50
php_rar.h
50
php_rar.h
@@ -51,7 +51,7 @@
|
||||
extern zend_module_entry rar_module_entry;
|
||||
#define phpext_rar_ptr &rar_module_entry
|
||||
|
||||
#define PHP_RAR_VERSION "4.2.0"
|
||||
#define PHP_RAR_VERSION "4.3.1-dev"
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
#define PHP_RAR_API __declspec(dllexport)
|
||||
@@ -77,6 +77,7 @@ extern zend_module_entry rar_module_entry;
|
||||
#include "unrar/dll.hpp"
|
||||
#include "unrar/version.hpp"
|
||||
/* These are in unrar/headers.hpp, but that header depends on several other */
|
||||
/* clang-format off */
|
||||
enum HOST_SYSTEM {
|
||||
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
|
||||
HOST_BEOS=5,HOST_MAX
|
||||
@@ -85,10 +86,12 @@ enum FILE_SYSTEM_REDIRECT {
|
||||
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
|
||||
FSREDIR_HARDLINK, FSREDIR_FILECOPY
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
/* maximum comment size if 64KB */
|
||||
#define RAR_MAX_COMMENT_SIZE 65536
|
||||
|
||||
/* clang-format off */
|
||||
typedef struct _rar_cb_user_data {
|
||||
char *password; /* can be NULL */
|
||||
zval *callable; /* can be NULL */
|
||||
@@ -105,13 +108,19 @@ typedef struct rar {
|
||||
rar_cb_user_data cb_userdata;
|
||||
int allow_broken;
|
||||
} rar_file_t;
|
||||
/* clang-format on */
|
||||
|
||||
/* Misc */
|
||||
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
|
||||
# define RAR_TSRMLS_TC , void ***
|
||||
#else
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define ARR_SIZE(arr) \
|
||||
(sizeof(arr) / sizeof((arr)[0]) + \
|
||||
0 * sizeof(char[1 - 2 * __builtin_types_compatible_p( \
|
||||
__typeof__(arr), __typeof__(&(arr)[0]))]))
|
||||
# else
|
||||
# define ARR_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
# endif
|
||||
|
||||
# define RAR_TSRMLS_TC
|
||||
#endif
|
||||
|
||||
#define RAR_RETNULL_ON_ARGS() \
|
||||
if (zend_parse_parameters_none() == FAILURE) { \
|
||||
@@ -158,33 +167,6 @@ ZEND_EXTERN_MODULE_GLOBALS(rar);
|
||||
# define RAR_G(v) (rar_globals.v)
|
||||
#endif
|
||||
|
||||
/* PHP 5.2 compatibility */
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
|
||||
#define zend_parse_parameters_none() \
|
||||
zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")
|
||||
#define Z_DELREF_P ZVAL_DELREF
|
||||
# define STREAM_ASSUME_REALPATH 0
|
||||
# define ALLOC_PERMANENT_ZVAL(z) \
|
||||
(z) = (zval*) malloc(sizeof(zval));
|
||||
# define OPENBASEDIR_CHECKPATH(filename) \
|
||||
(PG(safe_mode) && \
|
||||
(!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) \
|
||||
|| php_check_open_basedir(filename TSRMLS_CC)
|
||||
# undef ZEND_BEGIN_ARG_INFO_EX
|
||||
# define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
|
||||
static const zend_arg_info name[] = { \
|
||||
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
|
||||
#endif
|
||||
|
||||
/* Other compatibility quirks */
|
||||
/* PHP 5.3 doesn't have ZVAL_COPY_VALUE */
|
||||
#if !defined(ZEND_COPY_VALUE) && PHP_MAJOR_VERSION == 5
|
||||
#define ZVAL_COPY_VALUE(z, v) \
|
||||
do { \
|
||||
(z)->value = (v)->value; \
|
||||
Z_TYPE_P(z) = Z_TYPE_P(v); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_STRNLEN) || !HAVE_STRNLEN
|
||||
size_t _rar_strnlen(const char *s, size_t maxlen);
|
||||
@@ -248,7 +230,7 @@ typedef struct _rar_find_output {
|
||||
int found;
|
||||
size_t position;
|
||||
struct RARHeaderDataEx * header;
|
||||
unsigned long packed_size;
|
||||
zend_ulong packed_size;
|
||||
int eof;
|
||||
} rar_find_output;
|
||||
#define RAR_SEARCH_INDEX 0x01U
|
||||
@@ -297,7 +279,7 @@ extern zend_class_entry *rar_class_entry_ptr;
|
||||
void minit_rarentry(TSRMLS_D);
|
||||
void _rar_entry_to_zval(zval *parent,
|
||||
struct RARHeaderDataEx *entry,
|
||||
unsigned long packed_size,
|
||||
zend_ulong packed_size,
|
||||
size_t index,
|
||||
zval *entry_object TSRMLS_DC);
|
||||
|
||||
|
||||
189
php_upgrade.md
Normal file
189
php_upgrade.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# PHP 8.1–8.5 Upgrade Procedure for php-rar
|
||||
|
||||
This document describes the step-by-step procedure to extend php-rar support
|
||||
from PHP 8.0 to PHP 8.5. Each minor version is handled independently: CI is
|
||||
wired up, the extension is compiled and tested inside the matching Docker image,
|
||||
code changes are applied to fix any failures, and only then is the next version
|
||||
tackled.
|
||||
|
||||
---
|
||||
|
||||
## Overview of files touched per version
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `.github/docker-image-shas.yml` | Add new tag → SHA entries |
|
||||
| `.github/scripts/update-docker-shas.sh` | Add new tags to the `TAGS` array |
|
||||
| `Justfile` | Add image variables and `test-X_Y-*` targets |
|
||||
| `*.c` / `*.h` | C source changes for API compatibility |
|
||||
| `.github/workflows/tests.yml` | Windows job — update `php-version` (once per bump) |
|
||||
|
||||
The Linux CI matrix is generated automatically from `docker-image-shas.yml`, so
|
||||
no manual edit to `tests.yml` is needed for Linux jobs.
|
||||
|
||||
---
|
||||
|
||||
## Repeatable procedure for each version
|
||||
|
||||
Follow these numbered steps for **each** minor version in order. Example:
|
||||
8.0 → 8.1 → 8.2 → 8.3 → 8.4 → 8.5.
|
||||
|
||||
### Step 1 — Read the upgrade guides in php-src
|
||||
|
||||
Clone or browse php-src on the target branch, e.g. `PHP-8.1`:
|
||||
|
||||
```
|
||||
https://github.com/php/php-src/blob/PHP-8.X/UPGRADING
|
||||
https://github.com/php/php-src/blob/PHP-8.X/UPGRADING.INTERNALS
|
||||
```
|
||||
|
||||
Focus on sections relevant to C extensions:
|
||||
- Removed or renamed macros / functions
|
||||
- Changed return types (`int` → `zend_result`)
|
||||
- Changed struct member types
|
||||
- New mandatory includes
|
||||
- Any other backwards-incompatible changes
|
||||
|
||||
The per-version notes below summarise the items relevant to php-rar.
|
||||
|
||||
### Step 2 — Add the Docker image SHA
|
||||
|
||||
Fetch the OCI index digest from Docker Hub for the two new tags:
|
||||
|
||||
```bash
|
||||
# Quick one-liner — prints the index digest for a given tag
|
||||
curl -fsSL "https://hub.docker.com/v2/repositories/datadog/dd-appsec-php-ci/tags/php-X.Y-debug" \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin)['digest'])"
|
||||
```
|
||||
|
||||
Or regenerate everything at once with the provided script after adding the new
|
||||
tags to it (see Step 3):
|
||||
|
||||
```bash
|
||||
.github/scripts/update-docker-shas.sh
|
||||
```
|
||||
|
||||
Append the two lines to `.github/docker-image-shas.yml`:
|
||||
|
||||
```yaml
|
||||
php-X.Y-debug: "sha256:<INDEX-DIGEST>"
|
||||
php-X.Y-release-zts: "sha256:<INDEX-DIGEST>"
|
||||
```
|
||||
|
||||
Also add both tags to the `TAGS` array in `.github/scripts/update-docker-shas.sh`:
|
||||
|
||||
```bash
|
||||
TAGS=(
|
||||
...existing tags...
|
||||
php-X.Y-debug php-X.Y-release-zts
|
||||
)
|
||||
```
|
||||
|
||||
### Step 3 — Add Justfile targets
|
||||
|
||||
Add image variables and `test-X_Y-*` targets following the existing pattern:
|
||||
|
||||
```just
|
||||
image_X_Y_debug := _base + `grep 'php-X.Y-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
image_X_Y_release_zts := _base + `grep 'php-X.Y-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
|
||||
|
||||
test-X_Y-debug:
|
||||
{{_run}} {{image_X_Y_debug}} .github/scripts/build-and-test.sh
|
||||
test-X_Y-release-zts:
|
||||
{{_run}} {{image_X_Y_release_zts}} .github/scripts/build-and-test.sh
|
||||
|
||||
test-X_Y: test-X_Y-debug test-X_Y-release-zts
|
||||
```
|
||||
|
||||
Add `test-X_Y` to the `test-linux` aggregate at the bottom.
|
||||
|
||||
### Step 4 — Compile and test
|
||||
|
||||
Run both variants locally before pushing:
|
||||
|
||||
```bash
|
||||
just test-X_Y-debug
|
||||
just test-X_Y-release-zts
|
||||
```
|
||||
|
||||
Or both together:
|
||||
|
||||
```bash
|
||||
just test-X_Y
|
||||
```
|
||||
|
||||
Examine the output for compiler warnings, errors, and test failures.
|
||||
|
||||
### Step 5 — Apply C source changes
|
||||
|
||||
Based on the compilation output and the per-version notes below, make the
|
||||
minimum necessary changes to `.c`/`.h` files. Guard every change with `#if
|
||||
PHP_VERSION_ID >= XXYY00` so that older PHP versions continue to work.
|
||||
|
||||
### Step 6 — Re-run tests until green
|
||||
|
||||
Repeat Step 4 after each change. When both `debug` and `release-zts` pass,
|
||||
commit.
|
||||
|
||||
### Step 7 — Push and verify CI
|
||||
|
||||
Push the branch. The `linux` CI job matrix is auto-built from
|
||||
`docker-image-shas.yml` — the new versions appear automatically. Verify the
|
||||
GitHub Actions run is green for all new jobs.
|
||||
|
||||
### Step 8 — Update Windows CI (optional, once per bump)
|
||||
|
||||
The Windows job in `.github/workflows/tests.yml` pins a specific PHP version.
|
||||
Update it when the Linux jobs for the matching version are confirmed green:
|
||||
|
||||
```yaml
|
||||
- name: Build and test
|
||||
uses: php/php-windows-builder/extension@v1
|
||||
with:
|
||||
php-version: 'X.Y' # ← change here
|
||||
```
|
||||
|
||||
Also update the `name:` and artifact `name:` strings in the same Windows job
|
||||
block.
|
||||
|
||||
---
|
||||
|
||||
## Current Docker image SHAs (as of 2026-03-01)
|
||||
|
||||
These are the OCI index digests (multi-arch: amd64 + arm64) to use in
|
||||
`docker-image-shas.yml`.
|
||||
|
||||
```yaml
|
||||
php-8.1-debug: "sha256:1a1e5b44cf043e59768c65fd7c94aaefdacde5fa96d83102d35db11ad86f24c6"
|
||||
php-8.1-release-zts: "sha256:5b8a269b4228d9191420059daef820b660110be0aca6776557924172fd1ff0c8"
|
||||
php-8.2-debug: "sha256:52ad14560672fc8c5130f5758bbee3fa401bc1d35b412f4a230c6258143291a5"
|
||||
php-8.2-release-zts: "sha256:cb143d915b394f16a2d78018765705460f3d1b788fdd2a90ef50fad5f8f5918c"
|
||||
php-8.3-debug: "sha256:bb6df08160126374d3d9247428928aa19a9c2b2429c98356650199b85ae20212"
|
||||
php-8.3-release-zts: "sha256:e58e25a017f75df82691d408b8cb70453875ff36718e295ee8c6653a0f117331"
|
||||
php-8.4-debug: "sha256:15045688f6986f4625b1507a7f4be6104e7bbb88caf877f1611463b929f2bca2"
|
||||
php-8.4-release-zts: "sha256:8e0ac25a3306b4b9f692c593b8a509cc789c2e001ce52682928065a92c880136"
|
||||
php-8.5-debug: "sha256:bd0170331b34fb469e29d00b19b20fb88b726160f76df274a1bdc3a27ac18d30"
|
||||
php-8.5-release-zts: "sha256:e071b2095da55bd24686209422f43a01c65acfc6021f04156d9fb43fd3d4d426"
|
||||
```
|
||||
|
||||
Refresh at any time with `.github/scripts/update-docker-shas.sh` after adding
|
||||
the new tags.
|
||||
|
||||
---
|
||||
|
||||
## Summary checklist
|
||||
|
||||
For each version X.Y in order (8.1, 8.2, 8.3, 8.4, 8.5):
|
||||
|
||||
- [ ] Read `PHP-X.Y/UPGRADING.INTERNALS` on GitHub
|
||||
- [ ] Add two SHA entries to `.github/docker-image-shas.yml`
|
||||
- [ ] Add both tags to `TAGS` array in `.github/scripts/update-docker-shas.sh`
|
||||
- [ ] Add `image_X_Y_*` variables and `test-X_Y-*` targets to `Justfile`
|
||||
- [ ] Add `test-X_Y` to `test-linux` aggregate in `Justfile`
|
||||
- [ ] Run `just test-X_Y` and fix all compilation errors
|
||||
- [ ] Run `just test-X_Y` again; confirm all tests pass
|
||||
- [ ] Commit infrastructure + code changes together
|
||||
- [ ] Push; confirm GitHub Actions CI is green for the new matrix entries
|
||||
- [ ] (Optional) Update Windows `php-version` in `.github/workflows/tests.yml` to X.Y
|
||||
|
||||
<!-- vim: set tw=80: -->
|
||||
115
rar.c
115
rar.c
@@ -28,14 +28,12 @@
|
||||
/* $Id$ */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
@@ -50,7 +48,7 @@ extern "C" {
|
||||
#include <ext/standard/info.h>
|
||||
#include <ext/spl/spl_exceptions.h>
|
||||
|
||||
#if HAVE_RAR
|
||||
#include "unrar/rardefs.hpp"
|
||||
|
||||
#include "php_rar.h"
|
||||
|
||||
@@ -161,12 +159,8 @@ void _rar_destroy_userdata(rar_cb_user_data *udata) /* {{{ */
|
||||
}
|
||||
|
||||
if (udata->callable != NULL) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_ptr_dtor(&udata->callable);
|
||||
#else
|
||||
zval_ptr_dtor(udata->callable);
|
||||
efree(udata->callable);
|
||||
#endif
|
||||
}
|
||||
|
||||
udata->password = NULL;
|
||||
@@ -240,13 +234,16 @@ int _rar_find_file_w(struct RAROpenArchiveDataEx *open_data, /* IN */
|
||||
|
||||
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
|
||||
#if WCHAR_MAX > 0xffff
|
||||
_rar_fix_wide(used_header_data->FileNameW, NM);
|
||||
_rar_fix_wide(used_header_data->FileNameW,
|
||||
ARR_SIZE(used_header_data->FileNameW));
|
||||
#endif
|
||||
|
||||
if (wcsncmp(used_header_data->FileNameW, file_name, NM) == 0) {
|
||||
if (wcsncmp(used_header_data->FileNameW, file_name,
|
||||
ARR_SIZE(used_header_data->FileNameW)) == 0) {
|
||||
*found = TRUE;
|
||||
goto cleanup;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL);
|
||||
}
|
||||
if (process_result != 0) {
|
||||
@@ -383,6 +380,7 @@ int CALLBACK _rar_unrar_callback(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// TODO: maybe support UCM_NEEDPASSWORDW and UCM_CHANGEVOLUMEW
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -425,7 +423,7 @@ PHP_FUNCTION(rar_wrapper_cache_stats) /* {{{ */
|
||||
static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */
|
||||
{
|
||||
wchar_t *write,
|
||||
*read,
|
||||
*read,
|
||||
*max_fin;
|
||||
max_fin = str + max_size;
|
||||
for (write = str, read = str; *read != L'\0' && read != max_fin; read++) {
|
||||
@@ -442,61 +440,37 @@ static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */
|
||||
* because, in case we're using exceptions, we want to let an exception with
|
||||
* error code ERAR_EOPEN to be thrown.
|
||||
*/
|
||||
static int _rar_unrar_volume_user_callback(char* dst_buffer,
|
||||
static int _rar_unrar_volume_user_callback(char* dst_buffer, // MAXPATHSIZE
|
||||
zend_fcall_info *fci,
|
||||
zend_fcall_info_cache *cache
|
||||
TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval *failed_vol,
|
||||
*retval_ptr = NULL,
|
||||
**params;
|
||||
#else
|
||||
zval failed_vol,
|
||||
retval,
|
||||
*params,
|
||||
*const retval_ptr = &retval;
|
||||
#endif
|
||||
int ret = -1;
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(failed_vol);
|
||||
RAR_ZVAL_STRING(failed_vol, dst_buffer, 1);
|
||||
params = &failed_vol;
|
||||
fci->retval_ptr_ptr = &retval_ptr;
|
||||
fci->params = ¶ms;
|
||||
#else
|
||||
ZVAL_STRING(&failed_vol, dst_buffer);
|
||||
ZVAL_NULL(&retval);
|
||||
params = &failed_vol;
|
||||
fci->retval = &retval;
|
||||
fci->params = params;
|
||||
#endif
|
||||
fci->param_count = 1;
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (zend_call_function(fci, cache TSRMLS_CC) != SUCCESS ||
|
||||
fci->retval_ptr_ptr == NULL ||
|
||||
*fci->retval_ptr_ptr == NULL) {
|
||||
#else
|
||||
if (zend_call_function(fci, cache TSRMLS_CC) != SUCCESS || EG(exception)) {
|
||||
#endif
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Failure to call volume find callback");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
assert(*fci->retval_ptr_ptr == retval_ptr);
|
||||
#else
|
||||
assert(fci->retval == &retval);
|
||||
#endif
|
||||
if (Z_TYPE_P(retval_ptr) == IS_NULL) {
|
||||
/* let return -1 */
|
||||
}
|
||||
else if (Z_TYPE_P(retval_ptr) == IS_STRING) {
|
||||
char *filename = Z_STRVAL_P(retval_ptr);
|
||||
char resolved_path[MAXPATHLEN];
|
||||
char resolved_path[MAXPATHSIZE];
|
||||
size_t resolved_len;
|
||||
|
||||
if (OPENBASEDIR_CHECKPATH(filename)) {
|
||||
@@ -508,17 +482,15 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
resolved_len = _rar_strnlen(resolved_path, MAXPATHLEN);
|
||||
/* dst_buffer size is NM; first condition won't happen short of a bug
|
||||
* in expand_filepath */
|
||||
if (resolved_len == MAXPATHLEN || resolved_len > NM - 1) {
|
||||
resolved_len = _rar_strnlen(resolved_path, MAXPATHSIZE);
|
||||
if (resolved_len > MAXPATHSIZE - 1) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"Resolved path is too big for the unRAR library");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
strncpy(dst_buffer, resolved_path, NM);
|
||||
dst_buffer[NM - 1] = '\0';
|
||||
strncpy(dst_buffer, resolved_path, MAXPATHSIZE);
|
||||
dst_buffer[MAXPATHSIZE - 1] = '\0';
|
||||
ret = 1; /* try this new filename */
|
||||
}
|
||||
else {
|
||||
@@ -529,15 +501,8 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer,
|
||||
}
|
||||
|
||||
cleanup:
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_ptr_dtor(&failed_vol);
|
||||
if (retval_ptr != NULL) {
|
||||
zval_ptr_dtor(&retval_ptr);
|
||||
}
|
||||
#else
|
||||
zval_ptr_dtor(&failed_vol);
|
||||
zval_ptr_dtor(&retval);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -553,17 +518,6 @@ static int _rar_make_userdata_fcall(zval *callable,
|
||||
|
||||
*cache = empty_fcall_info_cache;
|
||||
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
|
||||
if (zend_fcall_info_init(callable, fci, cache TSRMLS_CC) != SUCCESS) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"The RAR file was not opened in rar_open/RarArchive::open with a "
|
||||
"valid callback.", error);
|
||||
return FAILURE;
|
||||
}
|
||||
else {
|
||||
return SUCCESS;
|
||||
}
|
||||
#else
|
||||
if (zend_fcall_info_init(callable, IS_CALLABLE_STRICT, fci, cache, NULL,
|
||||
&error TSRMLS_CC) == SUCCESS) {
|
||||
if (error) {
|
||||
@@ -583,7 +537,6 @@ static int _rar_make_userdata_fcall(zval *callable,
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
/* }}} */
|
||||
@@ -634,6 +587,7 @@ ZEND_END_ARG_INFO()
|
||||
/* {{{ rar_functions[]
|
||||
*
|
||||
*/
|
||||
/* clang-format off */
|
||||
static zend_function_entry rar_functions[] = {
|
||||
PHP_FE(rar_open, arginfo_rar_open)
|
||||
PHP_FE(rar_list, arginfo_rar_void_archmeth)
|
||||
@@ -646,16 +600,13 @@ static zend_function_entry rar_functions[] = {
|
||||
PHP_FE(rar_wrapper_cache_stats, arginfo_rar_wrapper_cache_stats)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* clang-format on */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Globals' related activities */
|
||||
ZEND_DECLARE_MODULE_GLOBALS(rar);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static int _rar_array_apply_remove_first(void *pDest TSRMLS_DC)
|
||||
#else
|
||||
static int _rar_array_apply_remove_first(zval *pDest TSRMLS_DC)
|
||||
#endif
|
||||
{
|
||||
return (ZEND_HASH_APPLY_STOP | ZEND_HASH_APPLY_REMOVE);
|
||||
}
|
||||
@@ -673,13 +624,7 @@ static void _rar_contents_cache_put(const char *key,
|
||||
assert(zend_hash_num_elements(cc->data) == cur_size - 1);
|
||||
}
|
||||
rar_zval_add_ref(&zv);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
assert(Z_REFCOUNT_P(zv) > 1);
|
||||
SEPARATE_ZVAL(&zv); /* ensure we store a heap allocated copy */
|
||||
zend_hash_update(cc->data, key, key_len, &zv, sizeof(zv), NULL);
|
||||
#else
|
||||
zend_hash_str_update(cc->data, key, key_len, zv);
|
||||
#endif
|
||||
}
|
||||
|
||||
static zval *_rar_contents_cache_get(const char *key,
|
||||
@@ -688,15 +633,7 @@ static zval *_rar_contents_cache_get(const char *key,
|
||||
{
|
||||
rar_contents_cache *cc = &RAR_G(contents_cache);
|
||||
zval *element = NULL;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval **element_p = NULL;
|
||||
zend_hash_find(cc->data, key, key_len, (void **) &element_p);
|
||||
if (element_p) {
|
||||
element = *element_p;
|
||||
}
|
||||
#else
|
||||
element = zend_hash_str_find(cc->data, key, key_len);
|
||||
#endif
|
||||
|
||||
if (element != NULL) {
|
||||
cc->hits++;
|
||||
@@ -755,16 +692,14 @@ ZEND_MODULE_STARTUP_D(rar)
|
||||
|
||||
php_register_url_stream_wrapper("rar", &php_stream_rar_wrapper TSRMLS_CC);
|
||||
|
||||
/* clang-format off */
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_MSDOS", HOST_MSDOS, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_OS2", HOST_OS2, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_WIN32", HOST_WIN32, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_UNIX", HOST_UNIX, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_MACOS", HOST_MACOS, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("RAR_HOST_BEOS", HOST_BEOS, CONST_CS | CONST_PERSISTENT);
|
||||
/* PHP < 5.3 doesn't have the PHP_MAXPATHLEN constant */
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
|
||||
REGISTER_LONG_CONSTANT("RAR_MAXPATHLEN", MAXPATHLEN, CONST_CS | CONST_PERSISTENT);
|
||||
#endif
|
||||
/* clang-format on */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -829,12 +764,6 @@ zend_module_entry rar_module_entry = {
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
#endif /* HAVE_RAR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
||||
45
rar_error.c
45
rar_error.c
@@ -25,10 +25,6 @@
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <zend_exceptions.h>
|
||||
#include "php_rar.h"
|
||||
@@ -70,11 +66,7 @@ void _rar_handle_ext_error(const char *format TSRMLS_DC, ...) /* {{{ */
|
||||
va_list arg;
|
||||
char *message;
|
||||
|
||||
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
|
||||
va_start(arg, TSRMLS_C);
|
||||
#else
|
||||
va_start(arg, format);
|
||||
#endif
|
||||
vspprintf(&message, 0, format, arg);
|
||||
va_end(arg);
|
||||
|
||||
@@ -91,13 +83,8 @@ int _rar_using_exceptions(TSRMLS_D)
|
||||
zval *pval;
|
||||
pval = zend_read_static_property(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, (zend_bool) 1 TSRMLS_CC);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
assert(Z_TYPE_P(pval) == IS_BOOL);
|
||||
return Z_BVAL_P(pval);
|
||||
#else
|
||||
assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
|
||||
return Z_TYPE_P(pval) == IS_TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* returns a string or NULL if not an error */
|
||||
@@ -186,39 +173,22 @@ PHP_METHOD(rarexception, setUsingExceptions)
|
||||
Return whether exceptions are being used */
|
||||
PHP_METHOD(rarexception, isUsingExceptions)
|
||||
{
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval **pval;
|
||||
#else
|
||||
zval *pval;
|
||||
#endif
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* or zend_read_static_property, which calls zend_std_get... after chg scope */
|
||||
#if PHP_VERSION_ID < 50399
|
||||
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, (zend_bool) 0 TSRMLS_CC);
|
||||
#elif PHP_MAJOR_VERSION < 7
|
||||
pval = zend_std_get_static_property(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, (zend_bool) 0, NULL TSRMLS_CC);
|
||||
#else
|
||||
zend_string *prop_name =
|
||||
zend_string_init("usingExceptions", sizeof("usingExceptions") - 1, 0);
|
||||
pval = zend_std_get_static_property(rarexception_ce_ptr, prop_name,
|
||||
(zend_bool) 0);
|
||||
zend_string_release(prop_name);
|
||||
#endif
|
||||
/* property always exists */
|
||||
assert(pval != NULL);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
assert(Z_TYPE_PP(pval) == IS_BOOL);
|
||||
RETURN_ZVAL(*pval, 0, 0);
|
||||
#else
|
||||
assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
|
||||
RETURN_ZVAL(pval, 0, 0);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -231,31 +201,24 @@ ZEND_BEGIN_ARG_INFO(arginfo_rarexception_void, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
/* clang-format off */
|
||||
static zend_function_entry php_rarexception_class_functions[] = {
|
||||
PHP_ME(rarexception, setUsingExceptions, arginfo_rarexception_sue, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
||||
PHP_ME(rarexception, isUsingExceptions, arginfo_rarexception_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
void minit_rarerror(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
zend_class_entry ce;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "RarException", php_rarexception_class_functions);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
rarexception_ce_ptr = zend_register_internal_class_ex(&ce,
|
||||
zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
|
||||
#else
|
||||
rarexception_ce_ptr = zend_register_internal_class_ex(&ce,
|
||||
zend_exception_get_default(TSRMLS_C));
|
||||
#endif
|
||||
/* zend_exception_get_default() was removed in PHP 8.5; use the global directly */
|
||||
rarexception_ce_ptr = zend_register_internal_class_ex(&ce, zend_ce_exception);
|
||||
rarexception_ce_ptr->ce_flags |= ZEND_ACC_FINAL;
|
||||
zend_declare_property_bool(rarexception_ce_ptr, "usingExceptions",
|
||||
sizeof("usingExceptions") -1, 0L /* FALSE */,
|
||||
ZEND_ACC_STATIC TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,21 +25,16 @@
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include <wchar.h>
|
||||
#include "php_rar.h"
|
||||
|
||||
#if HAVE_RAR
|
||||
|
||||
/* {{{ Structure definitions */
|
||||
|
||||
/* clang-format off */
|
||||
typedef struct _rar_find_state {
|
||||
rar_find_output out;
|
||||
rar_file_t *rar;
|
||||
@@ -49,7 +44,7 @@ typedef struct _rar_find_state {
|
||||
struct _rar_unique_entry {
|
||||
size_t id; /* position in the entries_array */
|
||||
struct RARHeaderDataEx entry; /* last entry */
|
||||
unsigned long packed_size;
|
||||
zend_ulong packed_size;
|
||||
int depth; /* number of directory separators */
|
||||
size_t name_wlen; /* excluding L'\0' terminator */
|
||||
};
|
||||
@@ -65,6 +60,7 @@ struct _rar_entries {
|
||||
struct _rar_unique_entry *last_accessed;
|
||||
int list_result; /* tell whether the archive's broken */
|
||||
};
|
||||
/* clang-format on */
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -73,9 +69,7 @@ static void _rar_nav_get_depth_and_length(wchar_t *filenamew, const size_t file_
|
||||
int *depth_out, size_t *wlen_out TSRMLS_DC);
|
||||
static int _rar_nav_get_depth(const wchar_t *filenamew, const size_t file_size);
|
||||
static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC);
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
static void _rar_nav_swap_entries(void *op1, void *op2);
|
||||
#endif
|
||||
static int _rar_nav_compare_entries_std(const void *op1, const void *op2);
|
||||
static inline int _rar_nav_compare_values(const wchar_t *str1, const int depth1,
|
||||
const wchar_t *str2, const int depth2,
|
||||
@@ -116,15 +110,9 @@ void _rar_entry_search_start(rar_file_t *rar,
|
||||
sizeof rar->entries->entries_array_s[0]);
|
||||
memcpy(rar->entries->entries_array_s, rar->entries->entries_array,
|
||||
rar->entries->num_entries * sizeof rar->entries->entries_array[0]);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
|
||||
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries
|
||||
TSRMLS_CC);
|
||||
#else
|
||||
zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
|
||||
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries,
|
||||
_rar_nav_swap_entries);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
@@ -336,7 +324,7 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
|
||||
int result = 0;
|
||||
size_t capacity = 0;
|
||||
int first_file_check = TRUE;
|
||||
unsigned long packed_size = 0UL;
|
||||
zend_ulong packed_size = 0;
|
||||
struct _rar_entries *ents;
|
||||
|
||||
if (rar->entries != NULL) {
|
||||
@@ -378,22 +366,16 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
|
||||
|
||||
/* reset packed size if not split before */
|
||||
if ((entry.Flags & RHDF_SPLITBEFORE) == 0)
|
||||
packed_size = 0UL;
|
||||
packed_size = 0;
|
||||
|
||||
/* we would exceed size of ulong. cap at ulong_max
|
||||
* equivalent to packed_size + entry.PackSize > ULONG_MAX,
|
||||
* but without overflowing */
|
||||
if (ULONG_MAX - packed_size < entry.PackSize)
|
||||
packed_size = ULONG_MAX;
|
||||
else {
|
||||
packed_size += entry.PackSize;
|
||||
if (entry.PackSizeHigh != 0) {
|
||||
#if ULONG_MAX > 0xffffffffUL
|
||||
packed_size += ((unsigned long) entry.PackSizeHigh) << 32;
|
||||
#else
|
||||
packed_size = ULONG_MAX; /* cap */
|
||||
#endif
|
||||
}
|
||||
/* accumulate packed size; cap at ZEND_LONG_MAX (the PHP int ceiling) */
|
||||
{
|
||||
zend_ulong entry_packed = ((zend_ulong)entry.PackSizeHigh << 32) | entry.PackSize;
|
||||
if (entry_packed > (zend_ulong)ZEND_LONG_MAX ||
|
||||
packed_size > (zend_ulong)ZEND_LONG_MAX - entry_packed)
|
||||
packed_size = (zend_ulong)ZEND_LONG_MAX;
|
||||
else
|
||||
packed_size += entry_packed;
|
||||
}
|
||||
|
||||
if (entry.Flags & RHDF_SPLITAFTER) /* do not commit */
|
||||
@@ -502,7 +484,6 @@ static int _rar_nav_compare_entries(const void *op1, const void *op2 TSRMLS_DC)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
static void _rar_nav_swap_entries(void *op1, void *op2) /* {{{ */
|
||||
{
|
||||
/* just swaps two pointer values */
|
||||
@@ -515,7 +496,6 @@ static void _rar_nav_swap_entries(void *op1, void *op2) /* {{{ */
|
||||
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
||||
static int _rar_nav_compare_entries_std(const void *op1, const void *op2) /* {{{ */
|
||||
{
|
||||
@@ -620,12 +600,6 @@ static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
|
||||
|
||||
/* end functions with internal linkage */
|
||||
|
||||
#endif /* HAVE_RAR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
@@ -634,5 +608,3 @@ static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
|
||||
* vim600: noet sw=4 ts=4 fdm=marker
|
||||
* vim<600: noet sw=4 ts=4
|
||||
*/
|
||||
|
||||
|
||||
|
||||
203
rar_stream.c
203
rar_stream.c
@@ -27,17 +27,11 @@
|
||||
/* $Id$ */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
|
||||
#if HAVE_RAR
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "php_rar.h"
|
||||
@@ -47,6 +41,7 @@ extern "C" {
|
||||
#include <ext/standard/php_string.h>
|
||||
#include <ext/standard/file.h>
|
||||
|
||||
/* clang-format off */
|
||||
typedef struct php_rar_stream_data_t {
|
||||
struct RAROpenArchiveDataEx open_data;
|
||||
struct RARHeaderDataEx header_data;
|
||||
@@ -73,12 +68,15 @@ typedef struct php_rar_dir_stream_data_t {
|
||||
int no_encode; /* do not urlencode entry names */
|
||||
php_stream *stream;
|
||||
} php_rar_dir_stream_data, *php_rar_dir_stream_data_P;
|
||||
/* clang-format on */
|
||||
|
||||
/* clang-format off */
|
||||
#define STREAM_DATA_FROM_STREAM \
|
||||
php_rar_stream_data_P self = (php_rar_stream_data_P) stream->abstract;
|
||||
|
||||
#define STREAM_DIR_DATA_FROM_STREAM \
|
||||
php_rar_dir_stream_data_P self = (php_rar_dir_stream_data_P) stream->abstract;
|
||||
/* clang-format on */
|
||||
|
||||
/* len can be -1 (calculate) */
|
||||
static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
|
||||
@@ -166,7 +164,7 @@ static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
|
||||
if (self->cursor > self->file_size) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
"The file size is supposed to be %lu bytes, but "
|
||||
"we read more: %lu bytes (corruption/wrong pwd)",
|
||||
"we read more: %" PRIu64 " bytes (corruption/wrong pwd)",
|
||||
self->file_size, self->cursor);
|
||||
}
|
||||
}
|
||||
@@ -179,11 +177,7 @@ static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
|
||||
stream->eof = 1;
|
||||
}
|
||||
|
||||
#if PHP_VERSION_ID < 50400
|
||||
return n;
|
||||
#else
|
||||
return (ssize_t) n;
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -424,19 +418,10 @@ static ssize_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count
|
||||
entry.d_name, sizeof entry.d_name);
|
||||
|
||||
if (!self->no_encode) { /* urlencode entry */
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
int new_len;
|
||||
char *encoded_name;
|
||||
encoded_name = php_url_encode(entry.d_name, strlen(entry.d_name),
|
||||
&new_len);
|
||||
strlcpy(entry.d_name, encoded_name, sizeof entry.d_name);
|
||||
efree(encoded_name);
|
||||
#else
|
||||
zend_string *encoded_name =
|
||||
php_url_encode(entry.d_name, strlen(entry.d_name));
|
||||
strlcpy(entry.d_name, encoded_name->val, sizeof entry.d_name);
|
||||
zend_string_release(encoded_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -452,11 +437,7 @@ static int php_rar_dir_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
|
||||
{
|
||||
STREAM_DIR_DATA_FROM_STREAM
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_dtor(&self->rar_obj);
|
||||
#else
|
||||
zval_ptr_dtor(&self->rar_obj);
|
||||
#endif
|
||||
efree(self->directory);
|
||||
efree(self->state);
|
||||
efree(self);
|
||||
@@ -587,67 +568,6 @@ cleanup:
|
||||
|
||||
/* {{{ Wrapper stuff */
|
||||
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 3
|
||||
/* PHP 5.2 has no zend_resolve_path. Adapted from 5.3's php_resolve_path */
|
||||
static char *zend_resolve_path(const char *filename,
|
||||
int filename_length TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
const char *path = PG(include_path);
|
||||
char resolved_path[MAXPATHLEN];
|
||||
char trypath[MAXPATHLEN];
|
||||
const char *ptr, *end;
|
||||
char *actual_path;
|
||||
|
||||
if (filename == NULL || filename[0] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do not use the include path in these circumstances */
|
||||
if ((*filename == '.' && (IS_SLASH(filename[1]) ||
|
||||
((filename[1] == '.') && IS_SLASH(filename[2])))) ||
|
||||
IS_ABSOLUTE_PATH(filename, filename_length) ||
|
||||
path == NULL || path[0] == '\0') {
|
||||
if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
|
||||
return estrdup(resolved_path);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = path;
|
||||
while (ptr && *ptr) {
|
||||
end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
|
||||
if (end) {
|
||||
if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
|
||||
ptr = end + 1;
|
||||
continue;
|
||||
}
|
||||
memcpy(trypath, ptr, end-ptr);
|
||||
trypath[end-ptr] = '/';
|
||||
memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
|
||||
ptr = end+1;
|
||||
} else {
|
||||
int len = strlen(ptr);
|
||||
|
||||
if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
|
||||
break;
|
||||
}
|
||||
memcpy(trypath, ptr, len);
|
||||
trypath[len] = '/';
|
||||
memcpy(trypath+len+1, filename, filename_length+1);
|
||||
ptr = NULL;
|
||||
}
|
||||
actual_path = trypath;
|
||||
if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
|
||||
return estrdup(resolved_path);
|
||||
}
|
||||
} /* end provided path */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
#endif
|
||||
|
||||
/* {{{ php_rar_process_context */
|
||||
/* memory is to be managed externally */
|
||||
static void php_rar_process_context(php_stream_context *context,
|
||||
@@ -658,9 +578,6 @@ static void php_rar_process_context(php_stream_context *context,
|
||||
zval **volume_cb TSRMLS_DC)
|
||||
{
|
||||
zval *ctx_opt;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval **ctx_opt_p = NULL;
|
||||
#endif
|
||||
|
||||
assert(context != NULL);
|
||||
assert(open_password != NULL);
|
||||
@@ -670,14 +587,8 @@ static void php_rar_process_context(php_stream_context *context,
|
||||
|
||||
/* TODO: don't know if I can log errors and not fail. check that */
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (php_stream_context_get_option(
|
||||
context, "rar", "open_password", &ctx_opt_p) == SUCCESS) {
|
||||
ctx_opt = *ctx_opt_p;
|
||||
#else
|
||||
if ((ctx_opt = php_stream_context_get_option(
|
||||
context, "rar", "open_password"))) {
|
||||
#endif
|
||||
if (Z_TYPE_P(ctx_opt) != IS_STRING)
|
||||
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
|
||||
"RAR open password was provided, but not a string.");
|
||||
@@ -685,14 +596,8 @@ static void php_rar_process_context(php_stream_context *context,
|
||||
*open_password = Z_STRVAL_P(ctx_opt);
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (file_password != NULL && php_stream_context_get_option(context, "rar",
|
||||
"file_password", &ctx_opt_p) == SUCCESS) {
|
||||
ctx_opt = *ctx_opt_p;
|
||||
#else
|
||||
if (file_password != NULL && (ctx_opt = php_stream_context_get_option(
|
||||
context, "rar", "file_password"))) {
|
||||
#endif
|
||||
if (Z_TYPE_P(ctx_opt) != IS_STRING)
|
||||
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
|
||||
"RAR file password was provided, but not a string.");
|
||||
@@ -700,19 +605,9 @@ static void php_rar_process_context(php_stream_context *context,
|
||||
*file_password = Z_STRVAL_P(ctx_opt);
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (php_stream_context_get_option(context, "rar", "volume_callback",
|
||||
&ctx_opt_p) == SUCCESS) {
|
||||
ctx_opt = *ctx_opt_p;
|
||||
#else
|
||||
if ((ctx_opt = php_stream_context_get_option(
|
||||
context, "rar", "volume_callback"))) {
|
||||
#endif
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
|
||||
if (zend_is_callable(ctx_opt, IS_CALLABLE_STRICT, NULL)) {
|
||||
#else
|
||||
if (zend_is_callable(ctx_opt, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
|
||||
#endif
|
||||
*volume_cb = ctx_opt;
|
||||
}
|
||||
else
|
||||
@@ -781,23 +676,19 @@ static int _rar_get_archive_and_fragment(php_stream_wrapper *wrapper,
|
||||
|
||||
if (!(options & STREAM_ASSUME_REALPATH)) {
|
||||
if (options & USE_PATH) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
*archive = zend_resolve_path(tmp_archive, tmp_arch_len TSRMLS_CC);
|
||||
#else
|
||||
# if PHP_VERSION_ID < 80100
|
||||
#if PHP_VERSION_ID < 80100
|
||||
zend_string *arc_str = zend_resolve_path(tmp_archive, tmp_arch_len);
|
||||
# else
|
||||
#else
|
||||
zend_string *tmp_archive_str = zend_string_init_fast(tmp_archive, tmp_arch_len);
|
||||
zend_string *arc_str = zend_resolve_path(tmp_archive_str);
|
||||
zend_string_free(tmp_archive_str);
|
||||
# endif
|
||||
#endif
|
||||
if (arc_str != NULL) {
|
||||
*archive = estrndup(arc_str->val, arc_str->len);
|
||||
} else {
|
||||
*archive = NULL;
|
||||
}
|
||||
zend_string_release(arc_str);
|
||||
#endif
|
||||
}
|
||||
if (*archive == NULL) {
|
||||
if ((*archive = expand_filepath(tmp_archive, NULL TSRMLS_CC))
|
||||
@@ -865,17 +756,10 @@ cleanup:
|
||||
|
||||
/* {{{ php_stream_rar_opener */
|
||||
static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
char *filename,
|
||||
char *mode,
|
||||
int options,
|
||||
char **opened_path,
|
||||
#else
|
||||
const char *filename,
|
||||
const char *mode,
|
||||
int options,
|
||||
zend_string **opened_path,
|
||||
#endif
|
||||
php_stream_context *context
|
||||
STREAMS_DC TSRMLS_DC)
|
||||
{
|
||||
@@ -987,12 +871,8 @@ cleanup:
|
||||
|
||||
if (tmp_open_path != NULL) {
|
||||
if (opened_path != NULL) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
*opened_path = tmp_open_path;
|
||||
#else
|
||||
*opened_path =
|
||||
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
|
||||
#endif
|
||||
} else {
|
||||
efree(tmp_open_path);
|
||||
}
|
||||
@@ -1048,11 +928,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
|
||||
zval *cache_zv;
|
||||
|
||||
assert(rar_obj != NULL);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
INIT_ZVAL(*rar_obj);
|
||||
#else
|
||||
ZVAL_UNDEF(rar_obj);
|
||||
#endif
|
||||
|
||||
_rar_arch_cache_get_key(arch_path, open_passwd, volume_cb, &cache_key,
|
||||
&cache_key_len);
|
||||
@@ -1115,56 +991,26 @@ cleanup:
|
||||
efree(cache_key);
|
||||
|
||||
if (ret != SUCCESS && Z_TYPE_P(rar_obj) == IS_OBJECT) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_dtor(rar_obj);
|
||||
Z_TYPE_P(rar_obj) = IS_NULL;
|
||||
#else
|
||||
zval_ptr_dtor(rar_obj);
|
||||
ZVAL_UNDEF(rar_obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _rar_stream_tidy_wrapper_error_log
|
||||
* These two different versions are because of PHP commit 7166298 */
|
||||
#if PHP_VERSION_ID <= 50310 || PHP_VERSION_ID == 50400
|
||||
/* copied from main/streams/streams.c because it's an internal function */
|
||||
static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
|
||||
{
|
||||
if (wrapper) {
|
||||
/* tidy up the error stack */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wrapper->err_count; i++) {
|
||||
efree(wrapper->err_stack[i]);
|
||||
}
|
||||
if (wrapper->err_stack) {
|
||||
efree(wrapper->err_stack);
|
||||
}
|
||||
wrapper->err_stack = NULL;
|
||||
wrapper->err_count = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* {{{ _rar_stream_tidy_wrapper_error_log */
|
||||
static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
|
||||
{
|
||||
if (wrapper && FG(wrapper_errors)) {
|
||||
zend_hash_str_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_stream_rar_stater */
|
||||
static int php_stream_rar_stater(php_stream_wrapper *wrapper,
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
char *url,
|
||||
#else
|
||||
const char *url,
|
||||
#endif
|
||||
int flags,
|
||||
php_stream_statbuf *ssb,
|
||||
php_stream_context *context TSRMLS_DC)
|
||||
@@ -1183,11 +1029,7 @@ static int php_stream_rar_stater(php_stream_wrapper *wrapper,
|
||||
int ret = FAILURE;
|
||||
|
||||
/* {{{ preliminaries */
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
Z_TYPE(rararch) = IS_NULL;
|
||||
#else
|
||||
ZVAL_UNDEF(&rararch);
|
||||
#endif
|
||||
|
||||
if (_rar_get_archive_and_fragment(wrapper, url, options, 1,
|
||||
&open_path, &fragment, NULL TSRMLS_CC) == FAILURE) {
|
||||
@@ -1238,11 +1080,7 @@ cleanup:
|
||||
}
|
||||
|
||||
if (Z_TYPE(rararch) == IS_OBJECT) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_dtor(&rararch);
|
||||
#else
|
||||
zval_ptr_dtor(&rararch);
|
||||
#endif
|
||||
}
|
||||
if (state != NULL) {
|
||||
_rar_entry_search_end(state);
|
||||
@@ -1265,17 +1103,10 @@ cleanup:
|
||||
|
||||
/* {{{ php_stream_rar_dir_opener */
|
||||
static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper,
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
char *filename,
|
||||
char *mode,
|
||||
int options,
|
||||
char **opened_path,
|
||||
#else
|
||||
const char *filename,
|
||||
const char *mode,
|
||||
int options,
|
||||
zend_string **opened_path,
|
||||
#endif
|
||||
php_stream_context *context
|
||||
STREAMS_DC TSRMLS_DC)
|
||||
{
|
||||
@@ -1374,12 +1205,8 @@ cleanup:
|
||||
|
||||
if (tmp_open_path != NULL) {
|
||||
if (opened_path != NULL) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
*opened_path = tmp_open_path;
|
||||
#else
|
||||
*opened_path =
|
||||
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
|
||||
#endif
|
||||
} else {
|
||||
efree(tmp_open_path);
|
||||
}
|
||||
@@ -1390,11 +1217,7 @@ cleanup:
|
||||
if (stream == NULL) { /* failed */
|
||||
if (self != NULL) {
|
||||
if (Z_TYPE(self->rar_obj) == IS_OBJECT) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_dtor(&self->rar_obj);
|
||||
#else
|
||||
zval_ptr_dtor(&self->rar_obj);
|
||||
#endif
|
||||
}
|
||||
if (self->directory != NULL) {
|
||||
efree(self->directory);
|
||||
@@ -1431,12 +1254,6 @@ php_stream_wrapper php_stream_rar_wrapper = {
|
||||
|
||||
/* end wrapper stuff }}} */
|
||||
|
||||
#endif /* HAVE_RAR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <php.h>
|
||||
#include "php_rar.h"
|
||||
|
||||
@@ -57,7 +53,3 @@ int rar_dos_time_convert(unsigned dos_time, time_t *to) /* {{{ */
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
230
rararch.c
230
rararch.c
@@ -29,9 +29,6 @@
|
||||
|
||||
#include "zend_types.h"
|
||||
#include <zend_API.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
@@ -45,26 +42,19 @@ extern "C" {
|
||||
#include "php_compat.h"
|
||||
|
||||
/* {{{ Type definitions reserved for this translation unit */
|
||||
/* clang-format off */
|
||||
typedef struct _ze_rararch_object {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zend_object parent;
|
||||
rar_file_t *rar_file;
|
||||
#else
|
||||
rar_file_t *rar_file;
|
||||
zend_object parent;
|
||||
#endif
|
||||
} ze_rararch_object;
|
||||
|
||||
typedef struct _rararch_iterator {
|
||||
zend_object_iterator parent;
|
||||
rar_find_output *state;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval *value;
|
||||
#else
|
||||
zval value;
|
||||
#endif
|
||||
int empty_iterator; /* iterator should give nothing */
|
||||
} rararch_iterator;
|
||||
/* clang-format on */
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Globals with internal linkage */
|
||||
@@ -88,30 +78,19 @@ static zend_object_handlers rararch_object_handlers;
|
||||
/* {{{ Function prototypes for functions with internal linkage */
|
||||
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv);
|
||||
static inline void rar_obj_ref_make_zv(rar_obj_ref zo, zval *zv TSRMLS_DC);
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
static inline ze_rararch_object *rararch_object_fetch(zend_object *zobj);
|
||||
|
||||
static ze_rararch_object *rararch_object_from_zv(const zval *zv);
|
||||
static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref);
|
||||
static zend_object *rararch_ce_create_object(zend_class_entry *ce);
|
||||
static void rararch_ce_free_object_storage(zend_object *zobj);
|
||||
#else
|
||||
#define rararch_object_from_zv zend_object_store_get_object
|
||||
#define rararch_object_from_ref(ref) zend_object_store_get_object_by_handle((ref) TSRMLS_CC)
|
||||
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC);
|
||||
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC);
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive handlers */
|
||||
static int rararch_handlers_preamble(handler_this_t *object, rar_file_t **rar TSRMLS_DC);
|
||||
static int rararch_dimensions_preamble(rar_file_t *rar, zval *offset, long *index, int quiet TSRMLS_DC);
|
||||
static int rararch_count_elements(handler_this_t *object, long *count TSRMLS_DC);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
|
||||
#else
|
||||
static int rararch_dimensions_preamble(rar_file_t *rar, zval *offset, zend_long *index, int quiet TSRMLS_DC);
|
||||
static int rararch_count_elements(handler_this_t *object, zend_long *count TSRMLS_DC);
|
||||
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv);
|
||||
#endif
|
||||
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC);
|
||||
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC);
|
||||
/* }}} */
|
||||
@@ -258,25 +237,17 @@ static void _rar_raw_entries_to_array(rar_file_t *rar, zval *target TSRMLS_DC) /
|
||||
state->position, entry_obj TSRMLS_CC);
|
||||
|
||||
add_next_index_zval(target, entry_obj);
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
/* PHP 7 copies the zval (but without increasing the refcount of the
|
||||
* obj), while 5.x simply copies the pointer. Only for PHP 5.x do we
|
||||
* keep the allocation) */
|
||||
* obj). Free the allocation. */
|
||||
efree(entry_obj);
|
||||
#endif
|
||||
}
|
||||
} while (state->eof == 0);
|
||||
_rar_entry_search_end(state);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_dtor(&rararch_obj);
|
||||
#else
|
||||
zval_ptr_dtor(&rararch_obj);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#if PHP_MAJOR_VERSION >=7
|
||||
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv)
|
||||
{
|
||||
return Z_OBJ(*zv);
|
||||
@@ -286,24 +257,7 @@ static inline void rar_obj_ref_make_zv(rar_obj_ref zo, zval *zv TSRMLS_DC)
|
||||
ZVAL_OBJ(zv, zo);
|
||||
zval_addref_p(zv);
|
||||
}
|
||||
#else
|
||||
inline rar_obj_ref rar_obj_ref_fetch(zval *zv)
|
||||
{
|
||||
return Z_OBJ_HANDLE_P(zv);
|
||||
}
|
||||
inline void rar_obj_ref_make_zv(rar_obj_ref zoh, zval *zv TSRMLS_DC)
|
||||
{
|
||||
INIT_ZVAL(*zv);
|
||||
Z_TYPE_P(zv) = IS_OBJECT;
|
||||
Z_OBJ_HANDLE_P(zv) = zoh;
|
||||
Z_OBJ_HT_P(zv) = &rararch_object_handlers;
|
||||
/* object has a new reference; if not incremented, the object would be
|
||||
* be destroyed when this new zval we created was destroyed */
|
||||
zend_objects_store_add_ref_by_handle(zoh TSRMLS_CC);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PHP_MAJOR_VERSION >=7
|
||||
static inline ze_rararch_object *rararch_object_fetch(zend_object *zobj)
|
||||
{
|
||||
return (ze_rararch_object *)
|
||||
@@ -317,35 +271,8 @@ static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref)
|
||||
{
|
||||
return rararch_object_fetch(ref);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* {{{ */
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static zend_object_value rararch_ce_create_object(zend_class_entry *class_type TSRMLS_DC)
|
||||
{
|
||||
zend_object_value zov;
|
||||
ze_rararch_object *zobj;
|
||||
|
||||
zobj = emalloc(sizeof *zobj);
|
||||
/* rararch_ce_free_object_storage will attempt to access it otherwise */
|
||||
zobj->rar_file = NULL;
|
||||
zend_object_std_init((zend_object*) zobj, class_type TSRMLS_CC);
|
||||
|
||||
#if PHP_VERSION_ID < 50399
|
||||
zend_hash_copy(((zend_object*)zobj)->properties,
|
||||
&(class_type->default_properties),
|
||||
(copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
|
||||
#else
|
||||
object_properties_init((zend_object*)zobj, class_type);
|
||||
#endif
|
||||
zov.handle = zend_objects_store_put(zobj,
|
||||
(zend_objects_store_dtor_t) zend_objects_destroy_object,
|
||||
(zend_objects_free_object_storage_t) rararch_ce_free_object_storage,
|
||||
NULL TSRMLS_CC);
|
||||
zov.handlers = &rararch_object_handlers;
|
||||
return zov;
|
||||
}
|
||||
#else
|
||||
static zend_object *rararch_ce_create_object(zend_class_entry *ce)
|
||||
{
|
||||
ze_rararch_object *zobj =
|
||||
@@ -357,18 +284,12 @@ static zend_object *rararch_ce_create_object(zend_class_entry *ce)
|
||||
|
||||
return &zobj->parent;
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* {{{ */
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static void rararch_ce_free_object_storage(ze_rararch_object *object TSRMLS_DC)
|
||||
{
|
||||
#else
|
||||
static void rararch_ce_free_object_storage(zend_object *zobj)
|
||||
{
|
||||
ze_rararch_object *object = rararch_object_fetch(zobj);
|
||||
#endif
|
||||
rar_file_t *rar = object->rar_file;
|
||||
|
||||
/* may be NULL if the user did new RarArchive() */
|
||||
@@ -392,9 +313,6 @@ static void rararch_ce_free_object_storage(zend_object *zobj)
|
||||
/* could call zend_objects_free_object_storage here (not before!), but
|
||||
* instead I'll mimic its behaviour */
|
||||
zend_object_std_dtor(&object->parent TSRMLS_CC);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
efree(object);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -420,7 +338,7 @@ static int rararch_handlers_preamble(handler_this_t *object,
|
||||
/* {{{ rararch_dimensions_preamble - semi-strict parsing of int argument */
|
||||
static int rararch_dimensions_preamble(rar_file_t *rar,
|
||||
zval *offset,
|
||||
long *index,
|
||||
zend_long *index,
|
||||
int quiet TSRMLS_DC)
|
||||
{
|
||||
if (offset == NULL) {
|
||||
@@ -444,36 +362,32 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
|
||||
return FAILURE;
|
||||
}
|
||||
else if (type == IS_DOUBLE) {
|
||||
if (d > (double) LONG_MAX || d < (double) LONG_MIN) {
|
||||
if (d > (double) ZEND_LONG_MAX || d < (double) ZEND_LONG_MIN) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index is out of integer bounds");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*index = (long) d;
|
||||
*index = (zend_long) d;
|
||||
}
|
||||
}
|
||||
else if (Z_TYPE_P(offset) == IS_DOUBLE) {
|
||||
if (Z_DVAL_P(offset) > (double) LONG_MAX ||
|
||||
Z_DVAL_P(offset) < (double) LONG_MIN) {
|
||||
if (Z_DVAL_P(offset) > (double) ZEND_LONG_MAX ||
|
||||
Z_DVAL_P(offset) < (double) ZEND_LONG_MIN) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index is out of integer bounds");
|
||||
return FAILURE;
|
||||
}
|
||||
*index = (long) Z_DVAL_P(offset);
|
||||
*index = (zend_long) Z_DVAL_P(offset);
|
||||
}
|
||||
else if (Z_TYPE_P(offset) == IS_OBJECT) {
|
||||
#if PHP_MAJOR_VERSION < 8
|
||||
if (Z_OBJ_HT_P(offset)->get) {
|
||||
zval *newoffset = NULL;
|
||||
int ret;
|
||||
# if PHP_MAJOR_VERSION < 7
|
||||
newoffset = Z_OBJ_HT_P(offset)->get(offset TSRMLS_CC);
|
||||
# else
|
||||
zval zv_holder;
|
||||
ZVAL_NULL(&zv_holder);
|
||||
newoffset = Z_OBJ_HT_P(offset)->get(offset, &zv_holder);
|
||||
# endif
|
||||
|
||||
/* get handler cannot return NULL */
|
||||
assert(newoffset != NULL);
|
||||
@@ -486,11 +400,7 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
|
||||
|
||||
ret = rararch_dimensions_preamble(rar, newoffset, index, quiet
|
||||
TSRMLS_CC);
|
||||
# if PHP_MAJOR_VERSION < 7
|
||||
zval_ptr_dtor(&newoffset);
|
||||
# else
|
||||
zval_ptr_dtor(newoffset);
|
||||
# endif
|
||||
return ret;
|
||||
} else
|
||||
#endif // PHP < 8
|
||||
@@ -527,9 +437,9 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (*index < 0L) {
|
||||
if (*index < 0) {
|
||||
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
|
||||
"Dimension index must be non-negative, given %ld", *index);
|
||||
"Dimension index must be non-negative, given " ZEND_LONG_FMT, *index);
|
||||
return FAILURE;
|
||||
}
|
||||
if ((size_t) *index >= _rar_entry_count(rar)) {
|
||||
@@ -544,34 +454,30 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive count_elements handler */
|
||||
static int rararch_count_elements(handler_this_t *object, long *count TSRMLS_DC)
|
||||
static int rararch_count_elements(handler_this_t *object, zend_long *count TSRMLS_DC)
|
||||
{
|
||||
rar_file_t *rar = NULL;
|
||||
size_t entry_count;
|
||||
|
||||
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
|
||||
*count = 0L;
|
||||
*count = 0;
|
||||
return SUCCESS; /* intentional */
|
||||
}
|
||||
|
||||
entry_count = _rar_entry_count(rar);
|
||||
if (entry_count > LONG_MAX)
|
||||
entry_count = (size_t) LONG_MAX;
|
||||
if (entry_count > ZEND_LONG_MAX)
|
||||
entry_count = (size_t) ZEND_LONG_MAX;
|
||||
|
||||
*count = (long) entry_count;
|
||||
*count = (zend_long) entry_count;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ RarArchive read_dimension handler */
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
|
||||
#else
|
||||
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv)
|
||||
#endif
|
||||
{
|
||||
long index;
|
||||
zend_long index;
|
||||
rar_file_t *rar = NULL;
|
||||
struct _rar_find_output *out;
|
||||
zval *ret = NULL;
|
||||
@@ -592,11 +498,7 @@ static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int ty
|
||||
_rar_entry_search_seek(out, (size_t) index);
|
||||
_rar_entry_search_advance(out, NULL, 0, 0);
|
||||
assert(out->found);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
ALLOC_INIT_ZVAL(ret);
|
||||
#else
|
||||
ret = rv;
|
||||
#endif
|
||||
#if PHP_MAJOR_VERSION >= 8
|
||||
zval object_zv;
|
||||
ZVAL_OBJ(&object_zv, object);
|
||||
@@ -608,9 +510,6 @@ static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int ty
|
||||
ret TSRMLS_CC);
|
||||
#endif
|
||||
_rar_entry_search_end(out);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
Z_DELREF_P(ret); /* set refcount to 0 */
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -626,7 +525,7 @@ static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *
|
||||
/* {{{ RarArchive has_dimension handler */
|
||||
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC)
|
||||
{
|
||||
long index;
|
||||
zend_long index;
|
||||
rar_file_t *rar = NULL;
|
||||
|
||||
(void) check_empty; /* don't care */
|
||||
@@ -681,11 +580,7 @@ PHP_FUNCTION(rar_open)
|
||||
assert(strnlen(resolved_path, MAXPATHLEN) < MAXPATHLEN);
|
||||
|
||||
if (callable != NULL) { /* given volume resolver callback */
|
||||
#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 2
|
||||
if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL)) {
|
||||
#else
|
||||
if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
|
||||
#endif
|
||||
_rar_handle_ext_error("%s" TSRMLS_CC, "Expected the third "
|
||||
"argument, if provided, to be a valid callback");
|
||||
RETURN_FALSE;
|
||||
@@ -970,8 +865,16 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_rararchive_void, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#if PHP_VERSION_ID >= 80200
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rararchive_tostring, 0, 0, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#else
|
||||
#define arginfo_rararchive_tostring arginfo_rararchive_void
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* clang-format off */
|
||||
static zend_function_entry php_rararch_class_functions[] = {
|
||||
PHP_ME_MAPPING(open, rar_open, arginfo_rararchive_open, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(getEntries, rar_list, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
@@ -984,13 +887,14 @@ static zend_function_entry php_rararch_class_functions[] = {
|
||||
PHP_ME_MAPPING(isBroken, rar_broken_is, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(setAllowBroken, rar_allow_broken_set, arginfo_rararchive_setallowbroken, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(close, rar_close, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rararch, __toString, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rararch, __toString, arginfo_rararchive_tostring, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rararchive_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
|
||||
#if PHP_MAJOR_VERSION >= 8
|
||||
PHP_ME(rararch, getIterator, arginfo_rararchive_getiterator, ZEND_ACC_PUBLIC)
|
||||
#endif
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
/* {{{ Iteration. Very boring stuff indeed. */
|
||||
|
||||
@@ -1002,12 +906,7 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
|
||||
static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC);
|
||||
static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC);
|
||||
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static void rararch_it_current_data(zend_object_iterator *iter,
|
||||
zval ***data TSRMLS_DC);
|
||||
#else
|
||||
static zval *rararch_it_current_data(zend_object_iterator *iter);
|
||||
#endif
|
||||
static void rararch_it_move_forward(zend_object_iterator *iter TSRMLS_DC);
|
||||
static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC);
|
||||
/* }}} */
|
||||
@@ -1016,15 +915,8 @@ static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC);
|
||||
static void rararch_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it = (rararch_iterator *) iter;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (it->value != NULL) {
|
||||
zval_ptr_dtor(&it->value);
|
||||
it->value = NULL;
|
||||
}
|
||||
#else
|
||||
zval_ptr_dtor(&it->value);
|
||||
ZVAL_UNDEF(&it->value);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1035,16 +927,9 @@ static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC)
|
||||
|
||||
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_ptr_dtor((zval**) &it->parent.data); /* decrease refcount on zval object */
|
||||
#else
|
||||
zval_ptr_dtor(&it->parent.data);
|
||||
#endif
|
||||
|
||||
_rar_entry_search_end(it->state);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
efree(it);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -1055,27 +940,14 @@ static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC)
|
||||
int res;
|
||||
zval *robj;
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
assert(it->value == NULL);
|
||||
#else
|
||||
assert(Z_TYPE(it->value) == IS_UNDEF);
|
||||
#endif
|
||||
|
||||
if (it->empty_iterator) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(it->value);
|
||||
ZVAL_FALSE(it->value);
|
||||
#else
|
||||
ZVAL_FALSE(&it->value);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
robj = it->parent.data;
|
||||
#else
|
||||
robj = &it->parent.data;
|
||||
#endif
|
||||
|
||||
res = _rar_get_file_resource_zv_ex(robj, &rar_file, 1 TSRMLS_CC);
|
||||
if (res == FAILURE)
|
||||
@@ -1083,50 +955,25 @@ static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC)
|
||||
"Cannot fetch RarArchive object");
|
||||
|
||||
_rar_entry_search_advance(it->state, NULL, 0, 0);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(it->value);
|
||||
if (it->state->found)
|
||||
_rar_entry_to_zval(robj, it->state->header, it->state->packed_size,
|
||||
it->state->position, it->value TSRMLS_CC);
|
||||
else {
|
||||
ZVAL_FALSE(it->value);
|
||||
}
|
||||
#else
|
||||
if (it->state->found)
|
||||
_rar_entry_to_zval(&it->parent.data, it->state->header,
|
||||
it->state->packed_size, it->state->position, &it->value TSRMLS_CC);
|
||||
else {
|
||||
ZVAL_FALSE(&it->value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_valid */
|
||||
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval *value = ((rararch_iterator *) iter)->value;
|
||||
assert(value != NULL);
|
||||
return (Z_TYPE_P(value) != IS_BOOL)?SUCCESS:FAILURE;
|
||||
#else
|
||||
zval *value = &((rararch_iterator *) iter)->value;
|
||||
assert(Z_TYPE_P(value) != IS_UNDEF);
|
||||
return Z_TYPE_P(value) != IS_FALSE ? SUCCESS : FAILURE;
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_current_data */
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static void rararch_it_current_data(zend_object_iterator *iter,
|
||||
zval ***data TSRMLS_DC)
|
||||
{
|
||||
zval **value = &(((rararch_iterator *) iter)->value);
|
||||
assert(*value != NULL);
|
||||
*data = value;
|
||||
}
|
||||
#else
|
||||
static zval *rararch_it_current_data(zend_object_iterator *iter)
|
||||
{
|
||||
zval *ret;
|
||||
@@ -1134,7 +981,6 @@ static zval *rararch_it_current_data(zend_object_iterator *iter)
|
||||
assert(Z_TYPE_P(ret) != IS_UNDEF);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* {{{ rararch_it_move_forward */
|
||||
@@ -1142,11 +988,7 @@ static void rararch_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
|
||||
{
|
||||
rararch_iterator *it = (rararch_iterator *) iter;
|
||||
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
it->value = NULL;
|
||||
#else
|
||||
ZVAL_UNDEF(&it->value);
|
||||
#endif
|
||||
rararch_it_fetch(it TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
@@ -1198,15 +1040,9 @@ static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
|
||||
|
||||
rararch_iterator *it = emalloc(sizeof *it);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval_add_ref(&object);
|
||||
it->parent.data = object;
|
||||
it->value = NULL;
|
||||
#else
|
||||
zend_iterator_init((zend_object_iterator *) it);
|
||||
ZVAL_COPY(&it->parent.data, object);
|
||||
ZVAL_UNDEF(&it->value);
|
||||
#endif
|
||||
|
||||
#if PHP_VERSION_ID < 70300
|
||||
it->parent.funcs = ce->iterator_funcs.funcs;
|
||||
@@ -1240,10 +1076,8 @@ void minit_rararch(TSRMLS_D)
|
||||
rararch_object_handlers.has_dimension = rararch_has_dimension;
|
||||
rararch_object_handlers.unset_dimension = rararch_unset_dimension;
|
||||
rararch_object_handlers.clone_obj = NULL;
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
rararch_object_handlers.free_obj = rararch_ce_free_object_storage;
|
||||
rararch_object_handlers.offset = XtOffsetOf(ze_rararch_object, parent);
|
||||
#endif
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "RarArchive", php_rararch_class_functions);
|
||||
rararch_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
|
||||
@@ -1260,7 +1094,3 @@ void minit_rararch(TSRMLS_D)
|
||||
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
69
rarentry.c
69
rarentry.c
@@ -51,11 +51,11 @@ static void _rar_dos_date_to_text(unsigned dos_time, char *date_string);
|
||||
/* {{{ Functions with external linkage */
|
||||
/* should be passed the last entry that corresponds to a given file
|
||||
* only that one has the correct CRC. Still, it may have a wrong packedSize */
|
||||
/* parent is zval to RarArchive object. The object (not the zval, in PHP 5.x)
|
||||
/* parent is zval to RarArchive object. The object
|
||||
* will have its refcount increased */
|
||||
void _rar_entry_to_zval(zval *parent,
|
||||
struct RARHeaderDataEx *entry,
|
||||
unsigned long packed_size,
|
||||
zend_ulong packed_size,
|
||||
size_t position,
|
||||
zval *object TSRMLS_DC)
|
||||
/* {{{ */
|
||||
@@ -65,15 +65,8 @@ void _rar_entry_to_zval(zval *parent,
|
||||
char *filename;
|
||||
int filename_size,
|
||||
filename_len;
|
||||
long unp_size; /* zval stores PHP ints as long, so use that here */
|
||||
zend_long unp_size;
|
||||
zval *parent_copy = parent;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
/* allocate zval on the heap */
|
||||
zval_addref_p(parent_copy);
|
||||
SEPARATE_ZVAL(&parent_copy);
|
||||
/* set refcount to 0; zend_update_property will increase it */
|
||||
Z_DELREF_P(parent_copy);
|
||||
#endif
|
||||
|
||||
object_init_ex(object, rar_class_entry_ptr);
|
||||
#if PHP_MAJOR_VERSION >= 8
|
||||
@@ -85,22 +78,17 @@ void _rar_entry_to_zval(zval *parent,
|
||||
zend_update_property(rar_class_entry_ptr, obj, "rarfile",
|
||||
sizeof("rararch") - 1, parent_copy TSRMLS_CC);
|
||||
|
||||
#if ULONG_MAX > 0xffffffffUL
|
||||
unp_size = ((long) entry->UnpSize) + (((long) entry->UnpSizeHigh) << 32);
|
||||
#else
|
||||
/* for 32-bit long, at least don't give negative values */
|
||||
if ((unsigned long) entry->UnpSize > (unsigned long) LONG_MAX
|
||||
|| entry->UnpSizeHigh != 0)
|
||||
unp_size = LONG_MAX;
|
||||
else
|
||||
unp_size = (long) entry->UnpSize;
|
||||
#endif
|
||||
{
|
||||
uint64_t raw_size = (uint64_t)entry->UnpSizeHigh << 32 | entry->UnpSize;
|
||||
unp_size = raw_size > (uint64_t)ZEND_LONG_MAX
|
||||
? ZEND_LONG_MAX : (zend_long)raw_size;
|
||||
}
|
||||
|
||||
filename_size = sizeof(entry->FileNameW) * 4;
|
||||
filename = (char*) emalloc(filename_size);
|
||||
|
||||
if (packed_size > (unsigned long) LONG_MAX)
|
||||
packed_size = LONG_MAX;
|
||||
if (packed_size > (zend_ulong) ZEND_LONG_MAX)
|
||||
packed_size = (zend_ulong) ZEND_LONG_MAX;
|
||||
_rar_wide_to_utf(entry->FileNameW, filename, filename_size);
|
||||
/* OK; safe usage below: */
|
||||
filename_len = _rar_strnlen(filename, filename_size);
|
||||
@@ -109,7 +97,7 @@ void _rar_entry_to_zval(zval *parent,
|
||||
* direct call to rarentry_object_handlers.write_property
|
||||
* zend_update_property_x updates the scope accordingly */
|
||||
zend_update_property_long(rar_class_entry_ptr, obj, "position",
|
||||
sizeof("position") - 1, (long) position TSRMLS_CC);
|
||||
sizeof("position") - 1, (zend_long) position TSRMLS_CC);
|
||||
zend_update_property_stringl(rar_class_entry_ptr, obj, "name",
|
||||
sizeof("name") - 1, filename, filename_len TSRMLS_CC);
|
||||
zend_update_property_long(rar_class_entry_ptr, obj, "unpacked_size",
|
||||
@@ -176,7 +164,7 @@ void _rar_entry_to_zval(zval *parent,
|
||||
|
||||
#define REG_RAR_CLASS_CONST_LONG(const_name, value) \
|
||||
zend_declare_class_constant_long(rar_class_entry_ptr, const_name, \
|
||||
sizeof(const_name) - 1, (long) value TSRMLS_CC)
|
||||
sizeof(const_name) - 1, (zend_long) value TSRMLS_CC)
|
||||
|
||||
#define REG_RAR_PROPERTY(name, comment) \
|
||||
_rar_decl_priv_prop_null(rar_class_entry_ptr, name, sizeof(name) -1, \
|
||||
@@ -186,13 +174,6 @@ static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
|
||||
int name_length, char *doc_comment,
|
||||
int doc_comment_len TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval *property;
|
||||
ALLOC_PERMANENT_ZVAL(property);
|
||||
INIT_ZVAL(*property);
|
||||
return zend_declare_property_ex(ce, name, name_length, property,
|
||||
ZEND_ACC_PRIVATE, doc_comment, doc_comment_len TSRMLS_CC);
|
||||
#else
|
||||
zval property;
|
||||
zend_string *name_str,
|
||||
*doc_str;
|
||||
@@ -212,16 +193,13 @@ static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
|
||||
zend_string_release(name_str);
|
||||
zend_string_release(doc_str);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *tmp;
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
zval zv;
|
||||
#endif
|
||||
#if PHP_VERSION_ID < 70100
|
||||
zend_class_entry *orig_scope = EG(scope);
|
||||
|
||||
@@ -230,10 +208,8 @@ static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TS
|
||||
|
||||
#if PHP_MAJOR_VERSION >= 8
|
||||
tmp = zend_read_property(Z_OBJCE_P(entry_obj), Z_OBJ_P(entry_obj), name, namelen, 1, &zv);
|
||||
#elif PHP_MAJOR_VERSION >= 7
|
||||
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv);
|
||||
#else
|
||||
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1 TSRMLS_CC);
|
||||
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv);
|
||||
#endif
|
||||
if (tmp == NULL) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
||||
@@ -289,7 +265,7 @@ PHP_METHOD(rarentry, extract)
|
||||
*tmp_position;
|
||||
rar_file_t *rar = NULL;
|
||||
zval *entry_obj = getThis();
|
||||
struct RARHeaderDataEx entry;
|
||||
struct RARHeaderDataEx entry = {0};
|
||||
HANDLE extract_handle = NULL;
|
||||
int result;
|
||||
int found;
|
||||
@@ -585,7 +561,7 @@ PHP_METHOD(rarentry, isDirectory)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
long flags;
|
||||
zend_long flags;
|
||||
int is_dir;
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
@@ -604,7 +580,7 @@ PHP_METHOD(rarentry, isEncrypted)
|
||||
{
|
||||
zval *tmp;
|
||||
zval *entry_obj = getThis();
|
||||
long flags;
|
||||
zend_long flags;
|
||||
int is_encrypted;
|
||||
|
||||
RAR_RETNULL_ON_ARGS();
|
||||
@@ -735,8 +711,16 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_rar_void, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#if PHP_VERSION_ID >= 80200
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rar_tostring, 0, 0, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
#else
|
||||
#define arginfo_rar_tostring arginfo_rar_void
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* clang-format off */
|
||||
static zend_function_entry php_rar_class_functions[] = {
|
||||
PHP_ME(rarentry, extract, arginfo_rarentry_extract, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getPosition, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
@@ -755,10 +739,11 @@ static zend_function_entry php_rar_class_functions[] = {
|
||||
PHP_ME(rarentry, getRedirType, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, isRedirectToDirectory, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, getRedirTarget, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, __toString, arginfo_rar_void, ZEND_ACC_PUBLIC)
|
||||
PHP_ME(rarentry, __toString, arginfo_rar_tostring, ZEND_ACC_PUBLIC)
|
||||
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
void minit_rarentry(TSRMLS_D)
|
||||
{
|
||||
@@ -785,6 +770,7 @@ void minit_rarentry(TSRMLS_D)
|
||||
REG_RAR_PROPERTY("redir_to_directory", "Whether the redirection target is a directory");
|
||||
REG_RAR_PROPERTY("redir_target", "Target of the redirectory");
|
||||
|
||||
/* clang-format off */
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_MSDOS", HOST_MSDOS);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_OS2", HOST_OS2);
|
||||
REG_RAR_CLASS_CONST_LONG("HOST_WIN32", HOST_WIN32);
|
||||
@@ -836,4 +822,5 @@ void minit_rarentry(TSRMLS_D)
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_REGULAR_FILE", 0x08000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SYM_LINK", 0x0A000L);
|
||||
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SOCKET", 0x0C000L);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
JOBS=3
|
||||
|
||||
function package_name {
|
||||
local readonly version=$1 zts=$2
|
||||
local zts_suffix=''
|
||||
if [[ $zts = 'true' ]]; then
|
||||
zts_suffix='-zts'
|
||||
fi
|
||||
|
||||
echo "php-${version}${zts_suffix}-bare-dbg"
|
||||
}
|
||||
|
||||
function prefix {
|
||||
local readonly version=$1 zts=$2
|
||||
|
||||
echo "/opt/$(package_name $version $zts)"
|
||||
}
|
||||
|
||||
function build_ext {
|
||||
local readonly version=$1 zts=$2 coverage=$3
|
||||
local readonly prefix=$(prefix $1 $2)
|
||||
local cflags= cxxflags= ldflags=
|
||||
"$prefix"/bin/phpize
|
||||
if [[ $coverage == true ]]; then
|
||||
cflags=--coverage
|
||||
cxxflags=--coverage
|
||||
ldflags=--coverage
|
||||
fi
|
||||
CFLAGS="$cflags" CXXFLAGS="$cxxflags" LDFLAGS="$ldflags" \
|
||||
./configure --with-php-config="$prefix/bin/php-config"
|
||||
make -j $JOBS
|
||||
}
|
||||
|
||||
function do_tests {
|
||||
local readonly prefix=$1
|
||||
local found_leaks= dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local ret=0
|
||||
sed -i s/-@if/@if/ Makefile
|
||||
TEST_PHP_EXECUTABLE="$prefix/bin/php" \
|
||||
TEST_PHP_JUNIT=report.xml \
|
||||
REPORT_EXIT_STATUS=1 \
|
||||
NO_INTERACTION=1 \
|
||||
TESTS="--set-timeout 300 --show-diff $RUN_TESTS_FLAGS" make test \
|
||||
|| ret=$?
|
||||
found_leaks=$(find tests -name '*.mem' | wc -l)
|
||||
if [[ $found_leaks -gt 0 ]]; then
|
||||
echo "Found $found_leaks leaks. Failing."
|
||||
find tests -name "*.mem" -print -exec cat {} \;
|
||||
fi
|
||||
return $ret
|
||||
}
|
||||
|
||||
function install_php {
|
||||
local readonly version=$1 zts=$2
|
||||
local readonly url="$MIRROR/php-$version.tar.gz"
|
||||
|
||||
sudo apt-get install -y gnupg
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 5D98E7264E3F3D89463B314B12229434A9F003C9
|
||||
echo deb [arch=amd64] http://artefacto-test.s3.amazonaws.com/php-bare-dbg bionic main | sudo tee -a /etc/apt/sources.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y $(package_name $version $zts)
|
||||
}
|
||||
|
||||
function run_tests {
|
||||
set -e
|
||||
set -o pipefail
|
||||
do_tests "$(prefix $1 $2)"
|
||||
}
|
||||
@@ -163,5 +163,5 @@ array(2) {
|
||||
|
||||
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: rar_list() expects parameter 1 to be RarArchive, boo%s given in %s on line %d
|
||||
Warning: rar_list() expects parameter 1 to be RarArchive, %s given in %s on line %d
|
||||
Done
|
||||
|
||||
@@ -91,5 +91,5 @@ object(RarEntry)#%d (%d) {
|
||||
|
||||
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: rar_entry_get() expects parameter 1 to be RarArchive, boo%s given in %s on line %d
|
||||
Warning: rar_entry_get() expects parameter 1 to be RarArchive, %s given in %s on line %d
|
||||
Done
|
||||
|
||||
@@ -31,6 +31,6 @@ bool(false)
|
||||
|
||||
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d
|
||||
|
||||
Warning: rar_entry_get() expects parameter 1 to be RarArchive, boo%s given in %s on line %d
|
||||
Warning: rar_entry_get() expects parameter 1 to be RarArchive, %s given in %s on line %d
|
||||
|
||||
Done
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (good RAR file, several volumes)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (store method)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (solid archive)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -12,4 +12,4 @@ foreach ($rarF as $k => $rarE) {
|
||||
}
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d
|
||||
Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d%A
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
--TEST--
|
||||
RarEntry::getStream() function (broken set fixed with volume callback)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
function resolve($vol) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
--TEST--
|
||||
RarEntry::extract() function (broken set fixed with volume callback)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip"; ?>
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
function resolve($vol) {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
--TEST--
|
||||
RarArchive::open() volume callback long return (case MAXPATHLEN > NM)
|
||||
RarArchive::open() volume callback long return (case MAXPATHLEN > MAXPATHSIZE)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
define('MAXPATHSIZE', 0x10000);
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if (!defined("PHP_MAXPATHLEN"))
|
||||
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
|
||||
if (!(PHP_MAXPATHLEN > 2048))
|
||||
if (!(PHP_MAXPATHLEN > MAXPATHSIZE))
|
||||
die("skip test is for systems where MAXPATHLEN > 2048");
|
||||
$rp = dirname(__FILE__) . "/" . str_repeat("a", 2048);
|
||||
$rp = dirname(__FILE__) . "/" . str_repeat("a", MAXPATHSIZE);
|
||||
if (strlen(dirname(__FILE__) > PHP_MAXPATHLEN - 1))
|
||||
die("skip current directory is too deep.");
|
||||
--FILE--
|
||||
@@ -18,7 +19,7 @@ if (!defined("PHP_MAXPATHLEN"))
|
||||
chdir(dirname(__FILE__));
|
||||
$fn = dirname(__FILE__) . '/multi_broken.part1.rar';
|
||||
|
||||
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", 2048); }
|
||||
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", MAXPATHSIZE); }
|
||||
$rar = RarArchive::open($fn, null, 'testA');
|
||||
$rar->getEntries();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Stream wrapper with volume find callback
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if(!extension_loaded("rar")) die("skip");
|
||||
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
|
||||
--FILE--
|
||||
<?php
|
||||
function resolve($vol) {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
--TEST--
|
||||
RarArchive direct instantiation does not crash (PHP 5.x)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded("rar")) die("skip");
|
||||
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID >= 70000) die("skip for PHP 5.x");
|
||||
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7');
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
new RarArchive();
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Fatal error: Call to private RarArchive::__construct() from invalid context in %s on line %d
|
||||
@@ -1,14 +0,0 @@
|
||||
--TEST--
|
||||
RarEntry direct instantiation does not crash (PHP 5.x)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) die("skip");
|
||||
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID >= 70000) die("skip for PHP 5.x");
|
||||
if (key_exists('USE_ZEND_ALLOC', $_ENV) && PHP_VERSION_ID < 70000) die('skip do not use with valgrind in PHP <7');
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
new RarEntry();
|
||||
|
||||
echo "Done\n";
|
||||
--EXPECTF--
|
||||
Fatal error: Call to private RarEntry::__construct() from invalid context in %s on line %d
|
||||
@@ -16,4 +16,4 @@ $a[0] = "jjj";
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): A RarArchive object is not writable in %s on line %d
|
||||
Fatal error: main(): A RarArchive object is not writable in %s on line %d%A
|
||||
|
||||
@@ -18,4 +18,4 @@ unset($a[0]["jj"]);
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): A RarArchive object is not modifiable in %s on line %d
|
||||
Fatal error: main(): A RarArchive object is not modifiable in %s on line %d%A
|
||||
|
||||
@@ -16,4 +16,4 @@ $a[0] = "hhh";
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): A RarArchive object is not writable in %s on line %d
|
||||
Fatal error: main(): A RarArchive object is not writable in %s on line %d%A
|
||||
|
||||
@@ -13,4 +13,4 @@ unset($a[0]);
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): A RarArchive object is not writable in %s on line %d
|
||||
Fatal error: main(): A RarArchive object is not writable in %s on line %d%A
|
||||
|
||||
@@ -15,4 +15,4 @@ foreach ($a as &$v) {
|
||||
echo "\n";
|
||||
echo "Done.\n";
|
||||
--EXPECTF--
|
||||
Fatal error: main(): An iterator cannot be used with foreach by reference in %s on line %d
|
||||
Fatal error: main(): An iterator cannot be used with foreach by reference in %s on line %d%A
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Supports version 5 RAR files
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) die("skip");
|
||||
if (isset($_ENV['APPVEYOR'])) die("skip failing on appveyor");
|
||||
--FILE--
|
||||
<?php
|
||||
RarException::setUsingExceptions(true);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
--TEST--
|
||||
Clone of RarArchive is forbidden (PHP 5.x)
|
||||
--SKIPIF--
|
||||
<?php if(!extension_loaded("rar")) print "skip";
|
||||
if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID >= 70000) die("skip for PHP 5.x");
|
||||
--FILE--
|
||||
<?php
|
||||
RarException::setUsingExceptions(true);
|
||||
$file = dirname(__FILE__) . '/rar5_multi.part1.rar';
|
||||
$rar = RarArchive::open($file);
|
||||
$rar2 = clone $rar;
|
||||
$rar2->getEntries();
|
||||
echo "Never reached.\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Trying to clone an uncloneable object of class RarArchive in %s on line %d
|
||||
3
unrar/.clang-format
Normal file
3
unrar/.clang-format
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
# Disable clang-format for vendored unrar sources.
|
||||
DisableFormat: true
|
||||
@@ -238,8 +238,10 @@
|
||||
<ClCompile Include="hash.cpp" />
|
||||
<ClCompile Include="headers.cpp" />
|
||||
<ClCompile Include="isnt.cpp" />
|
||||
<ClCompile Include="largepage.cpp" />
|
||||
<ClCompile Include="list.cpp" />
|
||||
<ClCompile Include="match.cpp" />
|
||||
<ClCompile Include="motw.cpp" />
|
||||
<ClCompile Include="options.cpp" />
|
||||
<ClCompile Include="pathfn.cpp" />
|
||||
<ClCompile Include="qopen.cpp" />
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||
<StructMemberAlignment>Default</StructMemberAlignment>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
|
||||
@@ -168,7 +168,7 @@
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||
<StructMemberAlignment>Default</StructMemberAlignment>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
|
||||
@@ -198,7 +198,7 @@
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||
<StructMemberAlignment>Default</StructMemberAlignment>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||
@@ -239,7 +239,7 @@
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||
<StructMemberAlignment>Default</StructMemberAlignment>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
@@ -274,7 +274,7 @@
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||
<StructMemberAlignment>Default</StructMemberAlignment>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||
@@ -315,7 +315,7 @@
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StructMemberAlignment>4Bytes</StructMemberAlignment>
|
||||
<StructMemberAlignment>Default</StructMemberAlignment>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
@@ -374,7 +374,9 @@
|
||||
<ClCompile Include="hash.cpp" />
|
||||
<ClCompile Include="headers.cpp" />
|
||||
<ClCompile Include="isnt.cpp" />
|
||||
<ClCompile Include="largepage.cpp" />
|
||||
<ClCompile Include="match.cpp" />
|
||||
<ClCompile Include="motw.cpp" />
|
||||
<ClCompile Include="options.cpp" />
|
||||
<ClCompile Include="pathfn.cpp" />
|
||||
<ClCompile Include="qopen.cpp" />
|
||||
|
||||
@@ -7,51 +7,18 @@
|
||||
for samples and ideas allowed to make Reed-Solomon coding
|
||||
more efficient.
|
||||
|
||||
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
|
||||
* RAR4 text compression algorithm is based on Dmitry Shkarin PPMII
|
||||
and Dmitry Subbotin carryless rangecoder public domain source code.
|
||||
You may find it in ftp.elf.stuba.sk/pub/pc/pack.
|
||||
You can find it in ftp.elf.stuba.sk/pub/pc/pack.
|
||||
|
||||
* RAR encryption includes parts of code from Szymon Stefanek
|
||||
and Brian Gladman AES implementations also as Steve Reid SHA-1 source.
|
||||
* RAR encryption includes parts of public domain code
|
||||
from Szymon Stefanek AES and Steve Reid SHA-1 implementations.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK.
|
||||
All rights reserved.
|
||||
* With exception of SFX modules, RAR uses CRC32 function based
|
||||
on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code
|
||||
is available here:
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Source code of this package also as other cryptographic technology
|
||||
and computing project related links are available on Brian Gladman's
|
||||
web site: http://www.gladman.me.uk
|
||||
|
||||
* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm.
|
||||
Original Intel Slicing-by-8 code is available here:
|
||||
|
||||
http://sourceforge.net/projects/slicing-by-8/
|
||||
https://sourceforge.net/projects/slicing-by-8/
|
||||
|
||||
Original Intel Slicing-by-8 code is licensed under BSD License
|
||||
available at http://www.opensource.org/licenses/bsd-license.html
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
static bool IsAnsiEscComment(const wchar *Data,size_t Size);
|
||||
|
||||
bool Archive::GetComment(Array<wchar> *CmtData)
|
||||
bool Archive::GetComment(std::wstring &CmtData)
|
||||
{
|
||||
if (!MainComment)
|
||||
return false;
|
||||
@@ -11,7 +11,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
|
||||
}
|
||||
|
||||
|
||||
bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
bool Archive::DoGetComment(std::wstring &CmtData)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
uint CmtLength;
|
||||
@@ -36,7 +36,12 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
{
|
||||
// Current (RAR 3.0+) version of archive comment.
|
||||
Seek(GetStartPos(),SEEK_SET);
|
||||
return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
|
||||
if (SearchSubBlock(SUBHEAD_TYPE_CMT)!=0)
|
||||
if (ReadCommentData(CmtData))
|
||||
return true;
|
||||
else
|
||||
uiMsg(UIERROR_CMTBROKEN,FileName);
|
||||
return false;
|
||||
}
|
||||
#ifndef SFX_MODULE
|
||||
// Old style (RAR 2.9) comment header embedded into the main
|
||||
@@ -101,23 +106,21 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
// 4x memory for OEM to UTF-8 output here.
|
||||
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
|
||||
#endif
|
||||
CmtData->Alloc(UnpDataSize+1);
|
||||
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
|
||||
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
|
||||
CmtData->Alloc(wcslen(CmtData->Addr(0)));
|
||||
std::string UnpStr((char*)UnpData,UnpDataSize);
|
||||
CharToWide(UnpStr,CmtData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CmtLength==0)
|
||||
return false;
|
||||
Array<byte> CmtRaw(CmtLength);
|
||||
int ReadSize=Read(&CmtRaw[0],CmtLength);
|
||||
std::vector<byte> CmtRaw(CmtLength);
|
||||
int ReadSize=Read(CmtRaw.data(),CmtLength);
|
||||
if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
|
||||
{
|
||||
CmtLength=ReadSize;
|
||||
CmtRaw.Alloc(CmtLength);
|
||||
CmtRaw.resize(CmtLength);
|
||||
}
|
||||
|
||||
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
|
||||
@@ -125,43 +128,41 @@ bool Archive::DoGetComment(Array<wchar> *CmtData)
|
||||
uiMsg(UIERROR_CMTBROKEN,FileName);
|
||||
return false;
|
||||
}
|
||||
CmtData->Alloc(CmtLength+1);
|
||||
CmtRaw.Push(0);
|
||||
// CmtData.resize(CmtLength+1);
|
||||
CmtRaw.push_back(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.
|
||||
OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
|
||||
OemToCharA((char *)CmtRaw.data(),(char *)CmtRaw.data());
|
||||
#endif
|
||||
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
|
||||
CmtData->Alloc(wcslen(CmtData->Addr(0)));
|
||||
CharToWide((const char *)CmtRaw.data(),CmtData);
|
||||
// CmtData->resize(wcslen(CmtData->data()));
|
||||
}
|
||||
#endif
|
||||
return CmtData->Size() > 0;
|
||||
return CmtData.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
bool Archive::ReadCommentData(Array<wchar> *CmtData)
|
||||
bool Archive::ReadCommentData(std::wstring &CmtData)
|
||||
{
|
||||
Array<byte> CmtRaw;
|
||||
std::vector<byte> CmtRaw;
|
||||
if (!ReadSubData(&CmtRaw,NULL,false))
|
||||
return false;
|
||||
size_t CmtSize=CmtRaw.Size();
|
||||
CmtRaw.Push(0);
|
||||
CmtData->Alloc(CmtSize+1);
|
||||
size_t CmtSize=CmtRaw.size();
|
||||
CmtRaw.push_back(0);
|
||||
// CmtData->resize(CmtSize+1);
|
||||
if (Format==RARFMT50)
|
||||
UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
|
||||
UtfToWide((char *)CmtRaw.data(),CmtData);
|
||||
else
|
||||
if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
|
||||
{
|
||||
RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
|
||||
(*CmtData)[CmtSize/2]=0;
|
||||
|
||||
CmtData=RawToWide(CmtRaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
|
||||
CharToWide((const char *)CmtRaw.data(),CmtData);
|
||||
}
|
||||
CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
|
||||
// CmtData->resize(wcslen(CmtData->data())); // Set buffer size to actual comment length.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -170,15 +171,16 @@ void Archive::ViewComment()
|
||||
{
|
||||
if (Cmd->DisableComment)
|
||||
return;
|
||||
Array<wchar> CmtBuf;
|
||||
if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
|
||||
std::wstring CmtBuf;
|
||||
if (GetComment(CmtBuf)) // In GUI too, so "Test" command detects broken comments.
|
||||
{
|
||||
size_t CmtSize=CmtBuf.Size();
|
||||
wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
|
||||
if (ChPtr!=NULL)
|
||||
CmtSize=ChPtr-&CmtBuf[0];
|
||||
mprintf(L"\n");
|
||||
OutComment(&CmtBuf[0],CmtSize);
|
||||
size_t CmtSize=CmtBuf.size();
|
||||
auto EndPos=CmtBuf.find(0x1A);
|
||||
if (EndPos!=std::wstring::npos)
|
||||
CmtSize=EndPos;
|
||||
mprintf(St(MArcComment));
|
||||
mprintf(L":\n");
|
||||
OutComment(CmtBuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
#include "arccmt.cpp"
|
||||
|
||||
|
||||
Archive::Archive(RAROptions *InitCmd)
|
||||
Archive::Archive(CommandData *InitCmd)
|
||||
{
|
||||
Cmd=NULL; // Just in case we'll have an exception in 'new' below.
|
||||
|
||||
DummyCmd=(InitCmd==NULL);
|
||||
Cmd=DummyCmd ? (new RAROptions):InitCmd;
|
||||
Cmd=DummyCmd ? (new CommandData):InitCmd;
|
||||
|
||||
OpenShared=Cmd->OpenShared;
|
||||
Format=RARFMT15;
|
||||
Format=RARFMT_NONE;
|
||||
Solid=false;
|
||||
Volume=false;
|
||||
MainComment=false;
|
||||
@@ -26,20 +26,21 @@ Archive::Archive(RAROptions *InitCmd)
|
||||
FailedHeaderDecryption=false;
|
||||
BrokenHeader=false;
|
||||
LastReadBlock=0;
|
||||
CurHeaderType=HEAD_UNKNOWN;
|
||||
|
||||
CurBlockPos=0;
|
||||
NextBlockPos=0;
|
||||
|
||||
RecoveryPercent=-1;
|
||||
|
||||
memset(&MainHead,0,sizeof(MainHead));
|
||||
memset(&CryptHead,0,sizeof(CryptHead));
|
||||
memset(&EndArcHead,0,sizeof(EndArcHead));
|
||||
MainHead.Reset();
|
||||
CryptHead={};
|
||||
EndArcHead.Reset();
|
||||
|
||||
VolNumber=0;
|
||||
VolWrite=0;
|
||||
AddingFilesSize=0;
|
||||
AddingHeadersSize=0;
|
||||
*FirstVolumeName=0;
|
||||
|
||||
Splitting=false;
|
||||
NewArchive=false;
|
||||
@@ -68,13 +69,13 @@ void Archive::CheckArc(bool EnableBroken)
|
||||
// password is incorrect.
|
||||
if (!FailedHeaderDecryption)
|
||||
uiMsg(UIERROR_BADARCHIVE,FileName);
|
||||
ErrHandler.Exit(RARX_FATAL);
|
||||
ErrHandler.Exit(RARX_BADARC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void Archive::CheckOpen(const wchar *Name)
|
||||
void Archive::CheckOpen(const std::wstring &Name)
|
||||
{
|
||||
TOpen(Name);
|
||||
CheckArc(false);
|
||||
@@ -82,7 +83,7 @@ void Archive::CheckOpen(const wchar *Name)
|
||||
#endif
|
||||
|
||||
|
||||
bool Archive::WCheckOpen(const wchar *Name)
|
||||
bool Archive::WCheckOpen(const std::wstring &Name)
|
||||
{
|
||||
if (!WOpen(Name))
|
||||
return false;
|
||||
@@ -110,9 +111,11 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
|
||||
// We check the last signature byte, so we can return a sensible
|
||||
// warning in case we'll want to change the archive format
|
||||
// sometimes in the future.
|
||||
#ifndef SFX_MODULE
|
||||
if (D[6]==0)
|
||||
Type=RARFMT15;
|
||||
else
|
||||
#endif
|
||||
if (D[6]==1)
|
||||
Type=RARFMT50;
|
||||
else
|
||||
@@ -148,9 +151,9 @@ bool Archive::IsArchive(bool EnableBroken)
|
||||
}
|
||||
else
|
||||
{
|
||||
Array<char> Buffer(MAXSFXSIZE);
|
||||
std::vector<char> Buffer(MAXSFXSIZE);
|
||||
long CurPos=(long)Tell();
|
||||
int ReadSize=Read(&Buffer[0],Buffer.Size()-16);
|
||||
int ReadSize=Read(Buffer.data(),Buffer.size()-16);
|
||||
for (int I=0;I<ReadSize;I++)
|
||||
if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE)
|
||||
{
|
||||
@@ -231,7 +234,7 @@ bool Archive::IsArchive(bool EnableBroken)
|
||||
// first file header to set "comment" flag when reading service header.
|
||||
// Unless we are in silent mode, we need to know about presence of comment
|
||||
// immediately after IsArchive call.
|
||||
if (HeadersLeft && (!SilentOpen || !Encrypted))
|
||||
if (HeadersLeft && (!SilentOpen || !Encrypted) && IsSeekable())
|
||||
{
|
||||
int64 SavePos=Tell();
|
||||
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
|
||||
@@ -265,7 +268,7 @@ bool Archive::IsArchive(bool EnableBroken)
|
||||
Seek(SavePos,SEEK_SET);
|
||||
}
|
||||
if (!Volume || FirstVolume)
|
||||
wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName));
|
||||
FirstVolumeName=FileName;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -301,7 +304,7 @@ uint Archive::FullHeaderSize(size_t Size)
|
||||
|
||||
|
||||
#ifdef USE_QOPEN
|
||||
bool Archive::Open(const wchar *Name,uint Mode)
|
||||
bool Archive::Open(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
// Important if we reuse Archive object and it has virtual QOpen
|
||||
// file position not matching real. For example, for 'l -v volname'.
|
||||
@@ -336,3 +339,23 @@ int64 Archive::Tell()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Return 0 if dictionary size is invalid. If size is RAR7 only, return
|
||||
// the adjusted nearest bottom value. Return header flags in Flags.
|
||||
uint64 Archive::GetWinSize(uint64 Size,uint &Flags)
|
||||
{
|
||||
Flags=0;
|
||||
// Allow 128 KB - 1 TB range.
|
||||
if (Size<0x20000 || Size>0x10000000000ULL)
|
||||
return 0;
|
||||
uint64 Pow2=0x20000; // Power of 2 dictionary size.
|
||||
for (;2*Pow2<=Size;Pow2*=2)
|
||||
Flags+=FCI_DICT_BIT0;
|
||||
if (Size==Pow2)
|
||||
return Size; // If 'Size' is the power of 2, return it as is.
|
||||
|
||||
// Get the number of Pow2/32 to add to Pow2 for nearest value not exceeding 'Size'.
|
||||
uint64 Fraction=(Size-Pow2)/(Pow2/32);
|
||||
Flags+=(uint)Fraction*FCI_DICT_FRACT0;
|
||||
return Pow2+Fraction*(Pow2/32);
|
||||
}
|
||||
|
||||
@@ -27,26 +27,27 @@ class Archive:public File
|
||||
{
|
||||
private:
|
||||
void UpdateLatestTime(FileHeader *CurBlock);
|
||||
void ConvertNameCase(wchar *Name);
|
||||
void ConvertNameCase(std::wstring &Name);
|
||||
void ConvertFileHeader(FileHeader *hd);
|
||||
size_t ReadHeader14();
|
||||
size_t ReadHeader15();
|
||||
size_t ReadHeader50();
|
||||
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
|
||||
void RequestArcPassword();
|
||||
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb);
|
||||
void RequestArcPassword(RarCheckPassword *SelPwd);
|
||||
void UnexpEndArcMsg();
|
||||
void BrokenHeaderMsg();
|
||||
void UnkEncVerMsg(const wchar *Name,const wchar *Info);
|
||||
bool DoGetComment(Array<wchar> *CmtData);
|
||||
bool ReadCommentData(Array<wchar> *CmtData);
|
||||
void UnkEncVerMsg(const std::wstring &Name,const std::wstring &Info);
|
||||
bool DoGetComment(std::wstring &CmtData);
|
||||
bool ReadCommentData(std::wstring &CmtData);
|
||||
|
||||
#if !defined(RAR_NOCRYPT)
|
||||
CryptData HeadersCrypt;
|
||||
#endif
|
||||
ComprDataIO SubDataIO;
|
||||
bool DummyCmd;
|
||||
RAROptions *Cmd;
|
||||
CommandData *Cmd;
|
||||
|
||||
int RecoveryPercent;
|
||||
|
||||
RarTime LatestTime;
|
||||
int LastReadBlock;
|
||||
@@ -58,18 +59,19 @@ class Archive:public File
|
||||
bool ProhibitQOpen;
|
||||
#endif
|
||||
public:
|
||||
Archive(RAROptions *InitCmd=NULL);
|
||||
Archive(CommandData *InitCmd=nullptr);
|
||||
~Archive();
|
||||
static RARFORMAT IsSignature(const byte *D,size_t Size);
|
||||
bool IsArchive(bool EnableBroken);
|
||||
size_t SearchBlock(HEADER_TYPE HeaderType);
|
||||
size_t SearchSubBlock(const wchar *Type);
|
||||
size_t SearchRR();
|
||||
int GetRecoveryPercent() {return RecoveryPercent;}
|
||||
size_t ReadHeader();
|
||||
void CheckArc(bool EnableBroken);
|
||||
void CheckOpen(const wchar *Name);
|
||||
bool WCheckOpen(const wchar *Name);
|
||||
bool GetComment(Array<wchar> *CmtData);
|
||||
void CheckOpen(const std::wstring &Name);
|
||||
bool WCheckOpen(const std::wstring &Name);
|
||||
bool GetComment(std::wstring &CmtData);
|
||||
void ViewComment();
|
||||
void SetLatestTime(RarTime *NewTime);
|
||||
void SeekToNext();
|
||||
@@ -79,23 +81,25 @@ class Archive:public File
|
||||
void VolSubtractHeaderSize(size_t SubSize);
|
||||
uint FullHeaderSize(size_t Size);
|
||||
int64 GetStartPos();
|
||||
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
|
||||
void AddSubData(const byte *SrcData,uint64 DataSize,File *SrcFile,
|
||||
const wchar *Name,uint Flags);
|
||||
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
|
||||
bool ReadSubData(std::vector<byte> *UnpData,File *DestFile,bool TestMode);
|
||||
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
|
||||
RAROptions* GetRAROptions() {return Cmd;}
|
||||
CommandData* GetCommandData() {return Cmd;}
|
||||
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
|
||||
#if 0
|
||||
void GetRecoveryInfo(bool Required,int64 *Size,int *Percent);
|
||||
#endif
|
||||
#ifdef USE_QOPEN
|
||||
bool Open(const wchar *Name,uint Mode=FMF_READ);
|
||||
int Read(void *Data,size_t Size);
|
||||
void Seek(int64 Offset,int Method);
|
||||
int64 Tell();
|
||||
bool Open(const std::wstring &Name,uint Mode=FMF_READ) override;
|
||||
int Read(void *Data,size_t Size) override;
|
||||
void Seek(int64 Offset,int Method) override;
|
||||
int64 Tell() override;
|
||||
void QOpenUnload() {QOpen.Unload();}
|
||||
void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;}
|
||||
#endif
|
||||
static uint64 GetWinSize(uint64 Size,uint &Flags);
|
||||
|
||||
// Needed to see wstring based Open from File. Otherwise compiler finds
|
||||
// Open in Archive and doesn't check the base class overloads.
|
||||
using File::Open;
|
||||
|
||||
BaseBlock ShortBlock;
|
||||
MarkHeader MarkHead;
|
||||
@@ -107,7 +111,6 @@ class Archive:public File
|
||||
FileHeader SubHead;
|
||||
CommentHeader CommHead;
|
||||
ProtectHeader ProtectHead;
|
||||
UnixOwnersHeader UOHead;
|
||||
EAHeader EAHead;
|
||||
StreamHeader StreamHead;
|
||||
|
||||
@@ -136,12 +139,19 @@ class Archive:public File
|
||||
|
||||
uint VolNumber;
|
||||
int64 VolWrite;
|
||||
|
||||
// Total size of files adding to archive. Might also include the size of
|
||||
// files repacked in solid archive.
|
||||
uint64 AddingFilesSize;
|
||||
|
||||
uint64 AddingHeadersSize;
|
||||
|
||||
bool NewArchive;
|
||||
|
||||
wchar FirstVolumeName[NM];
|
||||
std::wstring FirstVolumeName;
|
||||
#ifdef PROPAGATE_MOTW
|
||||
MarkOfTheWeb Motw;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,10 +20,10 @@ size_t Archive::ReadHeader()
|
||||
case RARFMT14:
|
||||
ReadSize=ReadHeader14();
|
||||
break;
|
||||
#endif
|
||||
case RARFMT15:
|
||||
ReadSize=ReadHeader15();
|
||||
break;
|
||||
#endif
|
||||
case RARFMT50:
|
||||
ReadSize=ReadHeader50();
|
||||
break;
|
||||
@@ -100,9 +100,15 @@ void Archive::UnexpEndArcMsg()
|
||||
// If block positions are equal to file size, this is not an error.
|
||||
// It can happen when we reached the end of older RAR 1.5 archive,
|
||||
// which did not have the end of archive block.
|
||||
// We can't replace this check by checking that read size is exactly 0
|
||||
// in the beginning of file header, because in this case the read position
|
||||
// still can be beyond the end of archive.
|
||||
if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
|
||||
{
|
||||
uiMsg(UIERROR_UNEXPEOF,FileName);
|
||||
if (CurHeaderType!=HEAD_FILE && CurHeaderType!=HEAD_UNKNOWN)
|
||||
uiMsg(UIERROR_TRUNCSERVICE,FileName,SubHead.FileName);
|
||||
|
||||
ErrHandler.SetErrorCode(RARX_WARNING);
|
||||
}
|
||||
}
|
||||
@@ -116,10 +122,10 @@ void Archive::BrokenHeaderMsg()
|
||||
}
|
||||
|
||||
|
||||
void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
|
||||
void Archive::UnkEncVerMsg(const std::wstring &Name,const std::wstring &Info)
|
||||
{
|
||||
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
|
||||
ErrHandler.SetErrorCode(RARX_WARNING);
|
||||
ErrHandler.SetErrorCode(RARX_FATAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +140,7 @@ inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
|
||||
}
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
size_t Archive::ReadHeader15()
|
||||
{
|
||||
RawRead Raw(this);
|
||||
@@ -142,10 +149,10 @@ size_t Archive::ReadHeader15()
|
||||
|
||||
if (Decrypt)
|
||||
{
|
||||
#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
|
||||
#ifdef RAR_NOCRYPT // For rarext.dll, Setup.SFX and unrar_nocrypt.dll.
|
||||
return 0;
|
||||
#else
|
||||
RequestArcPassword();
|
||||
RequestArcPassword(NULL);
|
||||
|
||||
byte Salt[SIZE_SALT30];
|
||||
if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
|
||||
@@ -219,7 +226,7 @@ size_t Archive::ReadHeader15()
|
||||
{
|
||||
case HEAD_MAIN:
|
||||
MainHead.Reset();
|
||||
*(BaseBlock *)&MainHead=ShortBlock;
|
||||
MainHead.SetBaseBlock(ShortBlock);
|
||||
MainHead.HighPosAV=Raw.Get2();
|
||||
MainHead.PosAV=Raw.Get4();
|
||||
|
||||
@@ -245,13 +252,17 @@ size_t Archive::ReadHeader15()
|
||||
FileHeader *hd=FileBlock ? &FileHead:&SubHead;
|
||||
hd->Reset();
|
||||
|
||||
*(BaseBlock *)hd=ShortBlock;
|
||||
hd->SetBaseBlock(ShortBlock);
|
||||
|
||||
hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
|
||||
hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
|
||||
hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
|
||||
hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
|
||||
|
||||
// RAR versions earlier than 2.0 do not set the solid flag
|
||||
// in file header. They use only a global solid archive flag.
|
||||
hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
|
||||
|
||||
hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
|
||||
hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
|
||||
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
|
||||
@@ -300,7 +311,7 @@ size_t Archive::ReadHeader15()
|
||||
if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
|
||||
{
|
||||
hd->RedirType=FSREDIR_UNIXSYMLINK;
|
||||
*hd->RedirName=0;
|
||||
hd->RedirName.clear();
|
||||
}
|
||||
|
||||
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
|
||||
@@ -327,27 +338,26 @@ size_t Archive::ReadHeader15()
|
||||
if (hd->UnknownUnpSize)
|
||||
hd->UnpSize=INT64NDF;
|
||||
|
||||
char FileName[NM*4];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
FileName[ReadNameSize]=0;
|
||||
size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
|
||||
std::string FileName(ReadNameSize,0);
|
||||
Raw.GetB((byte *)&FileName[0],ReadNameSize);
|
||||
|
||||
if (FileBlock)
|
||||
{
|
||||
*hd->FileName=0;
|
||||
hd->FileName.clear();
|
||||
if ((hd->Flags & LHD_UNICODE)!=0)
|
||||
{
|
||||
EncodeFileName NameCoder;
|
||||
size_t Length=strlen(FileName);
|
||||
size_t Length=strlen(FileName.data());
|
||||
Length++;
|
||||
if (ReadNameSize>Length)
|
||||
NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
|
||||
ReadNameSize-Length,hd->FileName,
|
||||
ASIZE(hd->FileName));
|
||||
NameCoder.Decode(FileName.data(),ReadNameSize,
|
||||
(byte *)&FileName[Length],
|
||||
ReadNameSize-Length,hd->FileName);
|
||||
}
|
||||
|
||||
if (*hd->FileName==0)
|
||||
ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
|
||||
if (hd->FileName.empty())
|
||||
ArcCharToWide(FileName.data(),hd->FileName,ACTW_OEM);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
ConvertNameCase(hd->FileName);
|
||||
@@ -356,7 +366,7 @@ size_t Archive::ReadHeader15()
|
||||
}
|
||||
else
|
||||
{
|
||||
CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
|
||||
CharToWide(FileName.data(),hd->FileName);
|
||||
|
||||
// Calculate the size of optional data.
|
||||
int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
|
||||
@@ -367,14 +377,15 @@ size_t Archive::ReadHeader15()
|
||||
{
|
||||
// Here we read optional additional fields for subheaders.
|
||||
// They are stored after the file name and before salt.
|
||||
hd->SubData.Alloc(DataSize);
|
||||
Raw.GetB(&hd->SubData[0],DataSize);
|
||||
hd->SubData.resize(DataSize);
|
||||
Raw.GetB(hd->SubData.data(),DataSize);
|
||||
|
||||
}
|
||||
|
||||
if (hd->CmpName(SUBHEAD_TYPE_CMT))
|
||||
MainComment=true;
|
||||
}
|
||||
|
||||
if ((hd->Flags & LHD_SALT)!=0)
|
||||
Raw.GetB(hd->Salt,SIZE_SALT30);
|
||||
hd->mtime.SetDos(FileTime);
|
||||
@@ -417,7 +428,7 @@ size_t Archive::ReadHeader15()
|
||||
NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
|
||||
|
||||
bool CRCProcessedOnly=hd->CommentInHeader;
|
||||
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
|
||||
uint HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
|
||||
if (hd->HeadCRC!=HeaderCRC)
|
||||
{
|
||||
BrokenHeader=true;
|
||||
@@ -434,7 +445,7 @@ size_t Archive::ReadHeader15()
|
||||
}
|
||||
break;
|
||||
case HEAD_ENDARC:
|
||||
*(BaseBlock *)&EndArcHead=ShortBlock;
|
||||
EndArcHead.SetBaseBlock(ShortBlock);
|
||||
EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
|
||||
EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
|
||||
EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
|
||||
@@ -446,14 +457,14 @@ size_t Archive::ReadHeader15()
|
||||
break;
|
||||
#ifndef SFX_MODULE
|
||||
case HEAD3_CMT:
|
||||
*(BaseBlock *)&CommHead=ShortBlock;
|
||||
CommHead.SetBaseBlock(ShortBlock);
|
||||
CommHead.UnpSize=Raw.Get2();
|
||||
CommHead.UnpVer=Raw.Get1();
|
||||
CommHead.Method=Raw.Get1();
|
||||
CommHead.CommCRC=Raw.Get2();
|
||||
break;
|
||||
case HEAD3_PROTECT:
|
||||
*(BaseBlock *)&ProtectHead=ShortBlock;
|
||||
ProtectHead.SetBaseBlock(ShortBlock);
|
||||
ProtectHead.DataSize=Raw.Get4();
|
||||
ProtectHead.Version=Raw.Get1();
|
||||
ProtectHead.RecSectors=Raw.Get2();
|
||||
@@ -462,26 +473,13 @@ size_t Archive::ReadHeader15()
|
||||
NextBlockPos+=ProtectHead.DataSize;
|
||||
break;
|
||||
case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
|
||||
*(BaseBlock *)&SubBlockHead=ShortBlock;
|
||||
SubBlockHead.SetBaseBlock(ShortBlock);
|
||||
SubBlockHead.DataSize=Raw.Get4();
|
||||
NextBlockPos+=SubBlockHead.DataSize;
|
||||
SubBlockHead.SubType=Raw.Get2();
|
||||
SubBlockHead.Level=Raw.Get1();
|
||||
switch(SubBlockHead.SubType)
|
||||
{
|
||||
case UO_HEAD:
|
||||
*(SubBlockHeader *)&UOHead=SubBlockHead;
|
||||
UOHead.OwnerNameSize=Raw.Get2();
|
||||
UOHead.GroupNameSize=Raw.Get2();
|
||||
if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
|
||||
UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
|
||||
if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
|
||||
UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
|
||||
Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
|
||||
Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
|
||||
UOHead.OwnerName[UOHead.OwnerNameSize]=0;
|
||||
UOHead.GroupName[UOHead.GroupNameSize]=0;
|
||||
break;
|
||||
case NTACL_HEAD:
|
||||
*(SubBlockHeader *)&EAHead=SubBlockHead;
|
||||
EAHead.UnpSize=Raw.Get4();
|
||||
@@ -496,10 +494,13 @@ size_t Archive::ReadHeader15()
|
||||
StreamHead.Method=Raw.Get1();
|
||||
StreamHead.StreamCRC=Raw.Get4();
|
||||
StreamHead.StreamNameSize=Raw.Get2();
|
||||
if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
|
||||
StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
|
||||
Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
|
||||
StreamHead.StreamName[StreamHead.StreamNameSize]=0;
|
||||
|
||||
const size_t MaxStreamName20=260; // Maximum allowed stream name in RAR 2.x format.
|
||||
if (StreamHead.StreamNameSize>MaxStreamName20)
|
||||
StreamHead.StreamNameSize=MaxStreamName20;
|
||||
|
||||
StreamHead.StreamName.resize(StreamHead.StreamNameSize);
|
||||
Raw.GetB(&StreamHead.StreamName[0],StreamHead.StreamNameSize);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -509,12 +510,16 @@ size_t Archive::ReadHeader15()
|
||||
NextBlockPos+=Raw.Get4();
|
||||
break;
|
||||
}
|
||||
|
||||
ushort HeaderCRC=Raw.GetCRC15(false);
|
||||
|
||||
uint HeaderCRC=Raw.GetCRC15(false);
|
||||
|
||||
// Old AV header does not have header CRC properly set.
|
||||
// Old Unix owners header didn't include string fields into header size,
|
||||
// but included them into CRC, so it couldn't be verified with generic
|
||||
// approach here.
|
||||
if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
|
||||
ShortBlock.HeaderType!=HEAD3_AV)
|
||||
ShortBlock.HeaderType!=HEAD3_AV &&
|
||||
(ShortBlock.HeaderType!=HEAD3_OLDSERVICE || SubBlockHead.SubType!=UO_HEAD))
|
||||
{
|
||||
bool Recovered=false;
|
||||
if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
|
||||
@@ -544,6 +549,7 @@ size_t Archive::ReadHeader15()
|
||||
|
||||
return Raw.Size();
|
||||
}
|
||||
#endif // #ifndef SFX_MODULE
|
||||
|
||||
|
||||
size_t Archive::ReadHeader50()
|
||||
@@ -558,6 +564,13 @@ size_t Archive::ReadHeader50()
|
||||
return 0;
|
||||
#else
|
||||
|
||||
if (Cmd->SkipEncrypted)
|
||||
{
|
||||
uiMsg(UIMSG_SKIPENCARC,FileName);
|
||||
FailedHeaderDecryption=true; // Suppress error messages and quit quietly.
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte HeadersInitV[SIZE_INITV];
|
||||
if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
|
||||
{
|
||||
@@ -570,15 +583,21 @@ size_t Archive::ReadHeader50()
|
||||
// in -p<pwd> to not stop batch processing for encrypted archives.
|
||||
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
|
||||
|
||||
RarCheckPassword CheckPwd;
|
||||
if (CryptHead.UsePswCheck && !BrokenHeader)
|
||||
CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck);
|
||||
|
||||
while (true) // Repeat the password prompt for wrong passwords.
|
||||
{
|
||||
RequestArcPassword();
|
||||
RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL);
|
||||
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
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)
|
||||
{
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
bool EncSet=HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
|
||||
// Verify password validity. If header is damaged, we cannot rely on
|
||||
// password check value, because it can be damaged too.
|
||||
if (EncSet && CryptHead.UsePswCheck && !BrokenHeader &&
|
||||
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.
|
||||
@@ -635,7 +654,7 @@ size_t Archive::ReadHeader50()
|
||||
}
|
||||
|
||||
int SizeToRead=int(BlockSize);
|
||||
SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
|
||||
SizeToRead-=int(FirstReadSize-SizeBytes-4); // Adjust overread size bytes if any.
|
||||
uint HeaderSize=4+SizeBytes+(uint)BlockSize;
|
||||
|
||||
if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
|
||||
@@ -700,13 +719,12 @@ size_t Archive::ReadHeader50()
|
||||
{
|
||||
case HEAD_CRYPT:
|
||||
{
|
||||
*(BaseBlock *)&CryptHead=ShortBlock;
|
||||
CryptHead.SetBaseBlock(ShortBlock);
|
||||
uint CryptVersion=(uint)Raw.GetV();
|
||||
if (CryptVersion>CRYPT_VERSION)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
|
||||
UnkEncVerMsg(FileName,Info);
|
||||
UnkEncVerMsg(FileName,L"h" + std::to_wstring(CryptVersion));
|
||||
FailedHeaderDecryption=true;
|
||||
return 0;
|
||||
}
|
||||
uint EncFlags=(uint)Raw.GetV();
|
||||
@@ -714,9 +732,8 @@ size_t Archive::ReadHeader50()
|
||||
CryptHead.Lg2Count=Raw.Get1();
|
||||
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
|
||||
UnkEncVerMsg(FileName,Info);
|
||||
UnkEncVerMsg(FileName,L"hc" + std::to_wstring(CryptHead.Lg2Count));
|
||||
FailedHeaderDecryption=true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -728,14 +745,15 @@ size_t Archive::ReadHeader50()
|
||||
byte csum[SIZE_PSWCHECK_CSUM];
|
||||
Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
|
||||
|
||||
sha256_context ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK);
|
||||
|
||||
// Exclude this code for rarext.dll, Setup.SFX and unrar_nocrypt.dll linked
|
||||
// without sha256. But still set Encrypted=true for rarext.dll here,
|
||||
// so it can recognize encrypted header archives in archive properties.
|
||||
#ifndef RAR_NOCRYPT
|
||||
byte Digest[SHA256_DIGEST_SIZE];
|
||||
sha256_done(&ctx, Digest);
|
||||
sha256_get(CryptHead.PswCheck, SIZE_PSWCHECK, Digest);
|
||||
|
||||
CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
|
||||
#endif
|
||||
}
|
||||
Encrypted=true;
|
||||
}
|
||||
@@ -743,7 +761,7 @@ size_t Archive::ReadHeader50()
|
||||
case HEAD_MAIN:
|
||||
{
|
||||
MainHead.Reset();
|
||||
*(BaseBlock *)&MainHead=ShortBlock;
|
||||
MainHead.SetBaseBlock(ShortBlock);
|
||||
uint ArcFlags=(uint)Raw.GetV();
|
||||
|
||||
Volume=(ArcFlags & MHFL_VOLUME)!=0;
|
||||
@@ -785,7 +803,7 @@ size_t Archive::ReadHeader50()
|
||||
case HEAD_SERVICE:
|
||||
{
|
||||
FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
|
||||
hd->Reset();
|
||||
hd->Reset(); // Clear hash, time fields and other stuff like flags.
|
||||
*(BaseBlock *)hd=ShortBlock;
|
||||
|
||||
bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
|
||||
@@ -821,9 +839,14 @@ size_t Archive::ReadHeader50()
|
||||
// we may need to use the compression algorithm 15 in the future,
|
||||
// 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;
|
||||
uint UnpVer=(CompInfo & 0x3f);
|
||||
if (UnpVer==0)
|
||||
hd->UnpVer=VER_PACK5;
|
||||
else
|
||||
if (UnpVer==1)
|
||||
hd->UnpVer=VER_PACK7;
|
||||
else
|
||||
hd->UnpVer=VER_UNKNOWN;
|
||||
|
||||
hd->HostOS=(byte)Raw.GetV();
|
||||
size_t NameSize=(size_t)Raw.GetV();
|
||||
@@ -841,16 +864,29 @@ size_t Archive::ReadHeader50()
|
||||
hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
|
||||
hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
|
||||
hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
|
||||
hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
|
||||
if (hd->Dir || UnpVer>1)
|
||||
hd->WinSize=0;
|
||||
else
|
||||
{
|
||||
hd->WinSize=0x20000ULL<<((CompInfo>>10)&(UnpVer==0 ? 0x0f:0x1f));
|
||||
if (UnpVer==1)
|
||||
{
|
||||
hd->WinSize+=hd->WinSize/32*((CompInfo>>15)&0x1f);
|
||||
|
||||
hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
|
||||
// RAR7 header with RAR5 compression. Needed to append RAR7 files
|
||||
// to RAR5 solid stream if new dictionary is larger than existing.
|
||||
if ((CompInfo & FCI_RAR5_COMPAT)!=0)
|
||||
hd->UnpVer=VER_PACK5;
|
||||
if (hd->WinSize>UNPACK_MAX_DICT)
|
||||
hd->UnpVer=VER_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
char FileName[NM*4];
|
||||
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
|
||||
Raw.GetB((byte *)FileName,ReadNameSize);
|
||||
FileName[ReadNameSize]=0;
|
||||
size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
|
||||
std::string FileName(ReadNameSize,0);
|
||||
Raw.GetB((byte *)&FileName[0],ReadNameSize);
|
||||
|
||||
UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName));
|
||||
UtfToWide(FileName.data(),hd->FileName);
|
||||
|
||||
// Should do it before converting names, because extra fields can
|
||||
// affect name processing, like in case of NTFS streams.
|
||||
@@ -868,28 +904,25 @@ size_t Archive::ReadHeader50()
|
||||
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
|
||||
MainComment=true;
|
||||
|
||||
#if 0
|
||||
// For RAR5 format we read the user specified recovery percent here.
|
||||
// It would be useful to do it for shell extension too, so we display
|
||||
// the correct recovery record size in archive properties. But then
|
||||
// we would need to include the entire recovery record processing
|
||||
// code to shell extension, which is not done now.
|
||||
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
|
||||
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.size()>0)
|
||||
{
|
||||
RecoveryPercent=hd->SubData[0];
|
||||
RSBlockHeader Header;
|
||||
GetRRInfo(this,&Header);
|
||||
RecoverySize=Header.RecSectionSize*Header.RecCount;
|
||||
// It is stored as a single byte up to RAR 6.02 and as vint since
|
||||
// 6.10, where we extended the maximum RR size from 99% to 1000%.
|
||||
RawRead RawPercent;
|
||||
RawPercent.Read(hd->SubData.data(),hd->SubData.size());
|
||||
RecoveryPercent=(int)RawPercent.GetV();
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (BadCRC) // Add the file name to broken header message displayed above.
|
||||
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
|
||||
}
|
||||
break;
|
||||
case HEAD_ENDARC:
|
||||
{
|
||||
*(BaseBlock *)&EndArcHead=ShortBlock;
|
||||
EndArcHead.SetBaseBlock(ShortBlock);
|
||||
uint ArcFlags=(uint)Raw.GetV();
|
||||
EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
|
||||
EndArcHead.StoreVolNumber=false;
|
||||
@@ -904,7 +937,7 @@ size_t Archive::ReadHeader50()
|
||||
|
||||
|
||||
#if !defined(RAR_NOCRYPT)
|
||||
void Archive::RequestArcPassword()
|
||||
void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
|
||||
{
|
||||
if (!Cmd->Password.IsSet())
|
||||
{
|
||||
@@ -921,7 +954,7 @@ void Archive::RequestArcPassword()
|
||||
*PasswordA=0;
|
||||
if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
|
||||
*PasswordA=0;
|
||||
GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
|
||||
CharToWide(PasswordA,PasswordW,ASIZE(PasswordW));
|
||||
cleandata(PasswordA,sizeof(PasswordA));
|
||||
}
|
||||
Cmd->Password.Set(PasswordW);
|
||||
@@ -934,7 +967,7 @@ void Archive::RequestArcPassword()
|
||||
ErrHandler.Exit(RARX_USERBREAK);
|
||||
}
|
||||
#else
|
||||
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password))
|
||||
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password,CheckPwd))
|
||||
{
|
||||
Close();
|
||||
uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
|
||||
@@ -947,7 +980,7 @@ void Archive::RequestArcPassword()
|
||||
#endif
|
||||
|
||||
|
||||
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb)
|
||||
{
|
||||
// Read extra data from the end of block skipping any fields before it.
|
||||
size_t ExtraStart=Raw->Size()-ExtraSize;
|
||||
@@ -970,22 +1003,52 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
if (bb->HeaderType==HEAD_MAIN)
|
||||
{
|
||||
MainHeader *hd=(MainHeader *)bb;
|
||||
if (FieldType==MHEXTRA_LOCATOR)
|
||||
switch(FieldType)
|
||||
{
|
||||
hd->Locator=true;
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->QOpenOffset=Offset+CurBlockPos;
|
||||
}
|
||||
if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->RROffset=Offset+CurBlockPos;
|
||||
}
|
||||
case MHEXTRA_LOCATOR:
|
||||
{
|
||||
hd->Locator=true;
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->QOpenOffset=Offset+CurBlockPos;
|
||||
}
|
||||
if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
|
||||
{
|
||||
uint64 Offset=Raw->GetV();
|
||||
if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
|
||||
hd->RROffset=Offset+CurBlockPos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHEXTRA_METADATA:
|
||||
{
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
if ((Flags & MHEXTRA_METADATA_NAME)!=0)
|
||||
{
|
||||
uint64 NameSize=Raw->GetV();
|
||||
if (NameSize>0 && NameSize<MAXPATHSIZE) // Prevent excessive allocation.
|
||||
{
|
||||
std::string NameU((size_t)NameSize,0); // UTF-8 name.
|
||||
Raw->GetB(&NameU[0],(size_t)NameSize);
|
||||
// If starts from 0, the name was longer than reserved space
|
||||
// when saving this extra field.
|
||||
if (NameU[0]!=0)
|
||||
UtfToWide(&NameU[0],hd->OrigName);
|
||||
}
|
||||
}
|
||||
if ((Flags & MHEXTRA_METADATA_CTIME)!=0)
|
||||
if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0)
|
||||
if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0)
|
||||
hd->OrigTime.SetUnixNS(Raw->Get8());
|
||||
else
|
||||
hd->OrigTime.SetUnix((time_t)Raw->Get4());
|
||||
else
|
||||
hd->OrigTime.SetWin(Raw->Get8());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,64 +1057,64 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
FileHeader *hd=(FileHeader *)bb;
|
||||
switch(FieldType)
|
||||
{
|
||||
#ifndef RAR_NOCRYPT // Except rarext.dll, Setup.SFX and unrar_nocrypt.dll.
|
||||
case FHEXTRA_CRYPT:
|
||||
{
|
||||
FileHeader *hd=(FileHeader *)bb;
|
||||
uint EncVersion=(uint)Raw->GetV();
|
||||
if (EncVersion > CRYPT_VERSION)
|
||||
if (EncVersion>CRYPT_VERSION)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
|
||||
UnkEncVerMsg(hd->FileName,Info);
|
||||
UnkEncVerMsg(hd->FileName,L"x" + std::to_wstring(EncVersion));
|
||||
hd->CryptMethod=CRYPT_UNKNOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
|
||||
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
|
||||
hd->Lg2Count=Raw->Get1();
|
||||
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
{
|
||||
wchar Info[20];
|
||||
swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
|
||||
UnkEncVerMsg(hd->FileName,Info);
|
||||
UnkEncVerMsg(hd->FileName,L"xc" + std::to_wstring(hd->Lg2Count));
|
||||
hd->CryptMethod=CRYPT_UNKNOWN;
|
||||
}
|
||||
Raw->GetB(hd->Salt,SIZE_SALT50);
|
||||
Raw->GetB(hd->InitV,SIZE_INITV);
|
||||
if (hd->UsePswCheck)
|
||||
else
|
||||
{
|
||||
Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
|
||||
hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
|
||||
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
|
||||
|
||||
// It is important to know if password check data is valid.
|
||||
// If it is damaged and header CRC32 fails to detect it,
|
||||
// archiver would refuse to decompress a possibly valid file.
|
||||
// Since we want to be sure distinguishing a wrong password
|
||||
// or corrupt file data, we use 64-bit password check data
|
||||
// and to control its validity we use 32 bits of password
|
||||
// check data SHA-256 additionally to 32-bit header CRC32.
|
||||
byte csum[SIZE_PSWCHECK_CSUM];
|
||||
Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
|
||||
Raw->GetB(hd->Salt,SIZE_SALT50);
|
||||
Raw->GetB(hd->InitV,SIZE_INITV);
|
||||
if (hd->UsePswCheck)
|
||||
{
|
||||
Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
|
||||
|
||||
sha256_context ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK);
|
||||
// It is important to know if password check data is valid.
|
||||
// If it is damaged and header CRC32 fails to detect it,
|
||||
// archiver would refuse to decompress a possibly valid file.
|
||||
// Since we want to be sure distinguishing a wrong password
|
||||
// or corrupt file data, we use 64-bit password check data
|
||||
// and to control its validity we use 32 bits of password
|
||||
// check data SHA-256 additionally to 32-bit header CRC32.
|
||||
byte csum[SIZE_PSWCHECK_CSUM];
|
||||
Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
|
||||
|
||||
byte Digest[SHA256_DIGEST_SIZE];
|
||||
sha256_done(&ctx, Digest);
|
||||
byte Digest[SHA256_DIGEST_SIZE];
|
||||
sha256_get(hd->PswCheck, SIZE_PSWCHECK, Digest);
|
||||
|
||||
hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
|
||||
hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
|
||||
|
||||
// RAR 5.21 and earlier set PswCheck field in service records to 0
|
||||
// even if UsePswCheck was present.
|
||||
if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
|
||||
hd->UsePswCheck=0;
|
||||
// RAR 5.21 and earlier set PswCheck field in service records to 0
|
||||
// even if UsePswCheck was present.
|
||||
if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
|
||||
hd->UsePswCheck=0;
|
||||
}
|
||||
hd->SaltSet=true;
|
||||
hd->CryptMethod=CRYPT_RAR50;
|
||||
hd->Encrypted=true;
|
||||
}
|
||||
hd->SaltSet=true;
|
||||
hd->CryptMethod=CRYPT_RAR50;
|
||||
hd->Encrypted=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case FHEXTRA_HASH:
|
||||
{
|
||||
FileHeader *hd=(FileHeader *)bb;
|
||||
@@ -1103,31 +1166,27 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
if (Version!=0)
|
||||
{
|
||||
hd->Version=true;
|
||||
|
||||
wchar VerText[20];
|
||||
swprintf(VerText,ASIZE(VerText),L";%u",Version);
|
||||
wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
|
||||
hd->FileName += L';' + std::to_wstring(Version);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FHEXTRA_REDIR:
|
||||
{
|
||||
hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
|
||||
FILE_SYSTEM_REDIRECT RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
|
||||
uint Flags=(uint)Raw->GetV();
|
||||
hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
|
||||
size_t NameSize=(size_t)Raw->GetV();
|
||||
|
||||
char UtfName[NM*4];
|
||||
*UtfName=0;
|
||||
if (NameSize<ASIZE(UtfName)-1)
|
||||
if (NameSize>0 && NameSize<MAXPATHSIZE)
|
||||
{
|
||||
Raw->GetB(UtfName,NameSize);
|
||||
UtfName[NameSize]=0;
|
||||
}
|
||||
std::string UtfName(NameSize,0);
|
||||
hd->RedirType=RedirType;
|
||||
hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
|
||||
Raw->GetB(&UtfName[0],NameSize);
|
||||
UtfToWide(&UtfName[0],hd->RedirName);
|
||||
#ifdef _WIN_ALL
|
||||
UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName));
|
||||
UnixSlashToDos(hd->RedirName,hd->RedirName);
|
||||
#endif
|
||||
UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FHEXTRA_UOWNER:
|
||||
@@ -1184,8 +1243,8 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
|
||||
// We cannot allocate too much memory here, because above
|
||||
// we check FieldSize againt Raw size and we control that Raw size
|
||||
// is sensible when reading headers.
|
||||
hd->SubData.Alloc((size_t)FieldSize);
|
||||
Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
|
||||
hd->SubData.resize((size_t)FieldSize);
|
||||
Raw->GetB(hd->SubData.data(),(size_t)FieldSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1208,7 +1267,7 @@ size_t Archive::ReadHeader14()
|
||||
Raw.GetB(Mark,4);
|
||||
uint HeadSize=Raw.Get2();
|
||||
if (HeadSize<7)
|
||||
return false;
|
||||
return 0;
|
||||
byte Flags=Raw.Get1();
|
||||
NextBlockPos=CurBlockPos+HeadSize;
|
||||
CurHeaderType=HEAD_MAIN;
|
||||
@@ -1231,7 +1290,7 @@ size_t Archive::ReadHeader14()
|
||||
FileHead.FileHash.CRC32=Raw.Get2();
|
||||
FileHead.HeadSize=Raw.Get2();
|
||||
if (FileHead.HeadSize<21)
|
||||
return false;
|
||||
return 0;
|
||||
uint FileTime=Raw.Get4();
|
||||
FileHead.FileAttr=Raw.Get1();
|
||||
FileHead.Flags=Raw.Get1()|LONG_BLOCK;
|
||||
@@ -1255,12 +1314,13 @@ size_t Archive::ReadHeader14()
|
||||
|
||||
Raw.Read(NameSize);
|
||||
|
||||
char FileName[NM];
|
||||
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));
|
||||
// RAR 1.4 name size is stored in a single byte field and it can't
|
||||
// exceed 255, so additional checks are not needed.
|
||||
std::string FileName(NameSize,0);
|
||||
Raw.GetB((byte *)&FileName[0],NameSize);
|
||||
std::string NameA;
|
||||
OemToExt(FileName,NameA);
|
||||
CharToWide(NameA,FileHead.FileName);
|
||||
ConvertNameCase(FileHead.FileName);
|
||||
ConvertFileHeader(&FileHead);
|
||||
|
||||
@@ -1274,7 +1334,7 @@ size_t Archive::ReadHeader14()
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void Archive::ConvertNameCase(wchar *Name)
|
||||
void Archive::ConvertNameCase(std::wstring &Name)
|
||||
{
|
||||
if (Cmd->ConvertNames==NAMES_UPPERCASE)
|
||||
wcsupper(Name);
|
||||
@@ -1292,7 +1352,7 @@ bool Archive::IsArcDir()
|
||||
|
||||
void Archive::ConvertAttributes()
|
||||
{
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
if (FileHead.HSType!=HSYS_WINDOWS)
|
||||
FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
|
||||
#endif
|
||||
@@ -1357,19 +1417,23 @@ void Archive::ConvertAttributes()
|
||||
|
||||
void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
{
|
||||
/*
|
||||
if (hd->HSType==HSYS_UNKNOWN)
|
||||
if (hd->Dir)
|
||||
hd->FileAttr=0x10;
|
||||
else
|
||||
hd->FileAttr=0x20;
|
||||
*/
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
|
||||
ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName));
|
||||
ConvertToPrecomposed(hd->FileName);
|
||||
#endif
|
||||
|
||||
for (wchar *s=hd->FileName;*s!=0;s++)
|
||||
for (uint I=0;I<hd->FileName.size();I++)
|
||||
{
|
||||
wchar *s=&hd->FileName[I];
|
||||
|
||||
#ifdef _UNIX
|
||||
// Backslash is the invalid character for Windows file headers,
|
||||
// but it can present in Unix file names extracted in Unix.
|
||||
@@ -1377,7 +1441,7 @@ void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
*s='_';
|
||||
#endif
|
||||
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
// RAR 5.0 archives do not use '\' as path separator, so if we see it,
|
||||
// it means that it is a part of Unix file name, which we cannot
|
||||
// extract in Windows.
|
||||
@@ -1402,6 +1466,9 @@ void Archive::ConvertFileHeader(FileHeader *hd)
|
||||
if (*s=='/' || *s=='\\' && Format!=RARFMT50)
|
||||
*s=CPATHDIVIDER;
|
||||
}
|
||||
|
||||
// Zeroes inside might be possible in broken Unicode names decoded with EncodeFileName::Decode.
|
||||
TruncateAtZero(hd->FileName); // Ensure there are no zeroes inside of string.
|
||||
}
|
||||
|
||||
|
||||
@@ -1416,7 +1483,7 @@ int64 Archive::GetStartPos()
|
||||
}
|
||||
|
||||
|
||||
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
bool Archive::ReadSubData(std::vector<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
{
|
||||
if (BrokenHeader)
|
||||
{
|
||||
@@ -1424,7 +1491,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
return false;
|
||||
}
|
||||
if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK))
|
||||
if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK7:VER_UNPACK))
|
||||
{
|
||||
uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
|
||||
return false;
|
||||
@@ -1441,7 +1508,9 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
{
|
||||
if (SubHead.UnpSize>0x1000000)
|
||||
{
|
||||
// So huge allocation must never happen in valid archives.
|
||||
// Prevent the excessive allocation. When reading to memory, normally
|
||||
// this function operates with reasonably small blocks, such as
|
||||
// the archive comment, NTFS ACL or "Zone.Identifier" NTFS stream.
|
||||
uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
|
||||
return false;
|
||||
}
|
||||
@@ -1449,7 +1518,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
SubDataIO.SetTestMode(true);
|
||||
else
|
||||
{
|
||||
UnpData->Alloc((size_t)SubHead.UnpSize);
|
||||
UnpData->resize((size_t)SubHead.UnpSize);
|
||||
SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
|
||||
}
|
||||
}
|
||||
@@ -1478,7 +1547,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
|
||||
uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
|
||||
ErrHandler.SetErrorCode(RARX_CRC);
|
||||
if (UnpData!=NULL)
|
||||
UnpData->Reset();
|
||||
UnpData->clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
191
unrar/array.hpp
191
unrar/array.hpp
@@ -1,191 +0,0 @@
|
||||
#ifndef _RAR_ARRAY_
|
||||
#define _RAR_ARRAY_
|
||||
|
||||
extern ErrorHandler ErrHandler;
|
||||
|
||||
template <class T> class Array
|
||||
{
|
||||
private:
|
||||
T *Buffer;
|
||||
size_t BufSize;
|
||||
size_t AllocSize;
|
||||
size_t MaxSize;
|
||||
bool Secure; // Clean memory if true.
|
||||
public:
|
||||
Array();
|
||||
Array(size_t Size);
|
||||
Array(const Array &Src); // Copy constructor.
|
||||
~Array();
|
||||
inline void CleanData();
|
||||
inline T& operator [](size_t Item) const;
|
||||
inline T* operator + (size_t Pos);
|
||||
inline size_t Size(); // Returns the size in items, not in bytes.
|
||||
void Add(size_t Items);
|
||||
void Alloc(size_t Items);
|
||||
void Reset();
|
||||
void SoftReset();
|
||||
void operator = (Array<T> &Src);
|
||||
void Push(T Item);
|
||||
void Append(T *Item,size_t Count);
|
||||
T* Addr(size_t Item) {return Buffer+Item;}
|
||||
void SetMaxSize(size_t Size) {MaxSize=Size;}
|
||||
T* Begin() {return Buffer;}
|
||||
T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
|
||||
void SetSecure() {Secure=true;}
|
||||
};
|
||||
|
||||
|
||||
template <class T> void Array<T>::CleanData()
|
||||
{
|
||||
Buffer=NULL;
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
MaxSize=0;
|
||||
Secure=false;
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array()
|
||||
{
|
||||
CleanData();
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::Array(size_t Size)
|
||||
{
|
||||
CleanData();
|
||||
Add(Size);
|
||||
}
|
||||
|
||||
|
||||
// Copy constructor in case we need to pass an object as value.
|
||||
template <class T> Array<T>::Array(const Array &Src)
|
||||
{
|
||||
CleanData();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T> Array<T>::~Array()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
if (Secure)
|
||||
cleandata(Buffer,AllocSize*sizeof(T));
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T& Array<T>::operator [](size_t Item) const
|
||||
{
|
||||
return Buffer[Item];
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline T* Array<T>::operator +(size_t Pos)
|
||||
{
|
||||
return Buffer+Pos;
|
||||
}
|
||||
|
||||
|
||||
template <class T> inline size_t Array<T>::Size()
|
||||
{
|
||||
return BufSize;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Add(size_t Items)
|
||||
{
|
||||
BufSize+=Items;
|
||||
if (BufSize>AllocSize)
|
||||
{
|
||||
if (MaxSize!=0 && BufSize>MaxSize)
|
||||
{
|
||||
ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize);
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
|
||||
size_t Suggested=AllocSize+AllocSize/4+32;
|
||||
size_t NewSize=Max(BufSize,Suggested);
|
||||
|
||||
T *NewBuffer;
|
||||
if (Secure)
|
||||
{
|
||||
NewBuffer=(T *)malloc(NewSize*sizeof(T));
|
||||
if (NewBuffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
|
||||
cleandata(Buffer,AllocSize*sizeof(T));
|
||||
free(Buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
|
||||
if (NewBuffer==NULL)
|
||||
ErrHandler.MemoryError();
|
||||
}
|
||||
Buffer=NewBuffer;
|
||||
AllocSize=NewSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Alloc(size_t Items)
|
||||
{
|
||||
if (Items>AllocSize)
|
||||
Add(Items-BufSize);
|
||||
else
|
||||
BufSize=Items;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Reset()
|
||||
{
|
||||
if (Buffer!=NULL)
|
||||
{
|
||||
free(Buffer);
|
||||
Buffer=NULL;
|
||||
}
|
||||
BufSize=0;
|
||||
AllocSize=0;
|
||||
}
|
||||
|
||||
|
||||
// Reset buffer size, but preserve already allocated memory if any,
|
||||
// so we can reuse it without wasting time to allocation.
|
||||
template <class T> void Array<T>::SoftReset()
|
||||
{
|
||||
BufSize=0;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::operator =(Array<T> &Src)
|
||||
{
|
||||
Reset();
|
||||
Alloc(Src.BufSize);
|
||||
if (Src.BufSize!=0)
|
||||
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Push(T Item)
|
||||
{
|
||||
Add(1);
|
||||
(*this)[Size()-1]=Item;
|
||||
}
|
||||
|
||||
|
||||
template <class T> void Array<T>::Append(T *Items,size_t Count)
|
||||
{
|
||||
size_t CurSize=Size();
|
||||
Add(Count);
|
||||
memcpy(Buffer+CurSize,Items,Count*sizeof(T));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
#include "rar.hpp"
|
||||
|
||||
static const byte blake2s_sigma[10][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
};
|
||||
|
||||
#ifdef USE_SSE
|
||||
#include "blake2s_sse.cpp"
|
||||
#endif
|
||||
@@ -18,20 +32,6 @@ static const uint32 blake2s_IV[8] =
|
||||
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
|
||||
};
|
||||
|
||||
static const byte blake2s_sigma[10][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
};
|
||||
|
||||
static inline void blake2s_set_lastnode( blake2s_state *S )
|
||||
{
|
||||
S->f[1] = ~0U;
|
||||
@@ -134,11 +134,7 @@ void blake2s_update( blake2s_state *S, const byte *in, size_t inlen )
|
||||
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
|
||||
|
||||
#ifdef USE_SSE
|
||||
#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode.
|
||||
if (_SSE_Version>=SSE_SSE2)
|
||||
#else
|
||||
if (_SSE_Version>=SSE_SSSE3)
|
||||
#endif
|
||||
blake2s_compress_sse( S, S->buf );
|
||||
else
|
||||
blake2s_compress( S, S->buf ); // Compress
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
#define BLAKE2_DIGEST_SIZE 32
|
||||
#define BLAKE2_THREADS_NUMBER 8
|
||||
|
||||
enum blake2s_constant
|
||||
{
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32
|
||||
};
|
||||
|
||||
// Use constexpr instead of enums for -std=c++20 compatibility.
|
||||
constexpr size_t BLAKE2S_BLOCKBYTES = 64;
|
||||
constexpr size_t BLAKE2S_OUTBYTES = 32;
|
||||
|
||||
// Alignment to 64 improves performance of both SSE and non-SSE versions.
|
||||
// Alignment to n*16 is required for SSE version, so we selected 64.
|
||||
@@ -20,10 +17,15 @@ enum blake2s_constant
|
||||
// 'new' operator.
|
||||
struct blake2s_state
|
||||
{
|
||||
enum { BLAKE_ALIGNMENT = 64 };
|
||||
// Use constexpr instead of enums, because otherwise clang -std=c++20
|
||||
// issues a warning about "arithmetic between different enumeration types"
|
||||
// in ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT] declaration.
|
||||
static constexpr size_t BLAKE_ALIGNMENT = 64;
|
||||
|
||||
// buffer and uint32 h[8], t[2], f[2];
|
||||
enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES };
|
||||
// 2 * BLAKE2S_BLOCKBYTES is the buf size in blake2_code_20140114.zip.
|
||||
// It might differ in later versions.
|
||||
static constexpr size_t BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES;
|
||||
|
||||
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// Based on public domain code written in 2012 by Samuel Neves
|
||||
|
||||
extern const byte blake2s_sigma[10][16];
|
||||
|
||||
// Initialization vector.
|
||||
static __m128i blake2s_IV_0_3, blake2s_IV_4_7;
|
||||
|
||||
#ifdef _WIN_64
|
||||
// Constants for cyclic rotation. Used in 64-bit mode in mm_rotr_epi32 macro.
|
||||
// Constants for cyclic rotation.
|
||||
static __m128i crotr8, crotr16;
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((target("sse2")))
|
||||
#endif
|
||||
static void blake2s_init_sse()
|
||||
{
|
||||
// We cannot initialize these 128 bit variables in place when declaring
|
||||
@@ -24,28 +23,18 @@ static void blake2s_init_sse()
|
||||
blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A );
|
||||
blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 );
|
||||
|
||||
#ifdef _WIN_64
|
||||
crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 );
|
||||
crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
|
||||
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
|
||||
|
||||
#ifdef _WIN_32
|
||||
// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient
|
||||
// to not use _mm_shuffle_epi8 here.
|
||||
#define mm_rotr_epi32(r, c) ( \
|
||||
_mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
|
||||
#else
|
||||
#define mm_rotr_epi32(r, c) ( \
|
||||
c==8 ? _mm_shuffle_epi8(r,crotr8) \
|
||||
: c==16 ? _mm_shuffle_epi8(r,crotr16) \
|
||||
: _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
|
||||
#endif
|
||||
|
||||
|
||||
#define G1(row1,row2,row3,row4,buf) \
|
||||
row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
|
||||
@@ -73,14 +62,6 @@ static void blake2s_init_sse()
|
||||
row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
|
||||
row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) );
|
||||
|
||||
#ifdef _WIN_64
|
||||
// MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load
|
||||
// from stack operations, which are slower than this code.
|
||||
#define _mm_set_epi32(i3,i2,i1,i0) \
|
||||
_mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \
|
||||
_mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3)))
|
||||
#endif
|
||||
|
||||
// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode
|
||||
// and about the same in x64 mode in our test. Perhaps depends on compiler.
|
||||
// We also tried _mm_i32gather_epi32 and _mm256_i32gather_epi32 AVX2 gather
|
||||
@@ -101,6 +82,9 @@ static void blake2s_init_sse()
|
||||
}
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((target("ssse3")))
|
||||
#endif
|
||||
static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
|
||||
{
|
||||
__m128i row[4];
|
||||
|
||||
@@ -20,7 +20,7 @@ void blake2sp_init( blake2sp_state *S )
|
||||
|
||||
blake2s_init_param( &S->R, 0, 1 ); // Init root.
|
||||
|
||||
for( uint i = 0; i < PARALLELISM_DEGREE; ++i )
|
||||
for( uint32 i = 0; i < PARALLELISM_DEGREE; ++i )
|
||||
blake2s_init_param( &S->S[i], i, 0 ); // Init leaf.
|
||||
|
||||
S->R.last_node = 1;
|
||||
@@ -49,6 +49,8 @@ void Blake2ThreadData::Update()
|
||||
if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES)
|
||||
_mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0);
|
||||
#endif
|
||||
// We tried to _forceinline blake2s_update and blake2s_compress_sse,
|
||||
// but it didn't improve performance.
|
||||
blake2s_update( S, in__, BLAKE2S_BLOCKBYTES );
|
||||
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
|
||||
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
|
||||
|
||||
@@ -13,8 +13,18 @@ void CommandData::Init()
|
||||
{
|
||||
RAROptions::Init();
|
||||
|
||||
*Command=0;
|
||||
*ArcName=0;
|
||||
Command.clear();
|
||||
ArcName.clear();
|
||||
ExtrPath.clear();
|
||||
TempPath.clear();
|
||||
SFXModule.clear();
|
||||
CommentFile.clear();
|
||||
ArcPath.clear();
|
||||
ExclArcPath.clear();
|
||||
LogName.clear();
|
||||
EmailTo.clear();
|
||||
UseStdin.clear();
|
||||
|
||||
FileLists=false;
|
||||
NoMoreSwitches=false;
|
||||
|
||||
@@ -26,60 +36,52 @@ void CommandData::Init()
|
||||
FileArgs.Reset();
|
||||
ExclArgs.Reset();
|
||||
InclArgs.Reset();
|
||||
StoreArgs.Reset();
|
||||
ArcNames.Reset();
|
||||
NextVolSizes.Reset();
|
||||
}
|
||||
|
||||
|
||||
// Return the pointer to next position in the string and store dynamically
|
||||
// allocated command line parameter in Par.
|
||||
static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par)
|
||||
{
|
||||
const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0);
|
||||
if (NextCmd==NULL)
|
||||
return NULL;
|
||||
size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero.
|
||||
*Par=(wchar *)malloc(ParSize*sizeof(wchar));
|
||||
if (*Par==NULL)
|
||||
return NULL;
|
||||
return GetCmdParam(CmdLine,*Par,ParSize);
|
||||
StoreArgs.Reset();
|
||||
#ifdef PROPAGATE_MOTW
|
||||
MotwList.Reset();
|
||||
#endif
|
||||
Password.Clean();
|
||||
NextVolSizes.clear();
|
||||
#ifdef RARDLL
|
||||
DllDestName.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
|
||||
{
|
||||
*Command=0;
|
||||
Command.clear();
|
||||
NoMoreSwitches=false;
|
||||
#ifdef CUSTOM_CMDLINE_PARSER
|
||||
// In Windows we may prefer to implement our own command line parser
|
||||
// to avoid replacing \" by " in standard parser. Such replacing corrupts
|
||||
// destination paths like "dest path\" in extraction commands.
|
||||
const wchar *CmdLine=GetCommandLine();
|
||||
std::wstring CmdLine=GetCommandLine();
|
||||
|
||||
std::wstring Param;
|
||||
std::wstring::size_type Pos=0;
|
||||
|
||||
wchar *Par;
|
||||
for (bool FirstParam=true;;FirstParam=false)
|
||||
{
|
||||
if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL)
|
||||
if (!GetCmdParam(CmdLine,Pos,Param))
|
||||
break;
|
||||
if (!FirstParam) // First parameter is the executable name.
|
||||
if (Preprocess)
|
||||
PreprocessArg(Par);
|
||||
PreprocessArg(Param.c_str());
|
||||
else
|
||||
ParseArg(Par);
|
||||
free(Par);
|
||||
ParseArg(Param.c_str());
|
||||
}
|
||||
#else
|
||||
Array<wchar> Arg;
|
||||
for (int I=1;I<argc;I++)
|
||||
{
|
||||
Arg.Alloc(strlen(argv[I])+1);
|
||||
CharToWide(argv[I],&Arg[0],Arg.Size());
|
||||
std::wstring Arg;
|
||||
CharToWide(argv[I],Arg);
|
||||
if (Preprocess)
|
||||
PreprocessArg(&Arg[0]);
|
||||
PreprocessArg(Arg.c_str());
|
||||
else
|
||||
ParseArg(&Arg[0]);
|
||||
ParseArg(Arg.c_str());
|
||||
}
|
||||
#endif
|
||||
if (!Preprocess)
|
||||
@@ -89,7 +91,7 @@ void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ParseArg(wchar *Arg)
|
||||
void CommandData::ParseArg(const wchar *Arg)
|
||||
{
|
||||
if (IsSwitch(*Arg) && !NoMoreSwitches)
|
||||
if (Arg[1]=='-' && Arg[2]==0)
|
||||
@@ -97,34 +99,52 @@ void CommandData::ParseArg(wchar *Arg)
|
||||
else
|
||||
ProcessSwitch(Arg+1);
|
||||
else
|
||||
if (*Command==0)
|
||||
if (Command.empty())
|
||||
{
|
||||
wcsncpyz(Command,Arg,ASIZE(Command));
|
||||
Command=Arg;
|
||||
|
||||
|
||||
*Command=toupperw(*Command);
|
||||
Command[0]=toupperw(Command[0]);
|
||||
// 'I' and 'S' commands can contain case sensitive strings after
|
||||
// the first character, so we must not modify their case.
|
||||
// 'S' can contain SFX name, which case is important in Unix.
|
||||
if (*Command!='I' && *Command!='S')
|
||||
if (Command[0]!='I' && Command[0]!='S')
|
||||
wcsupper(Command);
|
||||
if (Command[0]=='P') // Enforce -idq for print command.
|
||||
{
|
||||
MsgStream=MSG_ERRONLY;
|
||||
SetConsoleMsgStream(MSG_ERRONLY);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (*ArcName==0)
|
||||
wcsncpyz(ArcName,Arg,ASIZE(ArcName));
|
||||
if (ArcName.empty())
|
||||
ArcName=Arg;
|
||||
else
|
||||
{
|
||||
// Check if last character is the path separator.
|
||||
size_t Length=wcslen(Arg);
|
||||
wchar EndChar=Length==0 ? 0:Arg[Length-1];
|
||||
bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
|
||||
// Check if trailing path separator like path\ is present.
|
||||
bool FolderArg=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
|
||||
|
||||
wchar CmdChar=toupperw(*Command);
|
||||
// 2024.01.05: We were asked to support exotic d:. and d:.. paths.
|
||||
if (IsDriveLetter(Arg) && Arg[2]=='.' && (Arg[3]==0 || Arg[3]=='.' && Arg[4]==0))
|
||||
FolderArg=true;
|
||||
|
||||
// 2024.01.06: FindFile::FastFind check below fails in Windows 10 if
|
||||
// "." or ".." points at disk root. So we enforce it for "." and ".."
|
||||
// optionally preceded with some path like "..\..".
|
||||
size_t L=Length;
|
||||
if (L>0 && Arg[L-1]=='.' && (L==1 || L>=2 && (IsPathDiv(Arg[L-2]) ||
|
||||
Arg[L-2]=='.' && (L==2 || L>=3 && IsPathDiv(Arg[L-3])))))
|
||||
FolderArg=true;
|
||||
|
||||
wchar CmdChar=toupperw(Command[0]);
|
||||
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));
|
||||
if (FolderArg && !Add)
|
||||
ExtrPath=Arg;
|
||||
else
|
||||
if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
|
||||
FileArgs.AddString(Arg);
|
||||
@@ -141,10 +161,10 @@ void CommandData::ParseArg(wchar *Arg)
|
||||
|
||||
}
|
||||
else // We use 'destpath\' when extracting and reparing.
|
||||
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
|
||||
if (Found && FileData.IsDir && (Extract || Repair) && ExtrPath.empty())
|
||||
{
|
||||
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
|
||||
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
|
||||
ExtrPath=Arg;
|
||||
AddEndSlash(ExtrPath);
|
||||
}
|
||||
else
|
||||
FileArgs.AddString(Arg);
|
||||
@@ -172,12 +192,12 @@ void CommandData::ParseDone()
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ParseEnvVar()
|
||||
{
|
||||
char *EnvStr=getenv("RAR");
|
||||
if (EnvStr!=NULL)
|
||||
char *EnvVar=getenv("RARINISWITCHES");
|
||||
if (EnvVar!=NULL)
|
||||
{
|
||||
Array<wchar> EnvStrW(strlen(EnvStr)+1);
|
||||
CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size());
|
||||
ProcessSwitchesString(&EnvStrW[0]);
|
||||
std::wstring EnvStr;
|
||||
CharToWide(EnvVar,EnvStr);
|
||||
ProcessSwitchesString(EnvStr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -186,7 +206,7 @@ void CommandData::ParseEnvVar()
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
// Preprocess those parameters, which must be processed before the rest of
|
||||
// command line. Return 'false' to stop further processing.
|
||||
// command line.
|
||||
void CommandData::PreprocessArg(const wchar *Arg)
|
||||
{
|
||||
if (IsSwitch(Arg[0]) && !NoMoreSwitches)
|
||||
@@ -195,7 +215,7 @@ void CommandData::PreprocessArg(const wchar *Arg)
|
||||
if (Arg[0]=='-' && Arg[1]==0) // Switch "--".
|
||||
NoMoreSwitches=true;
|
||||
if (wcsicomp(Arg,L"cfg-")==0)
|
||||
ConfigDisabled=true;
|
||||
ProcessSwitch(Arg);
|
||||
if (wcsnicomp(Arg,L"ilog",4)==0)
|
||||
{
|
||||
// Ensure that correct log file name is already set
|
||||
@@ -207,13 +227,13 @@ void CommandData::PreprocessArg(const wchar *Arg)
|
||||
{
|
||||
// Process -sc before reading any file lists.
|
||||
ProcessSwitch(Arg);
|
||||
if (*LogName!=0)
|
||||
if (!LogName.empty())
|
||||
InitLogOptions(LogName,ErrlogCharset);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (*Command==0)
|
||||
wcsncpy(Command,Arg,ASIZE(Command)); // Need for rar.ini.
|
||||
if (Command.empty())
|
||||
Command=Arg; // Need for rar.ini.
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -231,10 +251,10 @@ void CommandData::ReadConfig()
|
||||
Str++;
|
||||
if (wcsnicomp(Str,L"switches=",9)==0)
|
||||
ProcessSwitchesString(Str+9);
|
||||
if (*Command!=0)
|
||||
if (!Command.empty())
|
||||
{
|
||||
wchar Cmd[16];
|
||||
wcsncpyz(Cmd,Command,ASIZE(Cmd));
|
||||
wcsncpyz(Cmd,Command.c_str(),ASIZE(Cmd));
|
||||
wchar C0=toupperw(Cmd[0]);
|
||||
wchar C1=toupperw(Cmd[1]);
|
||||
if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V')
|
||||
@@ -254,14 +274,19 @@ void CommandData::ReadConfig()
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void CommandData::ProcessSwitchesString(const wchar *Str)
|
||||
void CommandData::ProcessSwitchesString(const std::wstring &Str)
|
||||
{
|
||||
wchar *Par;
|
||||
while ((Str=AllocCmdParam(Str,&Par))!=NULL)
|
||||
std::wstring Par;
|
||||
std::wstring::size_type Pos=0;
|
||||
while (GetCmdParam(Str,Pos,Par))
|
||||
{
|
||||
if (IsSwitch(*Par))
|
||||
ProcessSwitch(Par+1);
|
||||
free(Par);
|
||||
if (IsSwitch(Par[0]))
|
||||
ProcessSwitch(&Par[1]);
|
||||
else
|
||||
{
|
||||
mprintf(St(MSwSyntaxError),Par.c_str());
|
||||
ErrHandler.Exit(RARX_USERERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -271,6 +296,9 @@ void CommandData::ProcessSwitchesString(const wchar *Str)
|
||||
void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
{
|
||||
|
||||
if (LargePageAlloc::ProcessSwitch(this,Switch))
|
||||
return;
|
||||
|
||||
switch(toupperw(Switch[0]))
|
||||
{
|
||||
case '@':
|
||||
@@ -309,13 +337,27 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'I':
|
||||
IgnoreGeneralAttr=true;
|
||||
break;
|
||||
case 'N': // Reserved for archive name.
|
||||
case 'M':
|
||||
switch(toupperw(Switch[2]))
|
||||
{
|
||||
case 0:
|
||||
case 'S':
|
||||
ArcMetadata=ARCMETA_SAVE;
|
||||
break;
|
||||
case 'R':
|
||||
ArcMetadata=ARCMETA_RESTORE;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
AddArcOnly=true;
|
||||
break;
|
||||
case 'P':
|
||||
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
|
||||
// Convert slashes here than before every comparison.
|
||||
SlashToNative(Switch+2,ArcPath);
|
||||
break;
|
||||
case 'S':
|
||||
SyncFiles=true;
|
||||
@@ -326,7 +368,14 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (Switch[2]==0)
|
||||
if (Switch[2]!=0)
|
||||
{
|
||||
if (wcsicomp(Switch+1,L"FG-")==0)
|
||||
ConfigDisabled=true;
|
||||
else
|
||||
BadSwitch(Switch);
|
||||
}
|
||||
else
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case '-':
|
||||
@@ -338,10 +387,15 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'L':
|
||||
ConvertNames=NAMES_LOWERCASE;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if (Switch[2]==0)
|
||||
if (Switch[2]!=0)
|
||||
BadSwitch(Switch);
|
||||
else
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case 'S':
|
||||
@@ -353,6 +407,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'F':
|
||||
DeleteFiles=true;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
@@ -373,6 +430,13 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case '3':
|
||||
ExclPath=EXCL_ABSPATH;
|
||||
break;
|
||||
case '4':
|
||||
// Convert slashes here than before every comparison.
|
||||
SlashToNative(Switch+3,ExclArcPath);
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -399,13 +463,17 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
EncryptHeaders=true;
|
||||
if (Switch[2]!=0)
|
||||
{
|
||||
// We use this code for other archive formats too, so MAXPASSWORD
|
||||
// instead of MAXPASSWORD_RAR.
|
||||
if (wcslen(Switch+2)>=MAXPASSWORD)
|
||||
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
|
||||
Password.Set(Switch+2);
|
||||
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
|
||||
}
|
||||
else
|
||||
if (!Password.IsSet())
|
||||
{
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,L"",&Password,NULL);
|
||||
eprintf(L"\n");
|
||||
}
|
||||
break;
|
||||
@@ -417,7 +485,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'I':
|
||||
if (wcsnicomp(Switch+1,L"LOG",3)==0)
|
||||
{
|
||||
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
|
||||
LogName=Switch[4]!=0 ? Switch+4:DefLogName;
|
||||
break;
|
||||
}
|
||||
if (wcsnicomp(Switch+1,L"SND",3)==0)
|
||||
@@ -435,7 +503,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
if (wcsnicomp(Switch+1,L"EML",3)==0)
|
||||
{
|
||||
wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
|
||||
EmailTo=Switch[4]!=0 ? Switch+4:L"@";
|
||||
break;
|
||||
}
|
||||
if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv.
|
||||
@@ -542,12 +610,14 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
switch(toupperw(*(Str++)))
|
||||
{
|
||||
case 'T': Type=FILTER_PPM; break;
|
||||
// case 'T': Type=FILTER_TEXT; break;
|
||||
case 'E': Type=FILTER_E8; break;
|
||||
case 'D': Type=FILTER_DELTA; break;
|
||||
case 'A': Type=FILTER_AUDIO; break;
|
||||
case 'C': Type=FILTER_RGB; break;
|
||||
case 'R': Type=FILTER_ARM; break;
|
||||
// case 'A': Type=FILTER_AUDIO; break;
|
||||
// case 'C': Type=FILTER_RGB; break;
|
||||
// case 'R': Type=FILTER_ARM; break;
|
||||
case 'L': Type=FILTER_LONGRANGE; break;
|
||||
case 'X': Type=FILTER_EXHAUSTIVE; break;
|
||||
}
|
||||
if (*Str=='+' || *Str=='-')
|
||||
State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
|
||||
@@ -557,42 +627,74 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
break;
|
||||
case 'D':
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
wchar StoreNames[1024];
|
||||
wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
|
||||
wchar *Names=StoreNames;
|
||||
while (*Names!=0)
|
||||
bool SetDictLimit=toupperw(Switch[2])=='X';
|
||||
|
||||
uint64 Size=atoiw(Switch+(SetDictLimit ? 3 : 2));
|
||||
wchar LastChar=toupperw(Switch[wcslen(Switch)-1]);
|
||||
if (IsDigit(LastChar))
|
||||
LastChar=SetDictLimit ? 'G':'M'; // Treat -md128 as -md128m and -mdx32 as -mdx32g.
|
||||
switch(LastChar)
|
||||
{
|
||||
wchar *End=wcschr(Names,';');
|
||||
if (End!=NULL)
|
||||
*End=0;
|
||||
if (*Names=='.')
|
||||
Names++;
|
||||
wchar Mask[NM];
|
||||
if (wcspbrk(Names,L"*?.")==NULL)
|
||||
swprintf(Mask,ASIZE(Mask),L"*.%ls",Names);
|
||||
else
|
||||
wcsncpyz(Mask,Names,ASIZE(Mask));
|
||||
StoreArgs.AddString(Mask);
|
||||
if (End==NULL)
|
||||
case 'K':
|
||||
Size*=1024;
|
||||
break;
|
||||
Names=End+1;
|
||||
case 'M':
|
||||
Size*=1024*1024;
|
||||
break;
|
||||
case 'G':
|
||||
Size*=1024*1024*1024;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
}
|
||||
|
||||
// 2023.07.22: For 4 GB and less we also check that it is power of 2,
|
||||
// so archives are compatible with RAR 5.0+.
|
||||
// We allow Size>PACK_MAX_DICT here, so we can use -md[x] to unpack
|
||||
// archives created by future versions with higher PACK_MAX_DICT.
|
||||
uint Flags;
|
||||
if ((Size=Archive::GetWinSize(Size,Flags))==0 ||
|
||||
Size<=0x100000000ULL && !IsPow2(Size))
|
||||
BadSwitch(Switch);
|
||||
else
|
||||
if (SetDictLimit)
|
||||
WinSizeLimit=Size;
|
||||
else
|
||||
{
|
||||
WinSize=Size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
if (toupperw(Switch[2])=='S' && Switch[3]==0)
|
||||
SkipEncrypted=true;
|
||||
break;
|
||||
case 'L':
|
||||
if (toupperw(Switch[2])=='P')
|
||||
{
|
||||
UseLargePages=true;
|
||||
if (!LargePageAlloc::IsPrivilegeAssigned() && LargePageAlloc::AssignConfirmation())
|
||||
{
|
||||
LargePageAlloc::AssignPrivilege();
|
||||
|
||||
// Quit immediately. We do not want to interrupt the current copy
|
||||
// archive processing with reboot after assigning privilege.
|
||||
SetupComplete=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
break;
|
||||
case 'S':
|
||||
GetBriefMaskList(Switch[2]==0 ? DefaultStoreList:Switch+2,StoreArgs);
|
||||
break;
|
||||
#ifdef RAR_SMP
|
||||
case 'T':
|
||||
Threads=atoiw(Switch+2);
|
||||
if (Threads>MaxPoolThreads || Threads<1)
|
||||
BadSwitch(Switch);
|
||||
else
|
||||
{
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -638,8 +740,31 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
#ifdef SAVE_LINKS
|
||||
case 'L':
|
||||
SaveSymLinks=true;
|
||||
if (toupperw(Switch[2])=='A')
|
||||
AbsoluteLinks=true;
|
||||
for (uint I=2;Switch[I]!=0;I++)
|
||||
switch(toupperw(Switch[I]))
|
||||
{
|
||||
case 'A':
|
||||
AbsoluteLinks=true;
|
||||
break;
|
||||
case '-':
|
||||
SkipSymLinks=true;
|
||||
break;
|
||||
default:
|
||||
BadSwitch(Switch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef PROPAGATE_MOTW
|
||||
case 'M':
|
||||
{
|
||||
MotwAllFields=Switch[2]=='1';
|
||||
const wchar *Sep=wcschr(Switch+2,'=');
|
||||
if (Switch[2]=='-')
|
||||
MotwList.Reset();
|
||||
else
|
||||
GetBriefMaskList(Sep==nullptr ? L"*":Sep+1,MotwList);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
@@ -648,6 +773,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
AllowIncompatNames=true;
|
||||
break;
|
||||
#endif
|
||||
case 'P':
|
||||
ExtrPath=Switch+2;
|
||||
AddEndSlash(ExtrPath);
|
||||
break;
|
||||
case 'R':
|
||||
Overwrite=OVERWRITE_AUTORENAME;
|
||||
break;
|
||||
@@ -667,11 +796,13 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'P':
|
||||
if (Switch[1]==0)
|
||||
{
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||||
uiGetPassword(UIPASSWORD_GLOBAL,L"",&Password,NULL);
|
||||
eprintf(L"\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wcslen(Switch+1)>=MAXPASSWORD)
|
||||
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
|
||||
Password.Set(Switch+1);
|
||||
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
|
||||
}
|
||||
@@ -738,7 +869,52 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case 0:
|
||||
case '=':
|
||||
Solid|=SOLID_NORMAL;
|
||||
if (Switch[1]=='=')
|
||||
{
|
||||
uint Par=0;
|
||||
for (const wchar *S=Switch+2;*S!=0;S++)
|
||||
{
|
||||
if (IsDigit(*S))
|
||||
Par=Par*10+*S-'0';
|
||||
switch(toupperw(*S))
|
||||
{
|
||||
case '-':
|
||||
Solid=SOLID_NONE;
|
||||
break;
|
||||
case 'D':
|
||||
Solid|=SOLID_VOLUME_DEPENDENT;
|
||||
break;
|
||||
case 'E':
|
||||
Solid|=SOLID_FILEEXT;
|
||||
break;
|
||||
case 'F':
|
||||
Solid|=SOLID_COUNT;
|
||||
SolidCount=Par;
|
||||
break;
|
||||
case 'K':
|
||||
Solid|=SOLID_BLOCK_SIZE;
|
||||
SolidBlockSize=Par*1024LL;
|
||||
break;
|
||||
case 'M':
|
||||
Solid|=SOLID_BLOCK_SIZE;
|
||||
SolidBlockSize=Par*1024LL*1024LL;
|
||||
break;
|
||||
case 'G':
|
||||
Solid|=SOLID_BLOCK_SIZE;
|
||||
SolidBlockSize=Par*1024LL*1024LL*1024LL;
|
||||
break;
|
||||
case 'R':
|
||||
Solid=SOLID_RESET;
|
||||
break;
|
||||
case 'V':
|
||||
Solid|=SOLID_VOLUME_INDEPENDENT;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
Solid=SOLID_NONE;
|
||||
@@ -752,13 +928,22 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'D':
|
||||
Solid|=SOLID_VOLUME_DEPENDENT;
|
||||
break;
|
||||
case 'I':
|
||||
ProhibitConsoleInput();
|
||||
// We do not assign the archive name automatically for -si
|
||||
// if archive name is omitted and require the archive name to
|
||||
// present always. Otherwise for"type arc.rar|rar x -si arc2.rar"
|
||||
// if arc2.rar is a dummy archive name or file inside of arc.rar,
|
||||
// which needs to be extracted.
|
||||
UseStdin=Switch[2] ? Switch+2:L"stdin";
|
||||
break;
|
||||
case 'L':
|
||||
if (IsDigit(Switch[2]))
|
||||
FileSizeLess=atoilw(Switch+2);
|
||||
FileSizeLess=GetModSize(Switch+2,1);
|
||||
break;
|
||||
case 'M':
|
||||
if (IsDigit(Switch[2]))
|
||||
FileSizeMore=atoilw(Switch+2);
|
||||
FileSizeMore=GetModSize(Switch+2,1);
|
||||
break;
|
||||
case 'C':
|
||||
{
|
||||
@@ -816,12 +1001,6 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
case 'T':
|
||||
switch(toupperw(Switch[1]))
|
||||
{
|
||||
case 'K':
|
||||
ArcTime=ARCTIME_KEEP;
|
||||
break;
|
||||
case 'L':
|
||||
ArcTime=ARCTIME_LATEST;
|
||||
break;
|
||||
case 'O':
|
||||
SetTimeFilters(Switch+2,true,true);
|
||||
break;
|
||||
@@ -873,8 +1052,8 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
wcsncpyz(TempPath,Switch+1,ASIZE(TempPath));
|
||||
AddEndSlash(TempPath,ASIZE(TempPath));
|
||||
TempPath=Switch+1;
|
||||
AddEndSlash(TempPath);
|
||||
break;
|
||||
case 'Y':
|
||||
AllYes=true;
|
||||
@@ -883,10 +1062,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
|
||||
if (Switch[1]==0)
|
||||
{
|
||||
// If comment file is not specified, we read data from stdin.
|
||||
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
|
||||
CommentFile=L"stdin";
|
||||
}
|
||||
else
|
||||
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
|
||||
CommentFile=Switch+1;
|
||||
break;
|
||||
case '?' :
|
||||
OutHelp(RARX_SUCCESS);
|
||||
@@ -913,34 +1092,41 @@ void CommandData::ProcessCommand()
|
||||
#ifndef SFX_MODULE
|
||||
|
||||
const wchar *SingleCharCommands=L"FUADPXETK";
|
||||
if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
|
||||
OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
|
||||
|
||||
const wchar *ArcExt=GetExt(ArcName);
|
||||
// RAR -mlp command is the legitimate way to assign the required privilege.
|
||||
if (Command.empty() && UseLargePages || SetupComplete)
|
||||
return;
|
||||
|
||||
if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || ArcName.empty())
|
||||
OutHelp(Command.empty() ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
|
||||
|
||||
size_t ExtPos=GetExtPos(ArcName);
|
||||
#ifdef _UNIX
|
||||
if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
|
||||
wcsncatz(ArcName,L".rar",ASIZE(ArcName));
|
||||
// If we want to update an archive without extension, in Windows we can use
|
||||
// "arcname." and it will be treated as "arcname". In Unix "arcname"
|
||||
// and "arcname." are two different names, so we check if "arcname" exists
|
||||
// and do not append ".rar", allowing user to update such archive.
|
||||
if (ExtPos==std::wstring::npos && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
|
||||
ArcName+=L".rar";
|
||||
#else
|
||||
if (ArcExt==NULL)
|
||||
wcsncatz(ArcName,L".rar",ASIZE(ArcName));
|
||||
if (ExtPos==std::wstring::npos)
|
||||
ArcName+=L".rar";
|
||||
#endif
|
||||
// Treat arcname.part1 as arcname.part1.rar.
|
||||
if (ArcExt!=NULL && wcsnicomp(ArcExt,L".part",5)==0 && IsDigit(ArcExt[5]) &&
|
||||
!FileExist(ArcName))
|
||||
if (ExtPos!=std::wstring::npos && wcsnicomp(&ArcName[ExtPos],L".part",5)==0 &&
|
||||
IsDigit(ArcName[ExtPos+5]) && !FileExist(ArcName))
|
||||
{
|
||||
wchar Name[NM];
|
||||
wcsncpyz(Name,ArcName,ASIZE(Name));
|
||||
wcsncatz(Name,L".rar",ASIZE(Name));
|
||||
std::wstring Name=ArcName+L".rar";
|
||||
if (FileExist(Name))
|
||||
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||||
ArcName=Name;
|
||||
}
|
||||
|
||||
if (wcschr(L"AFUMD",*Command)==NULL)
|
||||
if (wcschr(L"AFUMD",Command[0])==NULL && UseStdin.empty())
|
||||
{
|
||||
if (GenerateArcName)
|
||||
{
|
||||
const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
|
||||
GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
|
||||
GenerateArchiveName(ArcName,Mask,false);
|
||||
}
|
||||
|
||||
StringList ArcMasks;
|
||||
@@ -974,12 +1160,22 @@ void CommandData::ProcessCommand()
|
||||
OutHelp(RARX_USERERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Since messages usually include '\n' in the beginning, we also issue
|
||||
// the final '\n'. It is especially important in Unix, where otherwise
|
||||
// the shell can display the prompt on the same line as the last message.
|
||||
// mprintf is blocked with -idq and if error messages had been displayed
|
||||
// in this mode, we use eprintf to separate them from shell prompt.
|
||||
// If nothing was displayed with -idq, we avoid the excessive empty line.
|
||||
if (!BareOutput)
|
||||
mprintf(L"\n");
|
||||
if (MsgStream==MSG_ERRONLY && IsConsoleOutputPresent())
|
||||
eprintf(L"\n");
|
||||
else
|
||||
mprintf(L"\n");
|
||||
}
|
||||
|
||||
|
||||
void CommandData::AddArcName(const wchar *Name)
|
||||
void CommandData::AddArcName(const std::wstring &Name)
|
||||
{
|
||||
ArcNames.AddString(Name);
|
||||
}
|
||||
@@ -991,9 +1187,15 @@ bool CommandData::GetArcName(wchar *Name,int MaxSize)
|
||||
}
|
||||
|
||||
|
||||
bool CommandData::GetArcName(std::wstring &Name)
|
||||
{
|
||||
return ArcNames.GetString(Name);
|
||||
}
|
||||
|
||||
|
||||
bool CommandData::IsSwitch(int Ch)
|
||||
{
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
return Ch=='-' || Ch=='/';
|
||||
#else
|
||||
return Ch=='-';
|
||||
@@ -1019,7 +1221,7 @@ uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
|
||||
case 'V':
|
||||
Attr|=S_IFCHR;
|
||||
break;
|
||||
#elif defined(_WIN_ALL) || defined(_EMX)
|
||||
#elif defined(_WIN_ALL)
|
||||
case 'R':
|
||||
Attr|=0x1;
|
||||
break;
|
||||
@@ -1043,21 +1245,6 @@ uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
|
||||
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
bool CommandData::CheckWinSize()
|
||||
{
|
||||
// Define 0x100000000 as macro to avoid troubles with older compilers.
|
||||
const uint64 MaxDictSize=INT32TO64(1,0);
|
||||
// Limit the dictionary size to 4 GB.
|
||||
for (uint64 I=0x10000;I<=MaxDictSize;I*=2)
|
||||
if (WinSize==I)
|
||||
return true;
|
||||
WinSize=0x400000;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void CommandData::ReportWrongSwitches(RARFORMAT Format)
|
||||
{
|
||||
@@ -1087,3 +1274,57 @@ void CommandData::ReportWrongSwitches(RARFORMAT Format)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Get size for string with optional trailing modifiers like "100m".
|
||||
int64 CommandData::GetModSize(const wchar *S,uint DefMultiplier)
|
||||
{
|
||||
int64 Size=0,FloatingDivider=0;
|
||||
for (uint I=0;S[I]!=0;I++)
|
||||
if (IsDigit(S[I]))
|
||||
{
|
||||
Size=Size*10+S[I]-'0';
|
||||
FloatingDivider*=10;
|
||||
}
|
||||
else
|
||||
if (S[I]=='.')
|
||||
FloatingDivider=1;
|
||||
|
||||
if (*S!=0)
|
||||
{
|
||||
const wchar *ModList=L"bBkKmMgGtT";
|
||||
const wchar *Mod=wcschr(ModList,S[wcslen(S)-1]);
|
||||
if (Mod==nullptr)
|
||||
Size*=DefMultiplier;
|
||||
else
|
||||
for (ptrdiff_t I=2;I<=Mod-ModList;I+=2)
|
||||
Size*=((Mod-ModList)&1)!=0 ? 1000:1024;
|
||||
}
|
||||
if (FloatingDivider!=0)
|
||||
Size/=FloatingDivider;
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
// Treat the list like rar;zip as *.rar;*.zip for -ms and similar switches.
|
||||
void CommandData::GetBriefMaskList(const std::wstring &Masks,StringList &Args)
|
||||
{
|
||||
size_t Pos=0;
|
||||
while (Pos<Masks.size())
|
||||
{
|
||||
if (Masks[Pos]=='.')
|
||||
Pos++;
|
||||
size_t EndPos=Masks.find(';',Pos);
|
||||
std::wstring Mask=Masks.substr(Pos,EndPos==std::wstring::npos ? EndPos:EndPos-Pos);
|
||||
if (Mask.find_first_of(L"*?.")==std::wstring::npos)
|
||||
Mask.insert(0,L"*.");
|
||||
Args.AddString(Mask);
|
||||
if (EndPos==std::wstring::npos)
|
||||
break;
|
||||
Pos=EndPos+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
#ifndef _RAR_CMDDATA_
|
||||
#define _RAR_CMDDATA_
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
// In Windows we implement our own command line parser to avoid replacing
|
||||
// \" by " in standard parser. Such replacing corrupts destination paths
|
||||
// like "dest path\" in extraction commands.
|
||||
#define CUSTOM_CMDLINE_PARSER
|
||||
#endif
|
||||
|
||||
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx"
|
||||
#define DefaultStoreList L"7z;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tbz;tbz2;tgz;txz;xz;z;zip;zipx;zst;tzst"
|
||||
|
||||
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
|
||||
|
||||
@@ -18,6 +24,7 @@ class CommandData:public RAROptions
|
||||
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
|
||||
void SetStoreTimeMode(const wchar *S);
|
||||
#endif
|
||||
int64 GetModSize(const wchar *S,uint DefMultiplier);
|
||||
|
||||
bool FileLists;
|
||||
bool NoMoreSwitches;
|
||||
@@ -28,43 +35,69 @@ class CommandData:public RAROptions
|
||||
void Init();
|
||||
|
||||
void ParseCommandLine(bool Preprocess,int argc, char *argv[]);
|
||||
void ParseArg(wchar *ArgW);
|
||||
void ParseArg(const wchar *ArgW);
|
||||
void ParseDone();
|
||||
void ParseEnvVar();
|
||||
void ReadConfig();
|
||||
void PreprocessArg(const wchar *Arg);
|
||||
void ProcessSwitchesString(const wchar *Str);
|
||||
void ProcessSwitchesString(const std::wstring &Str);
|
||||
void OutTitle();
|
||||
void OutHelp(RAR_EXIT ExitCode);
|
||||
bool IsSwitch(int Ch);
|
||||
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 ExclCheck(const std::wstring &CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
|
||||
static bool CheckArgs(StringList *Args,bool Dir,const std::wstring &CheckName,bool CheckFullPath,int MatchMode);
|
||||
bool ExclDirByAttr(uint FileAttr);
|
||||
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
|
||||
bool SizeCheck(int64 Size);
|
||||
bool AnyFiltersActive();
|
||||
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
|
||||
bool Flags,wchar *MatchedArg,uint MatchedArgSize);
|
||||
bool Flags,std::wstring *MatchedArg);
|
||||
void ProcessCommand();
|
||||
void AddArcName(const wchar *Name);
|
||||
void AddArcName(const std::wstring &Name);
|
||||
bool GetArcName(wchar *Name,int MaxSize);
|
||||
bool CheckWinSize();
|
||||
bool GetArcName(std::wstring &Name);
|
||||
|
||||
int GetRecoverySize(const wchar *Str,int DefSize);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
void ReportWrongSwitches(RARFORMAT Format);
|
||||
#endif
|
||||
|
||||
wchar Command[NM+16];
|
||||
void GetBriefMaskList(const std::wstring &Masks,StringList &Args);
|
||||
|
||||
wchar ArcName[NM];
|
||||
|
||||
std::wstring Command;
|
||||
std::wstring ArcName;
|
||||
std::wstring ExtrPath;
|
||||
std::wstring TempPath;
|
||||
std::wstring SFXModule;
|
||||
std::wstring CommentFile;
|
||||
std::wstring ArcPath; // For -ap<path>.
|
||||
std::wstring ExclArcPath; // For -ep4<path> switch.
|
||||
std::wstring LogName;
|
||||
std::wstring EmailTo;
|
||||
|
||||
// Read data from stdin and store in archive under a name specified here
|
||||
// when archiving. Read an archive from stdin if any non-empty string
|
||||
// is specified here when extracting.
|
||||
std::wstring UseStdin;
|
||||
|
||||
StringList FileArgs;
|
||||
StringList ExclArgs;
|
||||
StringList InclArgs;
|
||||
StringList ArcNames;
|
||||
StringList StoreArgs;
|
||||
#ifdef PROPAGATE_MOTW
|
||||
StringList MotwList; // Extensions to assign the mark of the web.
|
||||
#endif
|
||||
|
||||
SecPassword Password;
|
||||
|
||||
std::vector<int64> NextVolSizes;
|
||||
|
||||
|
||||
#ifdef RARDLL
|
||||
std::wstring DllDestName;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 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)
|
||||
bool CommandData::ExclCheck(const std::wstring &CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
|
||||
{
|
||||
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
|
||||
return true;
|
||||
@@ -13,17 +13,21 @@ bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,b
|
||||
}
|
||||
|
||||
|
||||
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
|
||||
bool CommandData::CheckArgs(StringList *Args,bool Dir,const std::wstring &CheckName,bool CheckFullPath,int MatchMode)
|
||||
{
|
||||
wchar *Name=ConvertPath(CheckName,NULL,0);
|
||||
wchar FullName[NM];
|
||||
wchar CurMask[NM];
|
||||
*FullName=0;
|
||||
std::wstring Name,FullName,CurMask;
|
||||
ConvertPath(&CheckName,&Name);
|
||||
Args->Rewind();
|
||||
while (Args->GetString(CurMask,ASIZE(CurMask)))
|
||||
while (Args->GetString(CurMask))
|
||||
{
|
||||
wchar *LastMaskChar=PointToLastChar(CurMask);
|
||||
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
|
||||
#ifdef _WIN_ALL
|
||||
// 2025.09.11: Unix allows DOS slashes as a part of file name, so we do not
|
||||
// convert it for Unix. In Windows we wish -xdir\file and -xdir/file both
|
||||
// to exclude the file.
|
||||
UnixSlashToDos(CurMask,CurMask);
|
||||
#endif
|
||||
wchar LastMaskChar=GetLastChar(CurMask);
|
||||
bool DirMask=IsPathDiv(LastMaskChar); // Mask for directories only.
|
||||
|
||||
if (Dir)
|
||||
{
|
||||
@@ -33,16 +37,33 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// We process the directory and have the directory exclusion mask.
|
||||
// So let's convert "mask\" to "mask" and process it normally.
|
||||
|
||||
*LastMaskChar=0;
|
||||
CurMask.pop_back();
|
||||
}
|
||||
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;
|
||||
// This code doesn't allow to apply -n and -x wildcard masks without
|
||||
// trailing slash to folders unless these masks are * and *.*.
|
||||
// See the changes history below.
|
||||
// 2023.03.26: Previously we removed this code completely to let
|
||||
// 'rar a arc dir -ndir\path\*' include empty folders in 'path' too.
|
||||
// But then we received an email from user not willing -x*.avi to
|
||||
// exclude folders like dir.avi with non-avi files. Also rar.txt
|
||||
// mentions that masks like *.avi exclude only files. Initially
|
||||
// we wanted masks like -npath\* or -xpath\* to match the entire
|
||||
// contents of path including empty folders and added the special
|
||||
// check for "*" and "*.*". But this is not very straightforward,
|
||||
// when *.* and *.avi are processed differently, especially taking
|
||||
// into account that we can specify the exact folder name without
|
||||
// wildcards to process it and masks like 'dir*\' can be used to
|
||||
// exclude folders. So we decided to skip all usual wildcard masks
|
||||
// for folders.
|
||||
// 2023.11.22: We returned the special check for "*" and "*.*",
|
||||
// because users expected 'rar a arc dir -xdir\*' to exclude
|
||||
// everything including subfolders in 'dir'. For now we returned it
|
||||
// both for -n and -x, but we can limit it to -x only if needed.
|
||||
std::wstring Name=PointToName(CurMask);
|
||||
if (IsWildcard(Name) && Name!=L"*" && Name!=L"*.*")
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -54,7 +75,7 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// is excluded from further scanning.
|
||||
|
||||
if (DirMask)
|
||||
wcsncatz(CurMask,L"*",ASIZE(CurMask));
|
||||
CurMask+=L"*";
|
||||
}
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
@@ -66,19 +87,20 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// 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 (FullName.empty())
|
||||
ConvertNameToFull(CheckName,FullName);
|
||||
if (CmpName(CurMask,FullName,MatchMode))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
wchar NewName[NM+2],*CurName=Name;
|
||||
std::wstring CurName=Name;
|
||||
|
||||
// Important to convert before "*\" check below, so masks like
|
||||
// d:*\something are processed properly.
|
||||
wchar *CmpMask=ConvertPath(CurMask,NULL,0);
|
||||
size_t MaskOffset=ConvertPath(&CurMask,nullptr);
|
||||
std::wstring CmpMask=CurMask.substr(MaskOffset);
|
||||
|
||||
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
|
||||
{
|
||||
@@ -86,10 +108,9 @@ bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,boo
|
||||
// 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;
|
||||
CurName=L'.';
|
||||
CurName+=CPATHDIVIDER;
|
||||
CurName+=Name;
|
||||
}
|
||||
|
||||
if (CmpName(CmpMask,CurName,MatchMode))
|
||||
@@ -262,6 +283,8 @@ bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
|
||||
// Return 'true' if we need to exclude the file from processing.
|
||||
bool CommandData::SizeCheck(int64 Size)
|
||||
{
|
||||
if (Size==INT64NDF) // If called from archive formats like bzip2, not storing the file size.
|
||||
return false;
|
||||
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
|
||||
return true;
|
||||
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
|
||||
@@ -275,10 +298,10 @@ bool CommandData::SizeCheck(int64 Size)
|
||||
|
||||
// Return 0 if file must not be processed or a number of matched parameter otherwise.
|
||||
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
|
||||
bool Flags,wchar *MatchedArg,uint MatchedArgSize)
|
||||
bool Flags,std::wstring *MatchedArg)
|
||||
{
|
||||
if (MatchedArg!=NULL && MatchedArgSize>0)
|
||||
*MatchedArg=0;
|
||||
if (MatchedArg!=NULL)
|
||||
MatchedArg->clear();
|
||||
bool Dir=FileHead.Dir;
|
||||
if (ExclCheck(FileHead.FileName,Dir,false,true))
|
||||
return 0;
|
||||
@@ -287,23 +310,28 @@ int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchTy
|
||||
return 0;
|
||||
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
|
||||
return 0;
|
||||
if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
|
||||
FileHead.Dir && !InclDir))
|
||||
if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 &&
|
||||
(!FileHead.Dir || !InclDir))
|
||||
return 0;
|
||||
if (!Dir && SizeCheck(FileHead.UnpSize))
|
||||
return 0;
|
||||
#endif
|
||||
wchar *ArgName;
|
||||
std::wstring ArgName;
|
||||
FileArgs.Rewind();
|
||||
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
|
||||
for (int StringCount=1;FileArgs.GetString(ArgName);StringCount++)
|
||||
{
|
||||
// Ensure that both parameters of CmpName are either C++ strings or
|
||||
// pointers, so we avoid time consuming string construction for one of
|
||||
// parameters in this expensive loop.
|
||||
if (CmpName(ArgName,FileHead.FileName,MatchType))
|
||||
{
|
||||
if (ExactMatch!=NULL)
|
||||
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
|
||||
if (MatchedArg!=NULL)
|
||||
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
|
||||
*MatchedArg=ArgName;
|
||||
return StringCount;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ void CommandData::OutTitle()
|
||||
{
|
||||
if (BareOutput || DisableCopyright)
|
||||
return;
|
||||
#if defined(__GNUC__) && defined(SFX_MODULE)
|
||||
#ifdef SFX_MODULE
|
||||
mprintf(St(MCopyrightS));
|
||||
#else
|
||||
#ifndef SILENT
|
||||
@@ -61,26 +61,24 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
|
||||
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
|
||||
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDH,MCHelpSwEP,
|
||||
MCHelpSwEP3,MCHelpSwEP4,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
|
||||
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwME,MCHelpSwMLP,
|
||||
MCHelpSwN,MCHelpSwNa,MCHelpSwNal,MCHelpSwO,MCHelpSwOC,MCHelpSwOL,
|
||||
MCHelpSwOM,MCHelpSwOP,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,MCHelpSwR,
|
||||
MCHelpSwRI,MCHelpSwSC,MCHelpSwSI,MCHelpSwSL,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
|
||||
MCHelpSwEP2,MCHelpSwMLP,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
|
||||
};
|
||||
bool Found=false;
|
||||
for (uint J=0;J<ASIZE(Win32Only);J++)
|
||||
@@ -92,11 +90,18 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
|
||||
if (Found)
|
||||
continue;
|
||||
#endif
|
||||
#ifdef _UNIX
|
||||
if (CmpMSGID(Help[I],MRARTitle2))
|
||||
{
|
||||
mprintf(St(MFwrSlTitle2));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#if !defined(_UNIX) && !defined(_WIN_ALL)
|
||||
if (CmpMSGID(Help[I],MCHelpSwOW))
|
||||
continue;
|
||||
#endif
|
||||
#if !defined(_WIN_ALL) && !defined(_EMX)
|
||||
#ifndef _WIN_ALL
|
||||
if (CmpMSGID(Help[I],MCHelpSwAC))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
|
||||
inline unsigned int RangeCoder::GetChar()
|
||||
inline byte RangeCoder::GetChar()
|
||||
{
|
||||
return(UnpackRead->GetChar());
|
||||
return UnpackRead->GetChar();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ void RangeCoder::InitDecoder(Unpack *UnpackRead)
|
||||
RangeCoder::UnpackRead=UnpackRead;
|
||||
|
||||
low=code=0;
|
||||
range=uint(-1);
|
||||
for (int i=0;i < 4;i++)
|
||||
range=0xffffffff;
|
||||
for (uint i = 0; i < 4; i++)
|
||||
code=(code << 8) | GetChar();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class RangeCoder
|
||||
inline uint GetCurrentShiftCount(uint SHIFT);
|
||||
inline void Decode();
|
||||
inline void PutChar(unsigned int c);
|
||||
inline unsigned int GetChar();
|
||||
inline byte GetChar();
|
||||
|
||||
uint low, code, range;
|
||||
struct SUBRANGE
|
||||
|
||||
@@ -17,13 +17,16 @@ class PackDef
|
||||
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3;
|
||||
|
||||
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
|
||||
static const uint MAX3_INC_LZ_MATCH = MAX3_LZ_MATCH + 3;
|
||||
static const uint LOW_DIST_REP_COUNT = 16;
|
||||
|
||||
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
static const uint DC = 64;
|
||||
static const uint DCB = 64; // Base distance codes up to 4 GB.
|
||||
static const uint DCX = 80; // Extended distance codes up to 1 TB.
|
||||
static const uint LDC = 16;
|
||||
static const uint RC = 44;
|
||||
static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC;
|
||||
static const uint HUFF_TABLE_SIZEB = NC + DCB + RC + LDC;
|
||||
static const uint HUFF_TABLE_SIZEX = NC + DCX + RC + LDC;
|
||||
static const uint BC = 20;
|
||||
|
||||
static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
@@ -42,10 +45,6 @@ class PackDef
|
||||
// Largest alphabet size among all values listed above.
|
||||
static const uint LARGEST_TABLE_SIZE = 306;
|
||||
|
||||
enum {
|
||||
CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE,
|
||||
CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -53,7 +52,10 @@ enum FilterType {
|
||||
// These values must not be changed, because we use them directly
|
||||
// in RAR5 compression and decompression code.
|
||||
FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM,
|
||||
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE
|
||||
FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_TEXT,
|
||||
|
||||
// These values can be changed.
|
||||
FILTER_LONGRANGE,FILTER_EXHAUSTIVE,FILTER_NONE
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
231
unrar/consio.cpp
231
unrar/consio.cpp
@@ -3,8 +3,8 @@
|
||||
|
||||
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
|
||||
static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
|
||||
|
||||
const int MaxMsgSize=2*NM+2048;
|
||||
static bool ProhibitInput=false;
|
||||
static bool ConsoleOutputPresent=false;
|
||||
|
||||
static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
|
||||
|
||||
@@ -61,47 +61,53 @@ void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
|
||||
}
|
||||
|
||||
|
||||
void ProhibitConsoleInput()
|
||||
{
|
||||
ProhibitInput=true;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
|
||||
{
|
||||
// This buffer is for format string only, not for entire output,
|
||||
// so it can be short enough.
|
||||
wchar fmtw[1024];
|
||||
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
|
||||
ConsoleOutputPresent=true;
|
||||
|
||||
// No need for PrintfPrepareFmt here, vwstrprintf calls it.
|
||||
std::wstring s=vwstrprintf(fmt,arglist);
|
||||
|
||||
ReplaceEsc(s);
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
safebuf wchar Msg[MaxMsgSize];
|
||||
if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
|
||||
{
|
||||
HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
|
||||
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
|
||||
DWORD Written;
|
||||
if (RedirectCharset==RCH_UNICODE)
|
||||
WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL);
|
||||
WriteFile(hOut,s.data(),(DWORD)s.size()*sizeof(s[0]),&Written,NULL);
|
||||
else
|
||||
{
|
||||
// Avoid Unicode for redirect in Windows, it does not work with pipes.
|
||||
safebuf char MsgA[MaxMsgSize];
|
||||
std::string MsgA;
|
||||
if (RedirectCharset==RCH_UTF8)
|
||||
WideToUtf(Msg,MsgA,ASIZE(MsgA));
|
||||
WideToUtf(s,MsgA);
|
||||
else
|
||||
WideToChar(Msg,MsgA,ASIZE(MsgA));
|
||||
WideToChar(s,MsgA);
|
||||
if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
|
||||
CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
|
||||
CharToOemA(&MsgA[0],&MsgA[0]); // Console tools like 'more' expect OEM encoding.
|
||||
|
||||
// We already converted \n to \r\n above, so we use WriteFile instead
|
||||
// of C library to avoid unnecessary additional conversion.
|
||||
WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
|
||||
WriteFile(hOut,MsgA.data(),(DWORD)MsgA.size(),&Written,NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// MSVC2008 vfwprintf writes every character to console separately
|
||||
// and it is too slow. We use direct WriteConsole call instead.
|
||||
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
|
||||
HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
|
||||
DWORD Written;
|
||||
WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
|
||||
WriteConsole(hOut,s.data(),(DWORD)s.size(),&Written,NULL);
|
||||
#else
|
||||
vfwprintf(dest,fmtw,arglist);
|
||||
fputws(s.c_str(),dest);
|
||||
// We do not use setbuf(NULL) in Unix (see comments in InitConsole).
|
||||
fflush(dest);
|
||||
#endif
|
||||
@@ -141,81 +147,109 @@ void eprintf(const wchar *fmt,...)
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
static void GetPasswordText(wchar *Str,uint MaxLength)
|
||||
static void QuitIfInputProhibited()
|
||||
{
|
||||
if (MaxLength==0)
|
||||
return;
|
||||
// We cannot handle user prompts if -si is used to read file or archive data
|
||||
// from stdin.
|
||||
if (ProhibitInput)
|
||||
{
|
||||
mprintf(St(MStdinNoInput));
|
||||
ErrHandler.Exit(RARX_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void GetPasswordText(std::wstring &Str)
|
||||
{
|
||||
QuitIfInputProhibited();
|
||||
if (StdinRedirected)
|
||||
getwstr(Str,MaxLength); // Read from pipe or redirected file.
|
||||
getwstr(Str); // Read from pipe or redirected file.
|
||||
else
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD ConInMode,ConOutMode;
|
||||
DWORD Read=0;
|
||||
DWORD ConInMode;
|
||||
GetConsoleMode(hConIn,&ConInMode);
|
||||
GetConsoleMode(hConOut,&ConOutMode);
|
||||
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
|
||||
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||
SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT.
|
||||
|
||||
std::vector<wchar> Buf(MAXPASSWORD);
|
||||
|
||||
// We prefer ReadConsole to ReadFile, so we can read Unicode input.
|
||||
DWORD Read=0;
|
||||
ReadConsole(hConIn,Buf.data(),(DWORD)Buf.size()-1,&Read,NULL);
|
||||
Buf[Read]=0;
|
||||
Str=Buf.data();
|
||||
cleandata(Buf.data(),Buf.size()*sizeof(Buf[0]));
|
||||
|
||||
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
|
||||
Str[Read]=0;
|
||||
SetConsoleMode(hConIn,ConInMode);
|
||||
SetConsoleMode(hConOut,ConOutMode);
|
||||
|
||||
// 2023.03.12: Previously we checked for presence of "\n" in entered
|
||||
// passwords, supposing that truncated strings do not include it.
|
||||
// We did it to read the rest of excessively long string, so it is not
|
||||
// read later as the second password for -p switch. But this "\n" check
|
||||
// doesn't seem to work in Windows 10 anymore and "\r" is present even
|
||||
// in truncated strings. Also we increased MAXPASSWORD, so it is larger
|
||||
// than MAXPASSWORD_RAR. Thus we removed this check as not working
|
||||
// and not that necessary. Low level FlushConsoleInputBuffer doesn't help
|
||||
// for high level ReadConsole, which in line input mode seems to store
|
||||
// the rest of string in its own internal buffer.
|
||||
#else
|
||||
char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
|
||||
#if defined(_EMX) || defined (__VMS)
|
||||
fgets(StrA,ASIZE(StrA)-1,stdin);
|
||||
std::vector<char> StrA(MAXPASSWORD*4); // "*4" for multibyte UTF-8 characters.
|
||||
#ifdef __VMS
|
||||
fgets(StrA.data(),StrA.size()-1,stdin);
|
||||
#elif defined(__sun)
|
||||
strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
|
||||
strncpyz(StrA.data(),getpassphrase(""),StrA.size());
|
||||
#else
|
||||
strncpyz(StrA,getpass(""),ASIZE(StrA));
|
||||
strncpyz(StrA.data(),getpass(""),StrA.size());
|
||||
#endif
|
||||
CharToWide(StrA,Str,MaxLength);
|
||||
cleandata(StrA,sizeof(StrA));
|
||||
CharToWide(StrA.data(),Str);
|
||||
cleandata(StrA.data(),StrA.size()*sizeof(StrA[0]));
|
||||
#endif
|
||||
}
|
||||
Str[MaxLength-1]=0;
|
||||
RemoveLF(Str);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const std::wstring &FileName,SecPassword *Password)
|
||||
{
|
||||
if (!StdinRedirected)
|
||||
uiAlarm(UIALARM_QUESTION);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!StdinRedirected)
|
||||
// if (!StdinRedirected)
|
||||
if (Type==UIPASSWORD_GLOBAL)
|
||||
eprintf(L"\n%s: ",St(MAskPsw));
|
||||
else
|
||||
eprintf(St(MAskPswFor),FileName);
|
||||
eprintf(St(MAskPswFor),FileName.c_str());
|
||||
|
||||
wchar PlainPsw[MAXPASSWORD];
|
||||
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
|
||||
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
|
||||
std::wstring PlainPsw;
|
||||
GetPasswordText(PlainPsw);
|
||||
if (PlainPsw.empty() && Type==UIPASSWORD_GLOBAL)
|
||||
return false;
|
||||
if (PlainPsw.size()>=MAXPASSWORD)
|
||||
{
|
||||
PlainPsw.erase(MAXPASSWORD-1);
|
||||
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
|
||||
}
|
||||
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
|
||||
{
|
||||
eprintf(St(MReAskPsw));
|
||||
wchar CmpStr[MAXPASSWORD];
|
||||
GetPasswordText(CmpStr,ASIZE(CmpStr));
|
||||
if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
|
||||
std::wstring CmpStr;
|
||||
GetPasswordText(CmpStr);
|
||||
if (CmpStr.empty() || PlainPsw!=CmpStr)
|
||||
{
|
||||
eprintf(St(MNotMatchPsw));
|
||||
cleandata(PlainPsw,sizeof(PlainPsw));
|
||||
cleandata(CmpStr,sizeof(CmpStr));
|
||||
cleandata(&PlainPsw[0],PlainPsw.size()*sizeof(PlainPsw[0]));
|
||||
cleandata(&CmpStr[0],CmpStr.size()*sizeof(CmpStr[0]));
|
||||
continue;
|
||||
}
|
||||
cleandata(CmpStr,sizeof(CmpStr));
|
||||
cleandata(&CmpStr[0],CmpStr.size()*sizeof(CmpStr[0]));
|
||||
}
|
||||
Password->Set(PlainPsw);
|
||||
cleandata(PlainPsw,sizeof(PlainPsw));
|
||||
Password->Set(PlainPsw.c_str());
|
||||
cleandata(&PlainPsw[0],PlainPsw.size()*sizeof(PlainPsw[0]));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -224,12 +258,17 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
|
||||
|
||||
|
||||
#ifndef SILENT
|
||||
bool getwstr(wchar *str,size_t n)
|
||||
void getwstr(std::wstring &str)
|
||||
{
|
||||
// Print buffered prompt title function before waiting for input.
|
||||
fflush(stderr);
|
||||
|
||||
*str=0;
|
||||
QuitIfInputProhibited();
|
||||
|
||||
str.clear();
|
||||
|
||||
const size_t MaxRead=MAXPATHSIZE; // Large enough to read a file name.
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
// fgetws does not work well with non-English text in Windows,
|
||||
// so we do not use it.
|
||||
@@ -237,15 +276,16 @@ bool getwstr(wchar *str,size_t n)
|
||||
{
|
||||
// fgets does not work well with pipes in Windows in our test.
|
||||
// Let's use files.
|
||||
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
|
||||
std::vector<char> StrA(MaxRead*4); // Up to 4 UTF-8 characters per wchar_t.
|
||||
File SrcFile;
|
||||
SrcFile.SetHandleType(FILE_HANDLESTD);
|
||||
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
|
||||
SrcFile.SetLineInputMode(true);
|
||||
int ReadSize=SrcFile.Read(&StrA[0],StrA.size()-1);
|
||||
if (ReadSize<=0)
|
||||
{
|
||||
// Looks like stdin is a null device. We can enter to infinite loop
|
||||
// calling Ask(), so let's better exit.
|
||||
ErrHandler.Exit(RARX_USERBREAK);
|
||||
// calling Ask() or set an empty password, so let's better exit.
|
||||
ErrHandler.ReadError(L"stdin");
|
||||
}
|
||||
StrA[ReadSize]=0;
|
||||
|
||||
@@ -254,22 +294,32 @@ bool getwstr(wchar *str,size_t n)
|
||||
// use "chcp" in console. But we avoid OEM to ANSI conversion,
|
||||
// because we also want to handle ANSI files redirection correctly,
|
||||
// like "rar ... < ansifile.txt".
|
||||
CharToWide(&StrA[0],str,n);
|
||||
cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
|
||||
CharToWide(&StrA[0],str);
|
||||
cleandata(&StrA[0],StrA.size()); // We can use this function to enter passwords.
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<wchar> Buf(MaxRead); // Up to 4 UTF-8 characters per wchar_t.
|
||||
DWORD SizeToRead=(DWORD)Buf.size()-1;
|
||||
|
||||
// ReadConsole fails in Windows 7 for requested input exceeding 30 KB.
|
||||
// Not certain about Windows 8, so check for Windows 10 here.
|
||||
if (WinNT()<=WNT_W10)
|
||||
SizeToRead=Min(SizeToRead,0x4000);
|
||||
|
||||
DWORD ReadSize=0;
|
||||
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
|
||||
return false;
|
||||
str[ReadSize]=0;
|
||||
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&Buf[0],SizeToRead,&ReadSize,NULL)==0)
|
||||
ErrHandler.ReadError(L"stdin"); // Unknown user input, safer to abort.
|
||||
Buf[ReadSize]=0;
|
||||
str=Buf.data();
|
||||
}
|
||||
#else
|
||||
if (fgetws(str,n,stdin)==NULL)
|
||||
ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
|
||||
std::vector<wchar> Buf(MaxRead); // Up to 4 UTF-8 characters per wchar_t.
|
||||
if (fgetws(&Buf[0],Buf.size(),stdin)==NULL)
|
||||
ErrHandler.ReadError(L"stdin"); // Avoid infinite Ask() loop.
|
||||
str=Buf.data();
|
||||
#endif
|
||||
RemoveLF(str);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -283,22 +333,22 @@ int Ask(const wchar *AskStr)
|
||||
{
|
||||
uiAlarm(UIALARM_QUESTION);
|
||||
|
||||
const int MaxItems=10;
|
||||
const uint MaxItems=10;
|
||||
wchar Item[MaxItems][40];
|
||||
int ItemKeyPos[MaxItems],NumItems=0;
|
||||
uint ItemKeyPos[MaxItems],NumItems=0;
|
||||
|
||||
for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
|
||||
for (const wchar *NextItem=AskStr;NextItem!=nullptr;NextItem=wcschr(NextItem+1,'_'))
|
||||
{
|
||||
wchar *CurItem=Item[NumItems];
|
||||
wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
|
||||
wchar *EndItem=wcschr(CurItem,'_');
|
||||
if (EndItem!=NULL)
|
||||
if (EndItem!=nullptr)
|
||||
*EndItem=0;
|
||||
int KeyPos=0,CurKey;
|
||||
uint KeyPos=0,CurKey;
|
||||
while ((CurKey=CurItem[KeyPos])!=0)
|
||||
{
|
||||
bool Found=false;
|
||||
for (int I=0;I<NumItems && !Found;I++)
|
||||
for (uint I=0;I<NumItems && !Found;I++)
|
||||
if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
|
||||
Found=true;
|
||||
if (!Found && CurKey!=' ')
|
||||
@@ -309,19 +359,19 @@ int Ask(const wchar *AskStr)
|
||||
NumItems++;
|
||||
}
|
||||
|
||||
for (int I=0;I<NumItems;I++)
|
||||
for (uint I=0;I<NumItems;I++)
|
||||
{
|
||||
eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
|
||||
int KeyPos=ItemKeyPos[I];
|
||||
for (int J=0;J<KeyPos;J++)
|
||||
uint KeyPos=ItemKeyPos[I];
|
||||
for (uint J=0;J<KeyPos;J++)
|
||||
eprintf(L"%c",Item[I][J]);
|
||||
eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
|
||||
}
|
||||
eprintf(L" ");
|
||||
wchar Str[50];
|
||||
getwstr(Str,ASIZE(Str));
|
||||
std::wstring Str;
|
||||
getwstr(Str);
|
||||
wchar Ch=toupperw(Str[0]);
|
||||
for (int I=0;I<NumItems;I++)
|
||||
for (uint I=0;I<NumItems;I++)
|
||||
if (Ch==Item[I][ItemKeyPos[I]])
|
||||
return I+1;
|
||||
return 0;
|
||||
@@ -329,11 +379,11 @@ int Ask(const wchar *AskStr)
|
||||
#endif
|
||||
|
||||
|
||||
static bool IsCommentUnsafe(const wchar *Data,size_t Size)
|
||||
static bool IsCommentUnsafe(const std::wstring &Data)
|
||||
{
|
||||
for (size_t I=0;I<Size;I++)
|
||||
for (size_t I=0;I<Data.size();I++)
|
||||
if (Data[I]==27 && Data[I+1]=='[')
|
||||
for (size_t J=I+2;J<Size;J++)
|
||||
for (size_t J=I+2;J<Data.size();J++)
|
||||
{
|
||||
// Return true for <ESC>[{key};"{string}"p used to redefine
|
||||
// a keyboard key on some terminals.
|
||||
@@ -346,18 +396,21 @@ static bool IsCommentUnsafe(const wchar *Data,size_t Size)
|
||||
}
|
||||
|
||||
|
||||
void OutComment(const wchar *Comment,size_t Size)
|
||||
void OutComment(const std::wstring &Comment)
|
||||
{
|
||||
if (IsCommentUnsafe(Comment,Size))
|
||||
if (IsCommentUnsafe(Comment))
|
||||
return;
|
||||
const size_t MaxOutSize=0x400;
|
||||
for (size_t I=0;I<Size;I+=MaxOutSize)
|
||||
for (size_t I=0;I<Comment.size();I+=MaxOutSize)
|
||||
{
|
||||
wchar Msg[MaxOutSize+1];
|
||||
size_t CopySize=Min(MaxOutSize,Size-I);
|
||||
wcsncpy(Msg,Comment+I,CopySize);
|
||||
Msg[CopySize]=0;
|
||||
mprintf(L"%s",Msg);
|
||||
size_t CopySize=Min(MaxOutSize,Comment.size()-I);
|
||||
mprintf(L"%s",Comment.substr(I,CopySize).c_str());
|
||||
}
|
||||
mprintf(L"\n");
|
||||
}
|
||||
|
||||
|
||||
bool IsConsoleOutputPresent()
|
||||
{
|
||||
return ConsoleOutputPresent;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
void InitConsole();
|
||||
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
|
||||
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
|
||||
void OutComment(const wchar *Comment,size_t Size);
|
||||
void ProhibitConsoleInput();
|
||||
void OutComment(const std::wstring &Comment);
|
||||
bool IsConsoleOutputPresent();
|
||||
|
||||
#ifndef SILENT
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
|
||||
bool GetConsolePassword(UIPASSWORD_TYPE Type,const std::wstring &FileName,SecPassword *Password);
|
||||
#endif
|
||||
|
||||
#ifdef SILENT
|
||||
@@ -15,13 +17,13 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
|
||||
inline void eprintf(const wchar *fmt,...) {}
|
||||
inline void Alarm() {}
|
||||
inline int Ask(const wchar *AskStr) {return 0;}
|
||||
inline bool getwstr(wchar *str,size_t n) {return false;}
|
||||
inline void getwstr(std::wstring &str) {}
|
||||
#else
|
||||
void mprintf(const wchar *fmt,...);
|
||||
void eprintf(const wchar *fmt,...);
|
||||
void Alarm();
|
||||
int Ask(const wchar *AskStr);
|
||||
bool getwstr(wchar *str,size_t n);
|
||||
void getwstr(std::wstring &str);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
210
unrar/crc.cpp
210
unrar/crc.cpp
@@ -14,7 +14,17 @@
|
||||
|
||||
#include "rar.hpp"
|
||||
|
||||
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
|
||||
#ifndef SFX_MODULE
|
||||
// User suggested to avoid BSD license in SFX module, so they do not need
|
||||
// to include the license to SFX archive.
|
||||
#define USE_SLICING
|
||||
#endif
|
||||
|
||||
static uint crc_tables[16][256]; // Tables for Slicing-by-16.
|
||||
|
||||
#ifdef USE_NEON_CRC32
|
||||
static bool CRC_Neon;
|
||||
#endif
|
||||
|
||||
|
||||
// Build the classic CRC32 lookup table.
|
||||
@@ -30,6 +40,19 @@ void InitCRC32(uint *CRCTab)
|
||||
C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
|
||||
CRCTab[I]=C;
|
||||
}
|
||||
|
||||
#ifdef USE_NEON_CRC32
|
||||
#ifdef _APPLE
|
||||
// getauxval isn't available in OS X
|
||||
uint Value=0;
|
||||
size_t Size=sizeof(Value);
|
||||
int RetCode=sysctlbyname("hw.optional.armv8_crc32",&Value,&Size,NULL,0);
|
||||
CRC_Neon=RetCode==0 && Value!=0;
|
||||
#else
|
||||
CRC_Neon=(getauxval(AT_HWCAP) & HWCAP_CRC32)!=0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -37,15 +60,17 @@ static void InitTables()
|
||||
{
|
||||
InitCRC32(crc_tables[0]);
|
||||
|
||||
#ifdef USE_SLICING
|
||||
for (uint I=0;I<256;I++) // Build additional lookup tables.
|
||||
{
|
||||
uint C=crc_tables[0][I];
|
||||
for (uint J=1;J<8;J++)
|
||||
for (uint J=1;J<16;J++)
|
||||
{
|
||||
C=crc_tables[0][(byte)C]^(C>>8);
|
||||
crc_tables[J][I]=C;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -55,28 +80,68 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
|
||||
{
|
||||
byte *Data=(byte *)Addr;
|
||||
|
||||
// Align Data to 8 for better performance.
|
||||
for (;Size>0 && ((size_t)Data & 7);Size--,Data++)
|
||||
#ifdef USE_NEON_CRC32
|
||||
if (CRC_Neon)
|
||||
{
|
||||
for (;Size>=8;Size-=8,Data+=8)
|
||||
#ifdef __clang__
|
||||
StartCRC = __builtin_arm_crc32d(StartCRC, RawGet8(Data));
|
||||
#else
|
||||
StartCRC = __builtin_aarch64_crc32x(StartCRC, RawGet8(Data));
|
||||
#endif
|
||||
for (;Size>0;Size--,Data++) // Process left data.
|
||||
#ifdef __clang__
|
||||
StartCRC = __builtin_arm_crc32b(StartCRC, *Data);
|
||||
#else
|
||||
StartCRC = __builtin_aarch64_crc32b(StartCRC, *Data);
|
||||
#endif
|
||||
return StartCRC;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SLICING
|
||||
// Align Data to 16 for better performance and to avoid ALLOW_MISALIGNED
|
||||
// check below.
|
||||
for (;Size>0 && ((size_t)Data & 15)!=0;Size--,Data++)
|
||||
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
|
||||
for (;Size>=8;Size-=8,Data+=8)
|
||||
// 2023.12.06: We switched to slicing-by-16, which seems to be faster than
|
||||
// slicing-by-8 on modern CPUs. Slicing-by-32 would require 32 KB for tables
|
||||
// and could be limited by L1 cache size on some CPUs.
|
||||
for (;Size>=16;Size-=16,Data+=16)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24);
|
||||
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
|
||||
StartCRC ^= RawGet4(Data);
|
||||
uint D1 = RawGet4(Data+4);
|
||||
uint D2 = RawGet4(Data+8);
|
||||
uint D3 = RawGet4(Data+12);
|
||||
#else
|
||||
// We avoid RawGet4 here for performance reason, to access uint32
|
||||
// directly even if ALLOW_MISALIGNED isn't defined. We can do it,
|
||||
// because we aligned 'Data' above.
|
||||
StartCRC ^= *(uint32 *) Data;
|
||||
uint NextData = *(uint32 *) (Data+4);
|
||||
uint D1 = *(uint32 *) (Data+4);
|
||||
uint D2 = *(uint32 *) (Data+8);
|
||||
uint D3 = *(uint32 *) (Data+12);
|
||||
#endif
|
||||
StartCRC = crc_tables[7][(byte) StartCRC ] ^
|
||||
crc_tables[6][(byte)(StartCRC >> 8) ] ^
|
||||
crc_tables[5][(byte)(StartCRC >> 16)] ^
|
||||
crc_tables[4][(byte)(StartCRC >> 24)] ^
|
||||
crc_tables[3][(byte) NextData ] ^
|
||||
crc_tables[2][(byte)(NextData >> 8) ] ^
|
||||
crc_tables[1][(byte)(NextData >> 16)] ^
|
||||
crc_tables[0][(byte)(NextData >> 24)];
|
||||
StartCRC = crc_tables[15][(byte) StartCRC ] ^
|
||||
crc_tables[14][(byte)(StartCRC >> 8) ] ^
|
||||
crc_tables[13][(byte)(StartCRC >> 16)] ^
|
||||
crc_tables[12][(byte)(StartCRC >> 24)] ^
|
||||
crc_tables[11][(byte) D1 ] ^
|
||||
crc_tables[10][(byte)(D1 >> 8) ] ^
|
||||
crc_tables[ 9][(byte)(D1 >> 16)] ^
|
||||
crc_tables[ 8][(byte)(D1 >> 24)] ^
|
||||
crc_tables[ 7][(byte) D2 ] ^
|
||||
crc_tables[ 6][(byte)(D2 >> 8)] ^
|
||||
crc_tables[ 5][(byte)(D2 >> 16)] ^
|
||||
crc_tables[ 4][(byte)(D2 >> 24)] ^
|
||||
crc_tables[ 3][(byte) D3 ] ^
|
||||
crc_tables[ 2][(byte)(D3 >> 8)] ^
|
||||
crc_tables[ 1][(byte)(D3 >> 16)] ^
|
||||
crc_tables[ 0][(byte)(D3 >> 24)];
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;Size>0;Size--,Data++) // Process left data.
|
||||
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
|
||||
@@ -100,3 +165,116 @@ ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
static void TestCRC();
|
||||
struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC;
|
||||
|
||||
void TestCRC()
|
||||
{
|
||||
// This function is invoked from global object and _SSE_Version is global
|
||||
// and can be initialized after this function. So we explicitly initialize
|
||||
// it here to enable SSE support in Blake2sp.
|
||||
_SSE_Version=GetSSEVersion();
|
||||
|
||||
const uint FirstSize=300;
|
||||
byte b[FirstSize];
|
||||
|
||||
if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84)
|
||||
mprintf(L"\nCRC32 test1 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test1 FAILED");
|
||||
|
||||
if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE)
|
||||
mprintf(L"\nCRC32 test2 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test2 FAILED");
|
||||
|
||||
for (uint I=0;I<14;I++) // Check for possible int sign extension.
|
||||
b[I]=(byte)0x7f+I;
|
||||
if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA)
|
||||
mprintf(L"\nCRC32 test3 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test3 FAILED");
|
||||
|
||||
for (uint I=0;I<FirstSize;I++)
|
||||
b[I]=(byte)I;
|
||||
uint r32=CRC32(0xffffffff,b,FirstSize);
|
||||
for (uint I=FirstSize;I<1024;I++)
|
||||
{
|
||||
b[0]=(byte)I;
|
||||
r32=CRC32(r32,b,1);
|
||||
}
|
||||
if ((r32^0xffffffff)==0xB70B4C26)
|
||||
mprintf(L"\nCRC32 test4 OK");
|
||||
else
|
||||
mprintf(L"\nCRC32 test4 FAILED");
|
||||
|
||||
if ((CRC64(0xffffffffffffffff,(byte*)"testtesttest",12)^0xffffffffffffffff)==0x7B1C2D230EDEB436)
|
||||
mprintf(L"\nCRC64 test1 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test1 FAILED");
|
||||
|
||||
if (CRC64(0,(byte*)"te\x80st",5)==0xB5DBF9583A6EED4A)
|
||||
mprintf(L"\nCRC64 test2 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test2 FAILED");
|
||||
|
||||
for (uint I=0;I<14;I++) // Check for possible int sign extension.
|
||||
b[I]=(byte)0x7f+I;
|
||||
if ((CRC64(0xffffffffffffffff,b,14)^0xffffffffffffffff)==0xE019941C05B2820C)
|
||||
mprintf(L"\nCRC64 test3 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test3 FAILED");
|
||||
|
||||
for (uint I=0;I<FirstSize;I++)
|
||||
b[I]=(byte)I;
|
||||
uint64 r64=CRC64(0xffffffffffffffff,b,FirstSize);
|
||||
for (uint I=FirstSize;I<1024;I++)
|
||||
{
|
||||
b[0]=(byte)I;
|
||||
r64=CRC64(r64,b,1);
|
||||
}
|
||||
if ((r64^0xffffffffffffffff)==0xD51FB58DC789C400)
|
||||
mprintf(L"\nCRC64 test4 OK");
|
||||
else
|
||||
mprintf(L"\nCRC64 test4 FAILED");
|
||||
|
||||
const size_t BufSize=0x100000;
|
||||
byte *Buf=new byte[BufSize];
|
||||
GetRnd(Buf,BufSize);
|
||||
|
||||
clock_t StartTime=clock();
|
||||
r32=0xffffffff;
|
||||
const uint64 BufCount=5000;
|
||||
for (uint I=0;I<BufCount;I++)
|
||||
r32=CRC32(r32,Buf,BufSize);
|
||||
if (r32!=0) // Otherwise compiler optimizer removes CRC calculation.
|
||||
mprintf(L"\nCRC32 speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
|
||||
StartTime=clock();
|
||||
DataHash Hash;
|
||||
Hash.Init(HASH_CRC32,MaxPoolThreads);
|
||||
const uint64 BufCountMT=20000;
|
||||
for (uint I=0;I<BufCountMT;I++)
|
||||
Hash.Update(Buf,BufSize);
|
||||
HashValue Result;
|
||||
Hash.Result(&Result);
|
||||
mprintf(L"\nCRC32 MT speed: %llu MB/s",BufCountMT*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
|
||||
StartTime=clock();
|
||||
Hash.Init(HASH_BLAKE2,MaxPoolThreads);
|
||||
for (uint I=0;I<BufCount;I++)
|
||||
Hash.Update(Buf,BufSize);
|
||||
Hash.Result(&Result);
|
||||
mprintf(L"\nBlake2sp speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
|
||||
StartTime=clock();
|
||||
r64=0xffffffffffffffff;
|
||||
for (uint I=0;I<BufCount;I++)
|
||||
r64=CRC64(r64,Buf,BufSize);
|
||||
if (r64!=0) // Otherwise compiler optimizer removes CRC calculation.
|
||||
mprintf(L"\nCRC64 speed: %llu MB/s",BufCount*CLOCKS_PER_SEC/(clock()-StartTime));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11,21 +11,12 @@
|
||||
CryptData::CryptData()
|
||||
{
|
||||
Method=CRYPT_NONE;
|
||||
memset(KDF3Cache,0,sizeof(KDF3Cache));
|
||||
memset(KDF5Cache,0,sizeof(KDF5Cache));
|
||||
KDF3CachePos=0;
|
||||
KDF5CachePos=0;
|
||||
memset(CRCTab,0,sizeof(CRCTab));
|
||||
}
|
||||
|
||||
|
||||
CryptData::~CryptData()
|
||||
{
|
||||
cleandata(KDF3Cache,sizeof(KDF3Cache));
|
||||
cleandata(KDF5Cache,sizeof(KDF5Cache));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CryptData::DecryptBlock(byte *Buf,size_t Size)
|
||||
@@ -56,16 +47,28 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
|
||||
SecPassword *Password,const byte *Salt,
|
||||
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
|
||||
{
|
||||
if (!Password->IsSet() || Method==CRYPT_NONE)
|
||||
if (Method==CRYPT_NONE || !Password->IsSet())
|
||||
return false;
|
||||
|
||||
CryptData::Method=Method;
|
||||
|
||||
wchar PwdW[MAXPASSWORD];
|
||||
Password->Get(PwdW,ASIZE(PwdW));
|
||||
|
||||
// Display this warning only when encrypting. Users complained that
|
||||
// it is distracting when decrypting. It still can be useful when encrypting,
|
||||
// so users do not waste time to excessively long passwords.
|
||||
if (Encrypt && wcslen(PwdW)>=MAXPASSWORD_RAR)
|
||||
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD_RAR-1);
|
||||
|
||||
PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
|
||||
|
||||
char PwdA[MAXPASSWORD];
|
||||
WideToChar(PwdW,PwdA,ASIZE(PwdA));
|
||||
PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
|
||||
|
||||
bool Success=true;
|
||||
|
||||
switch(Method)
|
||||
{
|
||||
#ifndef SFX_MODULE
|
||||
@@ -83,12 +86,12 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
|
||||
SetKey30(Encrypt,Password,PwdW,Salt);
|
||||
break;
|
||||
case CRYPT_RAR50:
|
||||
SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
|
||||
Success=SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
|
||||
break;
|
||||
}
|
||||
cleandata(PwdA,sizeof(PwdA));
|
||||
cleandata(PwdW,sizeof(PwdW));
|
||||
return true;
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +120,7 @@ void GetRnd(byte *RndBuf,size_t BufSize)
|
||||
HCRYPTPROV hProvider = 0;
|
||||
if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
{
|
||||
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE;
|
||||
Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) != FALSE;
|
||||
CryptReleaseContext(hProvider, 0);
|
||||
}
|
||||
#elif defined(_UNIX)
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
|
||||
enum CRYPT_METHOD {
|
||||
CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50
|
||||
CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50,
|
||||
CRYPT_UNKNOWN
|
||||
};
|
||||
|
||||
#define SIZE_SALT50 16
|
||||
@@ -30,6 +31,18 @@ class CryptData
|
||||
uint Lg2Count; // Log2 of PBKDF2 repetition count.
|
||||
byte PswCheckValue[SHA256_DIGEST_SIZE];
|
||||
byte HashKeyValue[SHA256_DIGEST_SIZE];
|
||||
|
||||
KDF5CacheItem() {Clean();}
|
||||
~KDF5CacheItem() {Clean();}
|
||||
|
||||
void Clean()
|
||||
{
|
||||
cleandata(Salt,sizeof(Salt));
|
||||
cleandata(Key,sizeof(Key));
|
||||
cleandata(&Lg2Count,sizeof(Lg2Count));
|
||||
cleandata(PswCheckValue,sizeof(PswCheckValue));
|
||||
cleandata(HashKeyValue,sizeof(HashKeyValue));
|
||||
}
|
||||
};
|
||||
|
||||
struct KDF3CacheItem
|
||||
@@ -39,6 +52,17 @@ class CryptData
|
||||
byte Key[16];
|
||||
byte Init[16];
|
||||
bool SaltPresent;
|
||||
|
||||
KDF3CacheItem() {Clean();}
|
||||
~KDF3CacheItem() {Clean();}
|
||||
|
||||
void Clean()
|
||||
{
|
||||
cleandata(Salt,sizeof(Salt));
|
||||
cleandata(Key,sizeof(Key));
|
||||
cleandata(Init,sizeof(Init));
|
||||
cleandata(&SaltPresent,sizeof(SaltPresent));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +80,7 @@ class CryptData
|
||||
void DecryptBlock20(byte *Buf);
|
||||
|
||||
void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt);
|
||||
void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
|
||||
bool SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
|
||||
|
||||
KDF3CacheItem KDF3Cache[4];
|
||||
uint KDF3CachePos;
|
||||
@@ -77,17 +101,63 @@ class CryptData
|
||||
ushort Key15[4];
|
||||
public:
|
||||
CryptData();
|
||||
~CryptData();
|
||||
bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
|
||||
const byte *Salt,const byte *InitV,uint Lg2Cnt,
|
||||
byte *HashKey,byte *PswCheck);
|
||||
void SetAV15Encryption();
|
||||
void SetCmt13Encryption();
|
||||
void EncryptBlock(byte *Buf,size_t Size);
|
||||
void DecryptBlock(byte *Buf,size_t Size);
|
||||
static void SetSalt(byte *Salt,size_t SaltSize);
|
||||
};
|
||||
|
||||
|
||||
class CheckPassword
|
||||
{
|
||||
public:
|
||||
enum CONFIDENCE {CONFIDENCE_HIGH,CONFIDENCE_MEDIUM,CONFIDENCE_LOW};
|
||||
virtual CONFIDENCE GetConfidence()=0;
|
||||
virtual bool Check(SecPassword *Password)=0;
|
||||
};
|
||||
|
||||
class RarCheckPassword:public CheckPassword
|
||||
{
|
||||
private:
|
||||
CryptData *Crypt;
|
||||
uint Lg2Count;
|
||||
byte Salt[SIZE_SALT50];
|
||||
byte InitV[SIZE_INITV];
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
public:
|
||||
RarCheckPassword()
|
||||
{
|
||||
Crypt=NULL;
|
||||
}
|
||||
~RarCheckPassword()
|
||||
{
|
||||
delete Crypt;
|
||||
}
|
||||
void Set(byte *Salt,byte *InitV,uint Lg2Count,byte *PswCheck)
|
||||
{
|
||||
if (Crypt==NULL)
|
||||
Crypt=new CryptData;
|
||||
memcpy(this->Salt,Salt,sizeof(this->Salt));
|
||||
memcpy(this->InitV,InitV,sizeof(this->InitV));
|
||||
this->Lg2Count=Lg2Count;
|
||||
memcpy(this->PswCheck,PswCheck,sizeof(this->PswCheck));
|
||||
}
|
||||
bool IsSet() {return Crypt!=NULL;}
|
||||
|
||||
// RAR5 provides the higly reliable 64 bit password verification value.
|
||||
CONFIDENCE GetConfidence() {return CONFIDENCE_HIGH;}
|
||||
|
||||
bool Check(SecPassword *Password)
|
||||
{
|
||||
byte PswCheck[SIZE_PSWCHECK];
|
||||
Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck);
|
||||
return memcmp(PswCheck,this->PswCheck,sizeof(this->PswCheck))==0;
|
||||
}
|
||||
};
|
||||
|
||||
void GetRnd(byte *RndBuf,size_t BufSize);
|
||||
|
||||
void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
extern uint CRCTab[256];
|
||||
|
||||
void CryptData::SetKey13(const char *Password)
|
||||
{
|
||||
Key13[0]=Key13[1]=Key13[2]=0;
|
||||
@@ -25,22 +23,11 @@ void CryptData::SetKey15(const char *Password)
|
||||
{
|
||||
byte P=Password[I];
|
||||
Key15[2]^=P^CRCTab[P];
|
||||
Key15[3]+=P+(CRCTab[P]>>16);
|
||||
Key15[3]+=ushort(P+(CRCTab[P]>>16));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CryptData::SetAV15Encryption()
|
||||
{
|
||||
InitCRC32(CRCTab);
|
||||
Method=CRYPT_RAR15;
|
||||
Key15[0]=0x4765;
|
||||
Key15[1]=0x9021;
|
||||
Key15[2]=0x7382;
|
||||
Key15[3]=0x5215;
|
||||
}
|
||||
|
||||
|
||||
void CryptData::SetCmt13Encryption()
|
||||
{
|
||||
Method=CRYPT_RAR13;
|
||||
@@ -68,7 +55,7 @@ void CryptData::Crypt15(byte *Data,size_t Count)
|
||||
{
|
||||
Key15[0]+=0x1234;
|
||||
Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1];
|
||||
Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16;
|
||||
Key15[2]-=ushort(CRCTab[(Key15[0] & 0x1fe)>>1]>>16);
|
||||
Key15[0]^=Key15[2];
|
||||
Key15[3]=rotrs(Key15[3]&0xffff,1,16)^Key15[1];
|
||||
Key15[3]=rotrs(Key15[3]&0xffff,1,16);
|
||||
|
||||
@@ -18,8 +18,9 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
|
||||
if (!Cached)
|
||||
{
|
||||
byte RawPsw[2*MAXPASSWORD+SIZE_SALT30];
|
||||
WideToRaw(PwdW,RawPsw,ASIZE(RawPsw));
|
||||
size_t RawLength=2*wcslen(PwdW);
|
||||
size_t PswLength=wcslen(PwdW);
|
||||
size_t RawLength=2*PswLength;
|
||||
WideToRaw(PwdW,PswLength,RawPsw,RawLength);
|
||||
if (Salt!=NULL)
|
||||
{
|
||||
memcpy(RawPsw+RawLength,Salt,SIZE_SALT30);
|
||||
|
||||
@@ -21,7 +21,7 @@ static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
|
||||
sha256_context ICtx;
|
||||
|
||||
if (ICtxOpt!=NULL && *SetIOpt)
|
||||
ICtx=*ICtxOpt; // Use already calculated first block context.
|
||||
ICtx=*ICtxOpt; // Use already calculated the first block context.
|
||||
else
|
||||
{
|
||||
// This calculation is the same for all iterations with same password.
|
||||
@@ -90,10 +90,10 @@ void pbkdf2(const byte *Pwd, size_t PwdLength,
|
||||
byte SaltData[MaxSalt+4];
|
||||
memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
|
||||
|
||||
SaltData[SaltLength + 0] = 0; // Salt concatenated to 1.
|
||||
SaltData[SaltLength + 1] = 0;
|
||||
SaltData[SaltLength + 2] = 0;
|
||||
SaltData[SaltLength + 3] = 1;
|
||||
SaltData[SaltLength + 0] = 0; // Block index appened to salt.
|
||||
SaltData[SaltLength + 1] = 0; //
|
||||
SaltData[SaltLength + 2] = 0; // Since we do not request the key width
|
||||
SaltData[SaltLength + 3] = 1; // exceeding HMAC width, it is always 1.
|
||||
|
||||
// First iteration: HMAC of password, salt and block index (1).
|
||||
byte U1[SHA256_DIGEST_SIZE];
|
||||
@@ -128,19 +128,19 @@ void pbkdf2(const byte *Pwd, size_t PwdLength,
|
||||
}
|
||||
|
||||
|
||||
void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
||||
bool CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
||||
const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
|
||||
byte *PswCheck)
|
||||
{
|
||||
if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
return;
|
||||
return false;
|
||||
|
||||
byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
|
||||
bool Found=false;
|
||||
for (uint I=0;I<ASIZE(KDF5Cache);I++)
|
||||
{
|
||||
KDF5CacheItem *Item=KDF5Cache+I;
|
||||
if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
|
||||
if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt &&
|
||||
memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
|
||||
{
|
||||
memcpy(Key,Item->Key,sizeof(Key));
|
||||
@@ -186,6 +186,7 @@ void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
|
||||
rin.Init(Encrypt, Key, 256, InitV);
|
||||
|
||||
cleandata(Key,sizeof(Key));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +201,7 @@ void ConvertHashToMAC(HashValue *Value,byte *Key)
|
||||
Value->CRC32=0;
|
||||
for (uint I=0;I<ASIZE(Digest);I++)
|
||||
Value->CRC32^=Digest[I] << ((I & 3) * 8);
|
||||
Value->CRC32&=0xffffffff; // In case the variable size is larger than 32-bit.
|
||||
}
|
||||
if (Value->Type==HASH_BLAKE2)
|
||||
{
|
||||
|
||||
142
unrar/dll.cpp
142
unrar/dll.cpp
@@ -16,8 +16,7 @@ struct DataSet
|
||||
|
||||
HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
|
||||
{
|
||||
RAROpenArchiveDataEx rx;
|
||||
memset(&rx,0,sizeof(rx));
|
||||
RAROpenArchiveDataEx rx{};
|
||||
rx.ArcName=r->ArcName;
|
||||
rx.OpenMode=r->OpenMode;
|
||||
rx.CmtBuf=r->CmtBuf;
|
||||
@@ -32,7 +31,7 @@ HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
|
||||
|
||||
HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
{
|
||||
DataSet *Data=NULL;
|
||||
DataSet *Data=nullptr;
|
||||
try
|
||||
{
|
||||
ErrHandler.Clean();
|
||||
@@ -44,22 +43,21 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
Data->Cmd.FileArgs.AddString(L"*");
|
||||
Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0;
|
||||
|
||||
char AnsiArcName[NM];
|
||||
*AnsiArcName=0;
|
||||
if (r->ArcName!=NULL)
|
||||
std::string AnsiArcName;
|
||||
if (r->ArcName!=nullptr)
|
||||
{
|
||||
strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName));
|
||||
AnsiArcName=r->ArcName;
|
||||
#ifdef _WIN_ALL
|
||||
if (!AreFileApisANSI())
|
||||
{
|
||||
OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName));
|
||||
AnsiArcName[ASIZE(AnsiArcName)-1]=0;
|
||||
}
|
||||
OemToExt(r->ArcName,AnsiArcName);
|
||||
#endif
|
||||
}
|
||||
|
||||
wchar ArcName[NM];
|
||||
GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName));
|
||||
std::wstring ArcName;
|
||||
if (r->ArcNameW!=nullptr && *r->ArcNameW!=0)
|
||||
ArcName=r->ArcNameW;
|
||||
else
|
||||
CharToWide(AnsiArcName,ArcName);
|
||||
|
||||
Data->Cmd.AddArcName(ArcName);
|
||||
Data->Cmd.Overwrite=OVERWRITE_ALL;
|
||||
@@ -75,7 +73,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
{
|
||||
r->OpenResult=ERAR_EOPEN;
|
||||
delete Data;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (!Data->Arc.IsArchive(true))
|
||||
{
|
||||
@@ -90,7 +88,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
r->OpenResult=ERAR_BAD_ARCHIVE;
|
||||
}
|
||||
delete Data;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
r->Flags=0;
|
||||
|
||||
@@ -113,35 +111,47 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
|
||||
if (Data->Arc.FirstVolume)
|
||||
r->Flags|=ROADF_FIRSTVOLUME;
|
||||
|
||||
Array<wchar> CmtDataW;
|
||||
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
|
||||
std::wstring CmtDataW;
|
||||
if (r->CmtBufSize!=0 && Data->Arc.GetComment(CmtDataW))
|
||||
{
|
||||
if (r->CmtBufW!=NULL)
|
||||
if (r->CmtBufW!=nullptr)
|
||||
{
|
||||
CmtDataW.Push(0);
|
||||
size_t Size=wcslen(&CmtDataW[0])+1;
|
||||
// CmtDataW.push_back(0);
|
||||
size_t Size=wcslen(CmtDataW.data())+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));
|
||||
memcpy(r->CmtBufW,CmtDataW.data(),(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;
|
||||
std::vector<char> CmtData(CmtDataW.size()*4+1);
|
||||
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.size()-1);
|
||||
size_t Size=strlen(CmtData.data())+1;
|
||||
|
||||
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
|
||||
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
|
||||
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
|
||||
r->CmtBuf[r->CmtSize-1]=0;
|
||||
}
|
||||
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
|
||||
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
|
||||
memcpy(r->CmtBuf,CmtData.data(),r->CmtSize-1);
|
||||
r->CmtBuf[r->CmtSize-1]=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
r->CmtState=r->CmtSize=0;
|
||||
|
||||
#ifdef PROPAGATE_MOTW
|
||||
if (r->MarkOfTheWeb!=nullptr)
|
||||
{
|
||||
Data->Cmd.MotwAllFields=r->MarkOfTheWeb[0]=='1';
|
||||
const wchar *Sep=wcschr(r->MarkOfTheWeb,'=');
|
||||
if (r->MarkOfTheWeb[0]=='-')
|
||||
Data->Cmd.MotwList.Reset();
|
||||
else
|
||||
Data->Cmd.GetBriefMaskList(Sep==nullptr ? L"*":Sep+1,Data->Cmd.MotwList);
|
||||
}
|
||||
#endif
|
||||
|
||||
Data->Extract.ExtractArchiveInit(Data->Arc);
|
||||
return (HANDLE)Data;
|
||||
}
|
||||
@@ -183,8 +193,7 @@ int PASCAL RARCloseArchive(HANDLE hArcData)
|
||||
|
||||
int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D)
|
||||
{
|
||||
struct RARHeaderDataEx X;
|
||||
memset(&X,0,sizeof(X));
|
||||
struct RARHeaderDataEx X{};
|
||||
|
||||
int Code=RARReadHeaderEx(hArcData,&X);
|
||||
|
||||
@@ -241,14 +250,18 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
|
||||
else
|
||||
return Code;
|
||||
}
|
||||
wcsncpy(D->ArcNameW,Data->Arc.FileName,ASIZE(D->ArcNameW));
|
||||
wcsncpyz(D->ArcNameW,Data->Arc.FileName.c_str(),ASIZE(D->ArcNameW));
|
||||
WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName));
|
||||
if (D->ArcNameEx!=nullptr)
|
||||
wcsncpyz(D->ArcNameEx,Data->Arc.FileName.c_str(),D->ArcNameExSize);
|
||||
|
||||
wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW));
|
||||
wcsncpyz(D->FileNameW,hd->FileName.c_str(),ASIZE(D->FileNameW));
|
||||
WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName));
|
||||
#ifdef _WIN_ALL
|
||||
CharToOemA(D->FileName,D->FileName);
|
||||
#endif
|
||||
if (D->FileNameEx!=nullptr)
|
||||
wcsncpyz(D->FileNameEx,hd->FileName.c_str(),D->FileNameExSize);
|
||||
|
||||
D->Flags=0;
|
||||
if (hd->SplitBefore)
|
||||
@@ -310,7 +323,7 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
|
||||
// this RedirNameSize check sometimes later.
|
||||
if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL &&
|
||||
D->RedirNameSize>0 && D->RedirNameSize<100000)
|
||||
wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize);
|
||||
wcsncpyz(D->RedirName,hd->RedirName.c_str(),D->RedirNameSize);
|
||||
D->DirTarget=hd->DirTarget;
|
||||
|
||||
/* added by me */
|
||||
@@ -320,7 +333,16 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
|
||||
{
|
||||
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
|
||||
}
|
||||
return ERAR_SUCCESS;
|
||||
if (Data->Cmd.DllError!=0)
|
||||
return Data->Cmd.DllError;
|
||||
// Non-fatal errors like RARX_CRC (bad header checksum) or RARX_WARNING
|
||||
// can be set during a successful header read and should not be reported
|
||||
// as failures here; callers use BrokenHeader flag or the listing result to
|
||||
// detect them. Only propagate errors severe enough to warrant stopping.
|
||||
RAR_EXIT ErrCode=ErrHandler.GetErrorCode();
|
||||
if (ErrCode==RARX_SUCCESS || ErrCode==RARX_WARNING || ErrCode==RARX_CRC)
|
||||
return ERAR_SUCCESS;
|
||||
return RarErrorToDll(ErrCode);
|
||||
}
|
||||
|
||||
|
||||
@@ -365,45 +387,43 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
|
||||
{
|
||||
Data->Cmd.DllOpMode=Operation;
|
||||
|
||||
*Data->Cmd.ExtrPath=0;
|
||||
*Data->Cmd.DllDestName=0;
|
||||
Data->Cmd.ExtrPath.clear();
|
||||
Data->Cmd.DllDestName.clear();
|
||||
|
||||
if (DestPath!=NULL)
|
||||
{
|
||||
char ExtrPathA[NM];
|
||||
strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2);
|
||||
std::string ExtrPathA=DestPath;
|
||||
#ifdef _WIN_ALL
|
||||
// We must not apply OemToCharBuffA directly to DestPath,
|
||||
// because we do not know DestPath length and OemToCharBuffA
|
||||
// does not stop at 0.
|
||||
OemToCharA(ExtrPathA,ExtrPathA);
|
||||
OemToExt(ExtrPathA,ExtrPathA);
|
||||
#endif
|
||||
CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
|
||||
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
|
||||
CharToWide(ExtrPathA,Data->Cmd.ExtrPath);
|
||||
AddEndSlash(Data->Cmd.ExtrPath);
|
||||
}
|
||||
if (DestName!=NULL)
|
||||
{
|
||||
char DestNameA[NM];
|
||||
strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2);
|
||||
std::string DestNameA=DestName;
|
||||
#ifdef _WIN_ALL
|
||||
// We must not apply OemToCharBuffA directly to DestName,
|
||||
// because we do not know DestName length and OemToCharBuffA
|
||||
// does not stop at 0.
|
||||
OemToCharA(DestNameA,DestNameA);
|
||||
OemToExt(DestNameA,DestNameA);
|
||||
#endif
|
||||
CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName));
|
||||
CharToWide(DestNameA,Data->Cmd.DllDestName);
|
||||
}
|
||||
|
||||
if (DestPathW!=NULL)
|
||||
{
|
||||
wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath));
|
||||
AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
|
||||
Data->Cmd.ExtrPath=DestPathW;
|
||||
AddEndSlash(Data->Cmd.ExtrPath);
|
||||
}
|
||||
|
||||
if (DestNameW!=NULL)
|
||||
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
|
||||
Data->Cmd.DllDestName=DestNameW;
|
||||
|
||||
wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command));
|
||||
Data->Cmd.Command=Operation==RAR_EXTRACT ? L"X":L"T";
|
||||
Data->Cmd.Test=Operation!=RAR_EXTRACT;
|
||||
if (Operation == RAR_EXTRACT_CHUNK)
|
||||
{
|
||||
@@ -437,6 +457,10 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
|
||||
}
|
||||
|
||||
// Now we process extra file information if any.
|
||||
// It is important to do it in the same ProcessFile(), because caller
|
||||
// app can rely on this behavior, for example, to overwrite
|
||||
// the extracted Mark of the Web with propagated from archive
|
||||
// immediately after ProcessFile() call.
|
||||
//
|
||||
// Archive can be closed if we process volumes, next volume is missing
|
||||
// and current one is already removed or deleted. So we need to check
|
||||
@@ -466,7 +490,17 @@ int PASCAL ProcessFile(HANDLE hArcData, int Operation, char *DestPath,
|
||||
{
|
||||
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
|
||||
}
|
||||
return Data->Cmd.DllError;
|
||||
if (Data->Cmd.DllError!=0)
|
||||
return Data->Cmd.DllError;
|
||||
// Non-fatal errors like RARX_CRC (bad header checksum) or RARX_WARNING
|
||||
// can be set during a successful header read and should not cause skip/list
|
||||
// operations to fail. Only propagate errors severe enough to warrant stopping.
|
||||
{
|
||||
RAR_EXIT ErrCode=ErrHandler.GetErrorCode();
|
||||
if (ErrCode==RARX_SUCCESS || ErrCode==RARX_WARNING || ErrCode==RARX_CRC)
|
||||
return ERAR_SUCCESS;
|
||||
return RarErrorToDll(ErrCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,7 +568,7 @@ void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
|
||||
#ifndef RAR_NOCRYPT
|
||||
DataSet *Data=(DataSet *)hArcData;
|
||||
wchar PasswordW[MAXPASSWORD];
|
||||
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
|
||||
CharToWide(Password,PasswordW,ASIZE(PasswordW));
|
||||
Data->Cmd.Password.Set(PasswordW);
|
||||
cleandata(PasswordW,sizeof(PasswordW));
|
||||
#endif
|
||||
@@ -568,6 +602,8 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
|
||||
return ERAR_BAD_PASSWORD;
|
||||
case RARX_SUCCESS:
|
||||
return ERAR_SUCCESS; // 0.
|
||||
case RARX_BADARC:
|
||||
return ERAR_BAD_ARCHIVE;
|
||||
default:
|
||||
return ERAR_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define ERAR_MISSING_PASSWORD 22
|
||||
#define ERAR_EREFERENCE 23
|
||||
#define ERAR_BAD_PASSWORD 24
|
||||
#define ERAR_LARGE_DICT 25
|
||||
|
||||
#define RAR_OM_LIST 0
|
||||
#define RAR_OM_EXTRACT 1
|
||||
@@ -32,7 +33,7 @@
|
||||
#define RAR_VOL_ASK 0
|
||||
#define RAR_VOL_NOTIFY 1
|
||||
|
||||
#define RAR_DLL_VERSION 8
|
||||
#define RAR_DLL_VERSION 9
|
||||
#define RAR_DLL_EXT_VERSION 1 //added by me
|
||||
|
||||
#define RAR_HASH_NONE 0
|
||||
@@ -130,9 +131,13 @@ struct RARHeaderDataEx
|
||||
unsigned int CtimeHigh;
|
||||
unsigned int AtimeLow;
|
||||
unsigned int AtimeHigh;
|
||||
wchar_t *ArcNameEx;
|
||||
unsigned int ArcNameExSize;
|
||||
wchar_t *FileNameEx;
|
||||
unsigned int FileNameExSize;
|
||||
/* removed by me: we don't need to retain binary compatibility in case new
|
||||
* fields are added, so we avoid wasting space here */
|
||||
/* unsigned int Reserved[988]; */
|
||||
/* unsigned int Reserved[982]; */
|
||||
/* added by me */
|
||||
size_t WinSize; /* window size */
|
||||
};
|
||||
@@ -178,13 +183,14 @@ struct RAROpenArchiveDataEx
|
||||
LPARAM UserData;
|
||||
unsigned int OpFlags;
|
||||
wchar_t *CmtBufW;
|
||||
/* removed by me */
|
||||
/* unsigned int Reserved[25]; */
|
||||
wchar_t *MarkOfTheWeb;
|
||||
/* removed by me: we don't need to retain binary compatibility */
|
||||
/* unsigned int Reserved[23]; */
|
||||
};
|
||||
|
||||
enum UNRARCALLBACK_MESSAGES {
|
||||
UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW,
|
||||
UCM_NEEDPASSWORDW
|
||||
UCM_NEEDPASSWORDW,UCM_LARGEDICT
|
||||
};
|
||||
|
||||
typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode);
|
||||
|
||||
10
unrar/dll.rc
10
unrar/dll.rc
@@ -2,8 +2,8 @@
|
||||
#include <commctrl.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 6, 0, 2, 3610
|
||||
PRODUCTVERSION 6, 0, 2, 3610
|
||||
FILEVERSION 7, 20, 100, 1861
|
||||
PRODUCTVERSION 7, 20, 100, 1861
|
||||
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", "6.0.2\0"
|
||||
VALUE "ProductVersion", "6.0.2\0"
|
||||
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0"
|
||||
VALUE "FileVersion", "7.20.0\0"
|
||||
VALUE "ProductVersion", "7.20.0\0"
|
||||
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2026\0"
|
||||
VALUE "OriginalFilename", "Unrar.dll\0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,17 +11,16 @@ EncodeFileName::EncodeFileName()
|
||||
|
||||
|
||||
|
||||
void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize,
|
||||
wchar *NameW,size_t MaxDecSize)
|
||||
void EncodeFileName::Decode(const char *Name,size_t NameSize,
|
||||
const byte *EncName,size_t EncSize,
|
||||
std::wstring &NameW)
|
||||
{
|
||||
size_t EncPos=0,DecPos=0;
|
||||
byte HighByte=EncPos<EncSize ? EncName[EncPos++] : 0;
|
||||
while (EncPos<EncSize && DecPos<MaxDecSize)
|
||||
while (EncPos<EncSize)
|
||||
{
|
||||
if (FlagBits==0)
|
||||
{
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
Flags=EncName[EncPos++];
|
||||
FlagBits=8;
|
||||
}
|
||||
@@ -30,16 +29,20 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS
|
||||
case 0:
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
// We need DecPos also for ASCII "Name", so resize() instead of push_back().
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos++]=EncName[EncPos++];
|
||||
break;
|
||||
case 1:
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
|
||||
break;
|
||||
case 2:
|
||||
if (EncPos+1>=EncSize)
|
||||
break;
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
|
||||
EncPos+=2;
|
||||
break;
|
||||
@@ -53,17 +56,22 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS
|
||||
if (EncPos>=EncSize)
|
||||
break;
|
||||
byte Correction=EncName[EncPos++];
|
||||
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize && DecPos<NameSize;Length--,DecPos++)
|
||||
for (Length=(Length&0x7f)+2;Length>0 && DecPos<NameSize;Length--,DecPos++)
|
||||
{
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
|
||||
}
|
||||
}
|
||||
else
|
||||
for (Length+=2;Length>0 && DecPos<MaxDecSize && DecPos<NameSize;Length--,DecPos++)
|
||||
for (Length+=2;Length>0 && DecPos<NameSize;Length--,DecPos++)
|
||||
{
|
||||
NameW.resize(DecPos+1);
|
||||
NameW[DecPos]=Name[DecPos];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
Flags<<=2;
|
||||
FlagBits-=2;
|
||||
}
|
||||
NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0;
|
||||
}
|
||||
|
||||
@@ -4,17 +4,16 @@
|
||||
class EncodeFileName
|
||||
{
|
||||
private:
|
||||
void AddFlags(int Value);
|
||||
void AddFlags(byte Value,std::vector<byte> &EncName);
|
||||
|
||||
byte *EncName;
|
||||
byte Flags;
|
||||
uint FlagBits;
|
||||
size_t FlagsPos;
|
||||
size_t DestSize;
|
||||
public:
|
||||
EncodeFileName();
|
||||
size_t Encode(char *Name,wchar *NameW,byte *EncName);
|
||||
void Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
|
||||
void Encode(const std::string &Name,const std::wstring &NameW,std::vector<byte> &EncName);
|
||||
void Decode(const char *Name,size_t NameSize,const byte *EncName,size_t EncSize,std::wstring &NameW);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
119
unrar/errhnd.cpp
119
unrar/errhnd.cpp
@@ -26,7 +26,7 @@ void ErrorHandler::MemoryError()
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::OpenError(const wchar *FileName)
|
||||
void ErrorHandler::OpenError(const std::wstring &FileName)
|
||||
{
|
||||
#ifndef SILENT
|
||||
OpenErrorMsg(FileName);
|
||||
@@ -35,7 +35,7 @@ void ErrorHandler::OpenError(const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::CloseError(const wchar *FileName)
|
||||
void ErrorHandler::CloseError(const std::wstring &FileName)
|
||||
{
|
||||
if (!UserBreak)
|
||||
{
|
||||
@@ -51,7 +51,7 @@ void ErrorHandler::CloseError(const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ReadError(const wchar *FileName)
|
||||
void ErrorHandler::ReadError(const std::wstring &FileName)
|
||||
{
|
||||
#ifndef SILENT
|
||||
ReadErrorMsg(FileName);
|
||||
@@ -62,13 +62,13 @@ void ErrorHandler::ReadError(const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit)
|
||||
void ErrorHandler::AskRepeatRead(const std::wstring &FileName,bool &Ignore,bool &Retry,bool &Quit)
|
||||
{
|
||||
SetErrorCode(RARX_READ);
|
||||
#if !defined(SILENT) && !defined(SFX_MODULE)
|
||||
if (!Silent)
|
||||
{
|
||||
uiMsg(UIERROR_FILEREAD,UINULL,FileName);
|
||||
uiMsg(UIERROR_FILEREAD,L"",FileName);
|
||||
SysErrMsg();
|
||||
if (ReadErrIgnoreAll)
|
||||
Ignore=true;
|
||||
@@ -88,7 +88,7 @@ void ErrorHandler::AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::WriteError(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
#ifndef SILENT
|
||||
WriteErrorMsg(ArcName,FileName);
|
||||
@@ -100,7 +100,7 @@ void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
|
||||
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
void ErrorHandler::WriteErrorFAT(const wchar *FileName)
|
||||
void ErrorHandler::WriteErrorFAT(const std::wstring &FileName)
|
||||
{
|
||||
SysErrMsg();
|
||||
uiMsg(UIERROR_NTFSREQUIRED,FileName);
|
||||
@@ -111,7 +111,7 @@ void ErrorHandler::WriteErrorFAT(const wchar *FileName)
|
||||
#endif
|
||||
|
||||
|
||||
bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
|
||||
bool ErrorHandler::AskRepeatWrite(const std::wstring &FileName,bool DiskFull)
|
||||
{
|
||||
#ifndef SILENT
|
||||
if (!Silent)
|
||||
@@ -129,7 +129,7 @@ bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::SeekError(const wchar *FileName)
|
||||
void ErrorHandler::SeekError(const std::wstring &FileName)
|
||||
{
|
||||
if (!UserBreak)
|
||||
{
|
||||
@@ -144,13 +144,16 @@ void ErrorHandler::SeekError(const wchar *FileName)
|
||||
|
||||
void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
|
||||
{
|
||||
#ifndef RARDLL
|
||||
va_list arglist;
|
||||
va_start(arglist,fmt);
|
||||
wchar Msg[1024];
|
||||
vswprintf(Msg,ASIZE(Msg),fmt,arglist);
|
||||
|
||||
std::wstring Msg=vwstrprintf(fmt,arglist);
|
||||
uiMsg(UIERROR_GENERALERRMSG,Msg);
|
||||
SysErrMsg();
|
||||
|
||||
va_end(arglist);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -161,28 +164,31 @@ void ErrorHandler::MemoryErrorMsg()
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::OpenErrorMsg(const wchar *FileName)
|
||||
void ErrorHandler::OpenErrorMsg(const std::wstring &FileName)
|
||||
{
|
||||
OpenErrorMsg(NULL,FileName);
|
||||
OpenErrorMsg(L"",FileName);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::OpenErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
|
||||
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
SetErrorCode(RARX_OPEN);
|
||||
|
||||
// Keep GUI responsive if many files cannot be opened when archiving.
|
||||
// Call after SysErrMsg to avoid modifying the error code and SysErrMsg text.
|
||||
Wait();
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::CreateErrorMsg(const wchar *FileName)
|
||||
void ErrorHandler::CreateErrorMsg(const std::wstring &FileName)
|
||||
{
|
||||
CreateErrorMsg(NULL,FileName);
|
||||
CreateErrorMsg(L"",FileName);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::CreateErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_FILECREATE,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
@@ -190,13 +196,13 @@ void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ReadErrorMsg(const wchar *FileName)
|
||||
void ErrorHandler::ReadErrorMsg(const std::wstring &FileName)
|
||||
{
|
||||
ReadErrorMsg(NULL,FileName);
|
||||
ReadErrorMsg(L"",FileName);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::ReadErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_FILEREAD,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
@@ -204,7 +210,7 @@ void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::WriteErrorMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
|
||||
SysErrMsg();
|
||||
@@ -212,21 +218,21 @@ void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
|
||||
void ErrorHandler::ArcBrokenMsg(const std::wstring &ArcName)
|
||||
{
|
||||
uiMsg(UIERROR_ARCBROKEN,ArcName);
|
||||
SetErrorCode(RARX_CRC);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::ChecksumFailedMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
|
||||
SetErrorCode(RARX_CRC);
|
||||
}
|
||||
|
||||
|
||||
void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
|
||||
void ErrorHandler::UnknownMethodMsg(const std::wstring &ArcName,const std::wstring &FileName)
|
||||
{
|
||||
uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
|
||||
ErrHandler.SetErrorCode(RARX_FATAL);
|
||||
@@ -250,7 +256,8 @@ void ErrorHandler::SetErrorCode(RAR_EXIT Code)
|
||||
ExitCode=Code;
|
||||
break;
|
||||
case RARX_CRC:
|
||||
if (ExitCode!=RARX_BADPWD)
|
||||
// 2025.10.25: RARX_OPEN is set if next volume is missing.
|
||||
if (ExitCode!=RARX_BADPWD && ExitCode!=RARX_OPEN)
|
||||
ExitCode=Code;
|
||||
break;
|
||||
case RARX_FATAL:
|
||||
@@ -329,33 +336,44 @@ void ErrorHandler::Throw(RAR_EXIT Code)
|
||||
if (Code==RARX_USERBREAK && !EnableBreak)
|
||||
return;
|
||||
#if !defined(SILENT)
|
||||
// Do not write "aborted" when just displaying online help.
|
||||
if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
|
||||
mprintf(L"\n%s\n",St(MProgAborted));
|
||||
if (Code!=RARX_SUCCESS)
|
||||
if (Code==RARX_USERERROR) // Do not write "aborted" when just displaying the online help.
|
||||
mprintf(L"\n"); // For consistency with other errors, which print the final "\n".
|
||||
else
|
||||
mprintf(L"\n%s\n",St(MProgAborted));
|
||||
#endif
|
||||
SetErrorCode(Code);
|
||||
throw Code;
|
||||
}
|
||||
|
||||
|
||||
bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
|
||||
bool ErrorHandler::GetSysErrMsg(std::wstring &Msg)
|
||||
{
|
||||
#ifndef SILENT
|
||||
#ifdef _WIN_ALL
|
||||
int ErrType=GetLastError();
|
||||
if (ErrType!=0)
|
||||
return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
||||
Msg,(DWORD)Size,NULL)!=0;
|
||||
{
|
||||
wchar *Buf=nullptr;
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
||||
(LPTSTR)&Buf,0,NULL)!=0)
|
||||
{
|
||||
Msg=Buf;
|
||||
LocalFree(Buf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
#ifdef _UNIX
|
||||
if (errno!=0)
|
||||
{
|
||||
char *err=strerror(errno);
|
||||
if (err!=NULL)
|
||||
{
|
||||
CharToWide(err,Msg,Size);
|
||||
CharToWide(err,Msg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -367,32 +385,27 @@ bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
|
||||
|
||||
void ErrorHandler::SysErrMsg()
|
||||
{
|
||||
#if !defined(SFX_MODULE) && !defined(SILENT)
|
||||
wchar Msg[1024];
|
||||
if (!GetSysErrMsg(Msg,ASIZE(Msg)))
|
||||
#ifndef SILENT
|
||||
std::wstring Msg;
|
||||
if (!GetSysErrMsg(Msg))
|
||||
return;
|
||||
#ifdef _WIN_ALL
|
||||
wchar *CurMsg=Msg;
|
||||
while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
|
||||
// Print string with \r\n as several strings to multiple lines.
|
||||
size_t Pos=0;
|
||||
while (Pos!=std::wstring::npos)
|
||||
{
|
||||
while (*CurMsg=='\r' || *CurMsg=='\n')
|
||||
CurMsg++;
|
||||
if (*CurMsg==0)
|
||||
while (Msg[Pos]=='\r' || Msg[Pos]=='\n')
|
||||
Pos++;
|
||||
if (Pos==Msg.size())
|
||||
break;
|
||||
wchar *EndMsg=wcschr(CurMsg,'\r');
|
||||
if (EndMsg==NULL)
|
||||
EndMsg=wcschr(CurMsg,'\n');
|
||||
if (EndMsg!=NULL)
|
||||
{
|
||||
*EndMsg=0;
|
||||
EndMsg++;
|
||||
}
|
||||
size_t EndPos=Msg.find_first_of(L"\r\n",Pos);
|
||||
std::wstring CurMsg=Msg.substr(Pos,EndPos==std::wstring::npos ? EndPos:EndPos-Pos);
|
||||
uiMsg(UIERROR_SYSERRMSG,CurMsg);
|
||||
CurMsg=EndMsg;
|
||||
Pos=EndPos;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
#ifdef _UNIX
|
||||
uiMsg(UIERROR_SYSERRMSG,Msg);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ enum RAR_EXIT // RAR exit code.
|
||||
RARX_NOFILES = 10,
|
||||
RARX_BADPWD = 11,
|
||||
RARX_READ = 12,
|
||||
RARX_BADARC = 13,
|
||||
RARX_USERBREAK = 255
|
||||
};
|
||||
|
||||
@@ -33,26 +34,26 @@ class ErrorHandler
|
||||
ErrorHandler();
|
||||
void Clean();
|
||||
void MemoryError();
|
||||
void OpenError(const wchar *FileName);
|
||||
void CloseError(const wchar *FileName);
|
||||
void ReadError(const wchar *FileName);
|
||||
void AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit);
|
||||
void WriteError(const wchar *ArcName,const wchar *FileName);
|
||||
void WriteErrorFAT(const wchar *FileName);
|
||||
bool AskRepeatWrite(const wchar *FileName,bool DiskFull);
|
||||
void SeekError(const wchar *FileName);
|
||||
void OpenError(const std::wstring &FileName);
|
||||
void CloseError(const std::wstring &FileName);
|
||||
void ReadError(const std::wstring &FileName);
|
||||
void AskRepeatRead(const std::wstring &FileName,bool &Ignore,bool &Retry,bool &Quit);
|
||||
void WriteError(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void WriteErrorFAT(const std::wstring &FileName);
|
||||
bool AskRepeatWrite(const std::wstring &FileName,bool DiskFull);
|
||||
void SeekError(const std::wstring &FileName);
|
||||
void GeneralErrMsg(const wchar *fmt,...);
|
||||
void MemoryErrorMsg();
|
||||
void OpenErrorMsg(const wchar *FileName);
|
||||
void OpenErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void CreateErrorMsg(const wchar *FileName);
|
||||
void CreateErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void ReadErrorMsg(const wchar *FileName);
|
||||
void ReadErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void WriteErrorMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void ArcBrokenMsg(const wchar *ArcName);
|
||||
void ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void UnknownMethodMsg(const wchar *ArcName,const wchar *FileName);
|
||||
void OpenErrorMsg(const std::wstring &FileName);
|
||||
void OpenErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void CreateErrorMsg(const std::wstring &FileName);
|
||||
void CreateErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void ReadErrorMsg(const std::wstring &FileName);
|
||||
void ReadErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void WriteErrorMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void ArcBrokenMsg(const std::wstring &ArcName);
|
||||
void ChecksumFailedMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void UnknownMethodMsg(const std::wstring &ArcName,const std::wstring &FileName);
|
||||
void Exit(RAR_EXIT ExitCode);
|
||||
void SetErrorCode(RAR_EXIT Code);
|
||||
RAR_EXIT GetErrorCode() {return ExitCode;}
|
||||
@@ -60,7 +61,7 @@ class ErrorHandler
|
||||
void SetSignalHandlers(bool Enable);
|
||||
void Throw(RAR_EXIT Code);
|
||||
void SetSilent(bool Mode) {Silent=Mode;}
|
||||
bool GetSysErrMsg(wchar *Msg,size_t Size);
|
||||
bool GetSysErrMsg(std::wstring &Msg);
|
||||
void SysErrMsg();
|
||||
int GetSystemErrorCode();
|
||||
void SetSystemErrorCode(int Code);
|
||||
|
||||
@@ -19,19 +19,13 @@
|
||||
|
||||
// RAR2 service header extra records.
|
||||
#ifndef SFX_MODULE
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
if (Cmd->Test)
|
||||
return;
|
||||
switch(Arc.SubBlockHead.SubType)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
case UO_HEAD:
|
||||
if (Cmd->ProcessOwners)
|
||||
ExtractUnixOwner20(Arc,Name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
case NTACL_HEAD:
|
||||
if (Cmd->ProcessOwners)
|
||||
ExtractACL20(Arc,Name);
|
||||
@@ -39,19 +33,19 @@ void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
case STREAM_HEAD:
|
||||
ExtractStreams20(Arc,Name);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// RAR3 and RAR5 service header extra records.
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,const std::wstring &Name)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 &&
|
||||
Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
|
||||
ExtractUnixOwner30(Arc,Name);
|
||||
ExtractUnixOwner30(Arc,Name.c_str());
|
||||
#endif
|
||||
#ifdef _WIN_ALL
|
||||
if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL))
|
||||
@@ -63,7 +57,7 @@ void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
|
||||
|
||||
// Extra data stored directly in file header.
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,const std::wstring &Name)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
|
||||
@@ -74,36 +68,34 @@ void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name)
|
||||
|
||||
|
||||
|
||||
// Calculate a number of path components except \. and \..
|
||||
static int CalcAllowedDepth(const wchar *Name)
|
||||
// Calculate the number of path components except \. and \..
|
||||
static int CalcAllowedDepth(const std::wstring &Name)
|
||||
{
|
||||
int AllowedDepth=0;
|
||||
while (*Name!=0)
|
||||
{
|
||||
if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1]))
|
||||
for (size_t I=0;I<Name.size();I++)
|
||||
if (IsPathDiv(Name[I]))
|
||||
{
|
||||
bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0);
|
||||
bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0);
|
||||
bool Dot=Name[I+1]=='.' && (IsPathDiv(Name[I+2]) || Name[I+2]==0);
|
||||
bool Dot2=Name[I+1]=='.' && Name[I+2]=='.' && (IsPathDiv(Name[I+3]) || Name[I+3]==0);
|
||||
if (!Dot && !Dot2)
|
||||
AllowedDepth++;
|
||||
else
|
||||
if (Dot2)
|
||||
AllowedDepth--;
|
||||
}
|
||||
Name++;
|
||||
}
|
||||
return AllowedDepth;
|
||||
return AllowedDepth < 0 ? 0 : AllowedDepth;
|
||||
}
|
||||
|
||||
|
||||
// Check if all existing path components are directories and not links.
|
||||
static bool LinkInPath(const wchar *Name)
|
||||
static bool LinkInPath(std::wstring Path)
|
||||
{
|
||||
wchar Path[NM];
|
||||
if (wcslen(Name)>=ASIZE(Path))
|
||||
return true; // It should not be that long, skip.
|
||||
wcsncpyz(Path,Name,ASIZE(Path));
|
||||
for (wchar *s=Path+wcslen(Path)-1;s>Path;s--)
|
||||
if (IsPathDiv(*s))
|
||||
if (Path.empty()) // So we can safely use Path.size()-1 below.
|
||||
return false;
|
||||
for (size_t I=Path.size()-1;I>0;I--)
|
||||
if (IsPathDiv(Path[I]))
|
||||
{
|
||||
*s=0;
|
||||
Path.erase(I);
|
||||
FindData FD;
|
||||
if (FindFile::FastFind(Path,&FD,true) && (FD.IsLink || !FD.IsDir))
|
||||
return true;
|
||||
@@ -112,7 +104,7 @@ static bool LinkInPath(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const std::wstring &SrcName,std::wstring PrepSrcName,const std::wstring &TargetName)
|
||||
{
|
||||
// Catch root dir based /path/file paths also as stuff like \\?\.
|
||||
// Do not check PrepSrcName here, it can be root based if destination path
|
||||
@@ -122,19 +114,22 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
||||
|
||||
// Number of ".." in link target.
|
||||
int UpLevels=0;
|
||||
for (int Pos=0;*TargetName!=0;Pos++)
|
||||
for (uint Pos=0;Pos<TargetName.size();Pos++)
|
||||
{
|
||||
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
|
||||
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
|
||||
(Pos==0 || IsPathDiv(*(TargetName-1)));
|
||||
bool Dot2=TargetName[Pos]=='.' && TargetName[Pos+1]=='.' &&
|
||||
(IsPathDiv(TargetName[Pos+2]) || TargetName[Pos+2]==0) &&
|
||||
(Pos==0 || IsPathDiv(TargetName[Pos-1]));
|
||||
if (Dot2)
|
||||
UpLevels++;
|
||||
TargetName++;
|
||||
}
|
||||
// If link target includes "..", it must not have another links
|
||||
// in the path, because they can bypass our safety check. For example,
|
||||
// If link target includes "..", it must not have another links in its
|
||||
// source path, because they can bypass our safety check. For example,
|
||||
// suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
|
||||
// or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next.
|
||||
// or "dir/lnk1" -> ".." first, "dir/lnk1/lnk2" -> ".." next and
|
||||
// file "dir/lnk1/lnk2/poc.txt" last.
|
||||
// Do not confuse with link chains in target, this is in link source path.
|
||||
// It is important for Windows too, though this check can be omitted
|
||||
// if LinksToDirs is invoked in Windows as well.
|
||||
if (UpLevels>0 && LinkInPath(PrepSrcName))
|
||||
return false;
|
||||
|
||||
@@ -147,12 +142,12 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
||||
// Remove the destination path from prepared name if any. We should not
|
||||
// count the destination path depth, because the link target must point
|
||||
// inside of this path, not outside of it.
|
||||
size_t ExtrPathLength=wcslen(Cmd->ExtrPath);
|
||||
if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0)
|
||||
size_t ExtrPathLength=Cmd->ExtrPath.size();
|
||||
if (ExtrPathLength>0 && PrepSrcName.compare(0,ExtrPathLength,Cmd->ExtrPath)==0)
|
||||
{
|
||||
PrepSrcName+=ExtrPathLength;
|
||||
while (IsPathDiv(*PrepSrcName))
|
||||
PrepSrcName++;
|
||||
while (IsPathDiv(PrepSrcName[ExtrPathLength]))
|
||||
ExtrPathLength++;
|
||||
PrepSrcName.erase(0,ExtrPathLength);
|
||||
}
|
||||
int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName);
|
||||
|
||||
@@ -160,19 +155,30 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
|
||||
}
|
||||
|
||||
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const std::wstring &LinkName,bool &UpLink)
|
||||
{
|
||||
// Returning true in Uplink indicates that link target might include ".."
|
||||
// and enables additional checks. It is ok to falsely return true here,
|
||||
// as it implies only the minor performance penalty. But we shall always
|
||||
// return true for links with ".." in target for security reason.
|
||||
|
||||
UpLink=true; // Assume the target might include potentially unsafe "..".
|
||||
#if defined(SAVE_LINKS) && defined(_UNIX) || defined(_WIN_ALL)
|
||||
if (Arc.Format==RARFMT50) // For RAR5 archives we can check RedirName for both Unix and Windows.
|
||||
UpLink=Arc.FileHead.RedirName.find(L"..")!=std::wstring::npos;
|
||||
#endif
|
||||
|
||||
#if defined(SAVE_LINKS) && defined(_UNIX)
|
||||
// For RAR 3.x archives we process links even in test mode to skip link data.
|
||||
if (Arc.Format==RARFMT15)
|
||||
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName);
|
||||
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName.c_str(),UpLink);
|
||||
if (Arc.Format==RARFMT50)
|
||||
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
|
||||
#elif defined _WIN_ALL
|
||||
return ExtractUnixLink50(Cmd,LinkName.c_str(),&Arc.FileHead);
|
||||
#elif defined(_WIN_ALL)
|
||||
// RAR 5.0 archives store link information in file header, so there is
|
||||
// no need to additionally test it if we do not create a file.
|
||||
if (Arc.Format==RARFMT50)
|
||||
return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead);
|
||||
return CreateReparsePoint(Cmd,LinkName.c_str(),&Arc.FileHead);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
#ifndef _RAR_EXTINFO_
|
||||
#define _RAR_EXTINFO_
|
||||
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName);
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName);
|
||||
bool IsRelativeSymlinkSafe(CommandData *Cmd,const std::wstring &SrcName,std::wstring PrepSrcName,const std::wstring &TargetName);
|
||||
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const std::wstring &LinkName,bool &UpLink);
|
||||
#ifdef _UNIX
|
||||
void SetUnixOwner(Archive &Arc,const wchar *FileName);
|
||||
void SetUnixOwner(Archive &Arc,const std::wstring &FileName);
|
||||
#endif
|
||||
|
||||
bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
|
||||
bool ExtractHardlink(CommandData *Cmd,const std::wstring &NameNew,const std::wstring &NameExisting);
|
||||
|
||||
void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize);
|
||||
std::wstring GetStreamNameNTFS(Archive &Arc);
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
bool SetPrivilege(LPCTSTR PrivName);
|
||||
#endif
|
||||
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name);
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name);
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name);
|
||||
void SetExtraInfo20(CommandData *Cmd,Archive &Arc,const std::wstring &Name);
|
||||
void SetExtraInfo(CommandData *Cmd,Archive &Arc,const std::wstring &Name);
|
||||
void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,const std::wstring &Name);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1032
unrar/extract.cpp
1032
unrar/extract.cpp
File diff suppressed because it is too large
Load Diff
@@ -6,24 +6,44 @@ enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT};
|
||||
class CmdExtract
|
||||
{
|
||||
private:
|
||||
struct ExtractRef
|
||||
{
|
||||
std::wstring RefName;
|
||||
std::wstring TmpName;
|
||||
uint64 RefCount;
|
||||
};
|
||||
std::vector<ExtractRef> RefList;
|
||||
|
||||
struct AnalyzeData
|
||||
{
|
||||
std::wstring StartName;
|
||||
uint64 StartPos;
|
||||
std::wstring EndName;
|
||||
uint64 EndPos;
|
||||
} Analyze;
|
||||
|
||||
bool ArcAnalyzed;
|
||||
|
||||
void FreeAnalyzeData();
|
||||
EXTRACT_ARC_CODE ExtractArchive();
|
||||
bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
|
||||
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
|
||||
bool ExtractFileCopy(File &New,const std::wstring &ArcName,const std::wstring &RedirName,const std::wstring &NameNew,const std::wstring &NameExisting,int64 UnpSize);
|
||||
void ExtrPrepareName(Archive &Arc,const std::wstring &ArcFileName,std::wstring &DestName);
|
||||
#ifdef RARDLL
|
||||
bool ExtrDllGetPassword();
|
||||
#else
|
||||
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName);
|
||||
bool ExtrGetPassword(Archive &Arc,const std::wstring &ArcFileName,RarCheckPassword *CheckPwd);
|
||||
#endif
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
|
||||
#endif
|
||||
void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName);
|
||||
bool ExtrCreateFile(Archive &Arc,File &CurFile);
|
||||
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
|
||||
void ExtrCreateDir(Archive &Arc,const std::wstring &ArcFileName);
|
||||
bool ExtrCreateFile(Archive &Arc,File &CurFile,bool WriteOnly);
|
||||
bool CheckUnpVer(Archive &Arc,const std::wstring &ArcFileName);
|
||||
#ifndef SFX_MODULE
|
||||
bool DetectStartVolume(const wchar *VolName,bool NewNumbering);
|
||||
void GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize);
|
||||
void AnalyzeArchive(const std::wstring &ArcName,bool Volume,bool NewNumbering);
|
||||
void GetFirstVolIfFullSet(const std::wstring &SrcName,bool NewNumbering,std::wstring &DestName);
|
||||
#endif
|
||||
bool CheckWinLimit(Archive &Arc,std::wstring &ArcFileName);
|
||||
|
||||
RarTime StartTime; // Time when extraction started.
|
||||
|
||||
@@ -46,12 +66,21 @@ class CmdExtract
|
||||
// any wrong password hints.
|
||||
bool AnySolidDataUnpackedWell;
|
||||
|
||||
wchar ArcName[NM];
|
||||
std::wstring ArcName;
|
||||
|
||||
bool GlobalPassword;
|
||||
bool PrevProcessed; // If previous file was successfully extracted or tested.
|
||||
wchar DestFileName[NM];
|
||||
bool PasswordCancelled;
|
||||
std::wstring DestFileName;
|
||||
bool SuppressNoFilesMessage;
|
||||
|
||||
// In Windows it is set to true if at least one symlink with ".."
|
||||
// in target was extracted.
|
||||
bool ConvertSymlinkPaths;
|
||||
|
||||
// Last path checked for symlinks. We use it to improve the performance,
|
||||
// so we do not check recently checked folders again.
|
||||
std::wstring LastCheckedSymlink;
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
|
||||
bool Fat32,NotFat32;
|
||||
#endif
|
||||
|
||||
@@ -40,22 +40,21 @@ bool CmdExtract::ExtractCurrentFileChunkInit(Archive &Arc,
|
||||
|
||||
if (Arc.FileHead.SplitBefore && FirstFile)
|
||||
{
|
||||
wchar CurVolName[NM];
|
||||
wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName));
|
||||
VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering);
|
||||
std::wstring CurVolName=ArcName;
|
||||
VolNameToFirstName(ArcName,ArcName,Arc.NewNumbering);
|
||||
|
||||
if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
|
||||
{
|
||||
// If first volume name does not match the current name and if such
|
||||
// volume name really exists, let's unpack from this first volume.
|
||||
*ArcName=0;
|
||||
ArcName.clear();
|
||||
Repeat=true;
|
||||
ErrHandler.SetErrorCode(RARX_WARNING);
|
||||
/* Actually known. The problem is that the file doesn't start on this volume. */
|
||||
Cmd->DllError = ERAR_UNKNOWN;
|
||||
return false;
|
||||
}
|
||||
wcsncpyz(ArcName,CurVolName,ASIZE(ArcName));
|
||||
ArcName=CurVolName;
|
||||
}
|
||||
|
||||
DataIO.UnpVolume=Arc.FileHead.SplitAfter;
|
||||
@@ -73,16 +72,16 @@ bool CmdExtract::ExtractCurrentFileChunkInit(Archive &Arc,
|
||||
}
|
||||
}
|
||||
|
||||
if (*Cmd->DllDestName!=0)
|
||||
if (!Cmd->DllDestName.empty())
|
||||
{
|
||||
wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
|
||||
DestFileName=Cmd->DllDestName;
|
||||
// Do we need this code?
|
||||
// if (Cmd->DllOpMode!=RAR_EXTRACT)
|
||||
// ExtrFile=false;
|
||||
}
|
||||
|
||||
wchar ArcFileName[NM];
|
||||
ConvertPath(Arc.FileHead.FileName,ArcFileName,ASIZE(ArcFileName));
|
||||
std::wstring ArcFileName;
|
||||
ConvertPath(&Arc.FileHead.FileName,&ArcFileName);
|
||||
if (!CheckUnpVer(Arc,ArcFileName))
|
||||
{
|
||||
ErrHandler.SetErrorCode(RARX_FATAL);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
// If NewFile==NULL, we delete created file after user confirmation.
|
||||
// It is useful we we need to overwrite an existing folder or file,
|
||||
// It is useful if we need to overwrite an existing folder or file,
|
||||
// but need user confirmation for that.
|
||||
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool FileCreate(CommandData *Cmd,File *NewFile,std::wstring &Name,
|
||||
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
|
||||
{
|
||||
if (UserReject!=NULL)
|
||||
@@ -29,7 +29,7 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
// autorename below can change the name, so we need to check it again.
|
||||
ShortNameChanged=false;
|
||||
#endif
|
||||
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
|
||||
UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0));
|
||||
|
||||
if (Choice==UIASKREP_R_REPLACE)
|
||||
break;
|
||||
@@ -44,95 +44,82 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
}
|
||||
|
||||
// Try to truncate the existing file first instead of delete,
|
||||
// so we preserve existing file permissions such as NTFS permissions.
|
||||
// so we preserve existing file permissions, such as NTFS permissions,
|
||||
// also as "Compressed" attribute and hard links. In GUI version we avoid
|
||||
// deleting an existing file for non-.rar archive formats as well.
|
||||
uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD;
|
||||
if (NewFile!=NULL && NewFile->Create(Name,FileMode))
|
||||
return true;
|
||||
|
||||
CreatePath(Name,true);
|
||||
CreatePath(Name,true,Cmd->DisableNames);
|
||||
return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
|
||||
}
|
||||
|
||||
|
||||
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
|
||||
{
|
||||
wchar NewName[NM];
|
||||
size_t NameLength=wcslen(Name);
|
||||
wchar *Ext=GetExt(Name);
|
||||
if (Ext==NULL)
|
||||
Ext=Name+NameLength;
|
||||
for (uint FileVer=1;;FileVer++)
|
||||
{
|
||||
swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
|
||||
if (!FileExist(NewName))
|
||||
{
|
||||
wcsncpyz(Name,NewName,MaxNameSize);
|
||||
break;
|
||||
}
|
||||
if (FileVer>=1000000)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
// If we find a file, which short name is equal to 'Name', we try to change
|
||||
// its short name, while preserving the long name. It helps when unpacking
|
||||
// an archived file, which long name is equal to short name of already
|
||||
// existing file. Otherwise we would overwrite the already existing file,
|
||||
// even though its long name does not match the name of unpacking file.
|
||||
bool UpdateExistingShortName(const wchar *Name)
|
||||
bool UpdateExistingShortName(const std::wstring &Name)
|
||||
{
|
||||
wchar LongPathName[NM];
|
||||
DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
|
||||
if (Res==0 || Res>=ASIZE(LongPathName))
|
||||
DWORD Res=GetLongPathName(Name.c_str(),NULL,0);
|
||||
if (Res==0)
|
||||
return false;
|
||||
wchar ShortPathName[NM];
|
||||
Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName));
|
||||
if (Res==0 || Res>=ASIZE(ShortPathName))
|
||||
std::vector<wchar> LongPathBuf(Res);
|
||||
Res=GetLongPathName(Name.c_str(),LongPathBuf.data(),(DWORD)LongPathBuf.size());
|
||||
if (Res==0 || Res>=LongPathBuf.size())
|
||||
return false;
|
||||
wchar *LongName=PointToName(LongPathName);
|
||||
wchar *ShortName=PointToName(ShortPathName);
|
||||
Res=GetShortPathName(Name.c_str(),NULL,0);
|
||||
if (Res==0)
|
||||
return false;
|
||||
std::vector<wchar> ShortPathBuf(Res);
|
||||
Res=GetShortPathName(Name.c_str(),ShortPathBuf.data(),(DWORD)ShortPathBuf.size());
|
||||
if (Res==0 || Res>=ShortPathBuf.size())
|
||||
return false;
|
||||
std::wstring LongPathName=LongPathBuf.data();
|
||||
std::wstring ShortPathName=ShortPathBuf.data();
|
||||
|
||||
std::wstring LongName=PointToName(LongPathName);
|
||||
std::wstring ShortName=PointToName(ShortPathName);
|
||||
|
||||
// We continue only if file has a short name, which does not match its
|
||||
// long name, and this short name is equal to name of file which we need
|
||||
// to create.
|
||||
if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 ||
|
||||
if (ShortName.empty() || wcsicomp(LongName,ShortName)==0 ||
|
||||
wcsicomp(PointToName(Name),ShortName)!=0)
|
||||
return false;
|
||||
|
||||
// Generate the temporary new name for existing file.
|
||||
wchar NewName[NM];
|
||||
*NewName=0;
|
||||
for (int I=0;I<10000 && *NewName==0;I+=123)
|
||||
std::wstring NewName;
|
||||
for (uint I=0;I<10000 && NewName.empty();I+=123)
|
||||
{
|
||||
// Here we copy the path part of file to create. We'll make the temporary
|
||||
// file in the same folder.
|
||||
wcsncpyz(NewName,Name,ASIZE(NewName));
|
||||
NewName=Name;
|
||||
|
||||
// Here we set the random name part.
|
||||
swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
|
||||
SetName(NewName,std::wstring(L"rtmp") + std::to_wstring(I));
|
||||
|
||||
// If such file is already exist, try next random name.
|
||||
if (FileExist(NewName))
|
||||
*NewName=0;
|
||||
NewName.clear();
|
||||
}
|
||||
|
||||
// If we could not generate the name not used by any other file, we return.
|
||||
if (*NewName==0)
|
||||
if (NewName.empty())
|
||||
return false;
|
||||
|
||||
// FastFind returns the name without path, but we need the fully qualified
|
||||
// name for renaming, so we use the path from file to create and long name
|
||||
// from existing file.
|
||||
wchar FullName[NM];
|
||||
wcsncpyz(FullName,Name,ASIZE(FullName));
|
||||
SetName(FullName,LongName,ASIZE(FullName));
|
||||
std::wstring FullName=Name;
|
||||
SetName(FullName,LongName);
|
||||
|
||||
// Rename the existing file to randomly generated name. Normally it changes
|
||||
// the short name too.
|
||||
if (!MoveFile(FullName,NewName))
|
||||
if (!MoveFile(FullName.c_str(),NewName.c_str()))
|
||||
return false;
|
||||
|
||||
// Now we need to create the temporary empty file with same name as
|
||||
@@ -147,7 +134,7 @@ bool UpdateExistingShortName(const wchar *Name)
|
||||
// Now we rename the existing file from temporary name to original long name.
|
||||
// Since its previous short name is occupied by another file, it should
|
||||
// get another short name.
|
||||
MoveFile(NewName,FullName);
|
||||
MoveFile(NewName.c_str(),FullName.c_str());
|
||||
|
||||
if (Created)
|
||||
{
|
||||
@@ -155,9 +142,9 @@ bool UpdateExistingShortName(const wchar *Name)
|
||||
KeepShortFile.Close();
|
||||
KeepShortFile.Delete();
|
||||
}
|
||||
// We successfully changed the short name. Maybe sometimes we'll simplify
|
||||
// this function by use of SetFileShortName Windows API call.
|
||||
// But SetFileShortName is not available in older Windows.
|
||||
// We successfully changed the short name. We do not use the simpler
|
||||
// SetFileShortName Windows API call, because it requires SE_RESTORE_NAME
|
||||
// privilege.
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
#ifndef _RAR_FILECREATE_
|
||||
#define _RAR_FILECREATE_
|
||||
|
||||
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
|
||||
bool FileCreate(CommandData *Cmd,File *NewFile,std::wstring &Name,
|
||||
bool *UserReject,int64 FileSize=INT64NDF,
|
||||
RarTime *FileTime=NULL,bool WriteOnly=false);
|
||||
|
||||
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize);
|
||||
|
||||
#if defined(_WIN_ALL)
|
||||
bool UpdateExistingShortName(const wchar *Name);
|
||||
bool UpdateExistingShortName(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
216
unrar/file.cpp
216
unrar/file.cpp
@@ -3,10 +3,10 @@
|
||||
File::File()
|
||||
{
|
||||
hFile=FILE_BAD_HANDLE;
|
||||
*FileName=0;
|
||||
NewFile=false;
|
||||
LastWrite=false;
|
||||
HandleType=FILE_HANDLENORMAL;
|
||||
LineInput=false;
|
||||
SkipClose=false;
|
||||
ErrorType=FILE_SUCCESS;
|
||||
OpenShared=false;
|
||||
@@ -14,11 +14,11 @@ File::File()
|
||||
AllowExceptions=true;
|
||||
PreserveAtime=false;
|
||||
#ifdef _WIN_ALL
|
||||
NoSequentialRead=false;
|
||||
CreateMode=FMF_UNDEFINED;
|
||||
// CreateMode=FMF_UNDEFINED;
|
||||
#endif
|
||||
ReadErrorMode=FREM_ASK;
|
||||
TruncatedAfterReadError=false;
|
||||
CurFilePos=0;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,12 +39,12 @@ void File::operator = (File &SrcFile)
|
||||
LastWrite=SrcFile.LastWrite;
|
||||
HandleType=SrcFile.HandleType;
|
||||
TruncatedAfterReadError=SrcFile.TruncatedAfterReadError;
|
||||
wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName));
|
||||
FileName=SrcFile.FileName;
|
||||
SrcFile.SkipClose=true;
|
||||
}
|
||||
|
||||
|
||||
bool File::Open(const wchar *Name,uint Mode)
|
||||
bool File::Open(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
ErrorType=FILE_SUCCESS;
|
||||
FileHandle hNewFile;
|
||||
@@ -58,21 +58,21 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
|
||||
if (OpenShared)
|
||||
ShareMode|=FILE_SHARE_WRITE;
|
||||
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
|
||||
uint Flags=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);
|
||||
hNewFile=CreateFile(Name.c_str(),Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
|
||||
DWORD LastError;
|
||||
if (hNewFile==FILE_BAD_HANDLE)
|
||||
{
|
||||
LastError=GetLastError();
|
||||
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
{
|
||||
hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
hNewFile=CreateFile(LongName.c_str(),Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
|
||||
|
||||
// For archive names longer than 260 characters first CreateFile
|
||||
// (without \\?\) fails and sets LastError to 3 (access denied).
|
||||
@@ -100,6 +100,12 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
|
||||
#else
|
||||
int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
|
||||
|
||||
// 2025.06.09: We can't just set O_DIRECT for Unix like we set
|
||||
// FILE_FLAG_SEQUENTIAL_SCAN for Windows to minimize disk caching.
|
||||
// O_DIRECT might impose alignment requirements for data size, data address
|
||||
// and file offset. Also it might not be supported by some file systems
|
||||
// and fail with an error.
|
||||
#ifdef O_BINARY
|
||||
flags|=O_BINARY;
|
||||
#if defined(_AIX) && defined(_LARGE_FILE_API)
|
||||
@@ -111,10 +117,10 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
if (PreserveAtime)
|
||||
flags|=O_NOATIME;
|
||||
#endif
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
|
||||
int handle=open(NameA,flags);
|
||||
int handle=open(NameA.c_str(),flags);
|
||||
#ifdef LOCK_EX
|
||||
|
||||
#ifdef _OSF_SOURCE
|
||||
@@ -147,7 +153,7 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
if (Success)
|
||||
{
|
||||
hFile=hNewFile;
|
||||
wcsncpyz(FileName,Name,ASIZE(FileName));
|
||||
FileName=Name;
|
||||
TruncatedAfterReadError=false;
|
||||
}
|
||||
return Success;
|
||||
@@ -155,7 +161,7 @@ bool File::Open(const wchar *Name,uint Mode)
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void File::TOpen(const wchar *Name)
|
||||
void File::TOpen(const std::wstring &Name)
|
||||
{
|
||||
if (!WOpen(Name))
|
||||
ErrHandler.Exit(RARX_OPEN);
|
||||
@@ -163,7 +169,7 @@ void File::TOpen(const wchar *Name)
|
||||
#endif
|
||||
|
||||
|
||||
bool File::WOpen(const wchar *Name)
|
||||
bool File::WOpen(const std::wstring &Name)
|
||||
{
|
||||
if (Open(Name))
|
||||
return true;
|
||||
@@ -172,8 +178,9 @@ bool File::WOpen(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool File::Create(const wchar *Name,uint Mode)
|
||||
bool File::Create(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
// 2025.09.03: Likely outdated info, see https://www.illumos.org/issues/2000
|
||||
// OpenIndiana based NAS and CIFS shares fail to set the file time if file
|
||||
// was created in read+write mode and some data was written and not flushed
|
||||
// before SetFileTime call. So we should use the write only mode if we plan
|
||||
@@ -181,46 +188,46 @@ bool File::Create(const wchar *Name,uint Mode)
|
||||
bool WriteMode=(Mode & FMF_WRITE)!=0;
|
||||
bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared;
|
||||
#ifdef _WIN_ALL
|
||||
CreateMode=Mode;
|
||||
// CreateMode=Mode;
|
||||
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
|
||||
DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
|
||||
|
||||
// Windows automatically removes dots and spaces in the end of file name,
|
||||
// So we detect such names and process them with \\?\ prefix.
|
||||
wchar *LastChar=PointToLastChar(Name);
|
||||
bool Special=*LastChar=='.' || *LastChar==' ';
|
||||
wchar LastChar=GetLastChar(Name);
|
||||
bool Special=LastChar=='.' || LastChar==' ';
|
||||
|
||||
if (Special && (Mode & FMF_STANDARDNAMES)==0)
|
||||
hFile=FILE_BAD_HANDLE;
|
||||
else
|
||||
hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
hFile=CreateFile(Name.c_str(),Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
|
||||
if (hFile==FILE_BAD_HANDLE)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
hFile=CreateFile(LongName.c_str(),Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
#ifdef FILE_USE_OPEN
|
||||
hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
hFile=open(NameA.c_str(),(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666);
|
||||
#else
|
||||
hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
|
||||
hFile=fopen(NameA.c_str(),WriteMode ? WRITEBINARY:CREATEBINARY);
|
||||
#endif
|
||||
#endif
|
||||
NewFile=true;
|
||||
HandleType=FILE_HANDLENORMAL;
|
||||
SkipClose=false;
|
||||
wcsncpyz(FileName,Name,ASIZE(FileName));
|
||||
FileName=Name;
|
||||
return hFile!=FILE_BAD_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
void File::TCreate(const wchar *Name,uint Mode)
|
||||
void File::TCreate(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
if (!WCreate(Name,Mode))
|
||||
ErrHandler.Exit(RARX_FATAL);
|
||||
@@ -228,7 +235,7 @@ void File::TCreate(const wchar *Name,uint Mode)
|
||||
#endif
|
||||
|
||||
|
||||
bool File::WCreate(const wchar *Name,uint Mode)
|
||||
bool File::WCreate(const std::wstring &Name,uint Mode)
|
||||
{
|
||||
if (Create(Name,Mode))
|
||||
return true;
|
||||
@@ -249,7 +256,7 @@ bool File::Close()
|
||||
// We use the standard system handle for stdout in Windows
|
||||
// and it must not be closed here.
|
||||
if (HandleType==FILE_HANDLENORMAL)
|
||||
Success=CloseHandle(hFile)==TRUE;
|
||||
Success=CloseHandle(hFile)!=FALSE;
|
||||
#else
|
||||
#ifdef FILE_USE_OPEN
|
||||
Success=close(hFile)!=-1;
|
||||
@@ -279,16 +286,16 @@ bool File::Delete()
|
||||
}
|
||||
|
||||
|
||||
bool File::Rename(const wchar *NewName)
|
||||
bool File::Rename(const std::wstring &NewName)
|
||||
{
|
||||
// No need to rename if names are already same.
|
||||
bool Success=wcscmp(FileName,NewName)==0;
|
||||
bool Success=(NewName==FileName);
|
||||
|
||||
if (!Success)
|
||||
Success=RenameFile(FileName,NewName);
|
||||
|
||||
if (Success)
|
||||
wcsncpyz(FileName,NewName,ASIZE(FileName));
|
||||
FileName=NewName;
|
||||
|
||||
return Success;
|
||||
}
|
||||
@@ -326,13 +333,13 @@ bool File::Write(const void *Data,size_t Size)
|
||||
const size_t MaxSize=0x4000;
|
||||
for (size_t I=0;I<Size;I+=MaxSize)
|
||||
{
|
||||
Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)==TRUE;
|
||||
Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)!=FALSE;
|
||||
if (!Success)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE;
|
||||
Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)!=FALSE;
|
||||
#else
|
||||
#ifdef FILE_USE_OPEN
|
||||
ssize_t Written=write(hFile,Data,Size);
|
||||
@@ -361,7 +368,7 @@ bool File::Write(const void *Data,size_t Size)
|
||||
Seek(Tell()-Written,SEEK_SET);
|
||||
continue;
|
||||
}
|
||||
ErrHandler.WriteError(NULL,FileName);
|
||||
ErrHandler.WriteError(L"",FileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -379,10 +386,11 @@ int File::Read(void *Data,size_t Size)
|
||||
|
||||
if (ReadErrorMode==FREM_IGNORE)
|
||||
FilePos=Tell();
|
||||
int ReadSize;
|
||||
int TotalRead=0;
|
||||
while (true)
|
||||
{
|
||||
ReadSize=DirectRead(Data,Size);
|
||||
int ReadSize=DirectRead(Data,Size);
|
||||
|
||||
if (ReadSize==-1)
|
||||
{
|
||||
ErrorType=FILE_READERROR;
|
||||
@@ -396,12 +404,14 @@ int File::Read(void *Data,size_t Size)
|
||||
size_t SizeToRead=Min(Size-I,512);
|
||||
int ReadCode=DirectRead(Data,SizeToRead);
|
||||
ReadSize+=(ReadCode==-1) ? 512:ReadCode;
|
||||
if (ReadSize!=-1)
|
||||
TotalRead+=ReadSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool Ignore=false,Retry=false,Quit=false;
|
||||
if (ReadErrorMode==FREM_ASK && HandleType==FILE_HANDLENORMAL)
|
||||
if (ReadErrorMode==FREM_ASK && HandleType==FILE_HANDLENORMAL && IsOpened())
|
||||
{
|
||||
ErrHandler.AskRepeatRead(FileName,Ignore,Retry,Quit);
|
||||
if (Retry)
|
||||
@@ -415,9 +425,28 @@ int File::Read(void *Data,size_t Size)
|
||||
ErrHandler.ReadError(FileName);
|
||||
}
|
||||
}
|
||||
TotalRead+=ReadSize; // If ReadSize is -1, TotalRead is also set to -1 here.
|
||||
|
||||
if (HandleType==FILE_HANDLESTD && !LineInput && ReadSize>0 && (uint)ReadSize<Size)
|
||||
{
|
||||
// Unlike regular files, for pipe we can read only as much as was
|
||||
// written at the other end of pipe. We had seen data coming in small
|
||||
// ~80 byte chunks when piping from 'type arc.rar'. Extraction code
|
||||
// would fail if we read an incomplete archive header from stdin.
|
||||
// So here we ensure that requested size is completely read.
|
||||
// But we return the available data immediately in "line input" mode,
|
||||
// when processing user's input in console prompts. Otherwise apps
|
||||
// piping user responses to multiple Ask() prompts can hang if no more
|
||||
// data is available yet and pipe isn't closed.
|
||||
Data=(byte*)Data+ReadSize;
|
||||
Size-=ReadSize;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ReadSize; // It can return -1 only if AllowExceptions is disabled.
|
||||
if (TotalRead>0) // Can be -1 for error and AllowExceptions disabled.
|
||||
CurFilePos+=TotalRead;
|
||||
return TotalRead; // It can return -1 only if AllowExceptions is disabled.
|
||||
}
|
||||
|
||||
|
||||
@@ -499,6 +528,36 @@ bool File::RawSeek(int64 Offset,int Method)
|
||||
{
|
||||
if (hFile==FILE_BAD_HANDLE)
|
||||
return true;
|
||||
if (!IsSeekable()) // To extract archives from stdin with -si.
|
||||
{
|
||||
// We tried to dynamically allocate 32 KB buffer here, but it improved
|
||||
// speed in Windows 10 by mere ~1.5%.
|
||||
byte Buf[4096];
|
||||
if (Method==SEEK_CUR || Method==SEEK_SET && Offset>=CurFilePos)
|
||||
{
|
||||
uint64 SkipSize=Method==SEEK_CUR ? Offset:Offset-CurFilePos;
|
||||
while (SkipSize>0) // Reading to emulate seek forward.
|
||||
{
|
||||
int ReadSize=Read(Buf,(size_t)Min(SkipSize,ASIZE(Buf)));
|
||||
if (ReadSize<=0)
|
||||
return false;
|
||||
SkipSize-=ReadSize;
|
||||
CurFilePos+=ReadSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// May need it in FileLength() in Archive::UnexpEndArcMsg() when unpacking
|
||||
// RAR 4.x archives without the end of archive block created with -en.
|
||||
if (Method==SEEK_END)
|
||||
{
|
||||
int ReadSize;
|
||||
while ((ReadSize=Read(Buf,ASIZE(Buf)))>0)
|
||||
CurFilePos+=ReadSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Backward seek on unseekable file.
|
||||
}
|
||||
if (Offset<0 && Method!=SEEK_SET)
|
||||
{
|
||||
Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
|
||||
@@ -533,6 +592,8 @@ int64 File::Tell()
|
||||
ErrHandler.SeekError(FileName);
|
||||
else
|
||||
return -1;
|
||||
if (!IsSeekable())
|
||||
return CurFilePos;
|
||||
#ifdef _WIN_ALL
|
||||
LONG HighDist=0;
|
||||
uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
|
||||
@@ -591,7 +652,7 @@ void File::PutByte(byte Byte)
|
||||
bool File::Truncate()
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
return SetEndOfFile(hFile)==TRUE;
|
||||
return SetEndOfFile(hFile)!=FALSE;
|
||||
#else
|
||||
return ftruncate(GetFD(),(off_t)Tell())==0;
|
||||
#endif
|
||||
@@ -617,8 +678,10 @@ void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
// Workaround for OpenIndiana NAS time bug. If we cannot create a file
|
||||
// in write only mode, we need to flush the write buffer before calling
|
||||
// SetFileTime or file time will not be changed.
|
||||
if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
|
||||
FlushFileBuffers(hFile);
|
||||
// 2025.09.03: Removed this code as likely redundant now,
|
||||
// see https://www.illumos.org/issues/2000
|
||||
// if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0)
|
||||
// FlushFileBuffers(hFile);
|
||||
|
||||
bool sm=ftm!=NULL && ftm->IsSet();
|
||||
bool sc=ftc!=NULL && ftc->IsSet();
|
||||
@@ -649,15 +712,15 @@ void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
|
||||
}
|
||||
|
||||
|
||||
void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
||||
void File::SetCloseFileTimeByName(const std::wstring &Name,RarTime *ftm,RarTime *fta)
|
||||
{
|
||||
#ifdef _UNIX
|
||||
bool setm=ftm!=NULL && ftm->IsSet();
|
||||
bool seta=fta!=NULL && fta->IsSet();
|
||||
if (setm || seta)
|
||||
{
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
|
||||
#ifdef UNIX_TIME_NS
|
||||
timespec times[2];
|
||||
@@ -665,7 +728,7 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
||||
times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
|
||||
times[1].tv_sec=setm ? ftm->GetUnix() : 0;
|
||||
times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
|
||||
utimensat(AT_FDCWD,NameA,times,0);
|
||||
utimensat(AT_FDCWD,NameA.c_str(),times,0);
|
||||
#else
|
||||
utimbuf ut;
|
||||
if (setm)
|
||||
@@ -676,24 +739,47 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
|
||||
ut.actime=fta->GetUnix();
|
||||
else
|
||||
ut.actime=ut.modtime; // Need to set something, cannot left it 0.
|
||||
utime(NameA,&ut);
|
||||
utime(NameA.c_str(),&ut);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void File::GetOpenFileTime(RarTime *ft)
|
||||
#ifdef _UNIX
|
||||
void File::StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
{
|
||||
#ifdef UNIX_TIME_NS
|
||||
#if defined(_APPLE)
|
||||
if (ftm!=NULL) ftm->SetUnixNS(st.st_mtimespec.tv_sec*(uint64)1000000000+st.st_mtimespec.tv_nsec);
|
||||
if (ftc!=NULL) ftc->SetUnixNS(st.st_ctimespec.tv_sec*(uint64)1000000000+st.st_ctimespec.tv_nsec);
|
||||
if (fta!=NULL) fta->SetUnixNS(st.st_atimespec.tv_sec*(uint64)1000000000+st.st_atimespec.tv_nsec);
|
||||
#else
|
||||
if (ftm!=NULL) ftm->SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
|
||||
if (ftc!=NULL) ftc->SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
|
||||
if (fta!=NULL) fta->SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
|
||||
#endif
|
||||
#else
|
||||
if (ftm!=NULL) ftm->SetUnix(st.st_mtime);
|
||||
if (ftc!=NULL) ftc->SetUnix(st.st_ctime);
|
||||
if (fta!=NULL) fta->SetUnix(st.st_atime);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void File::GetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
FILETIME FileTime;
|
||||
GetFileTime(hFile,NULL,NULL,&FileTime);
|
||||
ft->SetWinFT(&FileTime);
|
||||
#endif
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
FILETIME ctime,atime,mtime;
|
||||
GetFileTime(hFile,&ctime,&atime,&mtime);
|
||||
if (ftm!=NULL) ftm->SetWinFT(&mtime);
|
||||
if (ftc!=NULL) ftc->SetWinFT(&ctime);
|
||||
if (fta!=NULL) fta->SetWinFT(&atime);
|
||||
#elif defined(_UNIX)
|
||||
struct stat st;
|
||||
fstat(GetFD(),&st);
|
||||
ft->SetUnix(st.st_mtime);
|
||||
StatToRarTime(st,ftm,ftc,fta);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -724,15 +810,23 @@ bool File::IsDevice()
|
||||
#ifndef SFX_MODULE
|
||||
int64 File::Copy(File &Dest,int64 Length)
|
||||
{
|
||||
Array<byte> Buffer(File::CopyBufferSize());
|
||||
int64 CopySize=0;
|
||||
bool CopyAll=(Length==INT64NDF);
|
||||
|
||||
// Adjust the buffer size to data size. So we do not waste too much time
|
||||
// to vector initialization when copying many small data blocks like
|
||||
// when updating an archive with many small files.
|
||||
size_t BufSize=File::CopyBufferSize();
|
||||
if (!CopyAll && Length<(int64)BufSize)
|
||||
BufSize=(size_t)Length;
|
||||
|
||||
std::vector<byte> Buffer(BufSize);
|
||||
int64 CopySize=0;
|
||||
|
||||
while (CopyAll || Length>0)
|
||||
{
|
||||
Wait();
|
||||
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
|
||||
byte *Buf=&Buffer[0];
|
||||
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.size()) ? (size_t)Length:Buffer.size();
|
||||
byte *Buf=Buffer.data();
|
||||
int ReadSize=Read(Buf,SizeToRead);
|
||||
if (ReadSize==0)
|
||||
break;
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#define FILE_BAD_HANDLE NULL
|
||||
#endif
|
||||
|
||||
class RAROptions;
|
||||
|
||||
enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD};
|
||||
|
||||
enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR};
|
||||
@@ -43,7 +41,7 @@ enum FILE_MODE_FLAGS {
|
||||
FMF_STANDARDNAMES=32,
|
||||
|
||||
// Mode flags are not defined yet.
|
||||
FMF_UNDEFINED=256
|
||||
// FMF_UNDEFINED=256
|
||||
};
|
||||
|
||||
enum FILE_READ_ERROR_MODE {
|
||||
@@ -59,21 +57,32 @@ class File
|
||||
FileHandle hFile;
|
||||
bool LastWrite;
|
||||
FILE_HANDLETYPE HandleType;
|
||||
|
||||
// If we read the user input in console prompts from stdin, we shall
|
||||
// process the available line immediately, not waiting for rest of data.
|
||||
// Otherwise apps piping user responses to multiple Ask() prompts can
|
||||
// hang if no more data is available yet and pipe isn't closed.
|
||||
// If we read RAR archive or other file data from stdin, we shall collect
|
||||
// the entire requested block as long as pipe isn't closed, so we get
|
||||
// complete archive headers, not split between different reads.
|
||||
bool LineInput;
|
||||
|
||||
bool SkipClose;
|
||||
FILE_READ_ERROR_MODE ReadErrorMode;
|
||||
bool NewFile;
|
||||
bool AllowDelete;
|
||||
bool AllowExceptions;
|
||||
#ifdef _WIN_ALL
|
||||
bool NoSequentialRead;
|
||||
uint CreateMode;
|
||||
// uint CreateMode;
|
||||
#endif
|
||||
bool PreserveAtime;
|
||||
bool TruncatedAfterReadError;
|
||||
|
||||
int64 CurFilePos; // Used for forward seeks in stdin files.
|
||||
protected:
|
||||
bool OpenShared; // Set by 'Archive' class.
|
||||
public:
|
||||
wchar FileName[NM];
|
||||
std::wstring FileName;
|
||||
|
||||
FILE_ERRORTYPE ErrorType;
|
||||
public:
|
||||
@@ -83,15 +92,15 @@ class File
|
||||
|
||||
// Several functions below are 'virtual', because they are redefined
|
||||
// by Archive for QOpen and by MultiFile for split files in WinRAR.
|
||||
virtual bool Open(const wchar *Name,uint Mode=FMF_READ);
|
||||
void TOpen(const wchar *Name);
|
||||
bool WOpen(const wchar *Name);
|
||||
bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
virtual bool Open(const std::wstring &Name,uint Mode=FMF_READ);
|
||||
void TOpen(const std::wstring &Name);
|
||||
bool WOpen(const std::wstring &Name);
|
||||
bool Create(const std::wstring &Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
void TCreate(const std::wstring &Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
bool WCreate(const std::wstring &Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
|
||||
virtual bool Close(); // 'virtual' for MultiFile class.
|
||||
bool Delete();
|
||||
bool Rename(const wchar *NewName);
|
||||
bool Rename(const std::wstring &NewName);
|
||||
bool Write(const void *Data,size_t Size);
|
||||
virtual int Read(void *Data,size_t Size);
|
||||
int DirectRead(void *Data,size_t Size);
|
||||
@@ -105,12 +114,17 @@ class File
|
||||
void Flush();
|
||||
void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
|
||||
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
|
||||
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
|
||||
void GetOpenFileTime(RarTime *ft);
|
||||
static void SetCloseFileTimeByName(const std::wstring &Name,RarTime *ftm,RarTime *fta);
|
||||
#ifdef _UNIX
|
||||
static void StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta);
|
||||
#endif
|
||||
void GetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
|
||||
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
|
||||
int64 FileLength();
|
||||
virtual int64 FileLength(); // 'virtual' for MultiFile class.
|
||||
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
|
||||
void SetLineInputMode(bool Mode) {LineInput=Mode;}
|
||||
FILE_HANDLETYPE GetHandleType() {return HandleType;}
|
||||
bool IsSeekable() {return HandleType!=FILE_HANDLESTD;}
|
||||
bool IsDevice();
|
||||
static bool RemoveCreated();
|
||||
FileHandle GetHandle() {return hFile;}
|
||||
@@ -119,9 +133,6 @@ class File
|
||||
int64 Copy(File &Dest,int64 Length=INT64NDF);
|
||||
void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
|
||||
void SetExceptions(bool Allow) {AllowExceptions=Allow;}
|
||||
#ifdef _WIN_ALL
|
||||
void RemoveSequentialFlag() {NoSequentialRead=true;}
|
||||
#endif
|
||||
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
|
||||
bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;}
|
||||
#ifdef _UNIX
|
||||
@@ -136,14 +147,9 @@ class File
|
||||
#endif
|
||||
static size_t CopyBufferSize()
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// USB flash performance is poor with 64 KB buffer, 256+ KB resolved it.
|
||||
// For copying from HDD to same HDD the best performance was with 256 KB
|
||||
// buffer in XP and with 1 MB buffer in Win10.
|
||||
return WinNT()==WNT_WXP ? 0x40000:0x100000;
|
||||
#else
|
||||
return 0x100000;
|
||||
#endif
|
||||
// Values in 0x100000 - 0x400000 range are ok, but multithreaded CRC32
|
||||
// seems to benefit from 0x400000, especially on ARM CPUs.
|
||||
return 0x400000;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
370
unrar/filefn.cpp
370
unrar/filefn.cpp
@@ -1,18 +1,18 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
|
||||
MKDIR_CODE MakeDir(const std::wstring &Name,bool SetAttr,uint Attr)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// Windows automatically removes dots and spaces in the end of directory
|
||||
// name. So we detect such names and process them with \\?\ prefix.
|
||||
wchar *LastChar=PointToLastChar(Name);
|
||||
bool Special=*LastChar=='.' || *LastChar==' ';
|
||||
BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL);
|
||||
wchar LastChar=GetLastChar(Name);
|
||||
bool Special=LastChar=='.' || LastChar==' ';
|
||||
BOOL RetCode=Special ? FALSE : CreateDirectory(Name.c_str(),NULL);
|
||||
if (RetCode==0 && !FileExist(Name))
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
RetCode=CreateDirectory(LongName,NULL);
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
RetCode=CreateDirectory(LongName.c_str(),NULL);
|
||||
}
|
||||
if (RetCode!=0) // Non-zero return code means success for CreateDirectory.
|
||||
{
|
||||
@@ -25,10 +25,10 @@ MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
|
||||
return MKDIR_BADPATH;
|
||||
return MKDIR_ERROR;
|
||||
#elif defined(_UNIX)
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
mode_t uattr=SetAttr ? (mode_t)Attr:0777;
|
||||
int ErrCode=mkdir(NameA,uattr);
|
||||
int ErrCode=mkdir(NameA.c_str(),uattr);
|
||||
if (ErrCode==-1)
|
||||
return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR;
|
||||
return MKDIR_SUCCESS;
|
||||
@@ -38,12 +38,19 @@ MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
|
||||
}
|
||||
|
||||
|
||||
bool CreatePath(const wchar *Path,bool SkipLastName)
|
||||
// Simplified version of MakeDir().
|
||||
bool CreateDir(const std::wstring &Name)
|
||||
{
|
||||
if (Path==NULL || *Path==0)
|
||||
return MakeDir(Name,false,0)==MKDIR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
bool CreatePath(const std::wstring &Path,bool SkipLastName,bool Silent)
|
||||
{
|
||||
if (Path.empty())
|
||||
return false;
|
||||
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
uint DirAttr=0;
|
||||
#else
|
||||
uint DirAttr=0777;
|
||||
@@ -51,42 +58,36 @@ bool CreatePath(const wchar *Path,bool SkipLastName)
|
||||
|
||||
bool Success=true;
|
||||
|
||||
for (const wchar *s=Path;*s!=0;s++)
|
||||
for (size_t I=0;I<Path.size();I++)
|
||||
{
|
||||
wchar DirName[NM];
|
||||
if (s-Path>=ASIZE(DirName))
|
||||
break;
|
||||
|
||||
// Process all kinds of path separators, so user can enter Unix style
|
||||
// path in Windows or Windows in Unix. s>Path check avoids attempting
|
||||
// path in Windows or Windows in Unix. I>0 check avoids attempting
|
||||
// creating an empty directory for paths starting from path separator.
|
||||
if (IsPathDiv(*s) && s>Path)
|
||||
if (IsPathDiv(Path[I]) && I>0)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// We must not attempt to create "D:" directory, because first
|
||||
// CreateDirectory will fail, so we'll use \\?\D:, which forces Wine
|
||||
// to create "D:" directory.
|
||||
if (s==Path+2 && Path[1]==':')
|
||||
if (I==2 && Path[1]==':')
|
||||
continue;
|
||||
#endif
|
||||
wcsncpy(DirName,Path,s-Path);
|
||||
DirName[s-Path]=0;
|
||||
|
||||
std::wstring DirName=Path.substr(0,I);
|
||||
Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
|
||||
if (Success)
|
||||
if (Success && !Silent)
|
||||
{
|
||||
mprintf(St(MCreatDir),DirName);
|
||||
mprintf(St(MCreatDir),DirName.c_str());
|
||||
mprintf(L" %s",St(MOk));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path)))
|
||||
if (!SkipLastName && !IsPathDiv(GetLastChar(Path)))
|
||||
Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS;
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
void SetDirTime(const std::wstring &Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
{
|
||||
#if defined(_WIN_ALL)
|
||||
bool sm=ftm!=NULL && ftm->IsSet();
|
||||
@@ -98,13 +99,13 @@ void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
if (ResetAttr)
|
||||
SetFileAttr(Name,0);
|
||||
|
||||
HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
HANDLE hFile=CreateFile(Name.c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
hFile=CreateFile(LongName.c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
||||
}
|
||||
|
||||
@@ -122,18 +123,20 @@ void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
|
||||
if (ResetAttr)
|
||||
SetFileAttr(Name,DirAttr);
|
||||
#endif
|
||||
#if defined(_UNIX) || defined(_EMX)
|
||||
#ifdef _UNIX
|
||||
File::SetCloseFileTimeByName(Name,ftm,fta);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool IsRemovable(const wchar *Name)
|
||||
|
||||
|
||||
bool IsRemovable(const std::wstring &Name)
|
||||
{
|
||||
#if defined(_WIN_ALL)
|
||||
wchar Root[NM];
|
||||
GetPathRoot(Name,Root,ASIZE(Root));
|
||||
int Type=GetDriveType(*Root!=0 ? Root:NULL);
|
||||
std::wstring Root;
|
||||
GetPathRoot(Name,Root);
|
||||
int Type=GetDriveType(Root.empty() ? nullptr : Root.c_str());
|
||||
return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM;
|
||||
#else
|
||||
return false;
|
||||
@@ -142,25 +145,25 @@ bool IsRemovable(const wchar *Name)
|
||||
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
int64 GetFreeDisk(const wchar *Name)
|
||||
int64 GetFreeDisk(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
wchar Root[NM];
|
||||
GetFilePath(Name,Root,ASIZE(Root));
|
||||
std::wstring Root;
|
||||
GetPathWithSep(Name,Root);
|
||||
|
||||
ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
|
||||
uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
|
||||
if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
|
||||
if (GetDiskFreeSpaceEx(Root.empty() ? NULL:Root.c_str(),&uiUserFree,&uiTotalSize,&uiTotalFree) &&
|
||||
uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
|
||||
return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart);
|
||||
return 0;
|
||||
#elif defined(_UNIX)
|
||||
wchar Root[NM];
|
||||
GetFilePath(Name,Root,ASIZE(Root));
|
||||
char RootA[NM];
|
||||
WideToChar(Root,RootA,ASIZE(RootA));
|
||||
std::wstring Root;
|
||||
GetPathWithSep(Name,Root);
|
||||
std::string RootA;
|
||||
WideToChar(Root,RootA);
|
||||
struct statvfs sfs;
|
||||
if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0)
|
||||
if (statvfs(RootA.empty() ? ".":RootA.c_str(),&sfs)!=0)
|
||||
return 0;
|
||||
int64 FreeSize=sfs.f_bsize;
|
||||
FreeSize=FreeSize*sfs.f_bavail;
|
||||
@@ -175,26 +178,27 @@ int64 GetFreeDisk(const wchar *Name)
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
|
||||
// Return 'true' for FAT and FAT32, so we can adjust the maximum supported
|
||||
// file size to 4 GB for these file systems.
|
||||
bool IsFAT(const wchar *Name)
|
||||
bool IsFAT(const std::wstring &Name)
|
||||
{
|
||||
wchar Root[NM];
|
||||
GetPathRoot(Name,Root,ASIZE(Root));
|
||||
std::wstring Root;
|
||||
GetPathRoot(Name,Root);
|
||||
wchar FileSystem[MAX_PATH+1];
|
||||
if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
|
||||
// Root can be empty, when we create volumes with -v in the current folder.
|
||||
if (GetVolumeInformation(Root.empty() ? NULL:Root.c_str(),NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem)))
|
||||
return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool FileExist(const wchar *Name)
|
||||
bool FileExist(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
return GetFileAttr(Name)!=0xffffffff;
|
||||
#elif defined(ENABLE_ACCESS)
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
return access(NameA,0)==0;
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
return access(NameA.c_str(),0)==0;
|
||||
#else
|
||||
FindData FD;
|
||||
return FindFile::FastFind(Name,&FD);
|
||||
@@ -202,7 +206,7 @@ bool FileExist(const wchar *Name)
|
||||
}
|
||||
|
||||
|
||||
bool WildFileExist(const wchar *Name)
|
||||
bool WildFileExist(const std::wstring &Name)
|
||||
{
|
||||
if (IsWildcard(Name))
|
||||
{
|
||||
@@ -230,8 +234,9 @@ bool IsUnreadable(uint Attr)
|
||||
{
|
||||
#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR)
|
||||
return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr);
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -261,70 +266,66 @@ bool IsDeleteAllowed(uint FileAttr)
|
||||
}
|
||||
|
||||
|
||||
void PrepareToDelete(const wchar *Name)
|
||||
void PrepareToDelete(const std::wstring &Name)
|
||||
{
|
||||
#if defined(_WIN_ALL) || defined(_EMX)
|
||||
#ifdef _WIN_ALL
|
||||
SetFileAttr(Name,0);
|
||||
#endif
|
||||
#ifdef _UNIX
|
||||
if (Name!=NULL)
|
||||
{
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR);
|
||||
}
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
chmod(NameA.c_str(),S_IRUSR|S_IWUSR|S_IXUSR);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint GetFileAttr(const wchar *Name)
|
||||
uint GetFileAttr(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
DWORD Attr=GetFileAttributes(Name);
|
||||
DWORD Attr=GetFileAttributes(Name.c_str());
|
||||
if (Attr==0xffffffff)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
Attr=GetFileAttributes(LongName);
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Attr=GetFileAttributes(LongName.c_str());
|
||||
}
|
||||
return Attr;
|
||||
#else
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
struct stat st;
|
||||
if (stat(NameA,&st)!=0)
|
||||
if (stat(NameA.c_str(),&st)!=0)
|
||||
return 0;
|
||||
return st.st_mode;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool SetFileAttr(const wchar *Name,uint Attr)
|
||||
bool SetFileAttr(const std::wstring &Name,uint Attr)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=SetFileAttributes(Name,Attr)!=0;
|
||||
bool Success=SetFileAttributes(Name.c_str(),Attr)!=0;
|
||||
if (!Success)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
Success=SetFileAttributes(LongName,Attr)!=0;
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Success=SetFileAttributes(LongName.c_str(),Attr)!=0;
|
||||
}
|
||||
return Success;
|
||||
#elif defined(_UNIX)
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
return chmod(NameA,(mode_t)Attr)==0;
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
return chmod(NameA.c_str(),(mode_t)Attr)==0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
wchar *MkTemp(wchar *Name,size_t MaxSize)
|
||||
// Ext is the extension with the leading dot, like L".bat", or nullptr to use
|
||||
// the default extension.
|
||||
bool MkTemp(std::wstring &Name,const wchar *Ext)
|
||||
{
|
||||
size_t Length=wcslen(Name);
|
||||
|
||||
RarTime CurTime;
|
||||
CurTime.SetCurrentTime();
|
||||
|
||||
@@ -343,18 +344,28 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
|
||||
|
||||
for (uint Attempt=0;;Attempt++)
|
||||
{
|
||||
uint Ext=Random%50000+Attempt;
|
||||
wchar RndText[50];
|
||||
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
|
||||
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
|
||||
return NULL;
|
||||
wcsncpyz(Name+Length,RndText,MaxSize-Length);
|
||||
if (!FileExist(Name))
|
||||
uint RandomExt=Random%50000+Attempt;
|
||||
if (Attempt==1000)
|
||||
return false;
|
||||
|
||||
// User asked to specify the single extension for all temporary files,
|
||||
// so it can be added to server ransomware protection exceptions.
|
||||
// He wrote, this protection blocks temporary files when adding
|
||||
// a file to RAR archive with drag and drop. So unless a calling code
|
||||
// requires a specific extension, like .bat file when uninstalling,
|
||||
// we set the uniform extension here.
|
||||
if (Ext==nullptr)
|
||||
Ext=L".rartemp";
|
||||
|
||||
std::wstring NewName=Name + std::to_wstring(PID) + L"." + std::to_wstring(RandomExt) + Ext;
|
||||
if (!FileExist(NewName))
|
||||
{
|
||||
Name=NewName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Name;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(SFX_MODULE)
|
||||
@@ -372,8 +383,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
SrcFile->Seek(0,SEEK_SET);
|
||||
|
||||
const size_t BufSize=0x100000;
|
||||
Array<byte> Data(BufSize);
|
||||
|
||||
std::vector<byte> Data(BufSize);
|
||||
|
||||
DataHash HashCRC,HashBlake2;
|
||||
HashCRC.Init(HASH_CRC32,Threads);
|
||||
@@ -388,7 +398,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
SizeToRead=BufSize; // Then always attempt to read the entire buffer.
|
||||
else
|
||||
SizeToRead=(size_t)Min((int64)BufSize,Size);
|
||||
int ReadSize=SrcFile->Read(&Data[0],SizeToRead);
|
||||
int ReadSize=SrcFile->Read(Data.data(),SizeToRead);
|
||||
if (ReadSize==0)
|
||||
break;
|
||||
TotalRead+=ReadSize;
|
||||
@@ -397,7 +407,11 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
{
|
||||
#ifndef SILENT
|
||||
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
|
||||
uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength);
|
||||
{
|
||||
// Update only the current file progress in WinRAR, set the total to 0
|
||||
// to keep it as is. It looks better for WinRAR.
|
||||
uiExtractProgress(TotalRead,FileLength,0,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
|
||||
@@ -408,9 +422,9 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
}
|
||||
|
||||
if (CRC32!=NULL)
|
||||
HashCRC.Update(&Data[0],ReadSize);
|
||||
HashCRC.Update(Data.data(),ReadSize);
|
||||
if (Blake2!=NULL)
|
||||
HashBlake2.Update(&Data[0],ReadSize);
|
||||
HashBlake2.Update(Data.data(),ReadSize);
|
||||
|
||||
if (Size!=INT64NDF)
|
||||
Size-=ReadSize;
|
||||
@@ -432,73 +446,109 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
|
||||
#endif
|
||||
|
||||
|
||||
bool RenameFile(const wchar *SrcName,const wchar *DestName)
|
||||
bool RenameFile(const std::wstring &SrcName,const std::wstring &DestName)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=MoveFile(SrcName,DestName)!=0;
|
||||
bool Success=MoveFile(SrcName.c_str(),DestName.c_str())!=0;
|
||||
if (!Success)
|
||||
{
|
||||
wchar LongName1[NM],LongName2[NM];
|
||||
if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) &&
|
||||
GetWinLongPath(DestName,LongName2,ASIZE(LongName2)))
|
||||
Success=MoveFile(LongName1,LongName2)!=0;
|
||||
std::wstring LongName1,LongName2;
|
||||
if (GetWinLongPath(SrcName,LongName1) && GetWinLongPath(DestName,LongName2))
|
||||
Success=MoveFile(LongName1.c_str(),LongName2.c_str())!=0;
|
||||
}
|
||||
return Success;
|
||||
#else
|
||||
char SrcNameA[NM],DestNameA[NM];
|
||||
WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA));
|
||||
WideToChar(DestName,DestNameA,ASIZE(DestNameA));
|
||||
bool Success=rename(SrcNameA,DestNameA)==0;
|
||||
std::string SrcNameA,DestNameA;
|
||||
WideToChar(SrcName,SrcNameA);
|
||||
WideToChar(DestName,DestNameA);
|
||||
bool Success=rename(SrcNameA.c_str(),DestNameA.c_str())==0;
|
||||
return Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool DelFile(const wchar *Name)
|
||||
bool DelFile(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=DeleteFile(Name)!=0;
|
||||
bool Success=DeleteFile(Name.c_str())!=0;
|
||||
if (!Success)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
Success=DeleteFile(LongName)!=0;
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Success=DeleteFile(LongName.c_str())!=0;
|
||||
}
|
||||
return Success;
|
||||
#else
|
||||
char NameA[NM];
|
||||
WideToChar(Name,NameA,ASIZE(NameA));
|
||||
bool Success=remove(NameA)==0;
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
bool Success=remove(NameA.c_str())==0;
|
||||
return Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool DelDir(const std::wstring &Name)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
bool Success=RemoveDirectory(Name.c_str())!=0;
|
||||
if (!Success)
|
||||
{
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
Success=RemoveDirectory(LongName.c_str())!=0;
|
||||
}
|
||||
return Success;
|
||||
#else
|
||||
std::string NameA;
|
||||
WideToChar(Name,NameA);
|
||||
bool Success=rmdir(NameA.c_str())==0;
|
||||
return Success;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
bool SetFileCompression(const wchar *Name,bool State)
|
||||
bool SetFileCompression(const std::wstring &Name,bool State)
|
||||
{
|
||||
HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
HANDLE hFile=CreateFile(Name.c_str(),FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wchar LongName[NM];
|
||||
if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
|
||||
hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
std::wstring LongName;
|
||||
if (GetWinLongPath(Name,LongName))
|
||||
hFile=CreateFile(LongName.c_str(),FILE_READ_DATA|FILE_WRITE_DATA,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
if (hFile==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
bool Success=SetFileCompression(hFile,State);
|
||||
CloseHandle(hFile);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
bool SetFileCompression(HANDLE hFile,bool State)
|
||||
{
|
||||
SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE;
|
||||
DWORD Result;
|
||||
int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState,
|
||||
sizeof(NewState),NULL,0,&Result,NULL);
|
||||
CloseHandle(hFile);
|
||||
return RetCode!=0;
|
||||
}
|
||||
|
||||
|
||||
void ResetFileCache(const std::wstring &Name)
|
||||
{
|
||||
// To reset file cache in Windows it is enough to open it with
|
||||
// FILE_FLAG_NO_BUFFERING and then close it.
|
||||
HANDLE hSrc=CreateFile(Name.c_str(),GENERIC_READ,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,NULL);
|
||||
if (hSrc!=INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hSrc);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -509,3 +559,73 @@ bool SetFileCompression(const wchar *Name,bool State)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Delete symbolic links in file path, if any, and replace them by directories.
|
||||
// Prevents extracting files outside of destination folder with symlink chains.
|
||||
bool LinksToDirs(const std::wstring &SrcName,const std::wstring &SkipPart,std::wstring &LastChecked)
|
||||
{
|
||||
// Unlike Unix, Windows doesn't expand lnk1 in symlink targets like
|
||||
// "lnk1/../dir", but converts the path to "dir". In Unix we need to call
|
||||
// this function to prevent placing unpacked files outside of destination
|
||||
// folder if previously we unpacked "dir/lnk1" -> "..",
|
||||
// "dir/lnk2" -> "lnk1/.." and "dir/lnk2/anypath/poc.txt".
|
||||
// We may still need this function to prevent abusing symlink chains
|
||||
// in link source path if we remove detection of such chains
|
||||
// in IsRelativeSymlinkSafe. This function seems to make other symlink
|
||||
// related safety checks redundant, but for now we prefer to keep them too.
|
||||
//
|
||||
// 2022.12.01: the performance impact is minimized after adding the check
|
||||
// against the previous path and enabling this verification only after
|
||||
// extracting a symlink with ".." in target. So we enabled it for Windows
|
||||
// as well for extra safety.
|
||||
//#ifdef _UNIX
|
||||
std::wstring Path=SrcName;
|
||||
|
||||
size_t SkipLength=SkipPart.size();
|
||||
|
||||
if (SkipLength>0 && !starts_with(Path,SkipPart))
|
||||
SkipLength=0; // Parameter validation, not really needed now.
|
||||
|
||||
// Do not check parts already checked in previous path to improve performance.
|
||||
for (size_t I=0;I<Path.size() && I<LastChecked.size() && Path[I]==LastChecked[I];I++)
|
||||
if (IsPathDiv(Path[I]) && I>SkipLength)
|
||||
SkipLength=I;
|
||||
|
||||
// Avoid converting symlinks in destination path part specified by user.
|
||||
while (SkipLength<Path.size() && IsPathDiv(Path[SkipLength]))
|
||||
SkipLength++;
|
||||
|
||||
if (Path.size()>0)
|
||||
for (size_t I=Path.size()-1;I>SkipLength;I--)
|
||||
if (IsPathDiv(Path[I]))
|
||||
{
|
||||
Path.erase(I);
|
||||
FindData FD;
|
||||
if (FindFile::FastFind(Path,&FD,true) && FD.IsLink)
|
||||
{
|
||||
#ifdef _WIN_ALL
|
||||
// Normally Windows symlinks to directory look like a directory
|
||||
// and are deleted with DelDir(). It is possible to create
|
||||
// a file-like symlink pointing at directory, which can be deleted
|
||||
// only with && DelFile, but such symlink isn't really functional.
|
||||
// Here we prefer to fail deleting such symlink and skip extracting
|
||||
// a file.
|
||||
if (!DelDir(Path))
|
||||
#else
|
||||
if (!DelFile(Path))
|
||||
#endif
|
||||
{
|
||||
ErrHandler.CreateErrorMsg(SrcName); // Extraction command will skip this file or directory.
|
||||
return false; // Couldn't delete the symlink to replace it with directory.
|
||||
}
|
||||
}
|
||||
}
|
||||
LastChecked=SrcName;
|
||||
//#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,48 +3,55 @@
|
||||
|
||||
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
|
||||
|
||||
MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr);
|
||||
bool CreatePath(const wchar *Path,bool SkipLastName);
|
||||
void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
|
||||
bool IsRemovable(const wchar *Name);
|
||||
MKDIR_CODE MakeDir(const std::wstring &Name,bool SetAttr,uint Attr);
|
||||
bool CreateDir(const std::wstring &Name);
|
||||
bool CreatePath(const std::wstring &Path,bool SkipLastName,bool Silent);
|
||||
|
||||
void SetDirTime(const std::wstring &Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
|
||||
|
||||
|
||||
bool IsRemovable(const std::wstring &Name);
|
||||
|
||||
#ifndef SFX_MODULE
|
||||
int64 GetFreeDisk(const wchar *Name);
|
||||
int64 GetFreeDisk(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
|
||||
bool IsFAT(const wchar *Root);
|
||||
bool IsFAT(const std::wstring &Root);
|
||||
#endif
|
||||
|
||||
bool FileExist(const wchar *Name);
|
||||
bool WildFileExist(const wchar *Name);
|
||||
bool FileExist(const std::wstring &Name);
|
||||
bool WildFileExist(const std::wstring &Name);
|
||||
bool IsDir(uint Attr);
|
||||
bool IsUnreadable(uint Attr);
|
||||
bool IsLink(uint Attr);
|
||||
void SetSFXMode(const wchar *FileName);
|
||||
void EraseDiskContents(const wchar *FileName);
|
||||
void SetSFXMode(const std::wstring &FileName);
|
||||
void EraseDiskContents(const std::wstring &FileName);
|
||||
bool IsDeleteAllowed(uint FileAttr);
|
||||
void PrepareToDelete(const wchar *Name);
|
||||
uint GetFileAttr(const wchar *Name);
|
||||
bool SetFileAttr(const wchar *Name,uint Attr);
|
||||
#if 0
|
||||
wchar* MkTemp(wchar *Name,size_t MaxSize);
|
||||
#endif
|
||||
void PrepareToDelete(const std::wstring &Name);
|
||||
uint GetFileAttr(const std::wstring &Name);
|
||||
bool SetFileAttr(const std::wstring &Name,uint Attr);
|
||||
bool MkTemp(std::wstring &Name,const wchar *Ext);
|
||||
|
||||
enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8};
|
||||
|
||||
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0);
|
||||
|
||||
bool RenameFile(const wchar *SrcName,const wchar *DestName);
|
||||
bool DelFile(const wchar *Name);
|
||||
bool DelDir(const wchar *Name);
|
||||
bool RenameFile(const std::wstring &SrcName,const std::wstring &DestName);
|
||||
bool DelFile(const std::wstring &Name);
|
||||
bool DelDir(const std::wstring &Name);
|
||||
|
||||
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
|
||||
bool SetFileCompression(const wchar *Name,bool State);
|
||||
bool SetFileCompression(const std::wstring &Name,bool State);
|
||||
bool SetFileCompression(HANDLE hFile,bool State);
|
||||
void ResetFileCache(const std::wstring &Name);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Keep it here and not in extinfo.cpp, because it is invoked from Zip.SFX too.
|
||||
bool LinksToDirs(const std::wstring &SrcName,const std::wstring &SkipPart,std::wstring &LastChecked);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "rar.hpp"
|
||||
|
||||
bool ReadTextFile(
|
||||
const wchar *Name,
|
||||
const std::wstring &Name,
|
||||
StringList *List,
|
||||
bool Config,
|
||||
bool AbortOnError,
|
||||
@@ -10,17 +10,15 @@ bool ReadTextFile(
|
||||
bool SkipComments,
|
||||
bool ExpandEnvStr)
|
||||
{
|
||||
wchar FileName[NM];
|
||||
*FileName=0;
|
||||
std::wstring FileName;
|
||||
|
||||
if (Name!=NULL)
|
||||
if (Config)
|
||||
GetConfigName(Name,FileName,ASIZE(FileName),true,false);
|
||||
else
|
||||
wcsncpyz(FileName,Name,ASIZE(FileName));
|
||||
if (Config)
|
||||
GetConfigName(Name,FileName,true,false);
|
||||
else
|
||||
FileName=Name;
|
||||
|
||||
File SrcFile;
|
||||
if (*FileName!=0)
|
||||
if (!FileName.empty())
|
||||
{
|
||||
bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0);
|
||||
|
||||
@@ -34,36 +32,36 @@ bool ReadTextFile(
|
||||
else
|
||||
SrcFile.SetHandleType(FILE_HANDLESTD);
|
||||
|
||||
uint DataSize=0,ReadSize;
|
||||
size_t DataSize=0,ReadSize;
|
||||
const int ReadBlock=4096;
|
||||
|
||||
Array<byte> Data(ReadBlock);
|
||||
std::vector<byte> Data(ReadBlock);
|
||||
while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0)
|
||||
{
|
||||
DataSize+=ReadSize;
|
||||
Data.Add(ReadSize); // Always have ReadBlock available for next data.
|
||||
Data.resize(DataSize+ReadBlock); // Always have ReadBlock available for next data.
|
||||
}
|
||||
// Set to really read size, so we can zero terminate it correctly.
|
||||
Data.Alloc(DataSize);
|
||||
Data.resize(DataSize);
|
||||
|
||||
int LittleEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
|
||||
int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0;
|
||||
bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf;
|
||||
|
||||
if (SrcCharset==RCH_DEFAULT)
|
||||
SrcCharset=DetectTextEncoding(&Data[0],DataSize);
|
||||
SrcCharset=DetectTextEncoding(Data.data(),DataSize);
|
||||
|
||||
Array<wchar> DataW;
|
||||
std::vector<wchar> DataW(ReadBlock);
|
||||
|
||||
if (SrcCharset==RCH_DEFAULT || SrcCharset==RCH_OEM || SrcCharset==RCH_ANSI)
|
||||
{
|
||||
Data.Push(0); // Zero terminate.
|
||||
Data.push_back(0); // Zero terminate.
|
||||
#if defined(_WIN_ALL)
|
||||
if (SrcCharset==RCH_OEM)
|
||||
OemToCharA((char *)&Data[0],(char *)&Data[0]);
|
||||
OemToCharA((char *)Data.data(),(char *)Data.data());
|
||||
#endif
|
||||
DataW.Alloc(Data.Size());
|
||||
CharToWide((char *)&Data[0],&DataW[0],DataW.Size());
|
||||
DataW.resize(Data.size());
|
||||
CharToWide((char *)Data.data(),DataW.data(),DataW.size());
|
||||
}
|
||||
|
||||
if (SrcCharset==RCH_UNICODE)
|
||||
@@ -75,8 +73,8 @@ bool ReadTextFile(
|
||||
LittleEndian=1;
|
||||
}
|
||||
|
||||
DataW.Alloc(Data.Size()/2+1);
|
||||
size_t End=Data.Size() & ~1; // We need even bytes number for UTF-16.
|
||||
DataW.resize(Data.size()/2+1);
|
||||
size_t End=Data.size() & ~1; // We need even bytes number for UTF-16.
|
||||
for (size_t I=Start;I<End;I+=2)
|
||||
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LittleEndian]*256;
|
||||
DataW[(End-Start)/2]=0;
|
||||
@@ -84,12 +82,12 @@ bool ReadTextFile(
|
||||
|
||||
if (SrcCharset==RCH_UTF8)
|
||||
{
|
||||
Data.Push(0); // Zero terminate data.
|
||||
DataW.Alloc(Data.Size());
|
||||
UtfToWide((const char *)(Data+(Utf8 ? 3:0)),&DataW[0],DataW.Size());
|
||||
Data.push_back(0); // Zero terminate data.
|
||||
DataW.resize(Data.size());
|
||||
UtfToWide((const char *)(Data.data()+(Utf8 ? 3:0)),DataW.data(),DataW.size());
|
||||
}
|
||||
|
||||
wchar *CurStr=&DataW[0];
|
||||
wchar *CurStr=DataW.data();
|
||||
|
||||
while (*CurStr!=0)
|
||||
{
|
||||
@@ -127,12 +125,11 @@ bool ReadTextFile(
|
||||
#if defined(_WIN_ALL)
|
||||
if (ExpandEnvStr && *CurStr=='%') // Expand environment variables in Windows.
|
||||
{
|
||||
wchar ExpName[NM];
|
||||
*ExpName=0;
|
||||
DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName));
|
||||
Expanded=Result!=0 && Result<ASIZE(ExpName);
|
||||
if (Expanded && *ExpName!=0)
|
||||
std::wstring ExpName=CurStr;
|
||||
ExpandEnvironmentStr(ExpName);
|
||||
if (!ExpName.empty())
|
||||
List->AddString(ExpName);
|
||||
Expanded=true;
|
||||
}
|
||||
#endif
|
||||
if (!Expanded && *CurStr!=0)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define _RAR_FILESTR_
|
||||
|
||||
bool ReadTextFile(
|
||||
const wchar *Name,
|
||||
const std::wstring &Name,
|
||||
StringList *List,
|
||||
bool Config,
|
||||
bool AbortOnError=false,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
FindFile::FindFile()
|
||||
{
|
||||
*FindMask=0;
|
||||
FirstCall=true;
|
||||
#ifdef _WIN_ALL
|
||||
hFind=INVALID_HANDLE_VALUE;
|
||||
@@ -24,9 +23,9 @@ FindFile::~FindFile()
|
||||
}
|
||||
|
||||
|
||||
void FindFile::SetMask(const wchar *Mask)
|
||||
void FindFile::SetMask(const std::wstring &Mask)
|
||||
{
|
||||
wcsncpyz(FindMask,Mask,ASIZE(FindMask));
|
||||
FindMask=Mask;
|
||||
FirstCall=true;
|
||||
}
|
||||
|
||||
@@ -34,7 +33,7 @@ void FindFile::SetMask(const wchar *Mask)
|
||||
bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
{
|
||||
fd->Error=false;
|
||||
if (*FindMask==0)
|
||||
if (FindMask.empty())
|
||||
return false;
|
||||
#ifdef _WIN_ALL
|
||||
if (FirstCall)
|
||||
@@ -48,14 +47,14 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
#else
|
||||
if (FirstCall)
|
||||
{
|
||||
wchar DirName[NM];
|
||||
wcsncpyz(DirName,FindMask,ASIZE(DirName));
|
||||
std::wstring DirName;
|
||||
DirName=FindMask;
|
||||
RemoveNameFromPath(DirName);
|
||||
if (*DirName==0)
|
||||
wcsncpyz(DirName,L".",ASIZE(DirName));
|
||||
char DirNameA[NM];
|
||||
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
|
||||
if ((dirp=opendir(DirNameA))==NULL)
|
||||
if (DirName.empty())
|
||||
DirName=L".";
|
||||
std::string DirNameA;
|
||||
WideToChar(DirName,DirNameA);
|
||||
if ((dirp=opendir(DirNameA.c_str()))==NULL)
|
||||
{
|
||||
fd->Error=(errno!=ENOENT);
|
||||
return false;
|
||||
@@ -63,32 +62,31 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
wchar Name[NM];
|
||||
std::wstring Name;
|
||||
struct dirent *ent=readdir(dirp);
|
||||
if (ent==NULL)
|
||||
return false;
|
||||
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
|
||||
continue;
|
||||
if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
|
||||
uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
|
||||
if (!CharToWide(std::string(ent->d_name),Name))
|
||||
uiMsg(UIERROR_INVALIDNAME,L"",Name);
|
||||
|
||||
if (CmpName(FindMask,Name,MATCH_NAMES))
|
||||
{
|
||||
wchar FullName[NM];
|
||||
wcsncpyz(FullName,FindMask,ASIZE(FullName));
|
||||
*PointToName(FullName)=0;
|
||||
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
|
||||
std::wstring FullName=FindMask;
|
||||
FullName.erase(GetNamePos(FullName));
|
||||
if (FullName.size()+Name.size()>=MAXPATHSIZE)
|
||||
{
|
||||
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
|
||||
return false;
|
||||
}
|
||||
wcsncatz(FullName,Name,ASIZE(FullName));
|
||||
FullName+=Name;
|
||||
if (!FastFind(FullName,fd,GetSymLink))
|
||||
{
|
||||
ErrHandler.OpenErrorMsg(FullName);
|
||||
continue;
|
||||
}
|
||||
wcsncpyz(fd->Name,FullName,ASIZE(fd->Name));
|
||||
fd->Name=FullName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -98,14 +96,14 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
|
||||
fd->IsLink=IsLink(fd->FileAttr);
|
||||
|
||||
FirstCall=false;
|
||||
wchar *NameOnly=PointToName(fd->Name);
|
||||
if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0)
|
||||
std::wstring NameOnly=PointToName(fd->Name);
|
||||
if (NameOnly==L"." || NameOnly==L"..")
|
||||
return Next(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
bool FindFile::FastFind(const std::wstring &FindMask,FindData *fd,bool GetSymLink)
|
||||
{
|
||||
fd->Error=false;
|
||||
#ifndef _UNIX
|
||||
@@ -117,17 +115,17 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
FindClose(hFind);
|
||||
#else
|
||||
char FindMaskA[NM];
|
||||
WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
|
||||
#elif defined(_UNIX)
|
||||
std::string FindMaskA;
|
||||
WideToChar(FindMask,FindMaskA);
|
||||
|
||||
struct stat st;
|
||||
if (GetSymLink)
|
||||
{
|
||||
#ifdef SAVE_LINKS
|
||||
if (lstat(FindMaskA,&st)!=0)
|
||||
if (lstat(FindMaskA.c_str(),&st)!=0)
|
||||
#else
|
||||
if (stat(FindMaskA,&st)!=0)
|
||||
if (stat(FindMaskA.c_str(),&st)!=0)
|
||||
#endif
|
||||
{
|
||||
fd->Error=(errno!=ENOENT);
|
||||
@@ -135,7 +133,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
}
|
||||
}
|
||||
else
|
||||
if (stat(FindMaskA,&st)!=0)
|
||||
if (stat(FindMaskA.c_str(),&st)!=0)
|
||||
{
|
||||
fd->Error=(errno!=ENOENT);
|
||||
return false;
|
||||
@@ -143,17 +141,9 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
fd->FileAttr=st.st_mode;
|
||||
fd->Size=st.st_size;
|
||||
|
||||
#ifdef UNIX_TIME_NS
|
||||
fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
|
||||
fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
|
||||
fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
|
||||
#else
|
||||
fd->mtime.SetUnix(st.st_mtime);
|
||||
fd->atime.SetUnix(st.st_atime);
|
||||
fd->ctime.SetUnix(st.st_ctime);
|
||||
#endif
|
||||
File::StatToRarTime(st,&fd->mtime,&fd->ctime,&fd->atime);
|
||||
|
||||
wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name));
|
||||
fd->Name=FindMask;
|
||||
#endif
|
||||
fd->Flags=0;
|
||||
fd->IsDir=IsDir(fd->FileAttr);
|
||||
@@ -164,17 +154,17 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
|
||||
|
||||
|
||||
#ifdef _WIN_ALL
|
||||
HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
|
||||
HANDLE FindFile::Win32Find(HANDLE hFind,const std::wstring &Mask,FindData *fd)
|
||||
{
|
||||
WIN32_FIND_DATA FindData;
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hFind=FindFirstFile(Mask,&FindData);
|
||||
hFind=FindFirstFile(Mask.c_str(),&FindData);
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wchar LongMask[NM];
|
||||
if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask)))
|
||||
hFind=FindFirstFile(LongMask,&FindData);
|
||||
std::wstring LongMask;
|
||||
if (GetWinLongPath(Mask,LongMask))
|
||||
hFind=FindFirstFile(LongMask.c_str(),&FindData);
|
||||
}
|
||||
if (hFind==INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@@ -198,8 +188,8 @@ HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
|
||||
|
||||
if (hFind!=INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wcsncpyz(fd->Name,Mask,ASIZE(fd->Name));
|
||||
SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name));
|
||||
fd->Name=Mask;
|
||||
SetName(fd->Name,FindData.cFileName);
|
||||
fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
|
||||
fd->FileAttr=FindData.dwFileAttributes;
|
||||
fd->ftCreationTime=FindData.ftCreationTime;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user