1 Commits

Author SHA1 Message Date
Gustavo Lopes 19bcaf064c Add badges 2017-07-21 18:47:10 +01:00
315 changed files with 7538 additions and 16780 deletions
-88
View File
@@ -1,88 +0,0 @@
---
# 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
-32
View File
@@ -1,32 +0,0 @@
# 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
ghcr.io/cataphract/php-minimal:
7.0-debug: "sha256:c1a08b9c71b30c3ed4c31bb6ca9f4c81f82f4351c5e6e0c423a8f980ce3c89ee"
7.0-release-zts: "sha256:9d9f1b1337822e1c069cf49c22f5f6b55ba806547cccbb4836e847fe8e32819a"
7.1-debug: "sha256:b670b5de5dd8d0791a86b29e336b5a7d801fbdeaeadf9148e616cf5357b9035e"
7.1-release-zts: "sha256:1f3164d4cdd57faa0911de43c4c77b7d18fdf84971db97ff2889f1a5ed8a0e5a"
7.2-debug: "sha256:7c1d2b2248a64339d8b0ae7bcbe4156fc8e3903653ce1d86347bfeacb9679c0d"
7.2-release-zts: "sha256:5e1f47179d730c22c8eada20f9cbedb034f3b97c89174ce4e6108e7d76bf7da5"
7.3-debug: "sha256:b0b4c0a57e52011469c7999b330020d4ef27628eb8ac745e7e74796c8ff8601a"
7.3-release-zts: "sha256:fe021f3979bc4c69be0d73ec74a30085915939a62f457557be91e003938d6e0a"
7.4-debug: "sha256:d2d827524eae4a7d391b5f71b33477a1affabc74f674f9680b7838c3a5154d7f"
7.4-release-zts: "sha256:6c5eacd2f493c1c07a68f451b72a62ed67ddb2406dab8e3dc82f20adc7e72bf7"
8.0-debug: "sha256:d46c15e648497cf55bb6b4806c726c58714f5b63fcb1096e4a8ec433ec17c835"
8.0-release-zts: "sha256:bcbaab72e7c0e704d7bdef01e8f91e1bc0636e6e98c0ab68cc2fc417e7a98a66"
8.1-debug: "sha256:dbdb437df0a4acbbd11e020461f7cef2f0e949f46f9ca841c5f058012ec7cc98"
8.1-release: "sha256:f401dba3b4249dc16acb90909951b88e3146dcd2e622203d95e80219258932c9"
8.1-release-zts: "sha256:2b330ce54679f29e09ea77c984cd409618142cc20cab48b5a114cc1e5b09257c"
8.2-debug: "sha256:efecf1cdbd09511aec12897a03682934243498c5bb2ba37874ae2100c1498011"
8.2-release: "sha256:e09be007096a29d64427afa99ea4d10f7e1a91a8e2129aeaa854daf045986d8f"
8.2-release-zts: "sha256:d67d1c370abdc5e629a2bec1ff4d308f0ccb7d3cbc7ecc3c7eee851cd6c2efaa"
8.3-debug: "sha256:1b8e6ba17c837a4035f6981dd38f9f447be57a3d558ca8f18071c8390a62ce6c"
8.3-release: "sha256:23abac21af8c95ccd6cd6a8b5fbb2d1dd67e122fc7630bbbfcc7b75e6a6fcc96"
8.3-release-zts: "sha256:158060357f81b495a5420b1f9d488abd61d59306946b352e4fbfc4011b7a2d89"
8.4-debug: "sha256:c863e2a60f144856f56d50ed1080bbe0377ca99760195f170c762ad46f0466e5"
8.4-release: "sha256:571251d31267c6960846727f0788f1d9a593a02adf6a68899a0582c5635d5c50"
8.4-release-zts: "sha256:6451c7104d874f8c4f7e0305e5baaecebbd74672a036c02de2cbb9d1a10c8906"
8.5-debug: "sha256:014a16949dd0da0581cda6768bd7751f66b6ada3becdc949aeb5b8e1efb3c5cf"
8.5-release: "sha256:bc58405b860c17ea5f36cbd466dc5c93b97283c148e3489ec78171d73727859c"
8.5-release-zts: "sha256:dadd96c4740bc9606f2985be51fb0b85d768132f93786c4ae52940552f3cbdc6"
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/env bash
# Build the extension and run the test suite.
# Expected to run inside a php-minimal container from the repo root.
set -euo pipefail
# Clean up all generated files so stale objects from a previous PHP version or
# build variant don't silently survive into this build.
if [ -f Makefile ]; then
make -f Makefile distclean
fi
# Remove any leftover object files even if Makefile is gone (e.g. after a
# partial prior build that ended before distclean could run).
find . -name '*.lo' -o -name '*.o' | xargs rm -f 2>/dev/null || true
find . -name '.libs' -type d | xargs rm -rf 2>/dev/null || true
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"
-61
View File
@@ -1,61 +0,0 @@
#!/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="ghcr.io/cataphract/php-minimal"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCK_FILE="$SCRIPT_DIR/../docker-image-shas.yml"
TAGS=(
7.0-debug 7.0-release-zts
7.1-debug 7.1-release-zts
7.2-debug 7.2-release-zts
7.3-debug 7.3-release-zts
7.4-debug 7.4-release-zts
8.0-debug 8.0-release-zts
8.1-debug 8.1-release 8.1-release-zts
8.2-debug 8.2-release 8.2-release-zts
8.3-debug 8.3-release 8.3-release-zts
8.4-debug 8.4-release 8.4-release-zts
8.5-debug 8.5-release 8.5-release-zts
)
get_index_digest() {
local tag="$1" digest attempt
for attempt in 1 2 3; do
digest=$(docker buildx imagetools inspect "${IMAGE}:${tag}" \
| awk '/^Digest:/ { print $2; exit }')
if [[ -n "$digest" ]]; then
echo "$digest"
return 0
fi
echo "Attempt $attempt failed for $tag, retrying..." >&2
sleep $((attempt * 5))
done
echo "ERROR: could not fetch digest for $tag after 3 attempts" >&2
return 1
}
# 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
-162
View File
@@ -1,162 +0,0 @@
name: Build Docker images
on:
push:
branches: [docker]
env:
MUSL_ENV_IMAGE: ghcr.io/cataphract/musl-build-env
PHP_IMAGE: ghcr.io/cataphract/php-minimal
jobs:
# ── Push: build musl-build-env for both arches ───────────────────────────
musl-build-env:
name: musl-build-env / ${{ matrix.arch }}
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- arch: x86_64
platform: linux/amd64
runner: ubuntu-latest
- arch: aarch64
platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: docker/musl-build-env
platforms: ${{ matrix.platform }}
push: true
tags: ${{ env.MUSL_ENV_IMAGE }}:latest-${{ matrix.arch }}
build-args: ARCH=${{ matrix.arch }}
cache-from: type=gha,scope=musl-build-env-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=musl-build-env-${{ matrix.arch }}
# ── Push: build php-minimal for all PHP versions and variants ─────────────
php-minimal:
name: php-minimal ${{ matrix.php }}-${{ matrix.variant }} / ${{ matrix.arch }}
needs: musl-build-env
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
php:
- "7.0"
- "7.1"
- "7.2"
- "7.3"
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- "8.3"
- "8.4"
- "8.5"
variant:
- debug
- release
- release-zts
arch:
- x86_64
- aarch64
include:
- arch: x86_64
platform: linux/amd64
runner: ubuntu-latest
- arch: aarch64
platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Resolve PHP patch version and build flags
id: cfg
run: |
declare -A PHP_VERSIONS=(
[7.0]=7.0.33 [7.1]=7.1.33 [7.2]=7.2.34 [7.3]=7.3.33 [7.4]=7.4.33
[8.0]=8.0.30 [8.1]=8.1.32 [8.2]=8.2.28 [8.3]=8.3.19 [8.4]=8.4.6
[8.5]=8.5.0
)
patch="${PHP_VERSIONS[${{ matrix.php }}]}"
case "${{ matrix.variant }}" in
debug) debug=yes; zts=no ;;
release) debug=no; zts=no ;;
release-zts) debug=no; zts=yes ;;
esac
echo "patch=${patch}" >> "$GITHUB_OUTPUT"
echo "debug=${debug}" >> "$GITHUB_OUTPUT"
echo "zts=${zts}" >> "$GITHUB_OUTPUT"
- name: Build and push
uses: docker/build-push-action@v6
with:
context: docker/php-minimal
platforms: ${{ matrix.platform }}
push: true
tags: ${{ env.PHP_IMAGE }}:${{ matrix.php }}-${{ matrix.variant }}-${{ matrix.arch }}
build-args: |
BUILD_ENV_IMAGE=${{ env.MUSL_ENV_IMAGE }}:latest-${{ matrix.arch }}
PHP_VERSION=${{ steps.cfg.outputs.patch }}
ARCH=${{ matrix.arch }}
PHP_ENABLE_DEBUG=${{ steps.cfg.outputs.debug }}
PHP_ENABLE_ZTS=${{ steps.cfg.outputs.zts }}
cache-from: type=gha,scope=php-${{ matrix.php }}-${{ matrix.variant }}-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=php-${{ matrix.php }}-${{ matrix.variant }}-${{ matrix.arch }}
# ── Push: create multi-arch manifests ────────────────────────────────────
merge-manifests:
name: Create multi-arch manifests
needs: php-minimal
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Merge musl-build-env manifest
run: |
docker buildx imagetools create \
-t ${{ env.MUSL_ENV_IMAGE }}:latest \
${{ env.MUSL_ENV_IMAGE }}:latest-x86_64 \
${{ env.MUSL_ENV_IMAGE }}:latest-aarch64
- name: Merge php-minimal manifests
run: |
for minor in 7.0 7.1 7.2 7.3 7.4 8.0 8.1 8.2 8.3 8.4 8.5; do
for variant in debug release release-zts; do
docker buildx imagetools create \
-t ${{ env.PHP_IMAGE }}:${minor}-${variant} \
${{ env.PHP_IMAGE }}:${minor}-${variant}-x86_64 \
${{ env.PHP_IMAGE }}:${minor}-${variant}-aarch64
done
done
-191
View File
@@ -1,191 +0,0 @@
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
linux-extension-matrix:
needs: [create-draft-release]
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 = 'ghcr.io/cataphract/php-minimal'
includes = []
for tag, sha in data[image].items():
ver, variant = tag.split('-', 1)
if variant not in ('release', 'release-zts'):
continue
if float(ver) < 8.1:
continue
for arch, runner in [('x86_64', 'ubuntu-latest'), ('aarch64', 'ubuntu-24.04-arm')]:
includes.append({'php': ver, 'variant': variant, 'image_sha': sha,
'arch': arch, 'runner': runner})
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write('matrix=' + json.dumps({'include': includes}) + '\n')
EOF
linux-build:
name: Linux PHP ${{ matrix.php }} (${{ matrix.variant }}, ${{ matrix.arch }})
needs: [linux-extension-matrix]
runs-on: ${{ matrix.runner }}
permissions:
contents: write
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.linux-extension-matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
- name: Install patchelf
run: sudo apt-get install -y patchelf
- name: Build rar.so in musl container
run: |
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$GITHUB_WORKSPACE:/workspace" \
-w /workspace \
"ghcr.io/cataphract/php-minimal@${{ matrix.image_sha }}" \
sh -c 'phpize && ./configure --with-php-config=$(which php-config) && make -j$(nproc)'
- name: Remove musl DT_NEEDED from rar.so
run: patchelf --remove-needed "libc.musl-$(uname -m).so.1" modules/rar.so
- name: Package and upload to release
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION="${GITHUB_REF_NAME#v}"
ARCH="${{ matrix.arch }}"
[ "$ARCH" = "aarch64" ] && ARCH="arm64"
ZTS_SUFFIX=""
[[ "${{ matrix.variant }}" == "release-zts" ]] && ZTS_SUFFIX="-zts"
ARTIFACT="php_rar-${VERSION}_php${{ matrix.php }}-${ARCH}-linux${ZTS_SUFFIX}.zip"
zip -j "$ARTIFACT" modules/rar.so
gh release upload "${{ github.ref_name }}" "$ARTIFACT" --clobber
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
-156
View File
@@ -1,156 +0,0 @@
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 = 'ghcr.io/cataphract/php-minimal'
includes = []
for tag, sha in data[image].items():
# tag: "7.0-debug" or "7.0-release-zts"; skip glibc-only entries
ver, variant = tag.split('-', 1)
if variant not in ('debug', 'release-zts'):
continue
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: ghcr.io/cataphract/php-minimal@${{ 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
glibc:
name: glibc (PHP 8.3 release, ${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- arch: x86_64
runner: ubuntu-latest
- arch: aarch64
runner: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Read build image SHA
id: image-sha
run: |
python3 -c "
import yaml, os
with open('.github/docker-image-shas.yml') as f:
d = yaml.safe_load(f)
sha = d['ghcr.io/cataphract/php-minimal']['8.3-release']
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write('sha=' + sha + '\n')
"
- name: Install PHP 8.3 and patchelf
run: |
sudo apt-get update -q
sudo apt-get install -y php8.3 php8.3-dev patchelf
- name: Build rar.so in musl container
run: |
docker run --rm \
--user "$(id -u):$(id -g)" \
-v "$GITHUB_WORKSPACE:/workspace" \
-w /workspace \
"ghcr.io/cataphract/php-minimal@${{ steps.image-sha.outputs.sha }}" \
sh -c 'phpize && ./configure --with-php-config=$(which php-config) && make -j$(nproc)'
- name: Remove musl DT_NEEDED from rar.so
run: patchelf --remove-needed "libc.musl-$(uname -m).so.1" modules/rar.so
- name: Run tests
run: |
TEST_PHP_EXECUTABLE=$(which php8.3) \
TEST_PHP_JUNIT=report.xml \
REPORT_EXIT_STATUS=1 \
NO_INTERACTION=1 \
php8.3 run-tests-rar.php \
-n -d extension_dir=modules/ -d extension=rar.so \
--set-timeout 300 --show-diff \
tests/
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-glibc-php8.3-release-${{ matrix.arch }}
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'
+1 -12
View File
@@ -1,6 +1,5 @@
*.o *.o
*.lo *.lo
/run-tests.php
/tests/*.sh /tests/*.sh
/tests/*.exp /tests/*.exp
/tests/*.diff /tests/*.diff
@@ -8,6 +7,7 @@
/tests/*.php /tests/*.php
/tests/*.out /tests/*.out
/tests/*.mem /tests/*.mem
/run-tests.php
/modules /modules
/missing /missing
/.deps /.deps
@@ -23,14 +23,12 @@
/config.guess /config.guess
/config.h /config.h
/config.h.in /config.h.in
/config.h.in~
/config.log /config.log
/config.nice /config.nice
/config.status /config.status
/config.sub /config.sub
/configure /configure
/configure.in /configure.in
/configure.ac
/install-sh /install-sh
/intl.la /intl.la
/libtool /libtool
@@ -43,12 +41,3 @@
/rar.la /rar.la
*.autosave *.autosave
/unrar/.libs /unrar/.libs
/tmp-php.ini
/php-rar.creator.user
/compile_commands.json
/.clangd
/report.xml
/.worktrees
*.dep
/configure~
/.cache/
+33
View File
@@ -0,0 +1,33 @@
language: c
dist: trusty
addons:
apt:
packages:
- valgrind
env:
#- PHP_VERSION=5.2.17 ZTS=yes MIRROR=http://museum.php.net/php5/
- PHP_VERSION=5.3.29 ZTS=yes
- PHP_VERSION=5.4.45 ZTS=yes
- PHP_VERSION=5.5.37 ZTS=yes
- PHP_VERSION=5.6.30 ZTS=yes RUN_TESTS_FLAGS=-m
- PHP_VERSION=5.6.30 ZTS=no
- PHP_VERSION=7.0.21 ZTS=yes COVERAGE=yes
- PHP_VERSION=7.1.7 ZTS=yes RUN_TESTS_FLAGS=-m
cache:
directories:
- $HOME/php_builds
before_install:
- source travis.sh
- maybe_install_php $PHP_VERSION $ZTS
install:
- build $PHP_VERSION $ZTS "$COVERAGE"
script:
- run_tests $PHP_VERSION $ZTS
after_success:
- 'test "$COVERAGE" != "yes" || bash <(curl -s https://codecov.io/bash)'
-113
View File
@@ -1,113 +0,0 @@
# 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 := "ghcr.io/cataphract/php-minimal@"
_shas := ".github/docker-image-shas.yml"
image_7_0_debug := _base + `grep '7.0-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_0_release_zts := _base + `grep '7.0-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_1_debug := _base + `grep '7.1-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_1_release_zts := _base + `grep '7.1-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_2_debug := _base + `grep '7.2-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_2_release_zts := _base + `grep '7.2-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_3_debug := _base + `grep '7.3-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_3_release_zts := _base + `grep '7.3-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_4_debug := _base + `grep '7.4-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_7_4_release_zts := _base + `grep '7.4-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_0_debug := _base + `grep '8.0-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_0_release_zts := _base + `grep '8.0-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_1_debug := _base + `grep '8.1-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_1_release_zts := _base + `grep '8.1-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_2_debug := _base + `grep '8.2-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_2_release_zts := _base + `grep '8.2-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_3_debug := _base + `grep '8.3-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_3_release_zts := _base + `grep '8.3-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_4_debug := _base + `grep '8.4-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_4_release_zts := _base + `grep '8.4-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_5_debug := _base + `grep '8.5-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
image_8_5_release_zts := _base + `grep '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
-7
View File
@@ -1,7 +0,0 @@
EXTRA_CFLAGS := $(EXTRA_CFLAGS) -Wall
.PHONY: replace-run-tests
replace-run-tests:
cp run-tests-rar.php run-tests.php
test: replace-run-tests
+3 -23
View File
@@ -10,26 +10,6 @@ unrar/LICENSE.txt for details.
Some modifications have been applied to the UnRAR library, mainly to allow Some modifications have been applied to the UnRAR library, mainly to allow
streaming extraction of files without using threads. streaming extraction of files without using threads.
## Installation [![Build Status Appveyor](https://ci.appveyor.com/api/projects/status/cbgpepx6kyax2198/branch/master?svg=true)](https://ci.appveyor.com/project/cataphract/php-rar/branch/master)
[![Build Status Travis](https://travis-ci.org/cataphract/php-rar.svg?branch=master)](https://travis-ci.org/cataphract/php-rar)
### With PECL [![codecov](https://codecov.io/gh/cataphract/php-rar/branch/master/graph/badge.svg)](https://codecov.io/gh/cataphract/php-rar)
To install a specific version directly from GitHub, use the `.tgz` release
asset — not the auto-generated tag archive, which has an incompatible directory
structure:
```sh
pecl install https://github.com/cataphract/php-rar/releases/download/v4.3.1/rar-4.3.1.tgz
```
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`.
+29
View File
@@ -0,0 +1,29 @@
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"
+26
View File
@@ -0,0 +1,26 @@
# 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
-31
View File
@@ -1,31 +0,0 @@
{
"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",
"role": "lead"
},
{
"name": "Antony Dovgal",
"email": "tony@daylessday.org",
"role": "developer"
}
],
"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"]
}
}
+3 -52
View File
@@ -29,63 +29,14 @@ unrar_sources="unrar/sha256.cpp unrar/qopen.cpp \
unrar/arcread.cpp unrar/filefn.cpp \ unrar/arcread.cpp unrar/filefn.cpp \
unrar/global.cpp unrar/list.cpp \ unrar/global.cpp unrar/list.cpp \
unrar/encname.cpp unrar/file.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++])
cxxflags_null=""
AC_DEFUN([CXXC_FLAG_CHECK],
[
ac_saved_cxxflags="$CXXFLAGS"
CXXFLAGS="$1 -Werror"
flag_to_add=m4_default([$2],[$1])
AC_MSG_CHECKING([whether the C++ compiler supports $1])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([])],
[AC_MSG_RESULT([yes])]
[cxxflags_null="$cxxflags_null $flag_to_add"],
[AC_MSG_RESULT([no])]
)
CXXFLAGS="$ac_saved_cxxflags"
])
CXXC_FLAG_CHECK([-Wparentheses], [-Wno-parentheses])
CXXC_FLAG_CHECK([-Wswitch], [-Wno-switch])
CXXC_FLAG_CHECK([-Wdangling-else], [-Wno-dangling-else])
CXXC_FLAG_CHECK([-Wlogical-op-parentheses], [-Wno-logical-op-parentheses])
CXXC_FLAG_CHECK([-Wmissing-braces], [-Wno-missing-braces])
CXXC_FLAG_CHECK([-Wunused-function], [-Wno-unused-function])
CXXC_FLAG_CHECK([-Wunused-variable], [-Wno-unused-variable])
CXXC_FLAG_CHECK([-Wsign-compare], [-Wno-sign-compare])
CXXC_FLAG_CHECK([-Wmisleading-indentation], [-Wno-misleading-indentation])
AC_LANG_POP([C++])
extra_cxxflags="-Wall $cxxflags_null"
echo "EXTRA_CXXFLAGS := \$(EXTRA_CXXFLAGS) $extra_cxxflags" >> Makefile.fragments
cat Makefile.frag >> Makefile.fragments
INCLUDES=`echo "$INCLUDES" | sed 's/-I/-isystem /g'`
dnl Move -Wall into CFLAGS/CXXFLAGS so it precedes EXTRA_CXXFLAGS in compile
dnl commands; the -Wno-* suppression flags in EXTRA_CXXFLAGS must come last.
CFLAGS="$CFLAGS -Wall"
CXXFLAGS="$CXXFLAGS -Wall"
if test "$PHP_RAR" != "no"; then if test "$PHP_RAR" != "no"; then
AC_DEFINE(HAVE_RAR, 1, [Whether you have rar support]) AC_DEFINE(HAVE_RAR, 1, [Whether you have rar support])
PHP_SUBST(RAR_SHARED_LIBADD) PHP_SUBST(RAR_SHARED_LIBADD)
PHP_REQUIRE_CXX() 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 -fPIC -fvisibility=hidden -I@ext_srcdir@/unrar, yes) PHP_NEW_EXTENSION(rar, rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c $unrar_sources, $ext_shared,,-DRARDLL -DSILENT -Wno-write-strings -Wall -I@ext_srcdir@/unrar)
PHP_ADD_BUILD_DIR($ext_builddir/unrar) PHP_ADD_BUILD_DIR($ext_builddir/unrar)
AC_MSG_CHECKING([whether linker supports version scripts])
rar_save_ldflags="$LDFLAGS"
LDFLAGS="$LDFLAGS -Wl,--version-script=$ext_srcdir/rar.map"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[void get_module(void) {}]], [])],
[AC_MSG_RESULT([yes])
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,--version-script=$ext_srcdir/rar.map"],
[AC_MSG_RESULT([no])]
)
LDFLAGS="$rar_save_ldflags"
PHP_SUBST(EXTRA_LDFLAGS)
fi fi
+3 -4
View File
@@ -4,7 +4,7 @@
ARG_ENABLE("rar", "Rar support", "no"); ARG_ENABLE("rar", "Rar support", "no");
if (PHP_RAR != "no") { if (PHP_RAR != "no") {
EXTENSION("rar", "rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c rar_time.c", PHP_RAR_SHARED, "/DRARDLL /DSILENT /EHsc /D_WSTDIO_DEFINED"); EXTENSION("rar", "rar.c rar_error.c rararch.c rarentry.c rar_stream.c rar_navigation.c", PHP_RAR_SHARED, "/DRARDLL /DSILENT /EHsc /D_WSTDIO_DEFINED");
ADD_SOURCES(configure_module_dirname + "/unrar", ADD_SOURCES(configure_module_dirname + "/unrar",
"sha256.cpp qopen.cpp \ "sha256.cpp qopen.cpp \
blake2s.cpp recvol.cpp \ blake2s.cpp recvol.cpp \
@@ -18,7 +18,7 @@ if (PHP_RAR != "no") {
crc.cpp rijndael.cpp crypt.cpp \ crc.cpp rijndael.cpp crypt.cpp \
rawread.cpp \ rawread.cpp \
rs.cpp smallfn.cpp \ rs.cpp smallfn.cpp \
isnt.cpp consio.cpp \ isnt.cpp rar.cpp consio.cpp \
scantree.cpp archive.cpp strfn.cpp \ scantree.cpp archive.cpp strfn.cpp \
strlist.cpp \ strlist.cpp \
getbits.cpp hash.cpp \ getbits.cpp hash.cpp \
@@ -31,8 +31,7 @@ if (PHP_RAR != "no") {
arcread.cpp filefn.cpp \ arcread.cpp filefn.cpp \
global.cpp list.cpp \ global.cpp list.cpp \
encname.cpp file.cpp \ encname.cpp file.cpp \
secpassword.cpp options.cpp \ secpassword.cpp options.cpp", "rar");
largepage.cpp motw.cpp", "rar");
AC_DEFINE("HAVE_RAR", 1, "Rar support"); AC_DEFINE("HAVE_RAR", 1, "Rar support");
} }
-113
View File
@@ -1,113 +0,0 @@
# Build environment using Alpine 3.23 with LLVM runtimes built from source.
# Provides a musl-based toolchain for building portable Linux binaries
# that work on both musl and glibc systems (via glibc_compat.a).
#
# Build:
# docker build --build-arg ARCH=aarch64 -t musl-build-env:latest .
# docker build --build-arg ARCH=x86_64 -t musl-build-env:latest .
FROM alpine:3.23
ARG ARCH
RUN test -n "${ARCH}" || (echo "ARCH build arg is required (aarch64 or x86_64)" && false)
# Install build tools and dependencies
RUN apk --no-cache add \
alpine-sdk bash binutils clang cmake compiler-rt \
coreutils git linux-headers lld llvm make \
musl-dev patchelf python3 wget xz
# Apply musl patches for glibc ABI compatibility
COPY locale.h.diff /locale.h.diff
RUN cd /usr/include && patch -p0 < /locale.h.diff
COPY alltypes.h.diff /alltypes.h.diff
RUN cd /usr/include && patch -p0 < /alltypes.h.diff
# Download and build LLVM runtimes (libunwind, libc++abi, libc++) matching
# the system clang version so headers, ABIs and compiler-rt all align.
# Detect the full version string (e.g. 21.1.2) from the installed clang.
# Only the runtimes are built from source — the system clang is the bootstrap.
RUN set -e && \
LLVM_VER=$(clang --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) && \
echo "Building LLVM ${LLVM_VER} runtimes to match system clang" && \
wget -q "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VER}/llvm-project-${LLVM_VER}.src.tar.xz" && \
tar -xf "llvm-project-${LLVM_VER}.src.tar.xz" && \
rm "llvm-project-${LLVM_VER}.src.tar.xz" && \
cd "llvm-project-${LLVM_VER}.src" && mkdir build && cd build && \
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_C_FLAGS="-fno-omit-frame-pointer" \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-fno-omit-frame-pointer" \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DLIBUNWIND_ENABLE_SHARED=OFF \
-DLIBUNWIND_ENABLE_STATIC=ON \
-DLIBUNWIND_USE_COMPILER_RT=ON \
-DLIBCXXABI_ENABLE_SHARED=OFF \
-DLIBCXXABI_USE_LLVM_UNWINDER=ON \
-DLIBCXXABI_ENABLE_STATIC_UNWINDER=ON \
-DLIBCXXABI_USE_COMPILER_RT=ON \
-DLIBCXX_ENABLE_SHARED=OFF \
-DLIBCXX_HAS_MUSL_LIBC=ON \
-DLIBCXX_USE_COMPILER_RT=ON \
-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
../runtimes && \
make -j$(nproc) install-unwind install-cxxabi install-cxx && \
cd / && rm -rf "/llvm-project-${LLVM_VER}.src"
# Set up symlinks using the system LLVM and GCC versions detected at build time.
# Use grep -oE (not -oP) since busybox grep lacks Perl regex support.
RUN set -e && \
SYS_LLVM_VER=$(clang --version | grep -oE '[0-9]+' | head -1) && \
GCC_VER=$(ls /usr/lib/gcc/${ARCH}-alpine-linux-musl/) && \
echo "System LLVM: ${SYS_LLVM_VER}, GCC: ${GCC_VER}" && \
GCC_DIR=/usr/lib/gcc/${ARCH}-alpine-linux-musl/${GCC_VER} && \
CLANG_DIR=/usr/lib/llvm${SYS_LLVM_VER}/lib/clang/${SYS_LLVM_VER} && \
ln -s ${GCC_DIR} /usr/lib/resource_dir && \
ln -s ${CLANG_DIR}/lib /usr/lib/resource_dir/lib && \
ln -s ${CLANG_DIR}/lib/${ARCH}-alpine-linux-musl/libclang_rt.builtins-${ARCH}.a \
/usr/lib/libclang_rt.builtins.a && \
GCC_STDATOMIC=${GCC_DIR}/include/stdatomic.h && \
if [ -f "${GCC_STDATOMIC}" ]; then \
mv "${GCC_STDATOMIC}" "${GCC_STDATOMIC}_" && \
cp ${CLANG_DIR}/include/stdatomic.h "${GCC_STDATOMIC}"; \
fi
# Set up sysroot directory structure.
# Programs compiled with --sysroot=/sysroot/ARCH-none-linux-musl will find
# headers and libraries via these symlinks.
RUN mkdir -p /sysroot/${ARCH}-none-linux-musl/usr && \
ln -s /usr/lib /sysroot/${ARCH}-none-linux-musl/usr/lib && \
ln -s /usr/include /sysroot/${ARCH}-none-linux-musl/usr/include && \
ln -s /lib /sysroot/${ARCH}-none-linux-musl/lib
# Build glibc_compat.c into a static archive.
# This library ensures binaries work on both musl and glibc:
# - On musl: musl exports __xstat and other glibc compat symbols, so the
# wrappers in glibc_compat resolve correctly.
# - On glibc: glibc_compat bridges the musl-compiled ABI to glibc internals.
# Always link against -lglibc_compat; the musl-clang wrapper does this by default.
COPY glibc_compat.c /sysroot/glibc_compat.c
RUN clang \
--target=${ARCH}-none-linux-musl \
--sysroot=/sysroot/${ARCH}-none-linux-musl \
-rtlib=compiler-rt \
-fpie -O2 -fno-omit-frame-pointer -ggdb3 \
-c /sysroot/glibc_compat.c -o /tmp/glibc_compat.o && \
ar rcs /sysroot/${ARCH}-none-linux-musl/usr/lib/libglibc_compat.a /tmp/glibc_compat.o && \
rm /tmp/glibc_compat.o
# Install CMake toolchain file for this architecture
COPY Toolchain.cmake.${ARCH} /sysroot/${ARCH}-none-linux-musl/Toolchain.cmake
# Install musl-clang / musl-clang++ wrapper scripts.
# These encode the target triple, sysroot, required compiler flags, and always
# link -lglibc_compat so every binary works on both musl and glibc systems.
COPY musl-clang.sh /usr/local/bin/musl-clang
COPY musl-clang++.sh /usr/local/bin/musl-clang++
RUN chmod +x /usr/local/bin/musl-clang /usr/local/bin/musl-clang++
@@ -1,28 +0,0 @@
# vim: set ft=cmake:
set(sysroot /sysroot/aarch64-none-linux-musl)
set(arch aarch64)
set(interpreter ld-musl-aarch64.so.1)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ${arch})
set(CMAKE_SYSROOT ${sysroot})
set(CMAKE_AR /usr/bin/llvm-ar)
set(triple ${arch}-none-linux-musl)
set(CMAKE_ASM_COMPILER_TARGET ${triple})
set(CMAKE_C_COMPILER /usr/bin/clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(c_cxx_flags "-Qunused-arguments -rtlib=compiler-rt -unwindlib=libunwind -static-libgcc -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_INIT ${c_cxx_flags})
set(CMAKE_CXX_COMPILER /usr/bin/clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++ ${c_cxx_flags}")
set(linker_flags "-fuse-ld=lld -nodefaultlibs -Wl,-Bstatic -lc++ -lc++abi ${sysroot}/usr/lib/libclang_rt.builtins.a -lunwind -lglibc_compat -Wl,-Bdynamic ${sysroot}/usr/lib/libclang_rt.builtins.a -Wl,--dynamic-linker,${sysroot}/lib/${interpreter} -Wl,-rpath=${sysroot} -resource-dir ${sysroot}/usr/lib/resource_dir")
set(CMAKE_EXE_LINKER_FLAGS_INIT "${linker_flags} -Wl,--dynamic-linker,${sysroot}/lib/${interpreter}")
set(CMAKE_SHARED_LINKER_FLAGS_INIT ${linker_flags})
set(CMAKE_C_STANDARD_LIBRARIES "-Wl,-Bdynamic -lc")
set(CMAKE_CXX_STANDARD_LIBRARIES "-Wl,-Bdynamic -lc")
set(CMAKE_NM /usr/bin/llvm-nm)
set(CMAKE_RANLIB /usr/bin/llvm-ranlib)
set(CMAKE_STRIP /usr/bin/strip)
@@ -1,28 +0,0 @@
# vim: set ft=cmake:
set(sysroot /sysroot/x86_64-none-linux-musl)
set(arch x86_64)
set(interpreter ld-musl-x86_64.so.1)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR ${arch})
set(CMAKE_SYSROOT ${sysroot})
set(CMAKE_AR /usr/bin/llvm-ar)
set(triple ${arch}-none-linux-musl)
set(CMAKE_ASM_COMPILER_TARGET ${triple})
set(CMAKE_C_COMPILER /usr/bin/clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(c_cxx_flags "-Qunused-arguments -rtlib=compiler-rt -unwindlib=libunwind -static-libgcc -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_INIT ${c_cxx_flags})
set(CMAKE_CXX_COMPILER /usr/bin/clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++ ${c_cxx_flags}")
set(linker_flags "-fuse-ld=lld -nodefaultlibs -Wl,-Bstatic -lc++ -lc++abi ${sysroot}/usr/lib/libclang_rt.builtins.a -lunwind -lglibc_compat -Wl,-Bdynamic ${sysroot}/usr/lib/libclang_rt.builtins.a -Wl,--dynamic-linker,${sysroot}/lib/${interpreter} -Wl,-rpath=${sysroot} -resource-dir ${sysroot}/usr/lib/resource_dir")
set(CMAKE_EXE_LINKER_FLAGS_INIT "${linker_flags} -Wl,--dynamic-linker,${sysroot}/lib/${interpreter}")
set(CMAKE_SHARED_LINKER_FLAGS_INIT ${linker_flags})
set(CMAKE_C_STANDARD_LIBRARIES "-Wl,-Bdynamic -lc")
set(CMAKE_CXX_STANDARD_LIBRARIES "-Wl,-Bdynamic -lc")
set(CMAKE_NM /usr/bin/llvm-nm)
set(CMAKE_RANLIB /usr/bin/llvm-ranlib)
set(CMAKE_STRIP /usr/bin/strip)
-60
View File
@@ -1,60 +0,0 @@
--- bits/alltypes.h
+++ bits/alltypes.h
@@ -299,17 +299,32 @@
#endif
#if defined(__NEED_pthread_mutexattr_t) && !defined(__DEFINED_pthread_mutexattr_t)
-typedef struct { unsigned __attr; } pthread_mutexattr_t;
+typedef struct { union { unsigned __attr;
+#ifdef __aarch64__
+ long __glibc_compat;
+#endif
+};
+} pthread_mutexattr_t;
#define __DEFINED_pthread_mutexattr_t
#endif
#if defined(__NEED_pthread_condattr_t) && !defined(__DEFINED_pthread_condattr_t)
-typedef struct { unsigned __attr; } pthread_condattr_t;
+typedef struct { union { unsigned __attr;
+#ifdef __aarch64__
+ long __glibc_compat;
+#endif
+};
+} pthread_condattr_t;
#define __DEFINED_pthread_condattr_t
#endif
#if defined(__NEED_pthread_barrierattr_t) && !defined(__DEFINED_pthread_barrierattr_t)
-typedef struct { unsigned __attr; } pthread_barrierattr_t;
+typedef struct { union { unsigned __attr;
+#ifdef __aarch64__
+ long __glibc_compat;
+#endif
+};
+} pthread_barrierattr_t;
#define __DEFINED_pthread_barrierattr_t
#endif
@@ -383,12 +398,20 @@
#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9];
+#ifdef __aarch64__
+ char __glibc_compat[64];
+#endif
+} __u; } pthread_attr_t;
#define __DEFINED_pthread_attr_t
#endif
#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6];
+#ifdef __aarch64__
+ char __glibc_compat[48];
+#endif
+} __u; } pthread_mutex_t;
#define __DEFINED_pthread_mutex_t
#endif
-306
View File
@@ -1,306 +0,0 @@
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <fenv.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#if defined(__linux__) && !defined(__GLIBC__)
# ifdef __x86_64__
float ceilf(float x)
{
float result;
// NOLINTNEXTLINE(hicpp-no-assembler)
__asm__("roundss $0x0A, %[x], %[result]"
: [result] "=x"(result)
: [x] "x"(x));
return result;
}
double ceil(double x)
{
double result;
// NOLINTNEXTLINE(hicpp-no-assembler)
__asm__("roundsd $0x0A, %[x], %[result]"
: [result] "=x"(result)
: [x] "x"(x));
return result;
}
# endif
# ifdef __aarch64__
float ceilf(float x)
{
float result;
__asm__("frintp %s0, %s1\n" : "=w"(result) : "w"(x));
return result;
}
double ceil(double x)
{
double result;
__asm__("frintp %d0, %d1\n" : "=w"(result) : "w"(x));
return result;
}
# endif
# ifdef __aarch64__
# define _STAT_VER 0
# else
# define _STAT_VER 1
# endif
// glibc before 2.33 (2021) doesn't have these
int stat(const char *restrict path, void *restrict buf)
{
int __xstat(int, const char *restrict, void *restrict);
return __xstat(_STAT_VER, path, buf);
}
int fstat(int fd, void *buf)
{
int __fxstat(int, int, void *);
return __fxstat(_STAT_VER, fd, buf);
}
int lstat(const char *restrict path, void *restrict buf)
{
int __lxstat(int, const char *restrict, void *restrict);
return __lxstat(_STAT_VER, path, buf);
}
int fstatat(int dirfd, const char *restrict pathname, void *restrict statbuf, int flags)
{
int __fxstatat(int, int, const char *restrict, void *restrict, int);
return __fxstatat(_STAT_VER, dirfd, pathname, statbuf, flags);
}
// glibc doesn't define pthread_atfork on aarch64. We need to delegate to
// glibc's __register_atfork() instead. __register_atfork() takes an extra
// argument, __dso_handle, which is a pointer to the DSO that is registering the
// fork handlers. This is used to ensure that the handlers are not called after
// the DSO is unloaded. glibc on amd64 also implements pthread_atfork() in terms
// of __register_atfork(). (musl never unloads modules so that potential
// problem doesn't exist)
// On amd64, even though pthread_atfork is exported by glibc, it should not be
// used. Code that uses pthread_atfork will compile to an import to
// __register_atfork(), but here we're compiling against musl, resulting in an
// an import to pthread_atfork. This will cause a runtime error when unloading
// a shared module. The reason is that when we call pthread_atfork in glibc,
// __register_atfork() is called with the __dso_handle of libc6.so, not the
// __dso_handle of our module. So the fork handler is not unregistered when our
// module is unloaded.
extern void *__dso_handle __attribute__((weak));
int __register_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void), void *__dso_handle) __attribute__((weak));
int pthread_atfork(
void (*prepare)(void), void (*parent)(void), void (*child)(void))
{
// glibc
if (__dso_handle && __register_atfork) {
return __register_atfork(prepare, parent, child, __dso_handle);
}
static int (*real_atfork)(void (*)(void), void (*)(void), void (*)(void));
if (!real_atfork) {
// dlopen musl
# ifdef __aarch64__
void *handle = dlopen("ld-musl-aarch64.so.1", RTLD_LAZY);
if (!handle) {
(void)fprintf(
// NOLINTNEXTLINE(concurrency-mt-unsafe)
stderr, "dlopen of ld-musl-aarch64.so.1 failed: %s\n",
dlerror());
abort();
}
# else
void *handle = dlopen("libc.musl-x86_64.so.1", RTLD_LAZY);
if (!handle) {
(void)fprintf(
// NOLINTNEXTLINE(concurrency-mt-unsafe)
stderr, "dlopen of libc.musl-x86_64.so.1 failed: %s\n",
dlerror());
abort();
}
# endif
real_atfork = dlsym(handle, "pthread_atfork");
if (!real_atfork) {
(void)fprintf(
// NOLINTNEXTLINE(concurrency-mt-unsafe)
stderr, "dlsym of pthread_atfork failed: %s\n", dlerror());
abort();
}
}
return real_atfork(prepare, parent, child);
}
# ifdef __x86_64__
struct pthread_cond;
struct pthread_condattr;
typedef struct pthread_cond pthread_cond_t;
typedef struct pthread_condattr pthread_condattr_t;
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
{
static int (*real_pthread_cond_init)(pthread_cond_t *cond, const pthread_condattr_t *cond_attr);
if (!real_pthread_cond_init) {
void *handle = dlopen("libc.so.6", RTLD_LAZY);
if (!handle) {
void *handle = dlopen("libc.musl-x86_64.so.1", RTLD_LAZY);
if (!handle) {
(void)fprintf(
// NOLINTNEXTLINE(concurrency-mt-unsafe)
stderr, "dlopen of libc.so.6 and libc.musl-x86_64.so.1 failed: %s\n",
dlerror());
abort();
}
}
real_pthread_cond_init = dlsym(handle, "pthread_cond_init");
if (!real_pthread_cond_init) {
(void)fprintf(
// NOLINTNEXTLINE(concurrency-mt-unsafe)
stderr, "dlsym of pthread_cond_init failed: %s\n", dlerror());
abort();
}
}
return real_pthread_cond_init(cond, cond_attr);
}
# endif
// the symbol strerror_r in glibc is not the POSIX version; it returns char *
// __xpg_sterror_r is exported by both glibc and musl
int strerror_r(int errnum, char *buf, size_t buflen)
{
int __xpg_strerror_r(int, char *, size_t);
return __xpg_strerror_r(errnum, buf, buflen);
}
// when compiling with --coverage, some references to atexit show up.
// glibc doesn't provide atexit for similar reasons as pthread_atfork presumably
int __cxa_atexit(void (*func)(void *), void *arg, void *dso_handle);
int atexit(void (*function)(void))
{
if (!__dso_handle) {
(void)fprintf(stderr, "Aborting because __dso_handle is NULL\n");
abort();
}
// the cast is harmless on amd64 and aarch64. Passing an extra argument to a
// function that expects none causes no problems
return __cxa_atexit((void (*)(void *))function, 0, __dso_handle);
}
// introduced in glibc 2.25
ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
int fd;
size_t bytes_read = 0;
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
return -1;
}
while (bytes_read < buflen) {
ssize_t result = read(fd, (char*)buf + bytes_read, buflen - bytes_read);
if (result < 0) {
if (errno == EINTR) {
continue;
}
close(fd);
return -1;
}
bytes_read += result;
}
close(fd);
return (ssize_t)bytes_read;
}
#ifdef __x86_64__
#define MEMFD_CREATE_SYSCALL 319
#elif __aarch64__
#define MEMFD_CREATE_SYSCALL 279
#endif
// introduced in glibc 2.27
int memfd_create(const char *name, unsigned flags) {
return syscall(MEMFD_CREATE_SYSCALL, name, flags);
}
// __flt_rounds is the backing function behind musl's FLT_ROUNDS macro: musl's
// <float.h> defines FLT_ROUNDS as (__flt_rounds()), making it dynamic — it
// reflects the current rounding mode after fesetround(). glibc/GCC does not
// export __flt_rounds; GCC's <float.h> defines FLT_ROUNDS as the compile-time
// constant 1 (round-to-nearest), so it never tracks fesetround() at all (GCC
// bug #59046 — GCC's own float.h has the comment "??? This is supposed to
// change with calls to fesetround in <fenv.h>"). fegetround() provides the
// actual hardware rounding mode on both.
int __flt_rounds(void)
{
switch (fegetround()) {
case FE_TONEAREST: return 1;
case FE_UPWARD: return 2;
case FE_DOWNWARD: return 3;
case FE_TOWARDZERO: return 0;
default: return -1;
}
}
// glibc has never exported sigsetjmp as a dynamic symbol — it is defined in
// <setjmp.h> as a macro expanding to __sigsetjmp, so only __sigsetjmp appears
// in the DSO. Musl exports both sigsetjmp ajd __sigsetjmp as real symbols.
// sigsetjmp is referenced directly in compiled code, so we provide this
// bridge.
int sigsetjmp(sigjmp_buf env, int savemask)
{
int __sigsetjmp(sigjmp_buf, int);
return __sigsetjmp(env, savemask);
}
// glibc no longer exports res_init as a dynamic symbol (it never did for amd64
// or aarch64, only for older archs). Only __res_init is exported.
// Musl-compiled code references res_init directly. __res_init is declared weak
// so linking succeeds on musl (where it doesn't exist). At runtime: on glibc
// it's non-NULL and called directly; on musl it's NULL and we fall through to
// dlopen musl's own res_init.
extern int __res_init(void) __attribute__((weak));
int res_init(void)
{
if (__res_init)
return __res_init();
// musl path: find res_init in musl's libc via dlopen
static int (*musl_res_init)(void);
if (!musl_res_init) {
# ifdef __aarch64__
void *handle = dlopen("ld-musl-aarch64.so.1", RTLD_LAZY);
# else
void *handle = dlopen("libc.musl-x86_64.so.1", RTLD_LAZY);
# endif
if (handle) {
musl_res_init = dlsym(handle, "res_init");
} else {
(void)fprintf(stderr, "Aborting because dlopen() of musl failed\n");
abort();
}
}
if (musl_res_init) {
return musl_res_init();
} else {
(void)fprintf(stderr, "Aborting because res_init/__res_init could not "
"be found");
abort();
}
}
#endif
-11
View File
@@ -1,11 +0,0 @@
-- locale.h
+++ locale.h
@@ -71,7 +71,7 @@
#define LC_COLLATE_MASK (1<<LC_COLLATE)
#define LC_MONETARY_MASK (1<<LC_MONETARY)
#define LC_MESSAGES_MASK (1<<LC_MESSAGES)
-#define LC_ALL_MASK 0x7fffffff
+#define LC_ALL_MASK 0x1fbf
locale_t duplocale(locale_t);
void freelocale(locale_t);
-23
View File
@@ -1,23 +0,0 @@
#!/bin/sh
# Wrapper for clang++ targeting musl libc with the correct sysroot and flags.
# Use this as CXX= for autoconf-based builds.
# -lglibc_compat is always appended so every binary works on both musl and glibc.
ARCH=$(uname -m)
SYSROOT="/sysroot/${ARCH}-none-linux-musl"
LLVM_MAJOR=$(clang --version | grep -oE '[0-9]+' | head -1)
BUILTINS_DIR="/usr/lib/llvm${LLVM_MAJOR}/lib/clang/${LLVM_MAJOR}/lib/linux"
exec clang++ \
--target="${ARCH}-none-linux-musl" \
--sysroot="${SYSROOT}" \
-stdlib=libc++ \
-rtlib=compiler-rt \
-unwindlib=libunwind \
-fno-omit-frame-pointer \
-Qunused-arguments \
-fuse-ld=lld \
"$@" \
-L"${SYSROOT}/usr/lib" \
-L"${BUILTINS_DIR}" \
-lglibc_compat \
-lclang_rt.builtins-${ARCH}
-22
View File
@@ -1,22 +0,0 @@
#!/bin/sh
# Wrapper for clang targeting musl libc with the correct sysroot and flags.
# Use this as CC= for autoconf-based builds (e.g. PHP, php-rar).
# -lglibc_compat is always appended so every binary works on both musl and glibc.
ARCH=$(uname -m)
SYSROOT="/sysroot/${ARCH}-none-linux-musl"
LLVM_MAJOR=$(clang --version | grep -oE '[0-9]+' | head -1)
BUILTINS_DIR="/usr/lib/llvm${LLVM_MAJOR}/lib/clang/${LLVM_MAJOR}/lib/linux"
exec clang \
--target="${ARCH}-none-linux-musl" \
--sysroot="${SYSROOT}" \
-rtlib=compiler-rt \
-unwindlib=libunwind \
-fno-omit-frame-pointer \
-Qunused-arguments \
-fuse-ld=lld \
"$@" \
-L"${SYSROOT}/usr/lib" \
-L"${BUILTINS_DIR}" \
-lglibc_compat \
-lclang_rt.builtins-${ARCH}
-115
View File
@@ -1,115 +0,0 @@
# Minimal PHP build using the musl-build-env toolchain.
# PHP is compiled with --disable-all so only the CLI binary is built,
# with minimal dependencies (only musl libc + glibc_compat shim).
#
# The resulting image is used to build and test PHP extensions like php-rar.
# glibc_compat is always linked (via the musl-clang wrapper) so the binary
# and any extensions built here work on both musl and glibc systems.
#
# Build:
# # First build musl-build-env:
# docker build --build-arg ARCH=aarch64 -t musl-build-env:latest ../musl-build-env
#
# # Then build this image:
# docker build \
# --build-arg BUILD_ENV_IMAGE=musl-build-env:latest \
# --build-arg PHP_VERSION=8.4.6 \
# --build-arg ARCH=aarch64 \
# -t php-minimal:8.4-aarch64 .
ARG BUILD_ENV_IMAGE=musl-build-env:latest
FROM ${BUILD_ENV_IMAGE}
ARG PHP_VERSION=8.4.6
ARG ARCH
# PHP build variants: set these for debug/ZTS builds
ARG PHP_ENABLE_DEBUG=no
ARG PHP_ENABLE_ZTS=no
RUN test -n "${ARCH}" || (echo "ARCH build arg is required (aarch64 or x86_64)" && false)
# PHP build-time dependencies (re2c for lexer, autoconf for configure regeneration)
RUN apk --no-cache add \
autoconf bison re2c \
libxml2-dev openssl-dev
# Download PHP source
RUN wget -q "https://www.php.net/distributions/php-${PHP_VERSION}.tar.gz" && \
tar -xf "php-${PHP_VERSION}.tar.gz" && \
rm "php-${PHP_VERSION}.tar.gz"
# Apply version-specific source patches for compatibility with modern clang.
#
# PHP 7.x patches:
# - reentrancy.c: configure wrongly detects HAVE_OLD_READDIR_R on musl,
# resulting in a 2-argument readdir_r call. Patch to the standard 3-arg form.
# - streams/cast.c: COOKIE_SEEKER_USES_OFF64_T is not detected by configure,
# so the by-value seek variant is compiled instead of the by-pointer variant
# that fopencookie requires on Linux. Fixed by passing -DCOOKIE_SEEKER_USES_OFF64_T.
#
# PHP 8.0 and 8.1 patches:
# - streams/cast.c: same COOKIE_SEEKER_USES_OFF64_T issue as PHP 7.x.
RUN \
VER_MAJOR=$(echo "${PHP_VERSION}" | cut -d. -f1) && \
if [ "${VER_MAJOR}" = "7" ]; then \
sed -i \
's/readdir_r(dirp, entry);/struct dirent *_rdr; (void)readdir_r(dirp, entry, \&_rdr);/' \
"php-${PHP_VERSION}/main/reentrancy.c"; \
fi
# Build PHP with clang targeting musl.
# --disable-all: disable all optional extensions (minimal build).
# musl-clang wrapper encodes the target triple, sysroot, clang flags, and
# always links -lglibc_compat so the binary works on both musl and glibc.
RUN \
DEBUG_FLAG=$([ "${PHP_ENABLE_DEBUG}" = "yes" ] && echo "--enable-debug" || echo "") && \
ZTS_FLAG=$([ "${PHP_ENABLE_ZTS}" = "yes" ] && echo "--enable-zts" || echo "") && \
VER_MAJOR=$(echo "${PHP_VERSION}" | cut -d. -f1) && \
VER_MINOR=$(echo "${PHP_VERSION}" | cut -d. -f2) && \
COMPAT_FLAGS=$([ "${VER_MAJOR}" = "7" ] || { [ "${VER_MAJOR}" = "8" ] && [ "${VER_MINOR}" -le 1 ]; } && echo "-DCOOKIE_SEEKER_USES_OFF64_T -D__off64_t=long -Doff64_t=long" || echo "") && \
ASAN_CFLAGS=$([ "${PHP_ENABLE_DEBUG}" = "yes" ] && echo "-fsanitize=address" || echo "") && \
ASAN_LDFLAGS=$([ "${PHP_ENABLE_DEBUG}" = "yes" ] && echo "-fsanitize=address" || echo "") && \
OPT_FLAG=$([ "${PHP_ENABLE_DEBUG}" = "yes" ] && echo "-O0" || echo "-O2") && \
cd "php-${PHP_VERSION}" && \
CC=musl-clang \
CXX=musl-clang++ \
CFLAGS="-g ${OPT_FLAG} ${COMPAT_FLAGS} ${ASAN_CFLAGS}" \
LDFLAGS="-fuse-ld=lld ${ASAN_LDFLAGS}" \
./configure \
--disable-all \
--disable-cgi \
--disable-fpm \
--without-pear \
--enable-cli \
${DEBUG_FLAG} \
${ZTS_FLAG} && \
make -j$(nproc) && \
make install
RUN rm -rf "/php-${PHP_VERSION}"
# Ensure extension builds (phpize + configure) use our musl toolchain.
ENV CC=musl-clang CXX=musl-clang++
# For debug builds: patch the musl-clang wrappers to add -fsanitize=address
# so that extensions compiled inside this image (e.g. by build-and-test.sh)
# are also ASAN-instrumented. This prevents the ASAN __cxa_throw interceptor
# crash that occurs when a non-instrumented extension (with statically-linked
# libc++) is loaded into an ASAN-instrumented PHP process.
RUN if [ "${PHP_ENABLE_DEBUG}" = "yes" ]; then \
for f in /usr/local/bin/musl-clang /usr/local/bin/musl-clang++; do \
sed -i 's|"$@"|"-fsanitize=address" "$@"|' "$f"; \
done; \
fi
# Verify: PHP binary should depend only on musl libc
RUN php --version
RUN echo "Dynamic dependencies of PHP binary:" && \
ldd /usr/local/bin/php && \
echo "" && \
NON_MUSL=$(ldd /usr/local/bin/php | grep -v 'musl\|linux-vdso\|ld-musl\|statically' || true) && \
if [ -n "$NON_MUSL" ]; then \
echo "WARNING: unexpected non-musl dependencies: $NON_MUSL"; \
else \
echo "OK: PHP depends only on musl libc"; \
fi
+20 -181
View File
@@ -23,11 +23,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
<active>no</active> <active>no</active>
</developer> </developer>
<date>2026-03-15</date> <date>2013-10-11</date>
<time>20:00:00</time> <time>13:00:00</time>
<version> <version>
<release>4.3.1</release> <release>3.0.2</release>
<api>4.0.0</api> <api>3.0.0</api>
</version> </version>
<stability> <stability>
@@ -36,8 +36,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
</stability> </stability>
<license uri="http://www.php.net/license">PHP License</license> <license uri="http://www.php.net/license">PHP License</license>
<notes>- Fix bug #75557: error opening archive with non-English characters in path on Windows. <notes>- Fixed build with PHP 5.5.
- Do not build unconditionally against listdc++. - Upgraded bundled unrar to version 4.2.4.
</notes> </notes>
<contents> <contents>
<dir name="/"> <dir name="/">
@@ -110,6 +110,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="065.phpt"/> <file role="test" name="065.phpt"/>
<file role="test" name="066.phpt"/> <file role="test" name="066.phpt"/>
<file role="test" name="067.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="070.phpt"/>
<file role="test" name="071.phpt"/> <file role="test" name="071.phpt"/>
<file role="test" name="072.phpt"/> <file role="test" name="072.phpt"/>
@@ -140,23 +142,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="097.phpt"/> <file role="test" name="097.phpt"/>
<file role="test" name="098.phpt"/> <file role="test" name="098.phpt"/>
<file role="test" name="099.phpt"/> <file role="test" name="099.phpt"/>
<file role="test" name="100.phpt"/>
<file role="test" name="101.phpt"/>
<file role="test" name="102.phpt"/>
<file role="test" name="103.phpt"/>
<file role="test" name="104.phpt"/>
<file role="test" name="106.phpt"/>
<file role="test" name="107.phpt"/>
<file role="test" name="108.phpt"/>
<file role="test" name="109.phpt"/>
<file role="test" name="110.phpt"/>
<file role="test" name="111.phpt"/>
<file role="test" name="112.phpt"/>
<file role="test" name="113.phpt"/>
<file role="test" name="114.phpt"/>
<file role="test" name="115.phpt"/>
<file role="test" name="bug75557.phpt"/>
<file role="test" name="75557тест.rar"/>
<file role="test" name="commented.rar"/> <file role="test" name="commented.rar"/>
<file role="test" name="corrupted.rar"/> <file role="test" name="corrupted.rar"/>
<file role="test" name="directories.rar"/> <file role="test" name="directories.rar"/>
@@ -172,7 +157,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="multi.part2.rar"/> <file role="test" name="multi.part2.rar"/>
<file role="test" name="multi.part3.rar"/> <file role="test" name="multi.part3.rar"/>
<file role="test" name="multi_broken.part1.rar"/> <file role="test" name="multi_broken.part1.rar"/>
<file role="test" name="php8compat.php.inc"/>
<file role="test" name="rar_notrar.rar"/> <file role="test" name="rar_notrar.rar"/>
<file role="test" name="rar_unicode.rar"/> <file role="test" name="rar_unicode.rar"/>
<file role="test" name="repeated_name.rar"/> <file role="test" name="repeated_name.rar"/>
@@ -181,9 +165,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file role="test" name="solid.rar"/> <file role="test" name="solid.rar"/>
<file role="test" name="sparsefiles_rar.rar"/> <file role="test" name="sparsefiles_rar.rar"/>
<file role="test" name="store_method.rar"/> <file role="test" name="store_method.rar"/>
<file role="test" name="rar5-links.rar"/>
<file role="test" name="rar5_multi.part1.rar"/>
<file role="test" name="rar5_multi.part2.rar"/>
</dir> <!-- /tests --> </dir> <!-- /tests -->
<dir name="unrar"> <dir name="unrar">
<file name="acknow.txt" role="doc" /> <file name="acknow.txt" role="doc" />
@@ -191,14 +172,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="archive.cpp" role="src" /> <file name="archive.cpp" role="src" />
<file name="archive.hpp" role="src" /> <file name="archive.hpp" role="src" />
<file name="arcread.cpp" role="src" /> <file name="arcread.cpp" role="src" />
<file name="blake2s.cpp" role="src" /> <file name="array.hpp" role="src" />
<file name="blake2s.hpp" role="src" /> <file name="beosea.cpp" role="src" />
<file name="blake2s_sse.cpp" role="src" />
<file name="blake2sp.cpp" role="src" />
<file name="cmddata.cpp" role="src" /> <file name="cmddata.cpp" role="src" />
<file name="cmddata.hpp" role="src" /> <file name="cmddata.hpp" role="src" />
<file name="cmdfilter.cpp" role="src" />
<file name="cmdmix.cpp" role="src" />
<file name="coder.cpp" role="src" /> <file name="coder.cpp" role="src" />
<file name="coder.hpp" role="src" /> <file name="coder.hpp" role="src" />
<file name="compress.hpp" role="src" /> <file name="compress.hpp" role="src" />
@@ -208,10 +185,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="crc.hpp" role="src" /> <file name="crc.hpp" role="src" />
<file name="crypt.cpp" role="src" /> <file name="crypt.cpp" role="src" />
<file name="crypt.hpp" role="src" /> <file name="crypt.hpp" role="src" />
<file name="crypt1.cpp" role="src" />
<file name="crypt2.cpp" role="src" />
<file name="crypt3.cpp" role="src" />
<file name="crypt5.cpp" role="src" />
<file name="dll.cpp" role="src" /> <file name="dll.cpp" role="src" />
<file name="dll.hpp" role="src" /> <file name="dll.hpp" role="src" />
<file name="encname.cpp" role="src" /> <file name="encname.cpp" role="src" />
@@ -237,16 +210,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="getbits.hpp" role="src" /> <file name="getbits.hpp" role="src" />
<file name="global.cpp" role="src" /> <file name="global.cpp" role="src" />
<file name="global.hpp" role="src" /> <file name="global.hpp" role="src" />
<file name="hardlinks.cpp" role="src" />
<file name="hash.cpp" role="src" />
<file name="hash.hpp" role="src" />
<file name="headers.cpp" role="src" />
<file name="headers.hpp" role="src" /> <file name="headers.hpp" role="src" />
<file name="headers5.hpp" role="src" />
<file name="isnt.cpp" role="src" /> <file name="isnt.cpp" role="src" />
<file name="isnt.hpp" 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="LICENSE.txt" role="doc" />
<file name="list.cpp" role="src" /> <file name="list.cpp" role="src" />
<file name="list.hpp" role="src" /> <file name="list.hpp" role="src" />
@@ -257,15 +223,12 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="match.hpp" role="src" /> <file name="match.hpp" role="src" />
<file name="model.cpp" role="src" /> <file name="model.cpp" role="src" />
<file name="model.hpp" 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.cpp" role="src" />
<file name="options.hpp" role="src" /> <file name="options.hpp" role="src" />
<file name="os.hpp" role="src" /> <file name="os.hpp" role="src" />
<file name="os2ea.cpp" role="src" />
<file name="pathfn.cpp" role="src" /> <file name="pathfn.cpp" role="src" />
<file name="pathfn.hpp" role="src" /> <file name="pathfn.hpp" role="src" />
<file name="qopen.cpp" role="src" />
<file name="qopen.hpp" role="src" />
<file name="rar.cpp" role="src" /> <file name="rar.cpp" role="src" />
<file name="rar.hpp" role="src" /> <file name="rar.hpp" role="src" />
<file name="rardefs.hpp" role="src" /> <file name="rardefs.hpp" role="src" />
@@ -274,31 +237,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="rartypes.hpp" role="src" /> <file name="rartypes.hpp" role="src" />
<file name="rarvm.cpp" role="src" /> <file name="rarvm.cpp" role="src" />
<file name="rarvm.hpp" role="src" /> <file name="rarvm.hpp" role="src" />
<file name="rawint.hpp" role="src" /> <file name="rarvmtbl.cpp" role="src" />
<file name="rawread.cpp" role="src" /> <file name="rawread.cpp" role="src" />
<file name="rawread.hpp" role="src" /> <file name="rawread.hpp" role="src" />
<file name="rdwrfn.cpp" role="src" /> <file name="rdwrfn.cpp" role="src" />
<file name="rdwrfn.hpp" role="src" /> <file name="rdwrfn.hpp" role="src" />
<file name="recvol3.cpp" role="src" />
<file name="recvol5.cpp" role="src" />
<file name="rs16.cpp" role="src" />
<file name="rs16.hpp" role="src" />
<file name="sha256.cpp" role="src" />
<file name="sha256.hpp" role="src" />
<file name="threadmisc.cpp" role="src" />
<file name="threadpool.cpp" role="src" />
<file name="threadpool.hpp" role="src" />
<file name="ui.cpp" role="src" />
<file name="ui.hpp" role="src" />
<file name="uicommon.cpp" role="src" />
<file name="uiconsole.cpp" role="src" />
<file name="uisilent.cpp" role="src" />
<file name="unpack30.cpp" role="src" />
<file name="unpack50.cpp" role="src" />
<file name="unpack50frag.cpp" role="src" />
<file name="unpack50mt.cpp" role="src" />
<file name="unpackinline.cpp" role="src" />
<file name="win32lnk.cpp" role="src" />
<file name="README.txt" role="doc" /> <file name="README.txt" role="doc" />
<file name="recvol.cpp" role="src" /> <file name="recvol.cpp" role="src" />
<file name="recvol.hpp" role="src" /> <file name="recvol.hpp" role="src" />
@@ -308,6 +251,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="rijndael.hpp" role="src" /> <file name="rijndael.hpp" role="src" />
<file name="rs.cpp" role="src" /> <file name="rs.cpp" role="src" />
<file name="rs.hpp" role="src" /> <file name="rs.hpp" role="src" />
<file name="savepos.cpp" role="src" />
<file name="savepos.hpp" role="src" />
<file name="scantree.cpp" role="src" /> <file name="scantree.cpp" role="src" />
<file name="scantree.hpp" role="src" /> <file name="scantree.hpp" role="src" />
<file name="secpassword.cpp" role="src" /> <file name="secpassword.cpp" role="src" />
@@ -327,8 +272,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="timefn.cpp" role="src" /> <file name="timefn.cpp" role="src" />
<file name="timefn.hpp" role="src" /> <file name="timefn.hpp" role="src" />
<file name="ulinks.cpp" role="src" /> <file name="ulinks.cpp" role="src" />
<file name="ulinks.hpp" role="src" />
<file name="unicode.cpp" role="src" /> <file name="unicode.cpp" role="src" />
<file name="unicode.hpp" role="src" /> <file name="unicode.hpp" role="src" />
<file name="unios2.cpp" role="src" />
<file name="unpack.cpp" role="src" /> <file name="unpack.cpp" role="src" />
<file name="unpack.hpp" role="src" /> <file name="unpack.hpp" role="src" />
<file name="unpack15.cpp" role="src" /> <file name="unpack15.cpp" role="src" />
@@ -344,18 +291,14 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="config.w32" role="src" /> <file name="config.w32" role="src" />
<file name="CREDITS" role="doc" /> <file name="CREDITS" role="doc" />
<file name="LICENSE" role="doc" /> <file name="LICENSE" role="doc" />
<file name="Makefile.frag" role="src" /> <file name="README" role="doc" />
<file name="README.md" role="doc" />
<file name="example.php" role="doc" /> <file name="example.php" role="doc" />
<file name="php_compat.h" role="src" />
<file name="php_rar.h" role="src" /> <file name="php_rar.h" role="src" />
<file name="rar.c" role="src" /> <file name="rar.c" role="src" />
<file name="rar_stream.c" role="src" /> <file name="rar_stream.c" role="src" />
<file name="rararch.c" role="src" /> <file name="rararch.c" role="src" />
<file name="rarentry.c" role="src" /> <file name="rarentry.c" role="src" />
<file name="rar_error.c" role="src" /> <file name="rar_error.c" role="src" />
<file name="rar_time.c" role="src" />
<file name="run-tests-rar.php" role="test" />
<file role="src" name="rar_navigation.c"/> <file role="src" name="rar_navigation.c"/>
</dir> <!-- / --> </dir> <!-- / -->
</contents> </contents>
@@ -363,7 +306,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<dependencies> <dependencies>
<required> <required>
<php> <php>
<min>7.0.0</min> <min>5.2.0</min>
</php> </php>
<pearinstaller> <pearinstaller>
<min>1.4.0</min> <min>1.4.0</min>
@@ -374,112 +317,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
<providesextension>rar</providesextension> <providesextension>rar</providesextension>
<extsrcrelease /> <extsrcrelease />
<changelog> <changelog>
<release>
<version>
<release>4.3.1</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2026-03-15</date>
<notes>Changes in this version:
- Fix bug #75557: error opening archive with non-English characters in path on Windows.
- Do not build unconditionally against listdc++.
</notes>
</release>
<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>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2020-10-11</date>
<notes>Changes in this version:
- Merge changes made to unrar up to version 5.5.6.
- Support PHP 7.2, PHP 7.3 and PHP 7.4.
- Update to unrar 5.9.4.
- Fix bug #76592: streaming unpacking of uncompressed files incomplete.
</notes>
</release>
<release>
<version>
<release>4.0.0</release>
<api>4.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2017-07-22</date>
<notes>Changes in this version:
- Added functions RarEntry::getRedirType(), RarEntry::isRedirectToDirectory() and RarEntry::getRedirTarget(), as well as the following constants on RarEntry: FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, FSREDIR_HARDLINK and FSREDIR_FILECOPY.
- Changed stat handler to return UTC time for creation, modification and access time (does not work reliably on Windows).
- Fix cloning of RarArchive being allowed.
</notes>
</release>
<release>
<version>
<release>3.0.2</release>
<api>3.0.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<date>2013-10-11</date>
<notes>Changes in this version:
- Fixed build with PHP 5.5.
- Upgraded bundled unrar to version 4.2.4.
</notes>
</release>
<release> <release>
<version> <version>
<release>3.0.1</release> <release>3.0.1</release>
@@ -567,7 +406,7 @@ Other changes:
- A lot of refactoring and compilation as C, not C++. - A lot of refactoring and compilation as C, not C++.
</notes> </notes>
</release> </release>
<release> <release>
<version> <version>
<release>1.0.0</release> <release>1.0.0</release>
-11
View File
@@ -1,11 +0,0 @@
// Add predefined macros for your project here. For example:
// #define THE_ANSWER 42
#define RARDLL 1
#define HAVE_CONFIG_H 1
#define _Float32 float
#define _Float32x float
#define _Float64 double
#define _Float64x double
#define _Float128 long double
#define _Float128x long double
#define _BITS_FLOATN_H
-1
View File
@@ -1 +0,0 @@
[General]
-161
View File
@@ -1,161 +0,0 @@
config.h
php_compat.h
php_compat.h
php_rar.h
rar.c
rar_error.c
rar_navigation.c
rar_stream.c
rar_time.c
rararch.c
rarentry.c
unrar/arccmt.cpp
unrar/archive.cpp
unrar/archive.hpp
unrar/arcread.cpp
unrar/array.hpp
unrar/blake2s.cpp
unrar/blake2s.hpp
unrar/blake2s_sse.cpp
unrar/blake2sp.cpp
unrar/cmddata.cpp
unrar/cmddata.hpp
unrar/cmdfilter.cpp
unrar/cmdmix.cpp
unrar/coder.cpp
unrar/coder.hpp
unrar/compress.hpp
unrar/consio.cpp
unrar/consio.hpp
unrar/crc.cpp
unrar/crc.hpp
unrar/crypt.cpp
unrar/crypt.hpp
unrar/crypt1.cpp
unrar/crypt2.cpp
unrar/crypt3.cpp
unrar/crypt5.cpp
unrar/dll.cpp
unrar/dll.hpp
unrar/encname.cpp
unrar/encname.hpp
unrar/errhnd.cpp
unrar/errhnd.hpp
unrar/extinfo.cpp
unrar/extinfo.hpp
unrar/extract.cpp
unrar/extract.hpp
unrar/extractchunk.cpp
unrar/filcreat.cpp
unrar/filcreat.hpp
unrar/file.cpp
unrar/file.hpp
unrar/filefn.cpp
unrar/filefn.hpp
unrar/filestr.cpp
unrar/filestr.hpp
unrar/find.cpp
unrar/find.hpp
unrar/getbits.cpp
unrar/getbits.hpp
unrar/global.cpp
unrar/global.hpp
unrar/hardlinks.cpp
unrar/hash.cpp
unrar/hash.hpp
unrar/headers.cpp
unrar/headers.hpp
unrar/headers5.hpp
unrar/isnt.cpp
unrar/isnt.hpp
unrar/list.cpp
unrar/list.hpp
unrar/loclang.hpp
unrar/log.cpp
unrar/log.hpp
unrar/match.cpp
unrar/match.hpp
unrar/model.cpp
unrar/model.hpp
unrar/options.cpp
unrar/options.hpp
unrar/os.hpp
unrar/pathfn.cpp
unrar/pathfn.hpp
unrar/qopen.cpp
unrar/qopen.hpp
unrar/rar.cpp
unrar/rar.hpp
unrar/rardefs.hpp
unrar/rarlang.hpp
unrar/raros.hpp
unrar/rartypes.hpp
unrar/rarvm.cpp
unrar/rarvm.hpp
unrar/rarvmtbl.cpp
unrar/rawint.hpp
unrar/rawread.cpp
unrar/rawread.hpp
unrar/rdwrfn.cpp
unrar/rdwrfn.hpp
unrar/recvol.cpp
unrar/recvol.hpp
unrar/recvol3.cpp
unrar/recvol5.cpp
unrar/resource.cpp
unrar/resource.hpp
unrar/rijndael.cpp
unrar/rijndael.hpp
unrar/rs.cpp
unrar/rs.hpp
unrar/rs16.cpp
unrar/rs16.hpp
unrar/savepos.hpp
unrar/scantree.cpp
unrar/scantree.hpp
unrar/secpassword.cpp
unrar/secpassword.hpp
unrar/sha1.cpp
unrar/sha1.hpp
unrar/sha256.cpp
unrar/sha256.hpp
unrar/smallfn.cpp
unrar/smallfn.hpp
unrar/strfn.cpp
unrar/strfn.hpp
unrar/strlist.cpp
unrar/strlist.hpp
unrar/suballoc.cpp
unrar/suballoc.hpp
unrar/system.cpp
unrar/system.hpp
unrar/threadmisc.cpp
unrar/threadpool.cpp
unrar/threadpool.hpp
unrar/timefn.cpp
unrar/timefn.hpp
unrar/ui.cpp
unrar/ui.hpp
unrar/uicommon.cpp
unrar/uiconsole.cpp
unrar/uisilent.cpp
unrar/ulinks.cpp
unrar/ulinks.hpp
unrar/unicode.cpp
unrar/unicode.hpp
unrar/unpack.cpp
unrar/unpack.hpp
unrar/unpack15.cpp
unrar/unpack20.cpp
unrar/unpack30.cpp
unrar/unpack50.cpp
unrar/unpack50frag.cpp
unrar/unpack50mt.cpp
unrar/unpackinline.cpp
unrar/uowners.cpp
unrar/version.hpp
unrar/volume.cpp
unrar/volume.hpp
unrar/win32acl.cpp
unrar/win32lnk.cpp
unrar/win32stm.cpp
-4
View File
@@ -1,4 +0,0 @@
/home/glopes/repos/php-src/Zend
/home/glopes/repos/php-src/TSRM
/home/glopes/repos/php-src/main
/home/glopes/repos/php-src
-54
View File
@@ -1,54 +0,0 @@
#include <php.h>
#if PHP_MAJOR_VERSION >= 8
# define TSRMLS_DC
# define TSRMLS_D
# define TSRMLS_CC
# define TSRMLS_C
# define TSRMLS_FETCH()
# define IS_CALLABLE_STRICT 0
# define zend_qsort zend_sort
# define ZV_TO_THIS_FOR_HANDLER(zv) (Z_OBJ_P(zv))
typedef zend_object handler_this_t;
#else
# define ZV_TO_THIS_FOR_HANDLER(zv) (zv)
typedef zval handler_this_t;
#endif
typedef zend_object* rar_obj_ref;
#define rar_zval_add_ref(ppzv) zval_add_ref(*ppzv)
#define ZVAL_ALLOC_DUP(dst, src) \
do { \
dst = (zval*) emalloc(sizeof(zval)); \
ZVAL_DUP(dst, src); \
} while (0)
#define RAR_RETURN_STRINGL(s, l, duplicate) \
do { \
RETVAL_STRINGL(s, l); \
if (duplicate == 0) { \
efree(s); \
} \
return; \
} while (0)
#define RAR_ZVAL_STRING(z, s, duplicate) \
do { \
ZVAL_STRING(z, s); \
if (duplicate == 0) { \
efree(s); \
} \
} while (0)
typedef size_t zpp_s_size_t;
#define MAKE_STD_ZVAL(zv_p) \
do { \
(zv_p) = emalloc(sizeof(zval)); \
ZVAL_NULL(zv_p); \
} while (0)
#define INIT_ZVAL(zv) ZVAL_UNDEF(&zv)
#define ZEND_ACC_FINAL_CLASS ZEND_ACC_FINAL
+93 -27
View File
@@ -51,7 +51,7 @@
extern zend_module_entry rar_module_entry; extern zend_module_entry rar_module_entry;
#define phpext_rar_ptr &rar_module_entry #define phpext_rar_ptr &rar_module_entry
#define PHP_RAR_VERSION "4.3.2-dev" #define PHP_RAR_VERSION "4.0.0"
#ifdef PHP_WIN32 #ifdef PHP_WIN32
#define PHP_RAR_API __declspec(dllexport) #define PHP_RAR_API __declspec(dllexport)
@@ -63,8 +63,6 @@ extern zend_module_entry rar_module_entry;
#include "TSRM.h" #include "TSRM.h"
#endif #endif
#include "php_compat.h"
/* causes linking errors (multiple definitions) in functions /* causes linking errors (multiple definitions) in functions
that were requested inlining but were not inlined by the compiler */ that were requested inlining but were not inlined by the compiler */
/* #include "unrar/rar.hpp */ /* #include "unrar/rar.hpp */
@@ -77,7 +75,6 @@ extern zend_module_entry rar_module_entry;
#include "unrar/dll.hpp" #include "unrar/dll.hpp"
#include "unrar/version.hpp" #include "unrar/version.hpp"
/* These are in unrar/headers.hpp, but that header depends on several other */ /* These are in unrar/headers.hpp, but that header depends on several other */
/* clang-format off */
enum HOST_SYSTEM { enum HOST_SYSTEM {
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4, HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX HOST_BEOS=5,HOST_MAX
@@ -86,12 +83,67 @@ enum FILE_SYSTEM_REDIRECT {
FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
FSREDIR_HARDLINK, FSREDIR_FILECOPY FSREDIR_HARDLINK, FSREDIR_FILECOPY
}; };
/* clang-format on */
/* maximum comment size if 64KB */ /* maximum comment size if 64KB */
#define RAR_MAX_COMMENT_SIZE 65536 #define RAR_MAX_COMMENT_SIZE 65536
/* clang-format off */ /* PHP 7+ abstraction */
#if PHP_MAJOR_VERSION >= 7
typedef zend_object* rar_obj_ref;
#define rar_zval_add_ref(ppzv) zval_add_ref(*ppzv)
#define ZVAL_ALLOC_DUP(dst, src) \
do { \
dst = (zval*) emalloc(sizeof(zval)); \
ZVAL_DUP(dst, src); \
} while (0)
#define RAR_RETURN_STRINGL(s, l, duplicate) \
do { \
RETVAL_STRINGL(s, l); \
if (duplicate == 0) { \
efree(s); \
} \
return; \
} while (0)
#define RAR_ZVAL_STRING(z, s, duplicate) \
do { \
ZVAL_STRING(z, s); \
if (duplicate == 0) { \
efree(s); \
} \
} while (0)
typedef size_t zpp_s_size_t;
#define MAKE_STD_ZVAL(zv_p) \
do { \
(zv_p) = emalloc(sizeof(zval)); \
ZVAL_NULL(zv_p); \
} while (0)
#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
typedef struct _rar_cb_user_data { typedef struct _rar_cb_user_data {
char *password; /* can be NULL */ char *password; /* can be NULL */
zval *callable; /* can be NULL */ zval *callable; /* can be NULL */
@@ -108,19 +160,13 @@ typedef struct rar {
rar_cb_user_data cb_userdata; rar_cb_user_data cb_userdata;
int allow_broken; int allow_broken;
} rar_file_t; } rar_file_t;
/* clang-format on */
/* Misc */ /* Misc */
# if defined(__GNUC__) || defined(__clang__) #if defined(ZTS) && PHP_MAJOR_VERSION < 7
# define ARR_SIZE(arr) \ # define RAR_TSRMLS_TC , void ***
(sizeof(arr) / sizeof((arr)[0]) + \ #else
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 # define RAR_TSRMLS_TC
#endif
#define RAR_RETNULL_ON_ARGS() \ #define RAR_RETNULL_ON_ARGS() \
if (zend_parse_parameters_none() == FAILURE) { \ if (zend_parse_parameters_none() == FAILURE) { \
@@ -167,6 +213,33 @@ ZEND_EXTERN_MODULE_GLOBALS(rar);
# define RAR_G(v) (rar_globals.v) # define RAR_G(v) (rar_globals.v)
#endif #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 #if !defined(HAVE_STRNLEN) || !HAVE_STRNLEN
size_t _rar_strnlen(const char *s, size_t maxlen); size_t _rar_strnlen(const char *s, size_t maxlen);
@@ -230,7 +303,7 @@ typedef struct _rar_find_output {
int found; int found;
size_t position; size_t position;
struct RARHeaderDataEx * header; struct RARHeaderDataEx * header;
zend_ulong packed_size; unsigned long packed_size;
int eof; int eof;
} rar_find_output; } rar_find_output;
#define RAR_SEARCH_INDEX 0x01U #define RAR_SEARCH_INDEX 0x01U
@@ -260,9 +333,8 @@ void _rar_close_file_resource(rar_file_t *rar);
/* Fetches the rar_file_t part of the RarArchive object in order to use the /* Fetches the rar_file_t part of the RarArchive object in order to use the
* operations above and (discouraged) to have direct access to the fields * operations above and (discouraged) to have direct access to the fields
* RarEntry::extract/getStream access extract_open_dat and cb_userdata */ * RarEntry::extract/getStream access extract_open_dat and cb_userdata */
int _rar_get_file_resource_zv(zval *zv_file, rar_file_t **rar_file TSRMLS_DC); int _rar_get_file_resource(zval *zval_file, rar_file_t **rar_file TSRMLS_DC);
int _rar_get_file_resource_zv_ex(zval *zv_file, rar_file_t **rar_file, int silent TSRMLS_DC); int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC);
int _rar_get_file_resource_ex(rar_obj_ref objref_file, rar_file_t **rar_file, int silent TSRMLS_DC);
void minit_rararch(TSRMLS_D); void minit_rararch(TSRMLS_D);
PHP_FUNCTION(rar_open); PHP_FUNCTION(rar_open);
@@ -279,7 +351,7 @@ extern zend_class_entry *rar_class_entry_ptr;
void minit_rarentry(TSRMLS_D); void minit_rarentry(TSRMLS_D);
void _rar_entry_to_zval(zval *parent, void _rar_entry_to_zval(zval *parent,
struct RARHeaderDataEx *entry, struct RARHeaderDataEx *entry,
zend_ulong packed_size, unsigned long packed_size,
size_t index, size_t index,
zval *entry_object TSRMLS_DC); zval *entry_object TSRMLS_DC);
@@ -290,12 +362,6 @@ php_stream *php_stream_rar_open(char *arc_name,
STREAMS_DC TSRMLS_DC); STREAMS_DC TSRMLS_DC);
extern php_stream_wrapper php_stream_rar_wrapper; extern php_stream_wrapper php_stream_rar_wrapper;
/* rar_time.c */
void rar_time_convert(unsigned low, unsigned high, time_t *to);
int rar_dos_time_convert(unsigned dos_time, time_t *to);
#ifdef PHP_WIN32
#define timegm _mkgmtime
#endif
#endif /* PHP_RAR_H */ #endif /* PHP_RAR_H */
-189
View File
@@ -1,189 +0,0 @@
# PHP 8.18.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: -->
+93 -22
View File
@@ -28,12 +28,14 @@
/* $Id$ */ /* $Id$ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" #include "config.h"
#endif #endif
#ifndef _GNU_SOURCE #ifdef __cplusplus
# define _GNU_SOURCE extern "C" {
#endif #endif
#define _GNU_SOURCE
#include <string.h> #include <string.h>
#ifdef PHP_WIN32 #ifdef PHP_WIN32
@@ -48,7 +50,7 @@
#include <ext/standard/info.h> #include <ext/standard/info.h>
#include <ext/spl/spl_exceptions.h> #include <ext/spl/spl_exceptions.h>
#include "unrar/rardefs.hpp" #if HAVE_RAR
#include "php_rar.h" #include "php_rar.h"
@@ -159,8 +161,12 @@ void _rar_destroy_userdata(rar_cb_user_data *udata) /* {{{ */
} }
if (udata->callable != NULL) { if (udata->callable != NULL) {
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&udata->callable);
#else
zval_ptr_dtor(udata->callable); zval_ptr_dtor(udata->callable);
efree(udata->callable); efree(udata->callable);
#endif
} }
udata->password = NULL; udata->password = NULL;
@@ -234,16 +240,13 @@ int _rar_find_file_w(struct RAROpenArchiveDataEx *open_data, /* IN */
while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) { while ((result = RARReadHeaderEx(*arc_handle, used_header_data)) == 0) {
#if WCHAR_MAX > 0xffff #if WCHAR_MAX > 0xffff
_rar_fix_wide(used_header_data->FileNameW, _rar_fix_wide(used_header_data->FileNameW, NM);
ARR_SIZE(used_header_data->FileNameW));
#endif #endif
if (wcsncmp(used_header_data->FileNameW, file_name, if (wcsncmp(used_header_data->FileNameW, file_name, NM) == 0) {
ARR_SIZE(used_header_data->FileNameW)) == 0) {
*found = TRUE; *found = TRUE;
goto cleanup; goto cleanup;
} } else {
else {
process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL); process_result = RARProcessFile(*arc_handle, RAR_SKIP, NULL, NULL);
} }
if (process_result != 0) { if (process_result != 0) {
@@ -380,7 +383,6 @@ int CALLBACK _rar_unrar_callback(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2
return ret; return ret;
} }
} }
// TODO: maybe support UCM_NEEDPASSWORDW and UCM_CHANGEVOLUMEW
return 0; return 0;
} }
@@ -423,7 +425,7 @@ PHP_FUNCTION(rar_wrapper_cache_stats) /* {{{ */
static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */ static void _rar_fix_wide(wchar_t *str, size_t max_size) /* {{{ */
{ {
wchar_t *write, wchar_t *write,
*read, *read,
*max_fin; *max_fin;
max_fin = str + max_size; max_fin = str + max_size;
for (write = str, read = str; *read != L'\0' && read != max_fin; read++) { for (write = str, read = str; *read != L'\0' && read != max_fin; read++) {
@@ -440,37 +442,61 @@ 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 * because, in case we're using exceptions, we want to let an exception with
* error code ERAR_EOPEN to be thrown. * error code ERAR_EOPEN to be thrown.
*/ */
static int _rar_unrar_volume_user_callback(char* dst_buffer, // MAXPATHSIZE static int _rar_unrar_volume_user_callback(char* dst_buffer,
zend_fcall_info *fci, zend_fcall_info *fci,
zend_fcall_info_cache *cache zend_fcall_info_cache *cache
TSRMLS_DC) /* {{{ */ TSRMLS_DC) /* {{{ */
{ {
#if PHP_MAJOR_VERSION < 7
zval *failed_vol,
*retval_ptr = NULL,
**params;
#else
zval failed_vol, zval failed_vol,
retval, retval,
*params, *params,
*const retval_ptr = &retval; *const retval_ptr = &retval;
#endif
int ret = -1; 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 = &params;
#else
ZVAL_STRING(&failed_vol, dst_buffer); ZVAL_STRING(&failed_vol, dst_buffer);
ZVAL_NULL(&retval); ZVAL_NULL(&retval);
params = &failed_vol; params = &failed_vol;
fci->retval = &retval; fci->retval = &retval;
fci->params = params; fci->params = params;
#endif
fci->param_count = 1; 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)) { if (zend_call_function(fci, cache TSRMLS_CC) != SUCCESS || EG(exception)) {
#endif
php_error_docref(NULL TSRMLS_CC, E_WARNING, php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Failure to call volume find callback"); "Failure to call volume find callback");
goto cleanup; goto cleanup;
} }
#if PHP_MAJOR_VERSION < 7
assert(*fci->retval_ptr_ptr == retval_ptr);
#else
assert(fci->retval == &retval); assert(fci->retval == &retval);
#endif
if (Z_TYPE_P(retval_ptr) == IS_NULL) { if (Z_TYPE_P(retval_ptr) == IS_NULL) {
/* let return -1 */ /* let return -1 */
} }
else if (Z_TYPE_P(retval_ptr) == IS_STRING) { else if (Z_TYPE_P(retval_ptr) == IS_STRING) {
char *filename = Z_STRVAL_P(retval_ptr); char *filename = Z_STRVAL_P(retval_ptr);
char resolved_path[MAXPATHSIZE]; char resolved_path[MAXPATHLEN];
size_t resolved_len; size_t resolved_len;
if (OPENBASEDIR_CHECKPATH(filename)) { if (OPENBASEDIR_CHECKPATH(filename)) {
@@ -482,15 +508,17 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer, // MAXPATHSIZE
goto cleanup; goto cleanup;
} }
resolved_len = _rar_strnlen(resolved_path, MAXPATHSIZE); resolved_len = _rar_strnlen(resolved_path, MAXPATHLEN);
if (resolved_len > MAXPATHSIZE - 1) { /* 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) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Resolved path is too big for the unRAR library"); "Resolved path is too big for the unRAR library");
goto cleanup; goto cleanup;
} }
strncpy(dst_buffer, resolved_path, MAXPATHSIZE); strncpy(dst_buffer, resolved_path, NM);
dst_buffer[MAXPATHSIZE - 1] = '\0'; dst_buffer[NM - 1] = '\0';
ret = 1; /* try this new filename */ ret = 1; /* try this new filename */
} }
else { else {
@@ -501,8 +529,15 @@ static int _rar_unrar_volume_user_callback(char* dst_buffer, // MAXPATHSIZE
} }
cleanup: 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(&failed_vol);
zval_ptr_dtor(&retval); zval_ptr_dtor(&retval);
#endif
return ret; return ret;
} }
/* }}} */ /* }}} */
@@ -518,6 +553,17 @@ static int _rar_make_userdata_fcall(zval *callable,
*cache = empty_fcall_info_cache; *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, if (zend_fcall_info_init(callable, IS_CALLABLE_STRICT, fci, cache, NULL,
&error TSRMLS_CC) == SUCCESS) { &error TSRMLS_CC) == SUCCESS) {
if (error) { if (error) {
@@ -537,6 +583,7 @@ static int _rar_make_userdata_fcall(zval *callable,
} }
return FAILURE; return FAILURE;
} }
#endif
} }
/* }}} */ /* }}} */
@@ -587,7 +634,6 @@ ZEND_END_ARG_INFO()
/* {{{ rar_functions[] /* {{{ rar_functions[]
* *
*/ */
/* clang-format off */
static zend_function_entry rar_functions[] = { static zend_function_entry rar_functions[] = {
PHP_FE(rar_open, arginfo_rar_open) PHP_FE(rar_open, arginfo_rar_open)
PHP_FE(rar_list, arginfo_rar_void_archmeth) PHP_FE(rar_list, arginfo_rar_void_archmeth)
@@ -600,13 +646,16 @@ static zend_function_entry rar_functions[] = {
PHP_FE(rar_wrapper_cache_stats, arginfo_rar_wrapper_cache_stats) PHP_FE(rar_wrapper_cache_stats, arginfo_rar_wrapper_cache_stats)
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
/* clang-format on */
/* }}} */ /* }}} */
/* {{{ Globals' related activities */ /* {{{ Globals' related activities */
ZEND_DECLARE_MODULE_GLOBALS(rar); 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) static int _rar_array_apply_remove_first(zval *pDest TSRMLS_DC)
#endif
{ {
return (ZEND_HASH_APPLY_STOP | ZEND_HASH_APPLY_REMOVE); return (ZEND_HASH_APPLY_STOP | ZEND_HASH_APPLY_REMOVE);
} }
@@ -624,7 +673,13 @@ static void _rar_contents_cache_put(const char *key,
assert(zend_hash_num_elements(cc->data) == cur_size - 1); assert(zend_hash_num_elements(cc->data) == cur_size - 1);
} }
rar_zval_add_ref(&zv); 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); zend_hash_str_update(cc->data, key, key_len, zv);
#endif
} }
static zval *_rar_contents_cache_get(const char *key, static zval *_rar_contents_cache_get(const char *key,
@@ -633,7 +688,15 @@ static zval *_rar_contents_cache_get(const char *key,
{ {
rar_contents_cache *cc = &RAR_G(contents_cache); rar_contents_cache *cc = &RAR_G(contents_cache);
zval *element = NULL; 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); element = zend_hash_str_find(cc->data, key, key_len);
#endif
if (element != NULL) { if (element != NULL) {
cc->hits++; cc->hits++;
@@ -692,14 +755,16 @@ ZEND_MODULE_STARTUP_D(rar)
php_register_url_stream_wrapper("rar", &php_stream_rar_wrapper TSRMLS_CC); 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_MSDOS", HOST_MSDOS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_OS2", HOST_OS2, 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_WIN32", HOST_WIN32, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_UNIX", HOST_UNIX, 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_MACOS", HOST_MACOS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("RAR_HOST_BEOS", HOST_BEOS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("RAR_HOST_BEOS", HOST_BEOS, CONST_CS | CONST_PERSISTENT);
/* clang-format on */ /* 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
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */
@@ -764,6 +829,12 @@ zend_module_entry rar_module_entry = {
}; };
/* }}} */ /* }}} */
#endif /* HAVE_RAR */
#ifdef __cplusplus
}
#endif
/* /*
* Local variables: * Local variables:
* tab-width: 4 * tab-width: 4
-1
View File
@@ -1 +0,0 @@
{ global: get_module; local: *; };
+42 -5
View File
@@ -25,6 +25,10 @@
+----------------------------------------------------------------------+ +----------------------------------------------------------------------+
*/ */
#ifdef __cplusplus
extern "C" {
#endif
#include <php.h> #include <php.h>
#include <zend_exceptions.h> #include <zend_exceptions.h>
#include "php_rar.h" #include "php_rar.h"
@@ -66,7 +70,11 @@ void _rar_handle_ext_error(const char *format TSRMLS_DC, ...) /* {{{ */
va_list arg; va_list arg;
char *message; char *message;
#if defined(ZTS) && PHP_MAJOR_VERSION < 7
va_start(arg, TSRMLS_C);
#else
va_start(arg, format); va_start(arg, format);
#endif
vspprintf(&message, 0, format, arg); vspprintf(&message, 0, format, arg);
va_end(arg); va_end(arg);
@@ -83,8 +91,13 @@ int _rar_using_exceptions(TSRMLS_D)
zval *pval; zval *pval;
pval = zend_read_static_property(rarexception_ce_ptr, "usingExceptions", pval = zend_read_static_property(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, (zend_bool) 1 TSRMLS_CC); 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); assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
return Z_TYPE_P(pval) == IS_TRUE; return Z_TYPE_P(pval) == IS_TRUE;
#endif
} }
/* returns a string or NULL if not an error */ /* returns a string or NULL if not an error */
@@ -173,22 +186,39 @@ PHP_METHOD(rarexception, setUsingExceptions)
Return whether exceptions are being used */ Return whether exceptions are being used */
PHP_METHOD(rarexception, isUsingExceptions) PHP_METHOD(rarexception, isUsingExceptions)
{ {
#if PHP_MAJOR_VERSION < 7
zval **pval;
#else
zval *pval; zval *pval;
#endif
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE ) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE ) {
return; return;
} }
/* or zend_read_static_property, which calls zend_std_get... after chg scope */ /* 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 *prop_name =
zend_string_init("usingExceptions", sizeof("usingExceptions") - 1, 0); zend_string_init("usingExceptions", sizeof("usingExceptions") - 1, 0);
pval = zend_std_get_static_property(rarexception_ce_ptr, prop_name, pval = zend_std_get_static_property(rarexception_ce_ptr, prop_name,
(zend_bool) 0); (zend_bool) 0);
zend_string_release(prop_name); zend_string_release(prop_name);
#endif
/* property always exists */ /* property always exists */
assert(pval != NULL); 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); assert(Z_TYPE_P(pval) == IS_TRUE || Z_TYPE_P(pval) == IS_FALSE);
RETURN_ZVAL(pval, 0, 0); RETURN_ZVAL(pval, 0, 0);
#endif
} }
/* }}} */ /* }}} */
@@ -201,24 +231,31 @@ ZEND_BEGIN_ARG_INFO(arginfo_rarexception_void, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
/* }}} */ /* }}} */
/* clang-format off */
static zend_function_entry php_rarexception_class_functions[] = { static zend_function_entry php_rarexception_class_functions[] = {
PHP_ME(rarexception, setUsingExceptions, arginfo_rarexception_sue, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 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) PHP_ME(rarexception, isUsingExceptions, arginfo_rarexception_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
/* clang-format on */
void minit_rarerror(TSRMLS_D) /* {{{ */ void minit_rarerror(TSRMLS_D) /* {{{ */
{ {
zend_class_entry ce; zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "RarException", php_rarexception_class_functions); INIT_CLASS_ENTRY(ce, "RarException", php_rarexception_class_functions);
/* zend_exception_get_default() was removed in PHP 8.5; use the global directly */ #if PHP_MAJOR_VERSION < 7
rarexception_ce_ptr = zend_register_internal_class_ex(&ce, zend_ce_exception); 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
rarexception_ce_ptr->ce_flags |= ZEND_ACC_FINAL; rarexception_ce_ptr->ce_flags |= ZEND_ACC_FINAL;
zend_declare_property_bool(rarexception_ce_ptr, "usingExceptions", zend_declare_property_bool(rarexception_ce_ptr, "usingExceptions",
sizeof("usingExceptions") -1, 0L /* FALSE */, sizeof("usingExceptions") -1, 0L /* FALSE */,
ZEND_ACC_STATIC TSRMLS_CC); ZEND_ACC_PRIVATE | ZEND_ACC_STATIC TSRMLS_CC);
} }
/* }}} */ /* }}} */
#ifdef __cplusplus
}
#endif
+49 -34
View File
@@ -25,16 +25,21 @@
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif #endif
#include <php.h> #include <php.h>
#include <wchar.h> #include <wchar.h>
#include "php_rar.h" #include "php_rar.h"
#if HAVE_RAR
/* {{{ Structure definitions */ /* {{{ Structure definitions */
/* clang-format off */
typedef struct _rar_find_state { typedef struct _rar_find_state {
rar_find_output out; rar_find_output out;
rar_file_t *rar; rar_file_t *rar;
@@ -44,7 +49,7 @@ typedef struct _rar_find_state {
struct _rar_unique_entry { struct _rar_unique_entry {
size_t id; /* position in the entries_array */ size_t id; /* position in the entries_array */
struct RARHeaderDataEx entry; /* last entry */ struct RARHeaderDataEx entry; /* last entry */
zend_ulong packed_size; unsigned long packed_size;
int depth; /* number of directory separators */ int depth; /* number of directory separators */
size_t name_wlen; /* excluding L'\0' terminator */ size_t name_wlen; /* excluding L'\0' terminator */
}; };
@@ -60,7 +65,6 @@ struct _rar_entries {
struct _rar_unique_entry *last_accessed; struct _rar_unique_entry *last_accessed;
int list_result; /* tell whether the archive's broken */ int list_result; /* tell whether the archive's broken */
}; };
/* clang-format on */
/* }}} */ /* }}} */
@@ -69,7 +73,9 @@ static void _rar_nav_get_depth_and_length(wchar_t *filenamew, const size_t file_
int *depth_out, size_t *wlen_out TSRMLS_DC); 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_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); 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); 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 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, static inline int _rar_nav_compare_values(const wchar_t *str1, const int depth1,
const wchar_t *str2, const int depth2, const wchar_t *str2, const int depth2,
@@ -110,9 +116,15 @@ void _rar_entry_search_start(rar_file_t *rar,
sizeof rar->entries->entries_array_s[0]); sizeof rar->entries->entries_array_s[0]);
memcpy(rar->entries->entries_array_s, rar->entries->entries_array, memcpy(rar->entries->entries_array_s, rar->entries->entries_array,
rar->entries->num_entries * sizeof rar->entries->entries_array[0]); 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, zend_qsort(rar->entries->entries_array_s, rar->entries->num_entries,
sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries, sizeof *rar->entries->entries_array_s, _rar_nav_compare_entries,
_rar_nav_swap_entries); _rar_nav_swap_entries);
#endif
} }
} }
/* }}} */ /* }}} */
@@ -301,9 +313,6 @@ void _rar_delete_entries(rar_file_t *rar TSRMLS_DC)
if (rar->entries->entries_array != NULL) { if (rar->entries->entries_array != NULL) {
size_t i; size_t i;
for (i = 0; i < rar->entries->num_entries; i++) { for (i = 0; i < rar->entries->num_entries; i++) {
if (rar->entries->entries_array[i]->entry.RedirName != NULL) {
efree(rar->entries->entries_array[i]->entry.RedirName);
}
efree(rar->entries->entries_array[i]); efree(rar->entries->entries_array[i]);
} }
efree(rar->entries->entries_array); efree(rar->entries->entries_array);
@@ -324,7 +333,7 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
int result = 0; int result = 0;
size_t capacity = 0; size_t capacity = 0;
int first_file_check = TRUE; int first_file_check = TRUE;
zend_ulong packed_size = 0; unsigned long packed_size = 0UL;
struct _rar_entries *ents; struct _rar_entries *ents;
if (rar->entries != NULL) { if (rar->entries != NULL) {
@@ -344,11 +353,7 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
ents->last_accessed = NULL; ents->last_accessed = NULL;
while (result == 0) { while (result == 0) {
struct _rar_unique_entry *ue;
struct RARHeaderDataEx entry = {0}; struct RARHeaderDataEx entry = {0};
wchar_t redir_name[1024] = L"";
entry.RedirName = redir_name;
entry.RedirNameSize = sizeof(redir_name) / sizeof(redir_name[0]);
result = RARReadHeaderEx(rar->arch_handle, &entry); result = RARReadHeaderEx(rar->arch_handle, &entry);
/* value of 2nd argument is irrelevant in RAR_OM_LIST_[SPLIT] mode */ /* value of 2nd argument is irrelevant in RAR_OM_LIST_[SPLIT] mode */
if (result == 0) { if (result == 0) {
@@ -366,16 +371,22 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
/* reset packed size if not split before */ /* reset packed size if not split before */
if ((entry.Flags & RHDF_SPLITBEFORE) == 0) if ((entry.Flags & RHDF_SPLITBEFORE) == 0)
packed_size = 0; packed_size = 0UL;
/* accumulate packed size; cap at ZEND_LONG_MAX (the PHP int ceiling) */ /* we would exceed size of ulong. cap at ulong_max
{ * equivalent to packed_size + entry.PackSize > ULONG_MAX,
zend_ulong entry_packed = ((zend_ulong)entry.PackSizeHigh << 32) | entry.PackSize; * but without overflowing */
if (entry_packed > (zend_ulong)ZEND_LONG_MAX || if (ULONG_MAX - packed_size < entry.PackSize)
packed_size > (zend_ulong)ZEND_LONG_MAX - entry_packed) packed_size = ULONG_MAX;
packed_size = (zend_ulong)ZEND_LONG_MAX; else {
else packed_size += entry.PackSize;
packed_size += entry_packed; if (entry.PackSizeHigh != 0) {
#if ULONG_MAX > 0xffffffffUL
packed_size += ((unsigned long) entry.PackSizeHigh) << 32;
#else
packed_size = ULONG_MAX; /* cap */
#endif
}
} }
if (entry.Flags & RHDF_SPLITAFTER) /* do not commit */ if (entry.Flags & RHDF_SPLITAFTER) /* do not commit */
@@ -390,22 +401,16 @@ int _rar_list_files(rar_file_t *rar TSRMLS_DC) /* {{{ */
} }
assert(capacity > ents->num_entries); assert(capacity > ents->num_entries);
ents->entries_array[ents->num_entries] = ue = ents->entries_array[ents->num_entries] =
emalloc(sizeof *ents->entries_array[0]); emalloc(sizeof *ents->entries_array[0]);
memcpy(&ue->entry, &entry, sizeof ents->entries_array[0]->entry); memcpy(&ents->entries_array[ents->num_entries]->entry, &entry,
ue->id = ents->num_entries; sizeof ents->entries_array[0]->entry);
ue->packed_size = packed_size; ents->entries_array[ents->num_entries]->id = ents->num_entries;
ents->entries_array[ents->num_entries]->packed_size = packed_size;
_rar_nav_get_depth_and_length(entry.FileNameW, _rar_nav_get_depth_and_length(entry.FileNameW,
sizeof(entry.FileNameW) / sizeof(entry.FileNameW[0]), /* = 1024 */ sizeof(entry.FileNameW) / sizeof(entry.FileNameW[0]), /* = 1024 */
&ue->depth, &ue->name_wlen TSRMLS_CC); &ents->entries_array[ents->num_entries]->depth,
if (redir_name[0] != L'\0') { &ents->entries_array[ents->num_entries]->name_wlen TSRMLS_CC);
size_t size = (wcslen(redir_name) + 1) * sizeof(redir_name[0]);
ue->entry.RedirName = emalloc(size);
memcpy(ue->entry.RedirName, redir_name, size);
} else {
ue->entry.RedirName = NULL;
ue->entry.RedirNameSize = 0;
}
ents->num_entries++; ents->num_entries++;
} }
@@ -484,6 +489,7 @@ 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) /* {{{ */ static void _rar_nav_swap_entries(void *op1, void *op2) /* {{{ */
{ {
/* just swaps two pointer values */ /* just swaps two pointer values */
@@ -496,6 +502,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 int _rar_nav_compare_entries_std(const void *op1, const void *op2) /* {{{ */
{ {
@@ -600,6 +607,12 @@ static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
/* end functions with internal linkage */ /* end functions with internal linkage */
#endif /* HAVE_RAR */
#ifdef __cplusplus
}
#endif
/* /*
* Local variables: * Local variables:
* tab-width: 4 * tab-width: 4
@@ -608,3 +621,5 @@ static size_t _rar_nav_position_on_dir_start(const wchar_t *dir_name,
* vim600: noet sw=4 ts=4 fdm=marker * vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4 * vim<600: noet sw=4 ts=4
*/ */
+265 -115
View File
@@ -27,30 +27,35 @@
/* $Id$ */ /* $Id$ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif #endif
#include <php.h> #include <php.h>
#if HAVE_RAR
#include <wchar.h> #include <wchar.h>
#include "php_rar.h" #include "php_rar.h"
#include "unrar/rartypes.hpp"
#include <php_streams.h> #include <php_streams.h>
#include <ext/standard/url.h> #include <ext/standard/url.h>
#include <ext/standard/php_string.h> #include <ext/standard/php_string.h>
#include <ext/standard/file.h> #include <ext/standard/file.h>
/* clang-format off */
typedef struct php_rar_stream_data_t { typedef struct php_rar_stream_data_t {
struct RAROpenArchiveDataEx open_data; struct RAROpenArchiveDataEx open_data;
struct RARHeaderDataEx header_data; struct RARHeaderDataEx header_data;
HANDLE rar_handle; HANDLE rar_handle;
size_t file_size;
/* TODO: consider encapsulating a php memory/tmpfile stream */ /* TODO: consider encapsulating a php memory/tmpfile stream */
unsigned char *buffer; unsigned char *buffer;
size_t buffer_size; size_t buffer_size;
size_t buffer_read_size; /* content size */ size_t buffer_cont_size; /* content size */
size_t buffer_pos; size_t buffer_pos;
uint64 cursor; uint64 cursor;
int no_more_data; int no_more_data;
@@ -68,15 +73,12 @@ typedef struct php_rar_dir_stream_data_t {
int no_encode; /* do not urlencode entry names */ int no_encode; /* do not urlencode entry names */
php_stream *stream; php_stream *stream;
} php_rar_dir_stream_data, *php_rar_dir_stream_data_P; } php_rar_dir_stream_data, *php_rar_dir_stream_data_P;
/* clang-format on */
/* clang-format off */
#define STREAM_DATA_FROM_STREAM \ #define STREAM_DATA_FROM_STREAM \
php_rar_stream_data_P self = (php_rar_stream_data_P) stream->abstract; php_rar_stream_data_P self = (php_rar_stream_data_P) stream->abstract;
#define STREAM_DIR_DATA_FROM_STREAM \ #define STREAM_DIR_DATA_FROM_STREAM \
php_rar_dir_stream_data_P self = (php_rar_dir_stream_data_P) stream->abstract; php_rar_dir_stream_data_P self = (php_rar_dir_stream_data_P) stream->abstract;
/* clang-format on */
/* len can be -1 (calculate) */ /* len can be -1 (calculate) */
static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len) static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
@@ -97,11 +99,7 @@ static char *_rar_wide_to_utf_with_alloc(const wchar_t *wide, int len)
/* {{{ RAR file streams */ /* {{{ RAR file streams */
/* {{{ php_rar_ops_read */ /* {{{ php_rar_ops_read */
#if PHP_VERSION_ID < 70400
static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) static size_t php_rar_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
#endif
{ {
size_t n = 0; size_t n = 0;
STREAM_DATA_FROM_STREAM STREAM_DATA_FROM_STREAM
@@ -116,12 +114,12 @@ static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
while (left > 0) { while (left > 0) {
size_t this_read_size; size_t this_read_size;
/* if nothing in the buffer or buffer already read, fill buffer */ /* if nothing in the buffer or buffer already read, fill buffer */
if (/*self->buffer_read_size == 0 || > condition not necessary */ if (/*self->buffer_cont_size == 0 || > condition not necessary */
self->buffer_pos == self->buffer_read_size) self->buffer_pos == self->buffer_cont_size)
{ {
int res; int res;
self->buffer_pos = 0; self->buffer_pos = 0;
self->buffer_read_size = 0; self->buffer_cont_size = 0;
/* Note: this condition is important, you cannot rely on /* Note: this condition is important, you cannot rely on
* having a call to RARProcessFileChunk return no data and * having a call to RARProcessFileChunk return no data and
* break on the condition self->buffer_cont_size == 0 because * break on the condition self->buffer_cont_size == 0 because
@@ -131,25 +129,25 @@ static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
if (self->no_more_data) if (self->no_more_data)
break; break;
res = RARProcessFileChunk(self->rar_handle, self->buffer, res = RARProcessFileChunk(self->rar_handle, self->buffer,
self->buffer_size, &self->buffer_read_size, self->buffer_size, &self->buffer_cont_size,
&self->no_more_data); &self->no_more_data);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) { if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
break; /* finish in case of failure */ break; /* finish in case of failure */
} }
assert(self->buffer_read_size <= self->buffer_size); assert(self->buffer_cont_size <= self->buffer_size);
/* we did not read anything. no need to continue */ /* we did not read anything. no need to continue */
if (self->buffer_read_size == 0) if (self->buffer_cont_size == 0)
break; break;
} }
/* if we get here we have data to be read in the buffer */ /* if we get here we have data to be read in the buffer */
this_read_size = MIN(left, this_read_size = MIN(left,
self->buffer_read_size - self->buffer_pos); self->buffer_cont_size - self->buffer_pos);
assert(this_read_size > 0); assert(this_read_size > 0);
memcpy(&buf[count-left], &self->buffer[self->buffer_pos], memcpy(&buf[count-left], &self->buffer[self->buffer_pos],
this_read_size); this_read_size);
left -= this_read_size; left -= this_read_size;
n += this_read_size; n += this_read_size;
self->buffer_pos += this_read_size; self->buffer_pos += this_read_size;
assert(left >= 0); assert(left >= 0);
} }
@@ -158,16 +156,9 @@ static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
/* no more data upstream (for sure), buffer already read and /* no more data upstream (for sure), buffer already read and
* caller asked for more data than we're giving */ * caller asked for more data than we're giving */
if (self->no_more_data && self->buffer_pos == self->buffer_read_size && if (self->no_more_data && self->buffer_pos == self->buffer_cont_size &&
n < count && stream->eof != 1) { ((size_t) n) < count)
stream->eof = 1; stream->eof = 1;
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: %" PRIu64 " bytes (corruption/wrong pwd)",
self->file_size, self->cursor);
}
}
/* we should only give no data if we have no more */ /* we should only give no data if we have no more */
if (!self->no_more_data && n == 0) { if (!self->no_more_data && n == 0) {
@@ -177,25 +168,17 @@ static ssize_t php_rar_ops_read(php_stream *stream, char *buf, size_t count)
stream->eof = 1; stream->eof = 1;
} }
return (ssize_t) n; return n;
} }
/* }}} */ /* }}} */
/* {{{ php_rar_ops_write */ /* {{{ php_rar_ops_write */
#if PHP_VERSION_ID < 70400
static size_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) static size_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_ops_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
#endif
{ {
php_error_docref(NULL TSRMLS_CC, E_WARNING, php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Write operation not supported for RAR streams."); "Write operation not supported for RAR streams.");
if (!stream) { if (!stream) {
#if PHP_VERSION_ID < 70400
return 0; return 0;
#else
return -1;
#endif
} }
return count; return count;
@@ -211,12 +194,6 @@ static int php_rar_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
efree(self->open_data.ArcName); efree(self->open_data.ArcName);
self->open_data.ArcName = NULL; self->open_data.ArcName = NULL;
} }
#ifdef PHP_WIN32
if (self->open_data.ArcNameW != NULL) {
efree(self->open_data.ArcNameW);
self->open_data.ArcNameW = NULL;
}
#endif
_rar_destroy_userdata(&self->cb_userdata); _rar_destroy_userdata(&self->cb_userdata);
if (self->buffer != NULL) { if (self->buffer != NULL) {
efree(self->buffer); efree(self->buffer);
@@ -303,6 +280,43 @@ static mode_t _rar_convert_file_attrs(unsigned os_attrs,
} }
/* }}} */ /* }}} */
static void _rar_time_convert(unsigned low, unsigned high, time_t *to) /* {{{ */
{
time_t default_ = (time_t) 0,
local_time;
struct tm tm = {0};
TSRMLS_FETCH();
if (high == 0U && low == 0U) {
*to = default_;
return;
}
/* 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970. */
uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
/* value is in 10^-7 seconds since 01-01-1601 */
/* convert to nanoseconds, shift to 01-01-1970 and convert to seconds */
local_time = (time_t) ((INT32TO64(high, low) * 100 - ushift) / 1000000000);
/* now we have the time in... I don't know what. It gives UTC - tz offset */
/* we need to try and convert it to UTC */
/* abuse gmtime, which is supposed to work with UTC */
#ifndef PHP_WIN32
if (gmtime_r(&local_time, &tm) == NULL) {
#else
if (gmtime_s(&tm, &local_time) != 0) {
#endif
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not convert time to UTC, using local time");
*to = local_time;
}
tm.tm_isdst = -1;
*to = local_time + (local_time - mktime(&tm));
}
/* }}} */
static int _rar_stat_from_header(struct RARHeaderDataEx *header, static int _rar_stat_from_header(struct RARHeaderDataEx *header,
php_stream_statbuf *ssb) /* {{{ */ php_stream_statbuf *ssb) /* {{{ */
{ {
@@ -317,7 +331,7 @@ static int _rar_stat_from_header(struct RARHeaderDataEx *header,
* SUBHEAD_TYPE_UOWNER), but it is not exposed in unRAR */ * SUBHEAD_TYPE_UOWNER), but it is not exposed in unRAR */
ssb->sb.st_uid = 0; ssb->sb.st_uid = 0;
ssb->sb.st_gid = 0; ssb->sb.st_gid = 0;
#if defined(HAVE_ST_RDEV) || defined(HAVE_STRUCT_STAT_ST_RDEV) #ifdef HAVE_ST_RDEV
ssb->sb.st_rdev = 0; ssb->sb.st_rdev = 0;
#endif #endif
/* never mind signedness, we'll never get sizes big enough for that to /* never mind signedness, we'll never get sizes big enough for that to
@@ -332,26 +346,34 @@ static int _rar_stat_from_header(struct RARHeaderDataEx *header,
ssb->sb.st_size = (long) (unsigned long) (int64) unp_size; ssb->sb.st_size = (long) (unsigned long) (int64) unp_size;
} }
rar_time_convert(header->AtimeLow, header->AtimeHigh, &ssb->sb.st_atime); _rar_time_convert(header->AtimeLow, header->AtimeHigh, &ssb->sb.st_atime);
rar_time_convert(header->CtimeLow, header->CtimeHigh, &ssb->sb.st_ctime); _rar_time_convert(header->CtimeLow, header->CtimeHigh, &ssb->sb.st_ctime);
if (header->MtimeLow == 0 && header->MtimeHigh == 0) { if (header->MtimeLow == 0 && header->MtimeHigh == 0) {
/* high precision mod time undefined */ /* high precision mod time undefined */
struct tm time_s = {0};
time_t time; time_t time;
if (rar_dos_time_convert(header->FileTime, &time) == FAILURE) { unsigned dos_time = header->FileTime;
time_s.tm_sec = (dos_time & 0x1f)*2;
time_s.tm_min = (dos_time>>5) & 0x3f;
time_s.tm_hour = (dos_time>>11) & 0x1f;
time_s.tm_mday = (dos_time>>16) & 0x1f;
time_s.tm_mon = ((dos_time>>21) & 0x0f) - 1;
time_s.tm_year = (dos_time>>25) + 80;
if ((time = mktime(&time_s)) == -1)
return FAILURE; return FAILURE;
}
ssb->sb.st_mtime = time; ssb->sb.st_mtime = time;
} }
else { else {
rar_time_convert(header->MtimeLow, header->MtimeHigh, _rar_time_convert(header->MtimeLow, header->MtimeHigh,
&ssb->sb.st_mtime); &ssb->sb.st_mtime);
} }
#if defined(HAVE_ST_BLKSIZE) || defined(HAVE_STRUCT_STAT_ST_BLKSIZE) #ifdef HAVE_ST_BLKSIZE
ssb->sb.st_blksize = 0; ssb->sb.st_blksize = 0;
#endif #endif
#if defined(HAVE_ST_BLOCKS) || defined (HAVE_STRUCT_STAT_ST_BLOCKS) #ifdef HAVE_ST_BLOCKS
ssb->sb.st_blocks = 0; ssb->sb.st_blocks = 0;
#endif #endif
/* php_stat in filestat.c doesn't check this one, so don't touch it */ /* php_stat in filestat.c doesn't check this one, so don't touch it */
@@ -387,32 +409,19 @@ static php_stream_ops php_stream_rario_ops = {
/* {{{ RAR directory streams */ /* {{{ RAR directory streams */
/* {{{ php_rar_dir_ops_read */ /* {{{ php_rar_dir_ops_read */
#if PHP_VERSION_ID < 70400
static size_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) static size_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#else
static ssize_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
#endif
{ {
php_stream_dirent entry; php_stream_dirent entry;
size_t offset; int offset;
STREAM_DIR_DATA_FROM_STREAM STREAM_DIR_DATA_FROM_STREAM
if (count != sizeof(entry)) { if (count != sizeof(entry))
#if PHP_VERSION_ID < 70400
return 0; return 0;
#else
return -1;
#endif
}
_rar_entry_search_advance(self->state, self->directory, self->dir_size, 1); _rar_entry_search_advance(self->state, self->directory, self->dir_size, 1);
if (!self->state->found) { if (!self->state->found) {
stream->eof = 1; stream->eof = 1;
#if PHP_VERSION_ID < 70400
return 0; return 0;
#else
return -1;
#endif
} }
if (self->dir_size == 1) /* root */ if (self->dir_size == 1) /* root */
@@ -424,10 +433,19 @@ static ssize_t php_rar_dir_ops_read(php_stream *stream, char *buf, size_t count
entry.d_name, sizeof entry.d_name); entry.d_name, sizeof entry.d_name);
if (!self->no_encode) { /* urlencode entry */ 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 = zend_string *encoded_name =
php_url_encode(entry.d_name, strlen(entry.d_name)); php_url_encode(entry.d_name, strlen(entry.d_name));
strlcpy(entry.d_name, encoded_name->val, sizeof entry.d_name); strlcpy(entry.d_name, encoded_name->val, sizeof entry.d_name);
zend_string_release(encoded_name); zend_string_release(encoded_name);
#endif
} }
@@ -443,7 +461,11 @@ static int php_rar_dir_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
{ {
STREAM_DIR_DATA_FROM_STREAM STREAM_DIR_DATA_FROM_STREAM
#if PHP_MAJOR_VERSION < 7
zval_dtor(&self->rar_obj);
#else
zval_ptr_dtor(&self->rar_obj); zval_ptr_dtor(&self->rar_obj);
#endif
efree(self->directory); efree(self->directory);
efree(self->state); efree(self->state);
efree(self); efree(self);
@@ -455,11 +477,7 @@ static int php_rar_dir_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
/* }}} */ /* }}} */
/* {{{ php_rar_dir_ops_rewind */ /* {{{ php_rar_dir_ops_rewind */
#if PHP_VERSION_ID < 70400
static int php_rar_dir_ops_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) static int php_rar_dir_ops_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC)
#else
static int php_rar_dir_ops_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
#endif
{ {
STREAM_DIR_DATA_FROM_STREAM STREAM_DIR_DATA_FROM_STREAM
@@ -517,13 +535,6 @@ php_stream *php_stream_rar_open(char *arc_name,
self = ecalloc(1, sizeof *self); self = ecalloc(1, sizeof *self);
self->open_data.ArcName = estrdup(arc_name); self->open_data.ArcName = estrdup(arc_name);
self->open_data.OpenMode = RAR_OM_EXTRACT; self->open_data.OpenMode = RAR_OM_EXTRACT;
#ifdef PHP_WIN32
{
size_t arcnamew_len = strlen(arc_name);
self->open_data.ArcNameW = safe_emalloc(arcnamew_len, sizeof(wchar_t), sizeof(wchar_t));
_rar_utf_to_wide(arc_name, self->open_data.ArcNameW, arcnamew_len + 1);
}
#endif
/* deep copy the callback userdata */ /* deep copy the callback userdata */
if (cb_udata_ptr->password != NULL) if (cb_udata_ptr->password != NULL)
self->cb_userdata.password = estrdup(cb_udata_ptr->password); self->cb_userdata.password = estrdup(cb_udata_ptr->password);
@@ -543,18 +554,16 @@ php_stream *php_stream_rar_open(char *arc_name,
TSRMLS_CC, position, arc_name); TSRMLS_CC, position, arc_name);
else { else {
/* no need to allocate a buffer bigger than the file uncomp size */ /* no need to allocate a buffer bigger than the file uncomp size */
size_t file_size = INT32TO64(self->header_data.UnpSizeHigh, size_t buffer_size = (size_t)
self->header_data.UnpSize); MIN((uint64) RAR_CHUNK_BUFFER_SIZE,
size_t buffer_size = MIN( INT32TO64(self->header_data.UnpSizeHigh,
MAX(RAR_CHUNK_BUFFER_SIZE, self->header_data.WinSize), self->header_data.UnpSize));
file_size);
int process_result = RARProcessFileChunkInit(self->rar_handle); int process_result = RARProcessFileChunkInit(self->rar_handle);
if (_rar_handle_error(process_result TSRMLS_CC) == FAILURE) { if (_rar_handle_error(process_result TSRMLS_CC) == FAILURE) {
goto cleanup; goto cleanup;
} }
self->file_size = file_size;
self->buffer = emalloc(buffer_size); self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size; self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, "rb"); stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, "rb");
@@ -566,10 +575,6 @@ cleanup:
if (self != NULL) { if (self != NULL) {
if (self->open_data.ArcName != NULL) if (self->open_data.ArcName != NULL)
efree(self->open_data.ArcName); efree(self->open_data.ArcName);
#ifdef PHP_WIN32
if (self->open_data.ArcNameW != NULL)
efree(self->open_data.ArcNameW);
#endif
_rar_destroy_userdata(&self->cb_userdata); _rar_destroy_userdata(&self->cb_userdata);
if (self->buffer != NULL) if (self->buffer != NULL)
efree(self->buffer); efree(self->buffer);
@@ -585,6 +590,67 @@ cleanup:
/* {{{ Wrapper stuff */ /* {{{ 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 */ /* {{{ php_rar_process_context */
/* memory is to be managed externally */ /* memory is to be managed externally */
static void php_rar_process_context(php_stream_context *context, static void php_rar_process_context(php_stream_context *context,
@@ -595,6 +661,9 @@ static void php_rar_process_context(php_stream_context *context,
zval **volume_cb TSRMLS_DC) zval **volume_cb TSRMLS_DC)
{ {
zval *ctx_opt; zval *ctx_opt;
#if PHP_MAJOR_VERSION < 7
zval **ctx_opt_p = NULL;
#endif
assert(context != NULL); assert(context != NULL);
assert(open_password != NULL); assert(open_password != NULL);
@@ -604,8 +673,14 @@ static void php_rar_process_context(php_stream_context *context,
/* TODO: don't know if I can log errors and not fail. check that */ /* 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( if ((ctx_opt = php_stream_context_get_option(
context, "rar", "open_password"))) { context, "rar", "open_password"))) {
#endif
if (Z_TYPE_P(ctx_opt) != IS_STRING) if (Z_TYPE_P(ctx_opt) != IS_STRING)
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"RAR open password was provided, but not a string."); "RAR open password was provided, but not a string.");
@@ -613,8 +688,14 @@ static void php_rar_process_context(php_stream_context *context,
*open_password = Z_STRVAL_P(ctx_opt); *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( if (file_password != NULL && (ctx_opt = php_stream_context_get_option(
context, "rar", "file_password"))) { context, "rar", "file_password"))) {
#endif
if (Z_TYPE_P(ctx_opt) != IS_STRING) if (Z_TYPE_P(ctx_opt) != IS_STRING)
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"RAR file password was provided, but not a string."); "RAR file password was provided, but not a string.");
@@ -622,9 +703,19 @@ static void php_rar_process_context(php_stream_context *context,
*file_password = Z_STRVAL_P(ctx_opt); *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( if ((ctx_opt = php_stream_context_get_option(
context, "rar", "volume_callback"))) { 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)) { if (zend_is_callable(ctx_opt, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
#endif
*volume_cb = ctx_opt; *volume_cb = ctx_opt;
} }
else else
@@ -693,19 +784,17 @@ static int _rar_get_archive_and_fragment(php_stream_wrapper *wrapper,
if (!(options & STREAM_ASSUME_REALPATH)) { if (!(options & STREAM_ASSUME_REALPATH)) {
if (options & USE_PATH) { if (options & USE_PATH) {
#if PHP_VERSION_ID < 80100 #if PHP_MAJOR_VERSION < 7
zend_string *arc_str = zend_resolve_path(tmp_archive, tmp_arch_len); *archive = zend_resolve_path(tmp_archive, tmp_arch_len TSRMLS_CC);
#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, tmp_arch_len);
zend_string *arc_str = zend_resolve_path(tmp_archive_str);
zend_string_free(tmp_archive_str);
#endif
if (arc_str != NULL) { if (arc_str != NULL) {
*archive = estrndup(arc_str->val, arc_str->len); *archive = estrndup(arc_str->val, arc_str->len);
} else { } else {
*archive = NULL; *archive = NULL;
} }
zend_string_release(arc_str); zend_string_release(arc_str);
#endif
} }
if (*archive == NULL) { if (*archive == NULL) {
if ((*archive = expand_filepath(tmp_archive, NULL TSRMLS_CC)) if ((*archive = expand_filepath(tmp_archive, NULL TSRMLS_CC))
@@ -773,10 +862,17 @@ cleanup:
/* {{{ php_stream_rar_opener */ /* {{{ php_stream_rar_opener */
static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper, 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 *filename,
const char *mode, const char *mode,
int options, int options,
zend_string **opened_path, zend_string **opened_path,
#endif
php_stream_context *context php_stream_context *context
STREAMS_DC TSRMLS_DC) STREAMS_DC TSRMLS_DC)
{ {
@@ -820,13 +916,6 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
self = ecalloc(1, sizeof *self); self = ecalloc(1, sizeof *self);
self->open_data.ArcName = estrdup(tmp_open_path); self->open_data.ArcName = estrdup(tmp_open_path);
self->open_data.OpenMode = RAR_OM_EXTRACT; self->open_data.OpenMode = RAR_OM_EXTRACT;
#ifdef PHP_WIN32
{
size_t arcnamew_len = strlen(tmp_open_path);
self->open_data.ArcNameW = safe_emalloc(arcnamew_len, sizeof(wchar_t), sizeof(wchar_t));
_rar_utf_to_wide(tmp_open_path, self->open_data.ArcNameW, arcnamew_len + 1);
}
#endif
if (open_passwd != NULL) if (open_passwd != NULL)
self->cb_userdata.password = estrdup(open_passwd); self->cb_userdata.password = estrdup(open_passwd);
if (volume_cb != NULL) { if (volume_cb != NULL) {
@@ -866,23 +955,21 @@ static php_stream *php_stream_rar_opener(php_stream_wrapper *wrapper,
{ {
/* no need to allocate a buffer bigger than the file uncomp size */ /* no need to allocate a buffer bigger than the file uncomp size */
size_t file_size = INT32TO64(self->header_data.UnpSizeHigh, size_t buffer_size = (size_t)
self->header_data.UnpSize); MIN((uint64) RAR_CHUNK_BUFFER_SIZE,
size_t buffer_size = MIN( INT32TO64(self->header_data.UnpSizeHigh,
MAX(RAR_CHUNK_BUFFER_SIZE, self->header_data.WinSize), self->header_data.UnpSize));
file_size);
rar_result = RARProcessFileChunkInit(self->rar_handle); rar_result = RARProcessFileChunkInit(self->rar_handle);
if ((rar_error = _rar_error_to_string(rar_result)) != NULL) { if ((rar_error = _rar_error_to_string(rar_result)) != NULL) {
char *mb_entry = _rar_wide_to_utf_with_alloc(fragment, -1); char *mb_entry = _rar_wide_to_utf_with_alloc(fragment, -1);
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Error opening file %s inside RAR archive %s: %s", "Error opening file %s inside RAR archive %s: %s",
mb_entry, tmp_open_path, rar_error); mb_entry, tmp_open_path, rar_error);
efree(mb_entry); efree(mb_entry);
goto cleanup; goto cleanup;
} }
self->file_size = file_size;
self->buffer = emalloc(buffer_size); self->buffer = emalloc(buffer_size);
self->buffer_size = buffer_size; self->buffer_size = buffer_size;
stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, mode); stream = php_stream_alloc(&php_stream_rario_ops, self, NULL, mode);
@@ -895,8 +982,12 @@ cleanup:
if (tmp_open_path != NULL) { if (tmp_open_path != NULL) {
if (opened_path != NULL) { if (opened_path != NULL) {
#if PHP_MAJOR_VERSION < 7
*opened_path = tmp_open_path;
#else
*opened_path = *opened_path =
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0); zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
#endif
} else { } else {
efree(tmp_open_path); efree(tmp_open_path);
} }
@@ -908,10 +999,6 @@ cleanup:
if (self != NULL) { if (self != NULL) {
if (self->open_data.ArcName != NULL) if (self->open_data.ArcName != NULL)
efree(self->open_data.ArcName); efree(self->open_data.ArcName);
#ifdef PHP_WIN32
if (self->open_data.ArcNameW != NULL)
efree(self->open_data.ArcNameW);
#endif
_rar_destroy_userdata(&self->cb_userdata); _rar_destroy_userdata(&self->cb_userdata);
if (self->buffer != NULL) if (self->buffer != NULL)
efree(self->buffer); efree(self->buffer);
@@ -956,7 +1043,11 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
zval *cache_zv; zval *cache_zv;
assert(rar_obj != NULL); assert(rar_obj != NULL);
#if PHP_MAJOR_VERSION < 7
INIT_ZVAL(*rar_obj);
#else
ZVAL_UNDEF(rar_obj); ZVAL_UNDEF(rar_obj);
#endif
_rar_arch_cache_get_key(arch_path, open_passwd, volume_cb, &cache_key, _rar_arch_cache_get_key(arch_path, open_passwd, volume_cb, &cache_key,
&cache_key_len); &cache_key_len);
@@ -982,7 +1073,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
int res; int res;
const char *err_str; const char *err_str;
if (_rar_get_file_resource_zv_ex(rar_obj, rar, 1 TSRMLS_CC) if (_rar_get_file_resource_ex(rar_obj, rar, 1 TSRMLS_CC)
== FAILURE) { == FAILURE) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Bug: could not retrieve RarArchive object from zval"); "Bug: could not retrieve RarArchive object from zval");
@@ -1006,7 +1097,7 @@ static int _rar_get_cachable_rararch(php_stream_wrapper *wrapper,
else { /* cache hit */ else { /* cache hit */
/* cache get already put the value in rar_obj and incremented the /* cache get already put the value in rar_obj and incremented the
* refcount of the object */ * refcount of the object */
if (_rar_get_file_resource_zv_ex(rar_obj, rar, 1 TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource_ex(rar_obj, rar, 1 TSRMLS_CC) == FAILURE) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, php_stream_wrapper_log_error(wrapper, options TSRMLS_CC,
"Bug: could not retrieve RarArchive object from zval"); "Bug: could not retrieve RarArchive object from zval");
goto cleanup; goto cleanup;
@@ -1019,26 +1110,56 @@ cleanup:
efree(cache_key); efree(cache_key);
if (ret != SUCCESS && Z_TYPE_P(rar_obj) == IS_OBJECT) { 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_ptr_dtor(rar_obj);
ZVAL_UNDEF(rar_obj); ZVAL_UNDEF(rar_obj);
#endif
} }
return ret; return ret;
} }
/* }}} */ /* }}} */
/* {{{ _rar_stream_tidy_wrapper_error_log */ /* {{{ _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
static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC) static void _rar_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
{ {
if (wrapper && FG(wrapper_errors)) { if (wrapper && FG(wrapper_errors)) {
zend_hash_str_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper); zend_hash_str_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
} }
} }
#endif
/* }}} */ /* }}} */
/* {{{ php_stream_rar_stater */ /* {{{ php_stream_rar_stater */
static int php_stream_rar_stater(php_stream_wrapper *wrapper, static int php_stream_rar_stater(php_stream_wrapper *wrapper,
#if PHP_MAJOR_VERSION < 7
char *url,
#else
const char *url, const char *url,
#endif
int flags, int flags,
php_stream_statbuf *ssb, php_stream_statbuf *ssb,
php_stream_context *context TSRMLS_DC) php_stream_context *context TSRMLS_DC)
@@ -1057,7 +1178,11 @@ static int php_stream_rar_stater(php_stream_wrapper *wrapper,
int ret = FAILURE; int ret = FAILURE;
/* {{{ preliminaries */ /* {{{ preliminaries */
#if PHP_MAJOR_VERSION < 7
Z_TYPE(rararch) = IS_NULL;
#else
ZVAL_UNDEF(&rararch); ZVAL_UNDEF(&rararch);
#endif
if (_rar_get_archive_and_fragment(wrapper, url, options, 1, if (_rar_get_archive_and_fragment(wrapper, url, options, 1,
&open_path, &fragment, NULL TSRMLS_CC) == FAILURE) { &open_path, &fragment, NULL TSRMLS_CC) == FAILURE) {
@@ -1108,7 +1233,11 @@ cleanup:
} }
if (Z_TYPE(rararch) == IS_OBJECT) { if (Z_TYPE(rararch) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 7
zval_dtor(&rararch);
#else
zval_ptr_dtor(&rararch); zval_ptr_dtor(&rararch);
#endif
} }
if (state != NULL) { if (state != NULL) {
_rar_entry_search_end(state); _rar_entry_search_end(state);
@@ -1131,10 +1260,17 @@ cleanup:
/* {{{ php_stream_rar_dir_opener */ /* {{{ php_stream_rar_dir_opener */
static php_stream *php_stream_rar_dir_opener(php_stream_wrapper *wrapper, 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 *filename,
const char *mode, const char *mode,
int options, int options,
zend_string **opened_path, zend_string **opened_path,
#endif
php_stream_context *context php_stream_context *context
STREAMS_DC TSRMLS_DC) STREAMS_DC TSRMLS_DC)
{ {
@@ -1233,8 +1369,12 @@ cleanup:
if (tmp_open_path != NULL) { if (tmp_open_path != NULL) {
if (opened_path != NULL) { if (opened_path != NULL) {
#if PHP_MAJOR_VERSION < 7
*opened_path = tmp_open_path;
#else
*opened_path = *opened_path =
zend_string_init(tmp_open_path, strlen(tmp_open_path), 0); zend_string_init(tmp_open_path, strlen(tmp_open_path), 0);
#endif
} else { } else {
efree(tmp_open_path); efree(tmp_open_path);
} }
@@ -1245,7 +1385,11 @@ cleanup:
if (stream == NULL) { /* failed */ if (stream == NULL) { /* failed */
if (self != NULL) { if (self != NULL) {
if (Z_TYPE(self->rar_obj) == IS_OBJECT) { 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); zval_ptr_dtor(&self->rar_obj);
#endif
} }
if (self->directory != NULL) { if (self->directory != NULL) {
efree(self->directory); efree(self->directory);
@@ -1282,6 +1426,12 @@ php_stream_wrapper php_stream_rar_wrapper = {
/* end wrapper stuff }}} */ /* end wrapper stuff }}} */
#endif /* HAVE_RAR */
#ifdef __cplusplus
}
#endif
/* /*
* Local variables: * Local variables:
* tab-width: 4 * tab-width: 4
-55
View File
@@ -1,55 +0,0 @@
#include <php.h>
#include "php_rar.h"
void rar_time_convert(unsigned low, unsigned high, time_t *to) /* {{{ */
{
time_t default_ = (time_t) 0,
local_time;
struct tm tm = {0};
TSRMLS_FETCH();
if (high == 0U && low == 0U) {
*to = default_;
return;
}
/* 11644473600000000000 - number of ns between 01-01-1601 and 01-01-1970. */
uint64 ushift=INT32TO64(0xA1997B0B,0x4C6A0000);
/* value is in 10^-7 seconds since 01-01-1601 */
/* convert to nanoseconds, shift to 01-01-1970 and convert to seconds */
local_time = (time_t) ((INT32TO64(high, low) * 100 - ushift) / 1000000000);
/* now we have the time in... I don't know what. It gives UTC - tz offset */
/* we need to try and convert it to UTC */
/* abuse gmtime, which is supposed to work with UTC */
if (php_gmtime_r(&local_time, &tm) == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not convert time to UTC, using local time");
*to = local_time;
}
tm.tm_isdst = -1;
*to = local_time + (local_time - mktime(&tm));
}
/* }}} */
int rar_dos_time_convert(unsigned dos_time, time_t *to) /* {{{ */
{
struct tm time_s = {0};
time_s.tm_sec = (dos_time & 0x1f)*2;
time_s.tm_min = (dos_time>>5) & 0x3f;
time_s.tm_hour = (dos_time>>11) & 0x1f;
time_s.tm_mday = (dos_time>>16) & 0x1f;
time_s.tm_mon = ((dos_time>>21) & 0x0f) - 1;
time_s.tm_year = (dos_time>>25) + 80;
/* the dos times that unrar gives out seem to be already in UTC.
* Or at least they don't depend on TZ */
if ((*to = timegm(&time_s)) == (time_t) -1) {
return FAILURE;
}
return SUCCESS;
}
/* }}} */
+274 -212
View File
@@ -27,34 +27,39 @@
/* $Id$ */ /* $Id$ */
#include "zend_types.h" #ifdef __cplusplus
#include <zend_API.h> extern "C" {
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif #endif
#define _GNU_SOURCE
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
#include <php.h> #include <php.h>
#include <zend_interfaces.h> #include <zend_interfaces.h>
#include "php_rar.h" #include "php_rar.h"
#include "php_compat.h"
/* {{{ Type definitions reserved for this translation unit */ /* {{{ Type definitions reserved for this translation unit */
/* clang-format off */
typedef struct _ze_rararch_object { typedef struct _ze_rararch_object {
#if PHP_MAJOR_VERSION < 7
zend_object parent;
rar_file_t *rar_file;
#else
rar_file_t *rar_file; rar_file_t *rar_file;
zend_object parent; zend_object parent;
#endif
} ze_rararch_object; } ze_rararch_object;
typedef struct _rararch_iterator { typedef struct _rararch_iterator {
zend_object_iterator parent; zend_object_iterator parent;
rar_find_output *state; rar_find_output *state;
#if PHP_MAJOR_VERSION < 7
zval *value;
#else
zval value; zval value;
#endif
int empty_iterator; /* iterator should give nothing */ int empty_iterator; /* iterator should give nothing */
} rararch_iterator; } rararch_iterator;
/* clang-format on */
/* }}} */ /* }}} */
/* {{{ Globals with internal linkage */ /* {{{ Globals with internal linkage */
@@ -78,46 +83,39 @@ static zend_object_handlers rararch_object_handlers;
/* {{{ Function prototypes for functions with internal linkage */ /* {{{ Function prototypes for functions with internal linkage */
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv); 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); 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 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_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 zend_object *rararch_ce_create_object(zend_class_entry *ce);
static void rararch_ce_free_object_storage(zend_object *zobj); static void rararch_ce_free_object_storage(zend_object *zobj);
#else
#define rararch_object_from_zv zend_object_store_get_object
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 */ /* {{{ RarArchive handlers */
static int rararch_handlers_preamble(handler_this_t *object, rar_file_t **rar TSRMLS_DC); static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC);
static int rararch_dimensions_preamble(rar_file_t *rar, zval *offset, zend_long *index, int quiet 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, zend_long *count TSRMLS_DC); static int rararch_count_elements(zval *object, long *count TSRMLS_DC);
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv); #if PHP_MAJOR_VERSION < 7
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC); static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC); #else
static zval *rararch_read_dimension(zval *object, zval *offset, int type, zval *rv);
#endif
static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC);
static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC);
/* }}} */ /* }}} */
/* {{{ Function definitions with external linkage */ /* {{{ Function definitions with external linkage */
int _rar_get_file_resource_zv(zval *zv, rar_file_t **rar_file TSRMLS_DC) /* {{{ */ int _rar_get_file_resource(zval *zval_file, rar_file_t **rar_file TSRMLS_DC) /* {{{ */
{ {
return _rar_get_file_resource_ex(rar_obj_ref_fetch(zv), return _rar_get_file_resource_ex(zval_file, rar_file, FALSE TSRMLS_CC);
rar_file, FALSE TSRMLS_CC);
}
int _rar_get_file_resource_zv_ex(zval *zv, rar_file_t **rar_file, int allow_closed TSRMLS_DC)
{
return _rar_get_file_resource_ex(rar_obj_ref_fetch(zv),
rar_file, allow_closed TSRMLS_CC);
} }
/* }}} */ /* }}} */
static int _rar_get_file_resource_handler(handler_this_t *thiz,
rar_file_t **rar_file TSRMLS_DC)
{
#if PHP_MAJOR_VERSION < 8
return _rar_get_file_resource_zv(thiz, rar_file TSRMLS_CC);
#else
return _rar_get_file_resource_ex(thiz, rar_file, FALSE);
#endif
}
/* Creates a RarArchive object, all three in args will be dupped */ /* Creates a RarArchive object, all three in args will be dupped */
int _rar_create_rararch_obj(const char* resolved_path, int _rar_create_rararch_obj(const char* resolved_path,
const char* open_password, const char* open_password,
@@ -135,15 +133,6 @@ int _rar_create_rararch_obj(const char* resolved_path,
rar->list_open_data->CmtBufSize = RAR_MAX_COMMENT_SIZE; rar->list_open_data->CmtBufSize = RAR_MAX_COMMENT_SIZE;
rar->extract_open_data = ecalloc(1, sizeof *rar->extract_open_data); rar->extract_open_data = ecalloc(1, sizeof *rar->extract_open_data);
rar->extract_open_data->ArcName = estrdup(resolved_path); rar->extract_open_data->ArcName = estrdup(resolved_path);
#ifdef PHP_WIN32
{
size_t arcnamew_len = strlen(resolved_path);
rar->list_open_data->ArcNameW = safe_emalloc(arcnamew_len, sizeof(wchar_t), sizeof(wchar));
_rar_utf_to_wide(resolved_path, rar->list_open_data->ArcNameW, arcnamew_len + 1);
rar->extract_open_data->ArcNameW = safe_emalloc(arcnamew_len, sizeof(wchar_t), sizeof(wchar));
_rar_utf_to_wide(resolved_path, rar->extract_open_data->ArcNameW, arcnamew_len + 1);
}
#endif
rar->extract_open_data->OpenMode = RAR_OM_EXTRACT; rar->extract_open_data->OpenMode = RAR_OM_EXTRACT;
rar->extract_open_data->CmtBuf = NULL; /* not interested in it again */ rar->extract_open_data->CmtBuf = NULL; /* not interested in it again */
rar->cb_userdata.password = NULL; rar->cb_userdata.password = NULL;
@@ -176,14 +165,8 @@ int _rar_create_rararch_obj(const char* resolved_path,
efree(rar->list_open_data->ArcName); efree(rar->list_open_data->ArcName);
efree(rar->list_open_data->CmtBuf); efree(rar->list_open_data->CmtBuf);
#ifdef PHP_WIN32
efree(rar->list_open_data->ArcNameW);
#endif
efree(rar->list_open_data); efree(rar->list_open_data);
efree(rar->extract_open_data->ArcName); efree(rar->extract_open_data->ArcName);
#ifdef PHP_WIN32
efree(rar->extract_open_data->ArcNameW);
#endif
efree(rar->extract_open_data); efree(rar->extract_open_data);
efree(rar); efree(rar);
return FAILURE; return FAILURE;
@@ -198,21 +181,20 @@ void _rar_close_file_resource(rar_file_t *rar) /* {{{ */
/* When changed from resource to custom object, instead of fiddling /* When changed from resource to custom object, instead of fiddling
* with the refcount to force object destruction, an indication that * with the refcount to force object destruction, an indication that
* the file is already closed is given by setting rar->arch_handle * the file is already closed is given by setting rar->arch_handle
* to NULL. This is checked by _rar_get_file_resource_zv. */ * to NULL. This is checked by _rar_get_file_resource. */
RARCloseArchive(rar->arch_handle); RARCloseArchive(rar->arch_handle);
rar->arch_handle = NULL; rar->arch_handle = NULL;
} }
/* }}} */ /* }}} */
/* Receives archive zval, returns object struct. /* Receives archive zval, returns object struct.
* If allow_closed is FALSE, it checks whether the archive is alredy closed, and if it * If silent is FALSE, it checks whether the archive is alredy closed, and if it
* is, an exception/error is raised and FAILURE is returned * is, an exception/error is raised and FAILURE is returned
*/ */
int _rar_get_file_resource_ex(rar_obj_ref zobjref_file, rar_file_t **rar_file, int _rar_get_file_resource_ex(zval *zval_file, rar_file_t **rar_file, int silent TSRMLS_DC) /* {{{ */
int allow_closed TSRMLS_DC) /* {{{ */
{ {
ze_rararch_object *zobj; ze_rararch_object *zobj;
zobj = rararch_object_from_ref(zobjref_file); zobj = rararch_object_from_zv(zval_file TSRMLS_CC);
if (zobj == NULL) { if (zobj == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Could not find object in the store. This is a bug, please report it."); "Could not find object in the store. This is a bug, please report it.");
@@ -220,7 +202,7 @@ int _rar_get_file_resource_ex(rar_obj_ref zobjref_file, rar_file_t **rar_file,
} }
*rar_file = zobj->rar_file; *rar_file = zobj->rar_file;
if ((*rar_file)->arch_handle == NULL && !allow_closed) { /* rar_close was called */ if ((*rar_file)->arch_handle == NULL && !silent) { /* rar_close was called */
_rar_handle_ext_error("The archive is already closed" TSRMLS_CC); _rar_handle_ext_error("The archive is already closed" TSRMLS_CC);
return FAILURE; return FAILURE;
} }
@@ -252,17 +234,25 @@ static void _rar_raw_entries_to_array(rar_file_t *rar, zval *target TSRMLS_DC) /
state->position, entry_obj TSRMLS_CC); state->position, entry_obj TSRMLS_CC);
add_next_index_zval(target, entry_obj); add_next_index_zval(target, entry_obj);
#if PHP_MAJOR_VERSION >= 7
/* PHP 7 copies the zval (but without increasing the refcount of the /* PHP 7 copies the zval (but without increasing the refcount of the
* obj). Free the allocation. */ * obj), while 5.x simply copies the pointer. Only for PHP 5.x do we
* keep the allocation) */
efree(entry_obj); efree(entry_obj);
#endif
} }
} while (state->eof == 0); } while (state->eof == 0);
_rar_entry_search_end(state); _rar_entry_search_end(state);
#if PHP_MAJOR_VERSION < 7
zval_dtor(&rararch_obj);
#else
zval_ptr_dtor(&rararch_obj); zval_ptr_dtor(&rararch_obj);
#endif
} }
/* }}} */ /* }}} */
#if PHP_MAJOR_VERSION >=7
static inline rar_obj_ref rar_obj_ref_fetch(zval *zv) static inline rar_obj_ref rar_obj_ref_fetch(zval *zv)
{ {
return Z_OBJ(*zv); return Z_OBJ(*zv);
@@ -272,7 +262,24 @@ static inline void rar_obj_ref_make_zv(rar_obj_ref zo, zval *zv TSRMLS_DC)
ZVAL_OBJ(zv, zo); ZVAL_OBJ(zv, zo);
zval_addref_p(zv); 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) static inline ze_rararch_object *rararch_object_fetch(zend_object *zobj)
{ {
return (ze_rararch_object *) return (ze_rararch_object *)
@@ -282,12 +289,35 @@ static ze_rararch_object *rararch_object_from_zv(const zval *zv)
{ {
return rararch_object_fetch(Z_OBJ_P(zv)); return rararch_object_fetch(Z_OBJ_P(zv));
} }
static ze_rararch_object *rararch_object_from_ref(const rar_obj_ref ref) #endif
{
return rararch_object_fetch(ref);
}
/* {{{ */ /* {{{ */
#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) static zend_object *rararch_ce_create_object(zend_class_entry *ce)
{ {
ze_rararch_object *zobj = ze_rararch_object *zobj =
@@ -299,12 +329,18 @@ static zend_object *rararch_ce_create_object(zend_class_entry *ce)
return &zobj->parent; 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) static void rararch_ce_free_object_storage(zend_object *zobj)
{ {
ze_rararch_object *object = rararch_object_fetch(zobj); ze_rararch_object *object = rararch_object_fetch(zobj);
#endif
rar_file_t *rar = object->rar_file; rar_file_t *rar = object->rar_file;
/* may be NULL if the user did new RarArchive() */ /* may be NULL if the user did new RarArchive() */
@@ -319,14 +355,8 @@ static void rararch_ce_free_object_storage(zend_object *zobj)
efree(rar->list_open_data->ArcName); efree(rar->list_open_data->ArcName);
efree(rar->list_open_data->CmtBuf); efree(rar->list_open_data->CmtBuf);
#ifdef PHP_WIN32
efree(rar->list_open_data->ArcNameW);
#endif
efree(rar->list_open_data); efree(rar->list_open_data);
efree(rar->extract_open_data->ArcName); efree(rar->extract_open_data->ArcName);
#ifdef PHP_WIN32
efree(rar->extract_open_data->ArcNameW);
#endif
efree(rar->extract_open_data); efree(rar->extract_open_data);
efree(rar); efree(rar);
} }
@@ -334,18 +364,20 @@ static void rararch_ce_free_object_storage(zend_object *zobj)
/* could call zend_objects_free_object_storage here (not before!), but /* could call zend_objects_free_object_storage here (not before!), but
* instead I'll mimic its behaviour */ * instead I'll mimic its behaviour */
zend_object_std_dtor(&object->parent TSRMLS_CC); zend_object_std_dtor(&object->parent TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
efree(object);
#endif
} }
/* }}} */ /* }}} */
/* }}} */ /* }}} */
/* {{{ RarArchive handlers */ /* {{{ RarArchive handlers */
static int rararch_handlers_preamble(handler_this_t *object, static int rararch_handlers_preamble(zval *object, rar_file_t **rar TSRMLS_DC) /* {{{ */
rar_file_t **rar TSRMLS_DC) /* {{{ */
{ {
/* don't call zend_objects_get_address or zend_object_store_get directly; /* don't call zend_objects_get_address or zend_object_store_get directly;
* _rar_get_file_resource_zv checks if the archive was closed */ * _rar_get_file_resource checks if the archive was closed */
if (_rar_get_file_resource_handler(object, rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(object, rar TSRMLS_CC) == FAILURE) {
return FAILURE; return FAILURE;
} }
@@ -359,7 +391,7 @@ static int rararch_handlers_preamble(handler_this_t *object,
/* {{{ rararch_dimensions_preamble - semi-strict parsing of int argument */ /* {{{ rararch_dimensions_preamble - semi-strict parsing of int argument */
static int rararch_dimensions_preamble(rar_file_t *rar, static int rararch_dimensions_preamble(rar_file_t *rar,
zval *offset, zval *offset,
zend_long *index, long *index,
int quiet TSRMLS_DC) int quiet TSRMLS_DC)
{ {
if (offset == NULL) { if (offset == NULL) {
@@ -383,32 +415,34 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
return FAILURE; return FAILURE;
} }
else if (type == IS_DOUBLE) { else if (type == IS_DOUBLE) {
if (d > (double) ZEND_LONG_MAX || d < (double) ZEND_LONG_MIN) { if (d > LONG_MAX || d < LONG_MIN) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING, RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index is out of integer bounds"); "Dimension index is out of integer bounds");
return FAILURE; return FAILURE;
} }
*index = (zend_long) d; *index = (long) d;
} }
} }
else if (Z_TYPE_P(offset) == IS_DOUBLE) { else if (Z_TYPE_P(offset) == IS_DOUBLE) {
if (Z_DVAL_P(offset) > (double) ZEND_LONG_MAX || if (Z_DVAL_P(offset) > LONG_MAX || Z_DVAL_P(offset) < LONG_MIN) {
Z_DVAL_P(offset) < (double) ZEND_LONG_MIN) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING, RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index is out of integer bounds"); "Dimension index is out of integer bounds");
return FAILURE; return FAILURE;
} }
*index = (zend_long) Z_DVAL_P(offset); *index = (long) Z_DVAL_P(offset);
} }
else if (Z_TYPE_P(offset) == IS_OBJECT) { else if (Z_TYPE_P(offset) == IS_OBJECT) {
#if PHP_MAJOR_VERSION < 8
if (Z_OBJ_HT_P(offset)->get) { if (Z_OBJ_HT_P(offset)->get) {
zval *newoffset = NULL; zval *newoffset = NULL;
int ret; int ret;
#if PHP_MAJOR_VERSION < 7
newoffset = Z_OBJ_HT_P(offset)->get(offset TSRMLS_CC);
#else
zval zv_holder; zval zv_holder;
ZVAL_NULL(&zv_holder); ZVAL_NULL(&zv_holder);
newoffset = Z_OBJ_HT_P(offset)->get(offset, &zv_holder); newoffset = Z_OBJ_HT_P(offset)->get(offset, &zv_holder);
#endif
/* get handler cannot return NULL */ /* get handler cannot return NULL */
assert(newoffset != NULL); assert(newoffset != NULL);
@@ -421,28 +455,12 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
ret = rararch_dimensions_preamble(rar, newoffset, index, quiet ret = rararch_dimensions_preamble(rar, newoffset, index, quiet
TSRMLS_CC); TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
zval_ptr_dtor(&newoffset);
#else
zval_ptr_dtor(newoffset); zval_ptr_dtor(newoffset);
#endif
return ret; return ret;
} else
#endif // PHP < 8
if (Z_OBJ_HT_P(offset)->cast_object) {
zval newoffset;
int res = Z_OBJ_HT_P(offset)->cast_object(
ZV_TO_THIS_FOR_HANDLER(offset), &newoffset, IS_LONG TSRMLS_CC);
if (res == FAILURE) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Could not convert object given as dimension index into "
"an integer (cast_object failed)");
return FAILURE;
}
if (Z_TYPE(newoffset) != IS_LONG) {
zval_dtor(&newoffset);
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Could not convert object given as dimension index into "
"an integer (cast_object did not return int as asked)");
return FAILURE;
}
*index = Z_LVAL(newoffset);
} }
else { else {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING, RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
@@ -458,9 +476,9 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
return FAILURE; return FAILURE;
} }
if (*index < 0) { if (*index < 0L) {
RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING, RAR_DOCREF_IF_UNQUIET(NULL TSRMLS_CC, E_WARNING,
"Dimension index must be non-negative, given " ZEND_LONG_FMT, *index); "Dimension index must be non-negative, given %ld", *index);
return FAILURE; return FAILURE;
} }
if ((size_t) *index >= _rar_entry_count(rar)) { if ((size_t) *index >= _rar_entry_count(rar)) {
@@ -475,30 +493,34 @@ static int rararch_dimensions_preamble(rar_file_t *rar,
/* }}} */ /* }}} */
/* {{{ RarArchive count_elements handler */ /* {{{ RarArchive count_elements handler */
static int rararch_count_elements(handler_this_t *object, zend_long *count TSRMLS_DC) static int rararch_count_elements(zval *object, long *count TSRMLS_DC)
{ {
rar_file_t *rar = NULL; rar_file_t *rar = NULL;
size_t entry_count; size_t entry_count;
if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) { if (rararch_handlers_preamble(object, &rar TSRMLS_CC) == FAILURE) {
*count = 0; *count = 0L;
return SUCCESS; /* intentional */ return SUCCESS; /* intentional */
} }
entry_count = _rar_entry_count(rar); entry_count = _rar_entry_count(rar);
if (entry_count > ZEND_LONG_MAX) if (entry_count > LONG_MAX)
entry_count = (size_t) ZEND_LONG_MAX; entry_count = (size_t) LONG_MAX;
*count = (zend_long) entry_count; *count = (long) entry_count;
return SUCCESS; return SUCCESS;
} }
/* }}} */ /* }}} */
/* {{{ RarArchive read_dimension handler */ /* {{{ RarArchive read_dimension handler */
static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int type, zval *rv) #if PHP_MAJOR_VERSION < 7
static zval *rararch_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
#else
static zval *rararch_read_dimension(zval *object, zval *offset, int type, zval *rv)
#endif
{ {
zend_long index; long index;
rar_file_t *rar = NULL; rar_file_t *rar = NULL;
struct _rar_find_output *out; struct _rar_find_output *out;
zval *ret = NULL; zval *ret = NULL;
@@ -519,24 +541,23 @@ static zval *rararch_read_dimension(handler_this_t *object, zval *offset, int ty
_rar_entry_search_seek(out, (size_t) index); _rar_entry_search_seek(out, (size_t) index);
_rar_entry_search_advance(out, NULL, 0, 0); _rar_entry_search_advance(out, NULL, 0, 0);
assert(out->found); assert(out->found);
ret = rv; #if PHP_MAJOR_VERSION < 7
#if PHP_MAJOR_VERSION >= 8 ALLOC_INIT_ZVAL(ret);
zval object_zv;
ZVAL_OBJ(&object_zv, object);
_rar_entry_to_zval(&object_zv, out->header, out->packed_size, out->position,
ret TSRMLS_CC);
#else #else
ret = rv;
#endif
_rar_entry_to_zval(object, out->header, out->packed_size, out->position, _rar_entry_to_zval(object, out->header, out->packed_size, out->position,
ret TSRMLS_CC); ret TSRMLS_CC);
#endif
_rar_entry_search_end(out); _rar_entry_search_end(out);
#if PHP_MAJOR_VERSION < 7
Z_DELREF_P(ret); /* set refcount to 0 */
#endif
return ret; return ret;
} }
/* }}} */ /* }}} */
/* {{{ RarArchive write_dimension handler */ /* {{{ RarArchive write_dimension handler */
static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *value TSRMLS_DC) static void rararch_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
{ {
php_error_docref(NULL TSRMLS_CC, E_ERROR, php_error_docref(NULL TSRMLS_CC, E_ERROR,
"A RarArchive object is not writable"); "A RarArchive object is not writable");
@@ -544,9 +565,9 @@ static void rararch_write_dimension(handler_this_t *object, zval *offset, zval *
/* }}} */ /* }}} */
/* {{{ RarArchive has_dimension handler */ /* {{{ RarArchive has_dimension handler */
static int rararch_has_dimension(handler_this_t *object, zval *offset, int check_empty TSRMLS_DC) static int rararch_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
{ {
zend_long index; long index;
rar_file_t *rar = NULL; rar_file_t *rar = NULL;
(void) check_empty; /* don't care */ (void) check_empty; /* don't care */
@@ -561,7 +582,7 @@ static int rararch_has_dimension(handler_this_t *object, zval *offset, int check
/* }}} */ /* }}} */
/* {{{ RarArchive unset_dimension handler */ /* {{{ RarArchive unset_dimension handler */
static void rararch_unset_dimension(handler_this_t *object, zval *offset TSRMLS_DC) static void rararch_unset_dimension(zval *object, zval *offset TSRMLS_DC)
{ {
php_error_docref(NULL TSRMLS_CC, E_ERROR, php_error_docref(NULL TSRMLS_CC, E_ERROR,
"A RarArchive object is not writable"); "A RarArchive object is not writable");
@@ -601,7 +622,11 @@ PHP_FUNCTION(rar_open)
assert(strnlen(resolved_path, MAXPATHLEN) < MAXPATHLEN); assert(strnlen(resolved_path, MAXPATHLEN) < MAXPATHLEN);
if (callable != NULL) { /* given volume resolver callback */ 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)) { if (!zend_is_callable(callable, IS_CALLABLE_STRICT, NULL TSRMLS_CC)) {
#endif
_rar_handle_ext_error("%s" TSRMLS_CC, "Expected the third " _rar_handle_ext_error("%s" TSRMLS_CC, "Expected the third "
"argument, if provided, to be a valid callback"); "argument, if provided, to be a valid callback");
RETURN_FALSE; RETURN_FALSE;
@@ -636,7 +661,7 @@ PHP_FUNCTION(rar_list)
RAR_THIS_OR_NO_ARGS(file); RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -671,7 +696,7 @@ PHP_FUNCTION(rar_entry_get)
return; return;
} }
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -708,7 +733,7 @@ PHP_FUNCTION(rar_solid_is)
RAR_THIS_OR_NO_ARGS(file); RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -726,7 +751,7 @@ PHP_FUNCTION(rar_comment_get)
RAR_THIS_OR_NO_ARGS(file); RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -757,7 +782,7 @@ PHP_FUNCTION(rar_broken_is)
RAR_THIS_OR_NO_ARGS(file); RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -788,7 +813,7 @@ PHP_FUNCTION(rar_allow_broken_set)
return; return;
} }
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -806,7 +831,7 @@ PHP_FUNCTION(rar_close)
RAR_THIS_OR_NO_ARGS(file); RAR_THIS_OR_NO_ARGS(file);
if (_rar_get_file_resource_zv(file, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(file, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -830,8 +855,7 @@ PHP_METHOD(rararch, __toString)
RAR_RETNULL_ON_ARGS(); RAR_RETNULL_ON_ARGS();
if (_rar_get_file_resource_zv_ex(arch_obj, &rar, TRUE TSRMLS_CC) if (_rar_get_file_resource_ex(arch_obj, &rar, TRUE TSRMLS_CC) == FAILURE) {
== FAILURE) {
RETURN_FALSE; /* should never happen */ RETURN_FALSE; /* should never happen */
} }
@@ -852,18 +876,6 @@ PHP_METHOD(rararch, __toString)
} }
/* }}} */ /* }}} */
/* {{{ proto string RarEntry::getIterator() */
#if PHP_MAJOR_VERSION >= 8
PHP_METHOD(rararch, getIterator)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
zend_create_internal_iterator_zval(return_value, getThis());
}
#endif
/* }}} */
/* {{{ arginfo */ /* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_open, 0, 0, 1) ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_open, 0, 0, 1)
ZEND_ARG_INFO(0, filename) ZEND_ARG_INFO(0, filename)
@@ -879,23 +891,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_rararchive_setallowbroken, 0, 0, 1)
ZEND_ARG_INFO(0, allow_broken) ZEND_ARG_INFO(0, allow_broken)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#if PHP_MAJOR_VERSION >= 8
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_rararchive_getiterator, 0, 0, Traversable, 0)
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO(arginfo_rararchive_void, 0) ZEND_BEGIN_ARG_INFO(arginfo_rararchive_void, 0)
ZEND_END_ARG_INFO() 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[] = { 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(open, rar_open, arginfo_rararchive_open, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(getEntries, rar_list, arginfo_rararchive_void, ZEND_ACC_PUBLIC) PHP_ME_MAPPING(getEntries, rar_list, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
@@ -908,14 +907,10 @@ static zend_function_entry php_rararch_class_functions[] = {
PHP_ME_MAPPING(isBroken, rar_broken_is, arginfo_rararchive_void, ZEND_ACC_PUBLIC) 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(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_MAPPING(close, rar_close, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
PHP_ME(rararch, __toString, arginfo_rararchive_tostring, ZEND_ACC_PUBLIC) PHP_ME(rararch, __toString, arginfo_rararchive_void, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rararchive_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR) 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} {NULL, NULL, NULL}
}; };
/* clang-format on */
/* {{{ Iteration. Very boring stuff indeed. */ /* {{{ Iteration. Very boring stuff indeed. */
@@ -927,17 +922,78 @@ 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_dtor(zend_object_iterator *iter TSRMLS_DC);
static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC); static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC);
static int rararch_it_valid(zend_object_iterator *iter 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); 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_move_forward(zend_object_iterator *iter TSRMLS_DC);
static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC); static void rararch_it_rewind(zend_object_iterator *iter TSRMLS_DC);
/* }}} */ /* }}} */
/* {{{ rararch_it_get_iterator */
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
zval *object,
int by_ref TSRMLS_DC)
{
rararch_iterator *it;
rar_file_t *rar;
int res;
if (by_ref) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"An iterator cannot be used with foreach by reference");
}
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
it->parent.funcs = ce->iterator_funcs.funcs;
it->state = NULL;
res = _rar_get_file_resource_ex(object, &rar, 1 TSRMLS_CC);
if (res == FAILURE)
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"Cannot fetch RarArchive object");
if (rar->arch_handle == NULL)
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"The archive is already closed, cannot give an iterator");
res = _rar_list_files(rar TSRMLS_CC);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
/* if it failed, do not expose the possibly incomplete entry list */
it->empty_iterator = 1;
}
else
it->empty_iterator = 0;
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &it->state TSRMLS_CC);
return (zend_object_iterator*) it;
}
/* }}} */
/* {{{ rararch_it_invalidate_current */ /* {{{ rararch_it_invalidate_current */
static void rararch_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC) static void rararch_it_invalidate_current(zend_object_iterator *iter TSRMLS_DC)
{ {
rararch_iterator *it = (rararch_iterator *) iter; 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_ptr_dtor(&it->value);
ZVAL_UNDEF(&it->value); ZVAL_UNDEF(&it->value);
#endif
} }
/* }}} */ /* }}} */
@@ -948,9 +1004,16 @@ static void rararch_it_dtor(zend_object_iterator *iter TSRMLS_DC)
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC); 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); zval_ptr_dtor(&it->parent.data);
#endif
_rar_entry_search_end(it->state); _rar_entry_search_end(it->state);
#if PHP_MAJOR_VERSION < 7
efree(it);
#endif
} }
/* }}} */ /* }}} */
@@ -961,47 +1024,91 @@ static void rararch_it_fetch(rararch_iterator *it TSRMLS_DC)
int res; int res;
zval *robj; zval *robj;
#if PHP_MAJOR_VERSION < 7
assert(it->value == NULL);
#else
assert(Z_TYPE(it->value) == IS_UNDEF); assert(Z_TYPE(it->value) == IS_UNDEF);
#endif
if (it->empty_iterator) { if (it->empty_iterator) {
#if PHP_MAJOR_VERSION < 7
MAKE_STD_ZVAL(it->value);
ZVAL_FALSE(it->value);
#else
ZVAL_FALSE(&it->value); ZVAL_FALSE(&it->value);
#endif
return; return;
} }
#if PHP_MAJOR_VERSION < 7
robj = it->parent.data;
#else
robj = &it->parent.data; robj = &it->parent.data;
#endif
res = _rar_get_file_resource_zv_ex(robj, &rar_file, 1 TSRMLS_CC); res = _rar_get_file_resource_ex(robj, &rar_file, 1 TSRMLS_CC);
if (res == FAILURE) if (res == FAILURE)
php_error_docref(NULL TSRMLS_CC, E_ERROR, php_error_docref(NULL TSRMLS_CC, E_ERROR,
"Cannot fetch RarArchive object"); "Cannot fetch RarArchive object");
_rar_entry_search_advance(it->state, NULL, 0, 0); _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) if (it->state->found)
_rar_entry_to_zval(&it->parent.data, it->state->header, _rar_entry_to_zval(&it->parent.data, it->state->header,
it->state->packed_size, it->state->position, &it->value TSRMLS_CC); it->state->packed_size, it->state->position, &it->value TSRMLS_CC);
else { else {
ZVAL_FALSE(&it->value); ZVAL_FALSE(&it->value);
} }
#endif
} }
/* }}} */ /* }}} */
/* {{{ rararch_it_valid */ /* {{{ rararch_it_valid */
static int rararch_it_valid(zend_object_iterator *iter TSRMLS_DC) 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; zval *value = &((rararch_iterator *) iter)->value;
assert(Z_TYPE_P(value) != IS_UNDEF); assert(Z_TYPE_P(value) != IS_UNDEF);
return Z_TYPE_P(value) != IS_FALSE ? SUCCESS : FAILURE; return Z_TYPE_P(value) != IS_FALSE ? SUCCESS : FAILURE;
#endif
} }
/* }}} */ /* }}} */
/* {{{ rararch_it_current_data */ /* {{{ 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) static zval *rararch_it_current_data(zend_object_iterator *iter)
{ {
zval *ret; zval *ret;
#if PHP_MAJOR_VERSION < 7
ret = ((rararch_iterator *) iter)->value;
assert(ret != NULL);
#else
ret = &((rararch_iterator *) iter)->value; ret = &((rararch_iterator *) iter)->value;
assert(Z_TYPE_P(ret) != IS_UNDEF); assert(Z_TYPE_P(ret) != IS_UNDEF);
#endif
return ret; return ret;
} }
#endif
/* }}} */ /* }}} */
/* {{{ rararch_it_move_forward */ /* {{{ rararch_it_move_forward */
@@ -1009,7 +1116,11 @@ static void rararch_it_move_forward(zend_object_iterator *iter TSRMLS_DC)
{ {
rararch_iterator *it = (rararch_iterator *) iter; rararch_iterator *it = (rararch_iterator *) iter;
rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC); rararch_it_invalidate_current((zend_object_iterator *) it TSRMLS_CC);
#if PHP_MAJOR_VERSION < 7
it->value = NULL;
#else
ZVAL_UNDEF(&it->value); ZVAL_UNDEF(&it->value);
#endif
rararch_it_fetch(it TSRMLS_CC); rararch_it_fetch(it TSRMLS_CC);
} }
/* }}} */ /* }}} */
@@ -1036,55 +1147,6 @@ static zend_object_iterator_funcs rararch_it_funcs = {
}; };
/* }}} */ /* }}} */
/* {{{ rararch_it_get_iterator */
static zend_object_iterator *rararch_it_get_iterator(zend_class_entry *ce,
zval *object,
int by_ref TSRMLS_DC)
{
rar_file_t *rar;
int res;
if (by_ref) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"An iterator cannot be used with foreach by reference");
}
res = _rar_get_file_resource_zv_ex(object, &rar, 1 TSRMLS_CC);
if (res == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"Cannot fetch RarArchive object");
}
if (rar->arch_handle == NULL) {
php_error_docref(NULL TSRMLS_CC, E_ERROR,
"The archive is already closed, cannot give an iterator");
}
rararch_iterator *it = emalloc(sizeof *it);
zend_iterator_init((zend_object_iterator *) it);
ZVAL_COPY(&it->parent.data, object);
ZVAL_UNDEF(&it->value);
#if PHP_VERSION_ID < 70300
it->parent.funcs = ce->iterator_funcs.funcs;
#else
it->parent.funcs = &rararch_it_funcs;
#endif
it->state = NULL;
res = _rar_list_files(rar TSRMLS_CC);
if (_rar_handle_error(res TSRMLS_CC) == FAILURE) {
/* if it failed, do not expose the possibly incomplete entry list */
it->empty_iterator = 1;
}
else
it->empty_iterator = 0;
_rar_entry_search_start(rar, RAR_SEARCH_TRAVERSE, &it->state TSRMLS_CC);
return (zend_object_iterator*) it;
}
/* }}} */
void minit_rararch(TSRMLS_D) void minit_rararch(TSRMLS_D)
{ {
zend_class_entry ce; zend_class_entry ce;
@@ -1097,8 +1159,10 @@ void minit_rararch(TSRMLS_D)
rararch_object_handlers.has_dimension = rararch_has_dimension; rararch_object_handlers.has_dimension = rararch_has_dimension;
rararch_object_handlers.unset_dimension = rararch_unset_dimension; rararch_object_handlers.unset_dimension = rararch_unset_dimension;
rararch_object_handlers.clone_obj = NULL; rararch_object_handlers.clone_obj = NULL;
#if PHP_MAJOR_VERSION >= 7
rararch_object_handlers.free_obj = rararch_ce_free_object_storage; rararch_object_handlers.free_obj = rararch_ce_free_object_storage;
rararch_object_handlers.offset = XtOffsetOf(ze_rararch_object, parent); rararch_object_handlers.offset = XtOffsetOf(ze_rararch_object, parent);
#endif
INIT_CLASS_ENTRY(ce, "RarArchive", php_rararch_class_functions); INIT_CLASS_ENTRY(ce, "RarArchive", php_rararch_class_functions);
rararch_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC); rararch_ce_ptr = zend_register_internal_class(&ce TSRMLS_CC);
@@ -1106,12 +1170,10 @@ void minit_rararch(TSRMLS_D)
rararch_ce_ptr->clone = NULL; rararch_ce_ptr->clone = NULL;
rararch_ce_ptr->create_object = &rararch_ce_create_object; rararch_ce_ptr->create_object = &rararch_ce_create_object;
rararch_ce_ptr->get_iterator = rararch_it_get_iterator; rararch_ce_ptr->get_iterator = rararch_it_get_iterator;
#if PHP_VERSION_ID < 70300
rararch_ce_ptr->iterator_funcs.funcs = &rararch_it_funcs; rararch_ce_ptr->iterator_funcs.funcs = &rararch_it_funcs;
#endif
#if PHP_MAJOR_VERSION >= 8
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_aggregate);
#else
zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable); zend_class_implements(rararch_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
#endif
} }
#ifdef __cplusplus
}
#endif
+80 -104
View File
@@ -27,10 +27,11 @@
/* $Id$ */ /* $Id$ */
#include <zend_types.h> #ifdef __cplusplus
#ifndef _GNU_SOURCE extern "C" {
# define _GNU_SOURCE
#endif #endif
#define _GNU_SOURCE
#include <string.h> #include <string.h>
#include <php.h> #include <php.h>
@@ -45,50 +46,55 @@ static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
int name_length, char *doc_comment, int name_length, char *doc_comment,
int doc_comment_len TSRMLS_DC); int doc_comment_len TSRMLS_DC);
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC); static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC);
static void _rar_dos_date_to_text(unsigned dos_time, char *date_string); static void _rar_dos_date_to_text(int dos_time, char *date_string);
/* }}} */ /* }}} */
/* {{{ Functions with external linkage */ /* {{{ Functions with external linkage */
/* should be passed the last entry that corresponds to a given file /* 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 */ * only that one has the correct CRC. Still, it may have a wrong packedSize */
/* parent is zval to RarArchive object. The object /* parent is zval to RarArchive object. The object (not the zval, in PHP 5.x)
* will have its refcount increased */ * will have its refcount increased */
void _rar_entry_to_zval(zval *parent, void _rar_entry_to_zval(zval *parent,
struct RARHeaderDataEx *entry, struct RARHeaderDataEx *entry,
zend_ulong packed_size, unsigned long packed_size,
size_t position, size_t position,
zval *object TSRMLS_DC) zval *object TSRMLS_DC) /* {{{ */
/* {{{ */
{ {
char tmp_s [MAX_LENGTH_OF_LONG + 1]; char tmp_s [MAX_LENGTH_OF_LONG + 1];
char time[50]; char time[50];
char *filename; char *filename;
int filename_size, int filename_size,
filename_len; filename_len;
zend_long unp_size; long unp_size; /* zval stores PHP ints as long, so use that here */
zval *parent_copy = parent; zval *parent_copy = parent;
#if PHP_MAJOR_VERSION < 7
object_init_ex(object, rar_class_entry_ptr); /* allocate zval on the heap */
#if PHP_MAJOR_VERSION >= 8 zval_addref_p(parent_copy);
zend_object *obj = Z_OBJ_P(object); SEPARATE_ZVAL(&parent_copy);
#else /* set refcount to 0; zend_update_property will increase it */
zval *obj = object; Z_DELREF_P(parent_copy);
#endif #endif
zend_update_property(rar_class_entry_ptr, obj, "rarfile", object_init_ex(object, rar_class_entry_ptr);
zend_update_property(rar_class_entry_ptr, object, "rarfile",
sizeof("rararch") - 1, parent_copy TSRMLS_CC); sizeof("rararch") - 1, parent_copy TSRMLS_CC);
{ #if ULONG_MAX > 0xffffffffUL
uint64_t raw_size = (uint64_t)entry->UnpSizeHigh << 32 | entry->UnpSize; unp_size = ((long) entry->UnpSize) + (((long) entry->UnpSizeHigh) << 32);
unp_size = raw_size > (uint64_t)ZEND_LONG_MAX #else
? ZEND_LONG_MAX : (zend_long)raw_size; /* 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
filename_size = sizeof(entry->FileNameW) * 4; filename_size = sizeof(entry->FileNameW) * 4;
filename = (char*) emalloc(filename_size); filename = (char*) emalloc(filename_size);
if (packed_size > (zend_ulong) ZEND_LONG_MAX) if (packed_size > (unsigned long) LONG_MAX)
packed_size = (zend_ulong) ZEND_LONG_MAX; packed_size = LONG_MAX;
_rar_wide_to_utf(entry->FileNameW, filename, filename_size); _rar_wide_to_utf(entry->FileNameW, filename, filename_size);
/* OK; safe usage below: */ /* OK; safe usage below: */
filename_len = _rar_strnlen(filename, filename_size); filename_len = _rar_strnlen(filename, filename_size);
@@ -96,42 +102,42 @@ void _rar_entry_to_zval(zval *parent,
* properties from here with add_property_x, or * properties from here with add_property_x, or
* direct call to rarentry_object_handlers.write_property * direct call to rarentry_object_handlers.write_property
* zend_update_property_x updates the scope accordingly */ * zend_update_property_x updates the scope accordingly */
zend_update_property_long(rar_class_entry_ptr, obj, "position", zend_update_property_long(rar_class_entry_ptr, object, "position",
sizeof("position") - 1, (zend_long) position TSRMLS_CC); sizeof("position") - 1, (long) position TSRMLS_CC);
zend_update_property_stringl(rar_class_entry_ptr, obj, "name", zend_update_property_stringl(rar_class_entry_ptr, object, "name",
sizeof("name") - 1, filename, filename_len TSRMLS_CC); sizeof("name") - 1, filename, filename_len TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "unpacked_size", zend_update_property_long(rar_class_entry_ptr, object, "unpacked_size",
sizeof("unpacked_size") - 1, unp_size TSRMLS_CC); sizeof("unpacked_size") - 1, unp_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "packed_size", zend_update_property_long(rar_class_entry_ptr, object, "packed_size",
sizeof("packed_size") - 1, packed_size TSRMLS_CC); sizeof("packed_size") - 1, packed_size TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "host_os", zend_update_property_long(rar_class_entry_ptr, object, "host_os",
sizeof("host_os") - 1, entry->HostOS TSRMLS_CC); sizeof("host_os") - 1, entry->HostOS TSRMLS_CC);
_rar_dos_date_to_text(entry->FileTime, time); _rar_dos_date_to_text(entry->FileTime, time);
zend_update_property_string(rar_class_entry_ptr, obj, "file_time", zend_update_property_string(rar_class_entry_ptr, object, "file_time",
sizeof("file_time") - 1, time TSRMLS_CC); sizeof("file_time") - 1, time TSRMLS_CC);
sprintf(tmp_s, "%x", entry->FileCRC); sprintf(tmp_s, "%x", entry->FileCRC);
zend_update_property_string(rar_class_entry_ptr, obj, "crc", zend_update_property_string(rar_class_entry_ptr, object, "crc",
sizeof("crc") - 1, tmp_s TSRMLS_CC); sizeof("crc") - 1, tmp_s TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "attr", zend_update_property_long(rar_class_entry_ptr, object, "attr",
sizeof("attr") - 1, entry->FileAttr TSRMLS_CC); sizeof("attr") - 1, entry->FileAttr TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "version", zend_update_property_long(rar_class_entry_ptr, object, "version",
sizeof("version") - 1, entry->UnpVer TSRMLS_CC); sizeof("version") - 1, entry->UnpVer TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "method", zend_update_property_long(rar_class_entry_ptr, object, "method",
sizeof("method") - 1, entry->Method TSRMLS_CC); sizeof("method") - 1, entry->Method TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "flags", zend_update_property_long(rar_class_entry_ptr, object, "flags",
sizeof("flags") - 1, entry->Flags TSRMLS_CC); sizeof("flags") - 1, entry->Flags TSRMLS_CC);
zend_update_property_long(rar_class_entry_ptr, obj, "redir_type", zend_update_property_long(rar_class_entry_ptr, object, "redir_type",
sizeof("redir_type") - 1, entry->RedirType TSRMLS_CC); sizeof("redir_type") - 1, entry->RedirType TSRMLS_CC);
if (entry->RedirName) { if (entry->RedirName) {
char *redir_target = NULL; char *redir_target = NULL;
size_t redir_target_size; size_t redir_target_size;
zend_update_property_bool(rar_class_entry_ptr, obj, zend_update_property_long(rar_class_entry_ptr, object,
"redir_to_directory", sizeof("redir_to_directory") - 1, "redir_to_directory", sizeof("redir_to_directory") - 1,
!!entry->DirTarget TSRMLS_CC); !!entry->DirTarget TSRMLS_CC);
@@ -140,7 +146,7 @@ void _rar_entry_to_zval(zval *parent,
assert(redir_target_size > 0); assert(redir_target_size > 0);
_rar_wide_to_utf(entry->RedirName, redir_target, redir_target_size); _rar_wide_to_utf(entry->RedirName, redir_target, redir_target_size);
zend_update_property_string(rar_class_entry_ptr, obj, "redir_target", zend_update_property_string(rar_class_entry_ptr, object, "redir_target",
sizeof("redir_target") - 1, redir_target TSRMLS_CC); sizeof("redir_target") - 1, redir_target TSRMLS_CC);
efree(redir_target); efree(redir_target);
@@ -164,7 +170,7 @@ void _rar_entry_to_zval(zval *parent,
#define REG_RAR_CLASS_CONST_LONG(const_name, value) \ #define REG_RAR_CLASS_CONST_LONG(const_name, value) \
zend_declare_class_constant_long(rar_class_entry_ptr, const_name, \ zend_declare_class_constant_long(rar_class_entry_ptr, const_name, \
sizeof(const_name) - 1, (zend_long) value TSRMLS_CC) sizeof(const_name) - 1, (long) value TSRMLS_CC)
#define REG_RAR_PROPERTY(name, comment) \ #define REG_RAR_PROPERTY(name, comment) \
_rar_decl_priv_prop_null(rar_class_entry_ptr, name, sizeof(name) -1, \ _rar_decl_priv_prop_null(rar_class_entry_ptr, name, sizeof(name) -1, \
@@ -174,6 +180,13 @@ static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
int name_length, char *doc_comment, int name_length, char *doc_comment,
int doc_comment_len TSRMLS_DC) /* {{{ */ 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; zval property;
zend_string *name_str, zend_string *name_str,
*doc_str; *doc_str;
@@ -182,32 +195,29 @@ static int _rar_decl_priv_prop_null(zend_class_entry *ce, const char *name,
ZVAL_NULL(&property); ZVAL_NULL(&property);
name_str = zend_string_init(name, (size_t) name_length, 1); name_str = zend_string_init(name, (size_t) name_length, 1);
doc_str = zend_string_init(doc_comment, (size_t) doc_comment_len, 1); doc_str = zend_string_init(doc_comment, (size_t) doc_comment_len, 1);
# if PHP_MAJOR_VERSION >= 8
zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str);
ret = SUCCESS;
# else
ret = zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE, ret = zend_declare_property_ex(ce, name_str, &property, ZEND_ACC_PRIVATE,
doc_str); doc_str);
#endif
zend_string_release(name_str); zend_string_release(name_str);
zend_string_release(doc_str); zend_string_release(doc_str);
return ret; return ret;
#endif
} }
/* }}} */ /* }}} */
static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */ static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TSRMLS_DC) /* {{{ */
{ {
zval *tmp; zval *tmp;
#if PHP_MAJOR_VERSION >= 7
zval zv; zval zv;
#endif
#if PHP_VERSION_ID < 70100 #if PHP_VERSION_ID < 70100
zend_class_entry *orig_scope = EG(scope); zend_class_entry *orig_scope = EG(scope);
EG(scope) = rar_class_entry_ptr; EG(scope) = rar_class_entry_ptr;
#endif #endif
#if PHP_MAJOR_VERSION >= 8 #if PHP_MAJOR_VERSION < 7
tmp = zend_read_property(Z_OBJCE_P(entry_obj), Z_OBJ_P(entry_obj), name, namelen, 1, &zv); tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1 TSRMLS_CC);
#else #else
tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv); tmp = zend_read_property(Z_OBJCE_P(entry_obj), entry_obj, name, namelen, 1, &zv);
#endif #endif
@@ -224,29 +234,24 @@ static zval *_rar_entry_get_property(zval *entry_obj, char *name, int namelen TS
} }
/* }}} */ /* }}} */
static void _rar_dos_date_to_text(unsigned dos_time, char *date_string) /* {{{ */ static void _rar_dos_date_to_text(int dos_time, char *date_string) /* {{{ */
{ {
time_t time = 0; int second, minute, hour, day, month, year;
struct tm tm = {0}; /* following lines were taken from timefn.cpp */
int res; second = (dos_time & 0x1f)*2;
minute = (dos_time>>5) & 0x3f;
res = rar_dos_time_convert(dos_time, &time) != FAILURE && hour = (dos_time>>11) & 0x1f;
php_gmtime_r(&time, &tm) != NULL; day = (dos_time>>16) & 0x1f;
month = (dos_time>>21) & 0x0f;
if (!res) { year = (dos_time>>25)+1980;
sprintf(date_string, "%s", "time conversion failure"); sprintf(date_string, "%u-%02u-%02u %02u:%02u:%02u", year, month, day, hour, minute, second);
}
sprintf(date_string, "%u-%02u-%02u %02u:%02u:%02u",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
tm.tm_sec);
} }
/* }}} */ /* }}} */
/* }}} */ /* }}} */
/* {{{ Methods */ /* {{{ Methods */
/* {{{ public function extract(?string $dir, ?string $filepath = '', /* {{{ proto bool RarEntry::extract(string dir [, string filepath = ''
?string $password = null, bool $extended_data = false): void {} [, string password = NULL [, bool extended_data = FALSE]])
Extract file from the archive */ Extract file from the archive */
PHP_METHOD(rarentry, extract) PHP_METHOD(rarentry, extract)
{ /* lots of variables, but no need to be intimidated */ { /* lots of variables, but no need to be intimidated */
@@ -265,7 +270,7 @@ PHP_METHOD(rarentry, extract)
*tmp_position; *tmp_position;
rar_file_t *rar = NULL; rar_file_t *rar = NULL;
zval *entry_obj = getThis(); zval *entry_obj = getThis();
struct RARHeaderDataEx entry = {0}; struct RARHeaderDataEx entry;
HANDLE extract_handle = NULL; HANDLE extract_handle = NULL;
int result; int result;
int found; int found;
@@ -273,14 +278,14 @@ PHP_METHOD(rarentry, extract)
* password that's different from the one stored in the rar_file_t object*/ * password that's different from the one stored in the rar_file_t object*/
rar_cb_user_data cb_udata = {NULL}; rar_cb_user_data cb_udata = {NULL};
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!|s!s!b", &dir, if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss!b", &dir,
&dir_len, &filepath, &filepath_len, &password, &password_len, &dir_len, &filepath, &filepath_len, &password, &password_len,
&process_ed) == FAILURE ) { &process_ed) == FAILURE ) {
return; return;
} }
RAR_GET_PROPERTY(tmp, "rarfile"); RAR_GET_PROPERTY(tmp, "rarfile");
if (_rar_get_file_resource_zv(tmp, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -341,25 +346,12 @@ PHP_METHOD(rarentry, extract)
cb_udata.password = password; cb_udata.password = password;
/* Do extraction */ /* Do extraction */
#ifdef PHP_WIN32
{
size_t path_w_len = strlen(considered_path_res);
wchar_t *path_w = safe_emalloc(path_w_len, sizeof(wchar_t), sizeof(wchar));
_rar_utf_to_wide(considered_path_res, path_w, path_w_len + 1);
if (!with_second_arg)
result = RARProcessFileW(extract_handle, RAR_EXTRACT, path_w, NULL);
else
result = RARProcessFileW(extract_handle, RAR_EXTRACT, NULL, path_w);
efree(path_w);
}
#else
if (!with_second_arg) if (!with_second_arg)
result = RARProcessFile(extract_handle, RAR_EXTRACT, result = RARProcessFile(extract_handle, RAR_EXTRACT,
considered_path_res, NULL); considered_path_res, NULL);
else else
result = RARProcessFile(extract_handle, RAR_EXTRACT, result = RARProcessFile(extract_handle, RAR_EXTRACT,
NULL, considered_path_res); NULL, considered_path_res);
#endif
if (_rar_handle_error(result TSRMLS_CC) == FAILURE) { if (_rar_handle_error(result TSRMLS_CC) == FAILURE) {
RETVAL_FALSE; RETVAL_FALSE;
@@ -547,7 +539,7 @@ PHP_METHOD(rarentry, getStream)
RAR_GET_PROPERTY(position, "position"); RAR_GET_PROPERTY(position, "position");
RAR_GET_PROPERTY(tmp, "rarfile"); RAR_GET_PROPERTY(tmp, "rarfile");
if (_rar_get_file_resource_zv(tmp, &rar TSRMLS_CC) == FAILURE) { if (_rar_get_file_resource(tmp, &rar TSRMLS_CC) == FAILURE) {
RETURN_FALSE; RETURN_FALSE;
} }
@@ -574,7 +566,7 @@ PHP_METHOD(rarentry, isDirectory)
{ {
zval *tmp; zval *tmp;
zval *entry_obj = getThis(); zval *entry_obj = getThis();
zend_long flags; long flags;
int is_dir; int is_dir;
RAR_RETNULL_ON_ARGS(); RAR_RETNULL_ON_ARGS();
@@ -593,7 +585,7 @@ PHP_METHOD(rarentry, isEncrypted)
{ {
zval *tmp; zval *tmp;
zval *entry_obj = getThis(); zval *entry_obj = getThis();
zend_long flags; long flags;
int is_encrypted; int is_encrypted;
RAR_RETNULL_ON_ARGS(); RAR_RETNULL_ON_ARGS();
@@ -702,21 +694,12 @@ PHP_METHOD(rarentry, __toString)
/* }}} */ /* }}} */
/* {{{ arginfo */ /* {{{ arginfo */
#if PHP_MAJOR_VERSION < 8
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_extract, 0, 0, 1) ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_extract, 0, 0, 1)
ZEND_ARG_INFO(0, path) ZEND_ARG_INFO(0, path)
ZEND_ARG_INFO(0, filename) ZEND_ARG_INFO(0, filename)
ZEND_ARG_INFO(0, password) ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, extended_data) ZEND_ARG_INFO(0, extended_data)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#else
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rarentry_extract, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, dir, IS_STRING, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, filepath, IS_STRING, 1, "\'\'")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, extended_data, _IS_BOOL, 0, "false")
ZEND_END_ARG_INFO()
#endif
ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_getstream, 0, 0, 0) ZEND_BEGIN_ARG_INFO_EX(arginfo_rarentry_getstream, 0, 0, 0)
ZEND_ARG_INFO(0, password) ZEND_ARG_INFO(0, password)
@@ -724,16 +707,8 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_rar_void, 0) ZEND_BEGIN_ARG_INFO(arginfo_rar_void, 0)
ZEND_END_ARG_INFO() 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[] = { static zend_function_entry php_rar_class_functions[] = {
PHP_ME(rarentry, extract, arginfo_rarentry_extract, ZEND_ACC_PUBLIC) PHP_ME(rarentry, extract, arginfo_rarentry_extract, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, getPosition, arginfo_rar_void, ZEND_ACC_PUBLIC) PHP_ME(rarentry, getPosition, arginfo_rar_void, ZEND_ACC_PUBLIC)
@@ -752,11 +727,10 @@ static zend_function_entry php_rar_class_functions[] = {
PHP_ME(rarentry, getRedirType, arginfo_rar_void, ZEND_ACC_PUBLIC) PHP_ME(rarentry, getRedirType, arginfo_rar_void, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, isRedirectToDirectory, 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, getRedirTarget, arginfo_rar_void, ZEND_ACC_PUBLIC)
PHP_ME(rarentry, __toString, arginfo_rar_tostring, ZEND_ACC_PUBLIC) PHP_ME(rarentry, __toString, arginfo_rar_void, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR) PHP_ME_MAPPING(__construct, rar_bogus_ctor, arginfo_rar_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
/* clang-format on */
void minit_rarentry(TSRMLS_D) void minit_rarentry(TSRMLS_D)
{ {
@@ -783,7 +757,6 @@ void minit_rarentry(TSRMLS_D)
REG_RAR_PROPERTY("redir_to_directory", "Whether the redirection target is a directory"); REG_RAR_PROPERTY("redir_to_directory", "Whether the redirection target is a directory");
REG_RAR_PROPERTY("redir_target", "Target of the redirectory"); 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_MSDOS", HOST_MSDOS);
REG_RAR_CLASS_CONST_LONG("HOST_OS2", HOST_OS2); REG_RAR_CLASS_CONST_LONG("HOST_OS2", HOST_OS2);
REG_RAR_CLASS_CONST_LONG("HOST_WIN32", HOST_WIN32); REG_RAR_CLASS_CONST_LONG("HOST_WIN32", HOST_WIN32);
@@ -835,5 +808,8 @@ void minit_rarentry(TSRMLS_D)
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_REGULAR_FILE", 0x08000L); 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_SYM_LINK", 0x0A000L);
REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SOCKET", 0x0C000L); REG_RAR_CLASS_CONST_LONG("ATTRIBUTE_UNIX_SOCKET", 0x0C000L);
/* clang-format on */
} }
#ifdef __cplusplus
}
#endif
-3797
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_open() function rar_open() function
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+6 -3
View File
@@ -1,9 +1,10 @@
--TEST-- --TEST--
rar_list() function rar_list() function
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
$list1 = rar_list($rar_file1); $list1 = rar_list($rar_file1);
var_dump($list1); var_dump($list1);
@@ -13,7 +14,8 @@ $list2 = rar_list($rar_file2);
var_dump($list2); var_dump($list2);
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar'); $rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
argerr(function() use ($rar_file3) { rar_list($rar_file3); }); $list3 = rar_list($rar_file3);
var_dump($list3);
echo "Done\n"; echo "Done\n";
?> ?>
@@ -161,5 +163,6 @@ array(2) {
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %d 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, %s given in %s on line %d Warning: rar_list() expects parameter 1 to be RarArchive, boolean given in %s on line %d
NULL
Done Done
+6 -5
View File
@@ -1,9 +1,10 @@
--TEST-- --TEST--
rar_entry_get() function rar_entry_get() function
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/linux_rar.rar');
$entry1 = rar_entry_get($rar_file1, 'test file with whitespaces.txt'); $entry1 = rar_entry_get($rar_file1, 'test file with whitespaces.txt');
var_dump($entry1); var_dump($entry1);
@@ -13,9 +14,8 @@ $entry2 = rar_entry_get($rar_file2, '2.txt');
var_dump($entry2); var_dump($entry2);
$rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar'); $rar_file3 = rar_open(dirname(__FILE__).'/no_such_file.rar');
argerr(function() use ($rar_file3) { $entry3 = rar_entry_get($rar_file3, '2.txt');
rar_entry_get($rar_file3, '2.txt'); var_dump($entry3);
});
echo "Done\n"; echo "Done\n";
?> ?>
@@ -89,5 +89,6 @@ object(RarEntry)#%d (%d) {
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %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, %s given in %s on line %d Warning: rar_entry_get() expects parameter 1 to be RarArchive, boolean given in %s on line %d
NULL
Done Done
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::extract() method RarEntry::extract() method
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_comment_get() function rar_comment_get() function
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getCrc() method in multi-volume archives (PECL bug #9470) RarEntry::getCrc() method in multi-volume archives (PECL bug #9470)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_open() function with a non-RAR rar_open() function with a non-RAR
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+6 -6
View File
@@ -1,10 +1,10 @@
--TEST-- --TEST--
rar_entry_get() function rar_entry_get() function
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
require __DIR__ . "/php8compat.php.inc";
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part1.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/multi.part1.rar');
$entry = rar_entry_get($rar_file1, "file1.txt"); $entry = rar_entry_get($rar_file1, "file1.txt");
echo "$entry\n"; echo "$entry\n";
@@ -13,9 +13,8 @@ var_dump($entry);
echo "\n"; echo "\n";
$rar_file2 = rar_open(dirname(__FILE__).'/nonexistent.rar'); $rar_file2 = rar_open(dirname(__FILE__).'/nonexistent.rar');
argerr(function() use ($rar_file2) { $entry = rar_entry_get($rar_file2, "file1.txt");
rar_entry_get($rar_file2, "file1.txt"); var_dump($entry);
});
echo "\n"; echo "\n";
echo "Done\n"; echo "Done\n";
@@ -29,6 +28,7 @@ bool(false)
Warning: rar_open(): Failed to open %s: ERAR_EOPEN (file open error) in %s on line %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, %s given in %s on line %d Warning: rar_entry_get() expects parameter 1 to be RarArchive, boolean given in %s on line %d
NULL
Done Done
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getName() function with unicode filenames RarEntry::getName() function with unicode filenames
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() function (good RAR file, one volume) RarEntry::getStream() function (good RAR file, one volume)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+1 -3
View File
@@ -1,9 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() function (good RAR file, several volumes) RarEntry::getStream() function (good RAR file, several volumes)
--SKIPIF-- --SKIPIF--
<?php <?php if(!extension_loaded("rar")) print "skip"; ?>
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() function (bad RAR file) RarEntry::getStream() function (bad RAR file)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/corrupted.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/corrupted.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_entry_get() and RarEntry::getName() coherence rar_entry_get() and RarEntry::getName() coherence
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() on unicode entry RarEntry::getStream() on unicode entry
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_close() liberates resource (PECL bug #9649) rar_close() liberates resource (PECL bug #9649)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
copy(dirname(__FILE__).'/latest_winrar.rar', dirname(__FILE__).'/temp.rar'); copy(dirname(__FILE__).'/latest_winrar.rar', dirname(__FILE__).'/temp.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::extract() method (corrupt RAR file) RarEntry::extract() method (corrupt RAR file)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/corrupted.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/corrupted.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::extract() with unicode files RarEntry::extract() with unicode files
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/rar_unicode.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/rar_unicode.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_list()/rar_entry_get() with not first volume rar_list()/rar_entry_get() with not first volume
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/multi.part2.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/multi.part2.rar');
+1 -3
View File
@@ -1,9 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() function (store method) RarEntry::getStream() function (store method)
--SKIPIF-- --SKIPIF--
<?php <?php if(!extension_loaded("rar")) print "skip"; ?>
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE-- --FILE--
<?php <?php
+1 -3
View File
@@ -1,9 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() function (solid archive) RarEntry::getStream() function (solid archive)
--SKIPIF-- --SKIPIF--
<?php <?php if(!extension_loaded("rar")) print "skip"; ?>
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE-- --FILE--
<?php <?php
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::isDirectory() basic test RarEntry::isDirectory() basic test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/directories.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/directories.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::extract() with directory RarEntry::extract() with directory
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/directories.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/directories.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() with directory RarEntry::getStream() with directory
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file1 = rar_open(dirname(__FILE__).'/directories.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/directories.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_open()/RarEntry::getStream() (headers level password) rar_open()/RarEntry::getStream() (headers level password)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
echo "--> should fail (no password):\n"; echo "--> should fail (no password):\n";
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_open()/RarEntry::extract() (headers level password) rar_open()/RarEntry::extract() (headers level password)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_file2 = rar_open(dirname(__FILE__).'/encrypted_headers.rar', 'samplepassword'); $rar_file2 = rar_open(dirname(__FILE__).'/encrypted_headers.rar', 'samplepassword');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() (file level password) RarEntry::getStream() (file level password)
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
echo "--> should fail (no password):\n"; echo "--> should fail (no password):\n";
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() with Linux directories and links RarEntry::getStream() with Linux directories and links
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar = rar_open(dirname(__FILE__) . "/dirlink_unix.rar"); $rar = rar_open(dirname(__FILE__) . "/dirlink_unix.rar");
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarArchive::open() basic test RarArchive::open() basic test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$arch = RarArchive::open(dirname(__FILE__) . "/dirlink_unix.rar"); $arch = RarArchive::open(dirname(__FILE__) . "/dirlink_unix.rar");
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarArchive::getEntries() basic test RarArchive::getEntries() basic test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$arch = RarArchive::open(dirname(__FILE__) . "/dirlink_unix.rar"); $arch = RarArchive::open(dirname(__FILE__) . "/dirlink_unix.rar");
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarArchive::getEntry() basic test RarArchive::getEntry() basic test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_arch = RarArchive::open(dirname(__FILE__) . '/solid.rar'); $rar_arch = RarArchive::open(dirname(__FILE__) . '/solid.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarArchive::getComment() basic test RarArchive::getComment() basic test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rar_arch = RarArchive::open(dirname(__FILE__) . '/commented.rar'); $rar_arch = RarArchive::open(dirname(__FILE__) . '/commented.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarArchive traversal with multi-part archive RarArchive traversal with multi-part archive
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rarF = RarArchive::open(dirname(__FILE__) . '/multi.part1.rar'); $rarF = RarArchive::open(dirname(__FILE__) . '/multi.part1.rar');
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_solid_is() basic test rar_solid_is() basic test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$arch1 = RarArchive::open(dirname(__FILE__) . "/store_method.rar"); $arch1 = RarArchive::open(dirname(__FILE__) . "/store_method.rar");
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarException::(set/is)UsingExceptions() test RarException::(set/is)UsingExceptions() test
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
echo "Initial state: " . (RarException::isUsingExceptions()?'yes':'no').".\n"; echo "Initial state: " . (RarException::isUsingExceptions()?'yes':'no').".\n";
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_entry_get() non-existent file with exceptions rar_entry_get() non-existent file with exceptions
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
RarException::setUsingExceptions(true); RarException::setUsingExceptions(true);
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
rar_open() non-existent archive with exceptions rar_open() non-existent archive with exceptions
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
RarException::setUsingExceptions(true); RarException::setUsingExceptions(true);
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream(), password not given, with exceptions RarEntry::getStream(), password not given, with exceptions
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
RarException::setUsingExceptions(true); RarException::setUsingExceptions(true);
+3 -1
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
RarArchive get iterator on closed file RarArchive get iterator on closed file
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rarF = RarArchive::open(dirname(__FILE__) . '/latest_winrar.rar'); $rarF = RarArchive::open(dirname(__FILE__) . '/latest_winrar.rar');
@@ -10,4 +12,4 @@ foreach ($rarF as $k => $rarE) {
} }
echo "Done.\n"; echo "Done.\n";
--EXPECTF-- --EXPECTF--
Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d%A Fatal error: main(): The archive is already closed, cannot give an iterator in %s on line %d
+2
View File
@@ -1,5 +1,7 @@
--TEST-- --TEST--
Access RAR archive with missing volumes Access RAR archive with missing volumes
--SKIPIF--
<?php if(!extension_loaded("rar")) print "skip"; ?>
--FILE-- --FILE--
<?php <?php
$rarF = RarArchive::open(dirname(__FILE__) . '/multi_broken.part1.rar'); $rarF = RarArchive::open(dirname(__FILE__) . '/multi_broken.part1.rar');
+1
View File
@@ -2,6 +2,7 @@
RarEntry::getUnpackedSize() on platforms with 32-bit longs RarEntry::getUnpackedSize() on platforms with 32-bit longs
--SKIPIF-- --SKIPIF--
<?php <?php
if(!extension_loaded("rar")) die("skip");
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platforms only"); if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platforms only");
--FILE-- --FILE--
<?php <?php
+1
View File
@@ -2,6 +2,7 @@
RarEntry::getUnpackedSize() on platforms with 64-bit longs RarEntry::getUnpackedSize() on platforms with 64-bit longs
--SKIPIF-- --SKIPIF--
<?php <?php
if(!extension_loaded("rar")) die("skip");
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platforms only"); if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platforms only");
--FILE-- --FILE--
<?php <?php
+5 -2
View File
@@ -1,12 +1,15 @@
--TEST-- --TEST--
rar_open() with volume find callback basic test rar_open() with volume find callback basic test
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
chdir(dirname(__FILE__)); chdir(dirname(__FILE__));
function volume_callback($vol) { function volume_callback($vol) {
if (strpos($vol, '_fail') !== false) if (preg_match('/_fail/', $vol))
$ret = basename(str_replace('_fail', '', $vol)); $ret = basename(str_replace('_fail', '', $vol));
elseif (strpos($vol, '_broken') !== false) elseif (preg_match('/_broken/', $vol))
$ret = basename(str_replace('_broken', '_fail', $vol)); $ret = basename(str_replace('_broken', '_fail', $vol));
else else
$ret = null; $ret = null;
+3
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
rar_open() with volume find (callback variants 1) rar_open() with volume find (callback variants 1)
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
class A { class A {
+1
View File
@@ -2,6 +2,7 @@
rar_open() with volume find (callback variants 2) rar_open() with volume find (callback variants 2)
--SKIPIF-- --SKIPIF--
<?php <?php
if(!extension_loaded("rar")) die("skip");
if(!defined('PHP_VERSION_ID') || PHP_VERSION_ID<50300) die("skip"); if(!defined('PHP_VERSION_ID') || PHP_VERSION_ID<50300) die("skip");
--FILE-- --FILE--
<?php <?php
+6 -26
View File
@@ -1,8 +1,10 @@
--TEST-- --TEST--
rar_open() with invalid volume callback rar_open() with invalid volume callback
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
require __DIR__ . "/php8compat.php.inc";
class A { class A {
public static function resolve($vol) { public static function resolve($vol) {
@@ -28,15 +30,11 @@ var_dump($rar);
echo "\nGiven callback that takes more arguments:\n"; echo "\nGiven callback that takes more arguments:\n";
$rar = RarArchive::open($fn, null, 'strpos'); $rar = RarArchive::open($fn, null, 'strpos');
argerr(function() use ($rar) { $rar->getEntries();
$rar->getEntries();
});
echo "\nGiven callback that takes another kind of arguments:\n"; echo "\nGiven callback that takes another kind of arguments:\n";
$rar = RarArchive::open($fn, null, 'array_keys'); $rar = RarArchive::open($fn, null, 'array_keys');
argerr(function() use ($rar) { $rar->getEntries();
$rar->getEntries();
});
echo "\nGiven callback that returns another kind of arguments:\n"; echo "\nGiven callback that returns another kind of arguments:\n";
function testA($vol) { return true; } function testA($vol) { return true; }
@@ -54,7 +52,7 @@ try {
} }
echo "Done.\n"; echo "Done.\n";
--EXPECTF_DYNAMIC-- --EXPECTF--
Not given a callback: Not given a callback:
Warning: RarArchive::open(): Expected the third argument, if provided, to be a valid callback in %s on line %d Warning: RarArchive::open(): Expected the third argument, if provided, to be a valid callback in %s on line %d
@@ -66,33 +64,15 @@ bool(false)
Given callback that takes more arguments: Given callback that takes more arguments:
<?php if (PHP_VERSION_ID >= 80000) { ?>
Warning: RarArchive::getEntries(): Failure to call volume find callback in %s on line %d
<?php } ?>
<?php if (PHP_VERSION_ID >= 80000) { ?>
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
Warning: strpos() expects at least %d parameters, 1 given in %s on line %d
<?php } else { ?>
Warning: strpos() expects at least %d parameters, 1 given in %s on line %d Warning: strpos() expects at least %d parameters, 1 given in %s on line %d
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
<?php } ?>
Given callback that takes another kind of arguments: Given callback that takes another kind of arguments:
<?php if (PHP_VERSION_ID >= 80000) { ?>
Warning: RarArchive::getEntries(): Failure to call volume find callback in %s on line %d
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
Warning: array_keys() expects parameter 1 to be array, string given in %s on line %d
<?php } else { ?>
Warning: array_keys() expects parameter 1 to be array, string given in %s on line %d Warning: array_keys() expects parameter 1 to be array, string given in %s on line %d
Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d Warning: RarArchive::getEntries(): ERAR_EOPEN (file open error) in %s on line %d
<?php } ?>
Given callback that returns another kind of arguments: Given callback that returns another kind of arguments:
+1 -3
View File
@@ -1,9 +1,7 @@
--TEST-- --TEST--
RarEntry::getStream() function (broken set fixed with volume callback) RarEntry::getStream() function (broken set fixed with volume callback)
--SKIPIF-- --SKIPIF--
<?php <?php if(!extension_loaded("rar")) print "skip"; ?>
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE-- --FILE--
<?php <?php
function resolve($vol) { function resolve($vol) {
+4 -6
View File
@@ -1,9 +1,7 @@
--TEST-- --TEST--
RarEntry::extract() function (broken set fixed with volume callback) RarEntry::extract() function (broken set fixed with volume callback)
--SKIPIF-- --SKIPIF--
<?php <?php if(!extension_loaded("rar")) print "skip"; ?>
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported");
?>
--FILE-- --FILE--
<?php <?php
function resolve($vol) { function resolve($vol) {
@@ -12,9 +10,9 @@ function resolve($vol) {
else else
return null; return null;
} }
function int32_to_hex($value) { function int32_to_hex($value) {
$value &= 0xffffffff; $value &= 0xffffffff;
return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT); return str_pad(strtoupper(dechex($value)), 8, "0", STR_PAD_LEFT);
} }
echo "Fail:\n"; echo "Fail:\n";
$rar_file1 = rar_open(dirname(__FILE__).'/multi_broken.part1.rar'); $rar_file1 = rar_open(dirname(__FILE__).'/multi_broken.part1.rar');
+1
View File
@@ -2,6 +2,7 @@
RarArchive::open() volume callback long return (case MAXPATHLEN <= NM) RarArchive::open() volume callback long return (case MAXPATHLEN <= NM)
--SKIPIF-- --SKIPIF--
<?php <?php
if(!extension_loaded("rar")) die("skip");
if (!defined("PHP_MAXPATHLEN")) if (!defined("PHP_MAXPATHLEN"))
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN); define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
if (!(PHP_MAXPATHLEN <= 1024)) if (!(PHP_MAXPATHLEN <= 1024))
+5 -5
View File
@@ -1,13 +1,13 @@
--TEST-- --TEST--
RarArchive::open() volume callback long return (case MAXPATHLEN > MAXPATHSIZE) RarArchive::open() volume callback long return (case MAXPATHLEN > NM)
--SKIPIF-- --SKIPIF--
<?php <?php
define('MAXPATHSIZE', 0x10000); if(!extension_loaded("rar")) die("skip");
if (!defined("PHP_MAXPATHLEN")) if (!defined("PHP_MAXPATHLEN"))
define("PHP_MAXPATHLEN", RAR_MAXPATHLEN); define("PHP_MAXPATHLEN", RAR_MAXPATHLEN);
if (!(PHP_MAXPATHLEN > MAXPATHSIZE)) if (!(PHP_MAXPATHLEN > 2048))
die("skip test is for systems where MAXPATHLEN > 2048"); die("skip test is for systems where MAXPATHLEN > 2048");
$rp = dirname(__FILE__) . "/" . str_repeat("a", MAXPATHSIZE); $rp = dirname(__FILE__) . "/" . str_repeat("a", 2048);
if (strlen(dirname(__FILE__) > PHP_MAXPATHLEN - 1)) if (strlen(dirname(__FILE__) > PHP_MAXPATHLEN - 1))
die("skip current directory is too deep."); die("skip current directory is too deep.");
--FILE-- --FILE--
@@ -18,7 +18,7 @@ if (!defined("PHP_MAXPATHLEN"))
chdir(dirname(__FILE__)); chdir(dirname(__FILE__));
$fn = dirname(__FILE__) . '/multi_broken.part1.rar'; $fn = dirname(__FILE__) . '/multi_broken.part1.rar';
function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", MAXPATHSIZE); } function testA($vol) { if ($vol[0] != 'a') return str_repeat("a", 2048); }
$rar = RarArchive::open($fn, null, 'testA'); $rar = RarArchive::open($fn, null, 'testA');
$rar->getEntries(); $rar->getEntries();
+3
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
Stream wrapper basic test Stream wrapper basic test
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
$stream = fopen("rar://" . $stream = fopen("rar://" .
+5 -2
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
Stream wrapper relative path test Stream wrapper relative path test
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--CLEAN-- --CLEAN--
<?php <?php
unlink(dirname(__FILE__) . '/temp/tmp.rar'); unlink(dirname(__FILE__) . '/temp/tmp.rar');
@@ -47,11 +50,11 @@ string(5) "11111"
Test with include path: Test with include path:
Should fail (not in include): Should fail (not in include):
Warning: fopen(rar://tmp.rar#1.txt): %cailed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d Warning: fopen(rar://tmp.rar#1.txt): failed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Should fail (include unused): Should fail (include unused):
Warning: fopen(rar://tmp.rar#1.txt): %cailed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d Warning: fopen(rar://tmp.rar#1.txt): failed to open stream: Error opening RAR archive %stmp.rar: ERAR_EOPEN (file open error) in %s on line %d
Should succeed: Should succeed:
string(5) "11111" string(5) "11111"
+6 -3
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
Stream wrapper archive/file not found Stream wrapper archive/file not found
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
@@ -17,9 +20,9 @@ echo "Done.\n";
--EXPECTF-- --EXPECTF--
Archive not found : Archive not found :
Warning: fopen(rar://%snot_found.rar#1.txt): %cailed to open stream: Error opening RAR archive %snot_found.rar: ERAR_EOPEN (file open error) in %s on line %d Warning: fopen(rar://%snot_found.rar#1.txt): failed to open stream: Error opening RAR archive %snot_found.rar: ERAR_EOPEN (file open error) in %s on line %d
File not found : File not found :
Warning: fopen(rar://%slatest_winrar.rar#not_found.txt): %cailed to open stream: Can't file not_found.txt in RAR archive %s on line %d Warning: fopen(rar://%slatest_winrar.rar#not_found.txt): failed to open stream: Can't file not_found.txt in RAR archive %s on line %d
Done. Done.
+8 -5
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
Stream wrapper malformed url Stream wrapper malformed url
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
@@ -24,21 +27,21 @@ echo "Done.\n";
--EXPECTF-- --EXPECTF--
Test empty: Test empty:
Warning: fopen(rar://): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d Warning: fopen(rar://): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test no fragment: Test no fragment:
Warning: fopen(rar://file.rar): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d Warning: fopen(rar://file.rar): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test empty fragment: Test empty fragment:
Warning: fopen(rar://file.rar#): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d Warning: fopen(rar://file.rar#): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test no path: Test no path:
Warning: fopen(rar://#frag): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d Warning: fopen(rar://#frag): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Test no path and empty fragment: Test no path and empty fragment:
Warning: fopen(rar://#): %cailed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d Warning: fopen(rar://#): failed to open stream: The url must contain a path and a non-empty fragment; it must be in the form "rar://<urlencoded path to RAR archive>[*]#<urlencoded entry name>" in %s on line %d
Done. Done.
+7 -4
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
Stream wrapper with header or file level passwords Stream wrapper with header or file level passwords
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
@@ -52,11 +55,11 @@ echo "\nDone.\n";
--EXPECTF-- --EXPECTF--
Headers: should not work (no password): Headers: should not work (no password):
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): %cailed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): failed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Headers: should not work (password given was file_password): Headers: should not work (password given was file_password):
Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): %cailed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d Warning: fopen(rar://%sencrypted_headers.rar#encfile1.txt): failed to open stream: Error opening RAR archive %sencrypted_headers.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Headers: should work (password given was open_password): Headers: should work (password given was open_password):
string(26) "Encrypted file 1 contents." string(26) "Encrypted file 1 contents."
@@ -64,11 +67,11 @@ string(26) "Encrypted file 1 contents."
Files: should not work (no password): Files: should not work (no password):
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): %cailed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): failed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Files: should not work (password given was open_password): Files: should not work (password given was open_password):
Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): %cailed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d Warning: fopen(rar://%sencrypted_only_files.rar#encfile1.txt): failed to open stream: Error opening file encfile1.txt inside RAR archive %sencrypted_only_files.rar: ERAR_MISSING_PASSWORD (password needed but not specified) in %s on line %d
Files: should work (password given was file_password): Files: should work (password given was file_password):
string(26) "Encrypted file 1 contents." string(26) "Encrypted file 1 contents."
+1 -1
View File
@@ -2,7 +2,7 @@
Stream wrapper with volume find callback Stream wrapper with volume find callback
--SKIPIF-- --SKIPIF--
<?php <?php
if(PHP_INT_SIZE < 8) die("skip 32-bit PHP not supported"); if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
function resolve($vol) { function resolve($vol) {
+3
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
RAR file stream stat RAR file stream stat
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--ENV-- --ENV--
TZ=Asia/Tokyo TZ=Asia/Tokyo
--FILE-- --FILE--
+3
View File
@@ -1,5 +1,8 @@
--TEST-- --TEST--
RAR file stream stat consistency with url stat RAR file stream stat consistency with url stat
--SKIPIF--
<?php
if(!extension_loaded("rar")) die("skip");
--FILE-- --FILE--
<?php <?php
$u = "rar://" . $u = "rar://" .

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