././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3975348 rarfile-4.1/0000755000175100001770000000000014501653017012411 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/.coveragerc0000644000175100001770000000016214501653005014526 0ustar00runnerdocker[report] exclude_lines = ^try: ^except pragma: no cover if __name__ raise NotImplementedError ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3815346 rarfile-4.1/.github/0000755000175100001770000000000014501653017013751 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3815346 rarfile-4.1/.github/workflows/0000755000175100001770000000000014501653017016006 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/.github/workflows/ci.yml0000644000175100001770000000742214501653005017126 0ustar00runnerdocker# # https://docs.github.com/en/actions # https://github.com/actions # # https://formulae.brew.sh/ # https://packages.msys2.org/ # name: CI on: pull_request: {} push: {} jobs: lint: name: "Lint - ${{matrix.pick.OS}} / Python ${{matrix.pick.PY}}" runs-on: ${{matrix.pick.OS}} strategy: matrix: pick: - {OS: "ubuntu-latest", PY: "3.10", TOXENV: "lint,docs"} steps: - name: "Checkout" uses: actions/checkout@v4 - name: "Setup Python ${{matrix.pick.PY}}" uses: actions/setup-python@v4 with: python-version: ${{matrix.pick.PY}} - name: "Install build tools" run: python -m pip install -r etc/requirements.build.txt --disable-pip-version-check - name: "Run tox - ${{matrix.pick.TOXENV}}" env: TOXENV: ${{matrix.pick.TOXENV}} run: | python -m tox -r -- --color=yes test: name: "Test - ${{matrix.pick.OS}} / ${{matrix.pick.PYNAME}}" runs-on: ${{matrix.pick.OS}} strategy: matrix: pick: - {OS: "ubuntu-20.04", PY: "3.7", PYNAME: "Python 3.7", TOXENV: "py37-cryptography"} - {OS: "ubuntu-latest", PY: "3.8", PYNAME: "Python 3.8", TOXENV: "py38"} - {OS: "ubuntu-latest", PY: "3.9", PYNAME: "Python 3.9", TOXENV: "py39-pycryptodome"} - {OS: "ubuntu-latest", PY: "3.10", PYNAME: "Python 3.10", TOXENV: "py310-cryptography"} - {OS: "ubuntu-latest", PY: "3.11", PYNAME: "Python 3.11", TOXENV: "py311-cryptography"} - {OS: "ubuntu-latest", PY: "pypy3.9", PYNAME: "PyPy3.9", TOXENV: "pypy39-cryptography"} - {OS: "ubuntu-latest", PY: "pypy3.10", PYNAME: "PyPy3.10", TOXENV: "pypy310-cryptography"} - {OS: "macos-latest", PY: "3.9", PYNAME: "Python 3.9", TOXENV: "py39-pycryptodome"} - {OS: "macos-latest", PY: "3.10", PYNAME: "Python 3.10", TOXENV: "py310-cryptography"} - {OS: "windows-latest", PY: "3.9", PYNAME: "Python 3.9", TOXENV: "py39-cryptography" } - {OS: "windows-latest", PY: "3.10", PYNAME: "Python 3.10", TOXENV: "py310-cryptography" } steps: - name: "Checkout" uses: actions/checkout@v4 - name: "Setup ${{matrix.pick.PYNAME}}" uses: actions/setup-python@v4 with: python-version: ${{matrix.pick.PY}} - name: "Install archivers (linux)" if: ${{runner.os == 'Linux'}} run: | sudo -nH apt-get -qqy install unrar unar libarchive-tools p7zip-rar unrar unar -h bsdtar -h 7z i - name: "Install archivers (macos)" if: ${{runner.os == 'macOS'}} run: | brew install rar unar libarchive sevenzip unrar unar -h bsdtar -h 7z i 7zz i - name: "Install archivers (windows)" if: ${{runner.os == 'Windows'}} shell: cmd run: | set "PATH=c:\msys64\usr\bin;%PATH%" pacman -S --noconfirm --needed bsdtar p7zip curl -sS -o unrarw32.exe https://www.rarlab.com/rar/unrarw32.exe 7z x unrarw32.exe unrar bsdtar -h 7z i - name: "Install tools" run: python -m pip install -r etc/requirements.build.txt --disable-pip-version-check - name: "Run tox - ${{matrix.pick.TOXENV}} - (linux/macos)" if: ${{runner.os == 'Linux' || runner.os == 'macOS'}} env: TOXENV: ${{matrix.pick.TOXENV}} run: | python -m tox -r -- --color=yes -n auto -v - name: "Run tox - ${{matrix.pick.TOXENV}} - (windows)" if: ${{runner.os == 'Windows'}} env: TOXENV: ${{matrix.pick.TOXENV}} shell: cmd run: | set "PATH=%PATH%;c:\msys64\usr\bin" python -m tox -r -- --color=yes -n auto -v ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/.github/workflows/release.yml0000644000175100001770000000601414501653005020147 0ustar00runnerdocker# # This runs when version tag is pushed # name: REL on: push: tags: ["v[0-9]*"] jobs: sdist: name: "Build source package" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: {python-version: "3.11"} - run: python3 -m pip install -r etc/requirements.build.txt --disable-pip-version-check - run: python3 setup.py sdist - run: python3 setup.py bdist_wheel - uses: actions/upload-artifact@v3 with: {name: "dist", path: "dist"} publish: name: "Publish" runs-on: ubuntu-latest needs: [sdist] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: {python-version: "3.11"} - run: python3 -m pip install -r etc/requirements.build.txt --disable-pip-version-check - name: "Get files" uses: actions/download-artifact@v3 with: {name: "dist", path: "dist"} - name: "Install pandoc" run: | sudo -nH apt-get -u -y install pandoc pandoc --version - name: "Prepare" run: | PACKAGE=$(python3 setup.py --name) VERSION=$(python3 setup.py --version) TGZ="${PACKAGE}-${VERSION}.tar.gz" # default - gh:release, pypi # PRERELEASE - gh:prerelease, pypi # DRAFT - gh:draft,prerelease, testpypi PRERELEASE="false"; DRAFT="false" case "${VERSION}" in *[ab]*|*rc*) PRERELEASE="true";; *dev*) PRERELEASE="true"; DRAFT="true";; esac test "${{github.ref}}" = "refs/tags/v${VERSION}" || { echo "ERR: tag mismatch"; exit 1; } test -f "dist/${TGZ}" || { echo "ERR: sdist failed"; exit 1; } echo "PACKAGE=${PACKAGE}" >> $GITHUB_ENV echo "VERSION=${VERSION}" >> $GITHUB_ENV echo "TGZ=${TGZ}" >> $GITHUB_ENV echo "PRERELEASE=${PRERELEASE}" >> $GITHUB_ENV echo "DRAFT=${DRAFT}" >> $GITHUB_ENV mkdir -p tmp make -s shownote > tmp/note.md cat tmp/note.md ls -l dist - name: "Create Github release" env: GH_TOKEN: ${{secrets.GITHUB_TOKEN}} run: | title="${PACKAGE} v${VERSION}" ghf="--notes-file=./tmp/note.md" if test "${DRAFT}" = "true"; then ghf="${ghf} --draft"; fi if test "${PRERELEASE}" = "true"; then ghf="${ghf} --prerelease"; fi gh release create "v${VERSION}" "dist/${TGZ}" --title="${title}" ${ghf} - name: "Upload to PYPI" id: pypi_upload env: PYPI_TOKEN: ${{secrets.PYPI_TOKEN}} PYPI_TEST_TOKEN: ${{secrets.PYPI_TEST_TOKEN}} run: | ls -l dist if test "${DRAFT}" = "false"; then python -m twine upload -u __token__ -p ${PYPI_TOKEN} \ --repository pypi --disable-progress-bar dist/* else python -m twine upload -u __token__ -p ${PYPI_TEST_TOKEN} \ --repository testpypi --disable-progress-bar dist/* fi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/.pylintrc0000644000175100001770000003621614501653005014263 0ustar00runnerdocker[MASTER] # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code. extension-pkg-whitelist= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS,tmp,dist # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the # number of processors available to use. jobs=1 # Control the amount of potential inferred values when inferring a single # object. This can help the performance when dealing with large functions or # complex, nested conditions. limit-inference-results=100 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Pickle collected data for later comparisons. persistent=yes # Specify a configuration file. #rcfile= # When enabled, pylint would attempt to guess common misconfiguration and emit # user-friendly hints instead of false-positive error messages. suggestion-mode=yes # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. confidence= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once). You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". disable=bare-except, broad-except, consider-using-f-string, consider-using-in, consider-using-ternary, consider-using-with, fixme, global-statement, invalid-name, missing-docstring, no-else-raise, no-else-return, trailing-newlines, unused-argument, unused-variable, protected-access, ungrouped-imports, chained-comparison, len-as-condition, redefined-builtin, import-outside-toplevel, duplicate-code, unnecessary-pass # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. enable=c-extension-no-member [REPORTS] # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details. #msg-template= # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. output-format=colorized # Tells whether to display a full report or only the messages. reports=no # Activate the evaluation score. score=no [REFACTORING] # Maximum number of nested blocks for function / method body max-nested-blocks=10 # Complete name of functions that never returns. When checking for # inconsistent-return-statements if a never returning function is called then # it will be considered as an explicit return statement and no message will be # printed. never-returning-functions=sys.exit [LOGGING] # Format style used to check logging format string. `old` means using % # formatting, while `new` is for `{}` formatting. logging-format-style=old # Logging modules to check that the string format arguments are in logging # function parameter format. logging-modules=logging [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, TODO [SPELLING] # Limits count of emitted suggestions for spelling mistakes. max-spelling-suggestions=4 # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package.. #spelling-dict=en_US # List of comma separated words that should not be checked. spelling-ignore-words=usr,bin,env # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file=.local.dict # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [BASIC] # Naming style matching correct argument names. argument-naming-style=snake_case # Regular expression matching correct argument names. Overrides argument- # naming-style. #argument-rgx= # Naming style matching correct attribute names. attr-naming-style=snake_case # Regular expression matching correct attribute names. Overrides attr-naming- # style. #attr-rgx= # Bad variable names which should always be refused, separated by a comma. bad-names=foo, bar, baz, toto, tutu, tata # Naming style matching correct class attribute names. class-attribute-naming-style=any # Regular expression matching correct class attribute names. Overrides class- # attribute-naming-style. #class-attribute-rgx= # Naming style matching correct class names. class-naming-style=PascalCase # Regular expression matching correct class names. Overrides class-naming- # style. #class-rgx= # Naming style matching correct constant names. const-naming-style=UPPER_CASE # Regular expression matching correct constant names. Overrides const-naming- # style. #const-rgx= # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 # Naming style matching correct function names. function-naming-style=snake_case # Regular expression matching correct function names. Overrides function- # naming-style. #function-rgx= # Good variable names which should always be accepted, separated by a comma. good-names=i, j, k, ex, Run, _ # Include a hint for the correct naming format with invalid-name. include-naming-hint=no # Naming style matching correct inline iteration names. inlinevar-naming-style=any # Regular expression matching correct inline iteration names. Overrides # inlinevar-naming-style. #inlinevar-rgx= # Naming style matching correct method names. method-naming-style=snake_case # Regular expression matching correct method names. Overrides method-naming- # style. #method-rgx= # Naming style matching correct module names. module-naming-style=snake_case # Regular expression matching correct module names. Overrides module-naming- # style. #module-rgx= # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. property-classes=abc.abstractproperty # Naming style matching correct variable names. variable-naming-style=snake_case # Regular expression matching correct variable names. Overrides variable- # naming-style. #variable-rgx= [STRING] # This flag controls whether the implicit-str-concat-in-sequence should # generate a warning on implicit string concatenation in sequences defined over # several lines. check-str-concat-over-line-jumps=no [SIMILARITIES] # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no # Minimum lines number of a similarity. min-similarity-lines=4 [VARIABLES] # List of additional names supposed to be defined in builtins. Remember that # you should avoid defining new builtins when possible. additional-builtins= # Tells whether unused global variables should be treated as a violation. allow-global-unused-variables=yes # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_, _cb # A regular expression matching the name of dummy variables (i.e. expected to # not be used). dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ # Argument names that match this expression will be ignored. Default to name # with leading underscore. ignored-argument-names=_.*|^ignored_|^unused_ # Tells whether we should check for unused import in __init__ files. init-import=no # List of qualified module names which can have objects that can redefine # builtins. redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io [TYPECHECK] # List of decorators that produce context managers, such as # contextlib.contextmanager. Add to this list to register other decorators that # produce valid context managers. contextmanager-decorators=contextlib.contextmanager # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # Tells whether to warn about missing members when the owner of the attribute # is inferred to be None. ignore-none=yes # This flag controls whether pylint should warn about no-member and similar # checks whenever an opaque object is returned when inferring. The inference # can return multiple potential results while evaluating a Python object, but # some branches might not be evaluated, which results in partial inference. In # that case, it might be useful to still emit no-member and other checks for # the rest of the inferred objects. ignore-on-opaque-inference=yes # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of # qualified names. ignored-classes=optparse.Values,thread._local,_thread._local # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # Show a hint with possible names when a member name was not found. The aspect # of finding the hint is based on edit distance. missing-member-hint=yes # The minimum edit distance a name should have in order to be considered a # similar match for a missing member name. missing-member-hint-distance=1 # The total number of similar names that should be taken in consideration when # showing a hint for a missing member. missing-member-max-choices=1 [FORMAT] # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format=LF # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Maximum number of characters on a single line. max-line-length=160 # Maximum number of lines in a module. max-module-lines=10000 # Allow the body of a class to be on the same line as the declaration if body # contains single statement. single-line-class-stmt=no # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__, __new__, setUp # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict, _fields, _replace, _source, _make # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=cls [DESIGN] # Maximum number of arguments for function / method. max-args=15 # Maximum number of attributes for a class (see R0902). max-attributes=17 # Maximum number of boolean expressions in an if statement. max-bool-expr=5 # Maximum number of branch for function / method body. max-branches=50 # Maximum number of locals for function / method body. max-locals=45 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of public methods for a class (see R0904). max-public-methods=420 # Maximum number of return / yield for function / method body. max-returns=16 # Maximum number of statements in function / method body. max-statements=150 # Minimum number of public methods for a class (see R0903). min-public-methods=0 [IMPORTS] # Allow wildcard imports from modules that define __all__. allow-wildcard-with-all=no # Analyse import fallback blocks. This can be used to support both Python 2 and # 3 compatible code, which means that the block might have code that exists # only in one or another interpreter, leading to false positives when analysed. analyse-fallback-blocks=no # Deprecated modules which should not be used, separated by a comma. deprecated-modules=optparse,tkinter.tix # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled). ext-import-graph= # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled). import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled). int-import-graph= # Force import order to recognize a module as part of the standard # compatibility libraries. known-standard-library= # Force import order to recognize a module as part of a third party library. known-third-party=enchant [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "BaseException, Exception". overgeneral-exceptions=builtins.BaseException, builtins.Exception ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/LICENSE0000644000175100001770000000136414501653005013417 0ustar00runnerdocker Copyright (c) 2005-2020 Marko Kreen Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/MANIFEST.in0000644000175100001770000000047314501653005014150 0ustar00runnerdockerinclude README.rst Makefile MANIFEST.in LICENSE dumprar.py include doc/*.rst doc/*.awk doc/Makefile doc/conf.py doc/make.bat include test/Makefile test/*.py test/*.sh include test/files/*.rar test/files/*.r[0-9][0-9] test/files/*.exp test/files/*.sfx include tox.ini .pylintrc .coveragerc .github/*/*.yml etc/*.txt ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/Makefile0000644000175100001770000000323114501653005014045 0ustar00runnerdocker prefix = /usr/local REPO = https://github.com/markokr/rarfile NEWS = doc/news.rst PACKAGE = $(shell python3 setup.py --name) VERSION = $(shell python3 setup.py --version) RXVERSION = $(shell python3 setup.py --version | sed 's/\./[.]/g') TAG = v$(VERSION) TGZ = $(PACKAGE)-$(VERSION).tar.gz WHEEL = $(PACKAGE)-$(VERSION)-py3-none-any.whl URL = $(REPO)/releases/download/$(TAG) all: pyflakes rarfile.py tox -e lint tox -e py38-cryptography -- -n auto install: python setup.py install --prefix=$(prefix) clean: rm -rf __pycache__ build dist .tox rm -f *.pyc MANIFEST *.orig *.rej *.html *.class test/*.pyc rm -rf doc/_build doc/_static doc/_templates doc/html rm -rf .coverage cover* rm -rf *.egg-info rm -f test/files/*.rar.[pjt]* *.diffs toxclean: clean rm -rf .tox ack: for fn in test/files/*.py38-cryptography; do \ cp $$fn `echo $$fn | sed 's/[.]py.*/.exp/'` || exit 1; \ done prepare: @echo "Checking version - $(VERSION)" @grep -qE '^\w+ $(RXVERSION)\b' $(NEWS) \ || { echo "Version '$(VERSION)' not in $(NEWS)"; exit 1; } @echo "Checking git repo" @git diff --stat --exit-code || { echo "ERROR: Unclean repo"; exit 1; } release: prepare git tag $(TAG) git push github $(TAG):$(TAG) upload: mkdir -p dist && rm -f dist/* cd dist && wget -q $(URL)/$(TGZ) cd dist && wget -q $(URL)/$(WHEEL) tar tvf dist/$(TGZ) unzip -t dist/$(WHEEL) twine upload dist/$(TGZ) dist/$(WHEEL) shownote: awk -v VER="$(VERSION)" -f doc/note.awk $(NEWS) \ | pandoc -f rst -t gfm --wrap=none unrelease: git push github :$(TAG) git tag -d $(TAG) dist-test: python3 setup.py sdist rm -rf $(PACKAGE)-$(VERSION) tar xf dist/$(TGZ) cd $(PACKAGE)-$(VERSION) && tox ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3975348 rarfile-4.1/PKG-INFO0000644000175100001770000001040514501653017013506 0ustar00runnerdockerMetadata-Version: 2.1 Name: rarfile Version: 4.1 Summary: RAR archive reader for Python Home-page: https://github.com/markokr/rarfile Author: Marko Kreen Author-email: markokr@gmail.com License: ISC Keywords: rar,unrar,archive Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: ISC License (ISCL) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Archiving :: Compression Requires-Python: >=3.6 License-File: LICENSE rarfile - RAR archive reader for Python ======================================= This is Python module for RAR_ archive reading. The interface follows the style of zipfile_. Licensed under ISC_ license. Features: * Supports both RAR3 and RAR5 format archives. * Supports multi volume archives. * Supports Unicode filenames. * Supports password-protected archives. * Supports archive and file comments. * Archive parsing and non-compressed files are handled in pure Python code. * Compressed files are extracted by executing external tool: unrar_ (preferred), unar_, 7zip_ or bsdtar_. * Works with Python 3.6+. .. _RAR: https://en.wikipedia.org/wiki/RAR_%28file_format%29 .. _zipfile: https://docs.python.org/3/library/zipfile.html .. _ISC: https://en.wikipedia.org/wiki/ISC_license .. _bsdtar: https://github.com/libarchive/libarchive .. _unrar: https://www.rarlab.com/ .. _unar: https://theunarchiver.com/command-line .. _7zip: https://www.7-zip.org/ Backends: +-------------+----------------------+-----------------------------------------------------+ | Backend | Status | Notes | +=============+======================+=====================================================+ | unrar_ | Supported | * Recommended: full format support. | | | | * Non-free software, but free to use. | +-------------+----------------------+-----------------------------------------------------+ | unar_ | Supported | * Not usable on Windows: last build is from 2013 | | | | (v1.8.1) that does support output to stdout. | | | | * Does not support RAR2 locked files. | | | | * Does not support RAR5 Blake2 hash checking. | +-------------+----------------------+-----------------------------------------------------+ | 7zip_ | Supported | * RAR support not available on Debian/Ubuntu repos. | +-------------+----------------------+-----------------------------------------------------+ | p7zip_ | Supported | * Unmaintained? | | | | * Requires ``p7zip-rar`` package on Debian/Ubuntu. | +-------------+----------------------+-----------------------------------------------------+ | bsdtar_ | Supported | * Not recommended: limited RAR format support. | | | | * Does not support multi-volume archives. | | | | * Does not support solid archives. | | | | * Does not support password-protected archives. | | | | * Does not support RARVM-based compression filters. | +-------------+----------------------+-----------------------------------------------------+ | unrar-free_ | Not supported | * Unusable: Does not support output to stdout. | | | | * Based on libarchive so similar format support | | | | as ``bsdtar``. | +-------------+----------------------+-----------------------------------------------------+ .. _p7zip: https://sourceforge.net/projects/p7zip/ .. _unrar-free: https://gitlab.com/bgermann/unrar-free Links: - `Documentation`_ - `Downloads`_ - `Git`_ repo .. _Git: https://github.com/markokr/rarfile .. _Downloads: https://pypi.org/project/rarfile/#files .. _Documentation: https://rarfile.readthedocs.io/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/README.rst0000644000175100001770000000717014501653005014102 0ustar00runnerdocker rarfile - RAR archive reader for Python ======================================= This is Python module for RAR_ archive reading. The interface follows the style of zipfile_. Licensed under ISC_ license. Features: * Supports both RAR3 and RAR5 format archives. * Supports multi volume archives. * Supports Unicode filenames. * Supports password-protected archives. * Supports archive and file comments. * Archive parsing and non-compressed files are handled in pure Python code. * Compressed files are extracted by executing external tool: unrar_ (preferred), unar_, 7zip_ or bsdtar_. * Works with Python 3.6+. .. _RAR: https://en.wikipedia.org/wiki/RAR_%28file_format%29 .. _zipfile: https://docs.python.org/3/library/zipfile.html .. _ISC: https://en.wikipedia.org/wiki/ISC_license .. _bsdtar: https://github.com/libarchive/libarchive .. _unrar: https://www.rarlab.com/ .. _unar: https://theunarchiver.com/command-line .. _7zip: https://www.7-zip.org/ Backends: +-------------+----------------------+-----------------------------------------------------+ | Backend | Status | Notes | +=============+======================+=====================================================+ | unrar_ | Supported | * Recommended: full format support. | | | | * Non-free software, but free to use. | +-------------+----------------------+-----------------------------------------------------+ | unar_ | Supported | * Not usable on Windows: last build is from 2013 | | | | (v1.8.1) that does support output to stdout. | | | | * Does not support RAR2 locked files. | | | | * Does not support RAR5 Blake2 hash checking. | +-------------+----------------------+-----------------------------------------------------+ | 7zip_ | Supported | * RAR support not available on Debian/Ubuntu repos. | +-------------+----------------------+-----------------------------------------------------+ | p7zip_ | Supported | * Unmaintained? | | | | * Requires ``p7zip-rar`` package on Debian/Ubuntu. | +-------------+----------------------+-----------------------------------------------------+ | bsdtar_ | Supported | * Not recommended: limited RAR format support. | | | | * Does not support multi-volume archives. | | | | * Does not support solid archives. | | | | * Does not support password-protected archives. | | | | * Does not support RARVM-based compression filters. | +-------------+----------------------+-----------------------------------------------------+ | unrar-free_ | Not supported | * Unusable: Does not support output to stdout. | | | | * Based on libarchive so similar format support | | | | as ``bsdtar``. | +-------------+----------------------+-----------------------------------------------------+ .. _p7zip: https://sourceforge.net/projects/p7zip/ .. _unrar-free: https://gitlab.com/bgermann/unrar-free Links: - `Documentation`_ - `Downloads`_ - `Git`_ repo .. _Git: https://github.com/markokr/rarfile .. _Downloads: https://pypi.org/project/rarfile/#files .. _Documentation: https://rarfile.readthedocs.io/ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3855345 rarfile-4.1/doc/0000755000175100001770000000000014501653017013156 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/Makefile0000644000175100001770000001270014501653005014613 0ustar00runnerdocker# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/RarFile.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/RarFile.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/RarFile" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/RarFile" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/api.rst0000644000175100001770000000330214501653005014454 0ustar00runnerdocker rarfile API documentation ========================= .. contents:: Table Of Contents Introduction ------------ .. automodule:: rarfile RarFile class ------------- .. autoclass:: RarFile :members: :special-members: __enter__, __exit__, __iter__ RarInfo class ------------- .. autoclass:: RarInfo :members: RarExtFile class ---------------- .. autoclass:: RarExtFile :show-inheritance: :members: :inherited-members: :exclude-members: truncate, flush nsdatetime class ---------------- .. autoclass:: nsdatetime :show-inheritance: :members: Functions --------- .. autofunction:: is_rarfile .. autofunction:: is_rarfile_sfx Constants --------- .. autodata:: RAR_M0 .. autodata:: RAR_M1 .. autodata:: RAR_M2 .. autodata:: RAR_M3 .. autodata:: RAR_M4 .. autodata:: RAR_M5 .. autodata:: RAR_OS_WIN32 .. autodata:: RAR_OS_UNIX .. autodata:: RAR_OS_MACOS .. autodata:: RAR_OS_BEOS .. autodata:: RAR_OS_OS2 .. autodata:: RAR_OS_MSDOS Warnings -------- .. autoclass:: UnsupportedWarning Exceptions ---------- .. autoclass:: Error .. autoclass:: BadRarFile .. autoclass:: NotRarFile .. autoclass:: BadRarName .. autoclass:: NoRarEntry .. autoclass:: PasswordRequired .. autoclass:: NeedFirstVolume .. autoclass:: NoCrypto .. autoclass:: RarExecError .. autoclass:: RarWarning .. autoclass:: RarFatalError .. autoclass:: RarCRCError .. autoclass:: RarLockedArchiveError .. autoclass:: RarWriteError .. autoclass:: RarOpenError .. autoclass:: RarUserError .. autoclass:: RarMemoryError .. autoclass:: RarCreateError .. autoclass:: RarNoFilesError .. autoclass:: RarUserBreak .. autoclass:: RarWrongPassword .. autoclass:: RarUnknownError .. autoclass:: RarSignalExit .. autoclass:: RarCannotExec ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/conf.py0000644000175100001770000001755014501653005014462 0ustar00runnerdocker# -*- coding: utf-8 -*- # # RarFile documentation build configuration file, created by # sphinx-quickstart on Sun Mar 24 13:29:46 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os, os.path # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) import rarfile # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = '1.3' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon'] autodoc_member_order = 'bysource' autoclass_content = 'class' autodoc_default_options = {} intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'RarFile' copyright = u'' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = rarfile.__version__ # The full version, including alpha/beta/rc tags. release = rarfile.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build', 'html'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = "RarFile documentation" # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". #html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. html_show_copyright = False # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. #htmlhelp_basename = 'RarFiledoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'RarFile.tex', u'RarFile Documentation', u'Marko Kreen', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). #man_pages = [ # ('index', 'rarfile', u'RarFile Documentation', # [u'Marko Kreen'], 1) #] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'RarFile', u'RarFile Documentation', u'Marko Kreen', 'RarFile', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/faq.rst0000644000175100001770000000737114501653005014464 0ustar00runnerdocker rarfile FAQ =========== .. contents:: Table of Contents What are the dependencies? -------------------------- It depends on ``unrar`` command-line utility to do the actual decompression. Note that by default it expect it to be in ``PATH``. If unrar launching fails, you need to fix this. Alternatively, :mod:`rarfile` can also use either unar_ from TheUnarchiver_ or bsdtar_ from libarchive_ as decompression backend. From those ``unar`` is preferred as ``bsdtar`` has very limited support for RAR archives. .. _unar: https://theunarchiver.com/command-line .. _TheUnarchiver: https://theunarchiver.com/ .. _bsdtar: https://github.com/libarchive/libarchive/wiki/ManPageBsdtar1 .. _libarchive: https://www.libarchive.org/ It depends on cryptography_ or PyCryptodome_ modules to process archives with password-protected headers. .. _cryptography: https://pypi.org/project/cryptography/ .. _PyCryptodome: https://pypi.org/project/pycryptodome/ Does it parse ``unrar`` output to get archive contents? ------------------------------------------------------- No, :mod:`rarfile` parses RAR structure in Python code. Also it can read uncompressed files from archive without external utility. Will rarfile support wrapping unrarlib/unrar.dll/unrar.so in the future? ------------------------------------------------------------------------ No. The current architecture - parsing in Python and decompression with command line tools work well across all interesting operating systems (Windows/Linux/MacOS), wrapping a library does not bring any advantages. Simple execution of command-line tools is also legally simpler situation than linking with external library. How can I get it work on Windows? --------------------------------- On Windows the ``unrar.exe`` is not in ``PATH`` so simple ``Popen("unrar ..")`` does not work. Solutions: 1. Add location of ``unrar.exe`` to PATH. 2. Copy ``unrar.exe`` to system directory that is in PATH, eg. ``C:\Windows``. It can be tested by simply opening command-line console and running ``unrar``. How can I get it work on Linux/MacOS? ------------------------------------- It fails because ``unrar`` is not installed or not in PATH. 1. Install ``unrar``. 2. Make sure the location is in PATH. It can be tested by simply opening command-line console and running ``unrar``. Instead ``unrar`` it might be preferable to install ``unar``. How to avoid the need for user to manually install rarfile/unrar? ----------------------------------------------------------------- Include ``rarfile.py`` and/or ``unrar`` (or ``unar``) with your application. Will it support creating RAR archives? -------------------------------------- No. RARLAB_ is not interested in RAR becoming open format and specifically discourages writing RAR creation software. In the meantime use either Zip_ (better compatibility) or 7z_ (better compression) format for your own archives. .. _RARLAB: https://www.rarlab.com/ .. _Zip: https://en.wikipedia.org/wiki/ZIP_%28file_format%29 .. _7z: https://en.wikipedia.org/wiki/7z What is the USE_EXTRACT_HACK? ----------------------------- RarFile uses ``unrar`` to extract compressed files. But when extracting single file from archive containing many entries, ``unrar`` needs to parse whole archive until it finds the right entry. This makes random-access to entries slow. To avoid that, RarFile remembers location of compressed data for each entry and on read it copies it to temporary archive containing only data for that one file, thus making ``unrar`` fast. The logic is only activated for entries smaller than :data:`rarfile.HACK_SIZE_LIMIT` (20M by default). Bigger files are accessed directly from RAR. Note - it only works for non-solid archives. So if you care about random access to files in your archive, do not create solid archives. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/index.rst0000644000175100001770000000035214501653005015014 0ustar00runnerdocker .. include:: ../README.rst Documentation: .. toctree:: :maxdepth: 1 API Documentation FAQs Release News Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/make.bat0000644000175100001770000001175214501653005014566 0ustar00runnerdocker@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\RarFile.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\RarFile.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/news.rst0000644000175100001770000003726314501653005014674 0ustar00runnerdocker rarfile history =============== .. py:currentmodule:: rarfile Version 4.1 (2023-09-17) ------------------------ Features: * Support 7zip/p7zip as decompression backend. [`#71 `_] * RAR5: check password before trying to read file (chigusa) [`#79 `_] New APIs: * Make get_rar_version a public function (Safihre) [`#63 `_] * New option: ``part_only`` for :class:`RarFile`, to read only single file and allow it to be middle-part of multi-volume archive. * Add :meth:`RarFile.printdir`, use it in dumprar. Needed to examine FILE_COPY or HARD_LINK entries that do not contain data. Fixes: * Use OS separator to access filename. Should fix subdirectory entry access on Windows. [`#96 `_] * DirectReader: check seek position on each read. Fixes read reading from multiple entries in parallel on RarFile backed by file object. [`#81 `_] * DirectReader: properly disable CRC check when seeking. [`#73 `_] * Reset _hdrenc_main before processing a new volume. Fixes CRC checks on multi-volume reads. [`#80 `_] * Adapt to Python 3.10 argparse (MeggyCal) [`#85 `_] * SFX: Handle volume numbering special cases better. * nsdatetime: support pypy internal use * Throw error if backend does not support passwords. Cleanups: * ci: Use proper unrar on Windows. MingW one tolaretes paths with ``/`` better than upstream build. * ci: Add Python 3.10 to the testing (Christian Clauss) [`#76 `_] * Avoid isascii, not in 3.6 Version 4.0 (2020-07-31) ------------------------ Main goals are: * Increased ``zipfile``-compatibility, thus also achieving smaller difference between RAR3 and RAR5 archives. * Implement :meth:`RarFile.extract` on top of :meth:`RarFile.open` instead using ``unrar x`` directly, thus making maintenance of alternative backends more manageable. Negative aspect of that is that there are features that internal extract code does not support - hard links, NTFS streams and junctions. Breaking changes: * Directory names will have "/" appended. [`#31 `_] * :meth:`RarFile.extract` operates only on single entry, so when used on directory it will create directory but not extract files under it. * :meth:`RarFile.extract`/:meth:`RarFile.extractall`/:meth:`RarFile.testrar` will not launch special unrar command line, instead they are implemented on top of :meth:`RarFile.open`. * Keyword args in top-level APIs were renamed to match zipfile: * RarFile(rarfile) -> RarFile(file) * RarFile.setpassword(password) -> .setpassword(pwd) * RarFile.getinfo(fname) -> .getinfo(name) * RarFile.open(fname, mode, psw) -> .open(name, mode, pwd) * RarFile.read(fname, psw) -> .read(name, pwd) * :data:`PATH_SEP` cannot be changed from "/". New features: * :meth:`RarFile.extract` will return final sanitized filename for target file. [`#42 `_, `#52 `_] * :meth:`RarInfo.is_dir` is now preferred spelling of ``isdir()``. Old method kept as alias. [`#44 `_] * New :meth:`RarInfo.is_file` and :meth:`RarInfo.is_symlink` methods. Only one of :meth:`~RarInfo.is_file`, :meth:`~RarInfo.is_dir` or :meth:`~RarInfo.is_symlink` can be True. * :meth:`RarFile.printdir` has ``file`` argument for output. * :meth:`RarFile.__iter__` loops over :class:`RarInfo` entries. * RAR3: throw :exc:`NeedFirstVolume` exception with current volume number, like RAR5 does. [`#58 `_] * Nanosecond timestamp support. Visible as :class:`nsdatetime` instance. * Minimal CLI when run as script: ``python3 -m rarfile`` * Skip old file versions in versioned archive. Cleanups: * Use PBKDF2 implementation from :mod:`hashlib`. * Improve test coverage. Version 3.3 (2020-07-26) ------------------------ Fixes: * Add the .sfx test files to MANIFEST.in for inclusion in pypi tarball. [`#60 `_] * Add all files in git to tarball. Version 3.2 (2020-07-19) ------------------------ New features: * Support ``unar`` as decompression backend. It has much better support for RAR features than ``bsdtar``. [`#36 `_] * Support SFX archives - archive header is searched in first 2MB of the file. [`#48 `_] * Add :data:`HACK_TMP_DIR` option, to force temp files into specific directory. [`#43 `_] Fixes: * Always use "/" for path separator in command-line, gives better results on Windows. Cleanups: * Drop module-level options from docs, they create confusion. [`#47 `_] * Drop support for Python 2 and 3.5 and earlier. Python 2 is dead and requiring Python 3.6 gives blake2s, stdlib that supports pathlib, and ordered dict without compat hacks. * Replace PyCrypto with PyCryptodome in tests. * Use Github Actions for CI. Version 3.1 (2019-09-15) ------------------------ **This will be last version with support for Python 2.x** New feature: * Accept pathlib objects as filenames. (Aleksey Popov) * Accept `bytes` filenames in Python 3 (Nate Bogdanowicz) Fixes: * Use bug-compatible SHA1 for longer passwords (> 28 chars) in RAR3 encrypted headers. (Marko Kreen) * Return true/false from _check_unrar_tool (miigotu) * Include all test files in archive (Benedikt Morbach) * Include volume number in NeedFirstVolume exception if available (rar5). Cleanups: * Convert tests to pytest. Version 3.0 (2016-12-27) ------------------------ New feature: * Support RAR5 archive format. It is actually completely different archive format from RAR3 one, only is uses same file extension and tools are old one. Except incompatibilies noted below, most of code should notice no change, existing :class:`RarInfo` fields will continue using RAR3-compatible values (eg. :attr:`RarInfo.host_os`). RAR5-specific values will use new fields. Incompatibilities between rarfile v2.x and 3.x: * Default :data:`PATH_SEP` is now '/' instead '\\'. * Removed :data:`NEED_COMMENTS` option, comments are always extracted. * Removed :data:`UNICODE_COMMENTS` option, they are always decoded. * Removed :data:`USE_DATETIME` option, :attr:`RarInfo.date_time` is always tuple, :attr:`RarInfo.mtime`, :attr:`RarInfo.atime`, :attr:`RarInfo.ctime` and :attr:`RarInfo.arctime` are always :class:`datetime.datetime` objects. Fixes: * Fixed bug when calling rarfp.open() on a RarInfo structure. Cleanups: * Code refactor to allow 2 different file format parsers. * Code cleanups to pass modern linters. * New testing and linting setup based on Tox_. * Use setuptools instead distutils for install. .. _Tox: https://tox.readthedocs.io/en/latest/ Version 2.8 (2016-06-07) ------------------------ * Fix: support solid archives from in-memory file object. Full archive will be written out to temp file. [`#21 `_] * Fix: ask unrar stop switches scanning, to handle archive names starting with "-". (Alexander Shadchin) [`#12 `_] * Fix: add missing _parse_error variable to RarFile object. (Gregory Mazzola) [`#20 `_] * Fix: return proper boolean from :meth:`RarInfo.needs_password`. [`#22 `_] * Fix: do not insert non-string rarfile into exception string. (Tim Muller) [`#23 `_] * Fix: make :meth:`RarFile.extract` and :meth:`RarFile.testrar` support in-memory archives. * Use cryptography_ module as preferred crypto backend. PyCrypto_ will be used as fallback. * Cleanup: remove compat code for Python 2.4/2.5/2.6. .. _cryptography: https://pypi.org/project/cryptography/ .. _PyCrypto: https://pypi.org/project/pycrypto/ Version 2.7 (2014-11-23) ------------------------ * Allow use of bsdtar_ as decompression backend. It sits on top of libarchive_, which has support for reading RAR archives. Limitations of ``libarchive`` RAR backend: - Does not support solid archives. - Does not support password-protected archives. - Does not support "parsing filters" used for audio/image/executable data, so few non-solid, non-encrypted archives also fail. Now :mod:`rarfile` checks if ``unrar`` and if not then tries ``bsdtar``. If that works, then keeps using it. If not then configuration stays with ``unrar`` which will then appear in error messages. .. _bsdtar: https://github.com/libarchive/libarchive/wiki/ManPageBsdtar1 .. _libarchive: https://www.libarchive.org/ * Both :class:`RarFile` and :func:`is_rarfile` now accept file-like object. Eg. :class:`io.BytesIO`. Only requirement is that the object must be seekable. This mirrors similar funtionality in zipfile. Based on patch by Chase Zhang. * Uniform error handling. :class:`RarFile` accepts ``errors="strict"`` argument. Allow user to tune whether parsing and missing file errors will raise exception. If error is not raised, the error string can be queried with :meth:`RarFile.strerror` method. Version 2.6 (2013-04-10) ------------------------ * Add context manager support for :class:`RarFile` class. Both :class:`RarFile` and :class:`RarExtFile` support :keyword:`with` statement now. (Wentao Han) * :meth:`RarFile.volumelist` method, returns filenames of archive volumes. * Re-throw clearer error in case ``unrar`` is not found in ``PATH``. * Sync new unrar4.x error code from ``rar.txt``. * Use Sphinx for documentation, push docs to rtfd.org_ .. _rtfd.org: https://rarfile.readthedocs.org/ Version 2.5 (2012-01-19) ------------------------ Fixes: * :meth:`RarExtFile.read` and :meth:`RarExtFile.readinto` now do looping read to work properly on short reads. Important for Python 3.2+ where read from pipe can return short result even on blocking file descriptor. * Proper error reporting in :meth:`RarFile.extract`, :meth:`RarFile.extractall` and :meth:`RarFile.testrar`. * :meth:`RarExtFile.read` from unrar pipe: prefer to return unrar error code, if thats not available, do own error checks. * Avoid string addition in :meth:`RarExtFile.read`, instead use always list+join to merge multi-part reads. * dumprar: dont re-encode byte strings (Python 2.x). This avoids unneccessary failure when printing invalid unicode. Version 2.4 (2011-11-05) ------------------------ Fixes: * :data:`USE_DATETIME`: survive bad values from RAR * Fix bug in corrupt unicode filename handling * dumprar: make unicode chars work with both pipe and console Version 2.3 (2011-07-03) ------------------------ Features: * Support .seek() method on file streams. (Kristian Larsson) * Support .readinto() method on file streams. Optimized implementation is available on Python 2.6+ where :class:`memoryview` is available. * Support file comments - :attr:`RarInfo.comment` contains decompressed data if available. * File objects returned by :meth:`RarFile.open()` are :class:`io.RawIOBase`-compatible. They can further wrapped with :class:`io.BufferedReader` and :class:`io.TextIOWrapper`. * Now .getinfo() uses dict lookup instead of sequential scan when searching archive entry. This speeds up prococessing for archives that have many entries. * Option :data:`UNICODE_COMMENTS` to decode both archive and file comments to unicode. It uses :data:`TRY_ENCODINGS` for list of encodings to try. If off, comments are left as byte strings. Default: 0 * Option :data:`PATH_SEP` to change path separator. Default: ``r'\'``, set ``rarfile.PATH_SEP='/'`` to be compatibe with zipfile. * Option :data:`USE_DATETIME` to convert timestamps to datetime objects. Default: 0, timestamps are tuples. * Option :data:`TRY_ENCODINGS` to allow tuning attempted encoding list. * Reorder :class:`RarInfo` fiels to better show zipfile-compatible fields. * Standard regtests to make sure various features work Compatibility: * Drop :attr:`RarInfo.unicode_filename`, plain :attr:`RarInfo.filename` is already unicode since 2.0. * .read(-1) reads now until EOF. Previously it returned empty buffer. Fixes: * Make encrypted headers work with Python 3.x bytes() and with old 2.x 'sha' module. * Simplify :class:`subprocess.Popen` usage when launching ``unrar``. Previously it tried to optimize and work around OS/Python bugs, but this is not maintainable. * Use temp rar file hack on multi-volume archives too. * Always .wait() on unrar, to avoid zombies * Convert struct.error to BadRarFile * Plug some fd leaks. Affected: Jython, PyPy. * Broken archives are handled more robustly. Version 2.2 (2010-08-19) ------------------------ Fixes: * Relaxed volume naming. Now it just calculates new volume name by finding number in old one and increasing it, without any expectations what that number should be. * Files with 4G of compressed data in one colume were handled wrong. Fix. * DOS timestamp seconds need to be multiplied with 2. * Correct EXTTIME parsing. Cleanups: * Compressed size is per-volume, sum them together, so that user sees complete compressed size for files split over several volumes. * dumprar: Show unknown bits. * Use :class:`struct.Struct` to cache unpack formats. * Support missing :data:`os.devnull`. (Python 2.3) Version 2.1 (2010-07-31) ------------------------ Features: * Minimal implmentation for :meth:`RarFile.extract`, :meth:`RarFile.extractall`, :meth:`RarFile.testrar`. They are simple shortcuts to ``unrar`` invocation. * Accept :class:`RarInfo` object where filename is expected. * Include ``dumprar.py`` in .tgz. It can be used to visualize RAR structure and test module. * Support for encrypted file headers. Fixes: * Don't read past ENDARC, there could be non-RAR data there. * RAR 2.x: It does not write ENDARC, but our volume code expected it. Fix that. * RAR 2.x: Support more than 200 old-style volumes. Cleanups: * Load comment only when requested. * Cleanup of internal config variables. They should have now final names. * :meth:`RarFile.open`: Add mode=r argument to match zipfile. * Doc and comments cleanup, minimize duplication. * Common wrappers for both compressed and uncompressed files, now :meth:`RarFile.open` also does CRC-checking. Version 2.0 (2010-04-29) ------------------------ Features: * Python 3 support. Still works with 2.x. * Parses extended time fields. (.mtime, .ctime, .atime) * :meth:`RarFile.open` method. This makes possible to process large entries that do not fit into memory. * Supports password-protected archives. * Supports archive comments. Cleanups: * Uses :mod:`subprocess` module to launch ``unrar``. * .filename is always Unicode string, .unicode_filename is now deprecated. * .CRC is unsigned again, as python3 crc32() is unsigned. Version 1.1 (2008-08-31) ------------------------ Fixes: * Replace :func:`os.tempnam` with :func:`tempfile.mkstemp`. (Jason Moiron) * Fix infinite loop in _extract_hack on unexpected EOF * :attr:`RarInfo.CRC` is now signed value to match crc32() * :meth:`RarFile.read` now checks file crc Cleanups: * more docstrings * throw proper exceptions (subclasses of :exc:`rarfile.Error`) * RarInfo has fields pre-initialized, so they appear in help() * rename RarInfo.data to RarInfo.header_data * dont use "print" when header parsing fails * use try/finally to delete temp rar Version 1.0 (2005-08-08) ------------------------ * First release. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/doc/note.awk0000644000175100001770000000046014501653005014624 0ustar00runnerdocker# extract version notes for version VER /^[-_0-9a-zA-Z]+ v?[0-9]/ { if ($2 == VER) { good = 1 next } else { good = 0 } } /^(===|---)/ { next } { if (good) { # also remove sphinx syntax print gensub(/:(\w+):`~?([^`]+)`/, "``\\2``", "g") } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/dumprar.py0000755000175100001770000004413214501653005014441 0ustar00runnerdocker#! /usr/bin/env python3 """Dump archive contents, test extraction.""" import binascii import getopt import io import sys from datetime import datetime import rarfile as rf usage = """ dumprar [switches] [ARC1 ARC2 ...] [@ARCLIST] switches: @file read archive names from file -pPWD set password -Ccharset set fallback charset -v increase verbosity -t attempt to read all files -x write read files out -c show archive comment -h show usage -bTOOL set backend tool (unrar, unar, bsdtar, 7z, 7zz) -- stop switch parsing """.strip() os_list = ["DOS", "OS2", "WIN", "UNIX", "MACOS", "BEOS"] block_strs = ["MARK", "MAIN", "FILE", "OLD_COMMENT", "OLD_EXTRA", "OLD_SUB", "OLD_RECOVERY", "OLD_AUTH", "SUB", "ENDARC"] r5_block_types = { rf.RAR5_BLOCK_MAIN: "R5_MAIN", rf.RAR5_BLOCK_FILE: "R5_FILE", rf.RAR5_BLOCK_SERVICE: "R5_SVC", rf.RAR5_BLOCK_ENCRYPTION: "R5_ENC", rf.RAR5_BLOCK_ENDARC: "R5_ENDARC", } def rar3_type(btype): """RAR3 type code as string.""" if btype < rf.RAR_BLOCK_MARK or btype > rf.RAR_BLOCK_ENDARC: return "*UNKNOWN*" return block_strs[btype - rf.RAR_BLOCK_MARK] def rar5_type(btype): """RAR5 type code as string.""" return r5_block_types.get(btype, "*UNKNOWN*") main_bits = ( (rf.RAR_MAIN_VOLUME, "VOL"), (rf.RAR_MAIN_COMMENT, "COMMENT"), (rf.RAR_MAIN_LOCK, "LOCK"), (rf.RAR_MAIN_SOLID, "SOLID"), (rf.RAR_MAIN_NEWNUMBERING, "NEWNR"), (rf.RAR_MAIN_AUTH, "AUTH"), (rf.RAR_MAIN_RECOVERY, "RECOVERY"), (rf.RAR_MAIN_PASSWORD, "PASSWORD"), (rf.RAR_MAIN_FIRSTVOLUME, "FIRSTVOL"), (rf.RAR_SKIP_IF_UNKNOWN, "SKIP"), (rf.RAR_LONG_BLOCK, "LONG"), ) endarc_bits = ( (rf.RAR_ENDARC_NEXT_VOLUME, "NEXTVOL"), (rf.RAR_ENDARC_DATACRC, "DATACRC"), (rf.RAR_ENDARC_REVSPACE, "REVSPACE"), (rf.RAR_ENDARC_VOLNR, "VOLNR"), (rf.RAR_SKIP_IF_UNKNOWN, "SKIP"), (rf.RAR_LONG_BLOCK, "LONG"), ) file_bits = ( (rf.RAR_FILE_SPLIT_BEFORE, "SPLIT_BEFORE"), (rf.RAR_FILE_SPLIT_AFTER, "SPLIT_AFTER"), (rf.RAR_FILE_PASSWORD, "PASSWORD"), (rf.RAR_FILE_COMMENT, "COMMENT"), (rf.RAR_FILE_SOLID, "SOLID"), (rf.RAR_FILE_LARGE, "LARGE"), (rf.RAR_FILE_UNICODE, "UNICODE"), (rf.RAR_FILE_SALT, "SALT"), (rf.RAR_FILE_VERSION, "VERSION"), (rf.RAR_FILE_EXTTIME, "EXTTIME"), (rf.RAR_FILE_EXTFLAGS, "EXTFLAGS"), (rf.RAR_SKIP_IF_UNKNOWN, "SKIP"), (rf.RAR_LONG_BLOCK, "LONG"), ) generic_bits = ( (rf.RAR_SKIP_IF_UNKNOWN, "SKIP"), (rf.RAR_LONG_BLOCK, "LONG"), ) file_parms = ("D64", "D128", "D256", "D512", "D1024", "D2048", "D4096", "DIR") r5_block_flags = ( (rf.RAR5_BLOCK_FLAG_EXTRA_DATA, "EXTRA"), (rf.RAR5_BLOCK_FLAG_DATA_AREA, "DATA"), (rf.RAR5_BLOCK_FLAG_SKIP_IF_UNKNOWN, "SKIP"), (rf.RAR5_BLOCK_FLAG_SPLIT_BEFORE, "SPLIT_BEFORE"), (rf.RAR5_BLOCK_FLAG_SPLIT_AFTER, "SPLIT_AFTER"), (rf.RAR5_BLOCK_FLAG_DEPENDS_PREV, "DEPENDS"), (rf.RAR5_BLOCK_FLAG_KEEP_WITH_PARENT, "KEEP"), ) r5_main_flags = ( (rf.RAR5_MAIN_FLAG_ISVOL, "ISVOL"), (rf.RAR5_MAIN_FLAG_HAS_VOLNR, "VOLNR"), (rf.RAR5_MAIN_FLAG_SOLID, "SOLID"), (rf.RAR5_MAIN_FLAG_RECOVERY, "RECOVERY"), (rf.RAR5_MAIN_FLAG_LOCKED, "LOCKED"), ) r5_file_flags = ( (rf.RAR5_FILE_FLAG_ISDIR, "DIR"), (rf.RAR5_FILE_FLAG_HAS_MTIME, "MTIME"), (rf.RAR5_FILE_FLAG_HAS_CRC32, "CRC32"), (rf.RAR5_FILE_FLAG_UNKNOWN_SIZE, "NOSIZE"), ) r5_enc_flags = ( (rf.RAR5_ENC_FLAG_HAS_CHECKVAL, "CHECKVAL"), ) r5_endarc_flags = ( (rf.RAR5_ENDARC_FLAG_NEXT_VOL, "NEXTVOL"), ) r5_file_enc_flags = ( (rf.RAR5_XENC_CHECKVAL, "CHECKVAL"), (rf.RAR5_XENC_TWEAKED, "TWEAKED"), ) r5_file_redir_types = { rf.RAR5_XREDIR_UNIX_SYMLINK: "UNIX_SYMLINK", rf.RAR5_XREDIR_WINDOWS_SYMLINK: "WINDOWS_SYMLINK", rf.RAR5_XREDIR_WINDOWS_JUNCTION: "WINDOWS_JUNCTION", rf.RAR5_XREDIR_HARD_LINK: "HARD_LINK", rf.RAR5_XREDIR_FILE_COPY: "FILE_COPY", } r5_file_redir_flags = ( (rf.RAR5_XREDIR_ISDIR, "DIR"), ) dos_mode_bits = ( (0x01, "READONLY"), (0x02, "HIDDEN"), (0x04, "SYSTEM"), (0x08, "VOLUME_ID"), (0x10, "DIRECTORY"), (0x20, "ARCHIVE"), (0x40, "DEVICE"), (0x80, "NORMAL"), (0x0100, "TEMPORARY"), (0x0200, "SPARSE_FILE"), (0x0400, "REPARSE_POINT"), (0x0800, "COMPRESSED"), (0x1000, "OFFLINE"), (0x2000, "NOT_CONTENT_INDEXED"), (0x4000, "ENCRYPTED"), (0x8000, "INTEGRITY_STREAM"), (0x00010000, "VIRTUAL"), (0x00020000, "NO_SCRUB_DATA"), (0x00040000, "RECALL_ON_OPEN"), (0x00080000, "PINNED"), (0x00100000, "UNPINNED"), (0x00400000, "RECALL_ON_DATA_ACCESS"), (0x20000000, "STRICTLY_SEQUENTIAL"), ) def xprint(m, *args): """Print string to stdout. """ if args: m = m % args print(m) def tohex(data): """Return hex string.""" return binascii.hexlify(data).decode("ascii") def render_flags(flags, bit_list): """Show bit names. """ res = [] known = 0 for bit in bit_list: known = known | bit[0] if flags & bit[0]: res.append(bit[1]) unknown = flags & ~known n = 0 while unknown: if unknown & 1: res.append("UNK_%04x" % (1 << n)) unknown = unknown >> 1 n += 1 if not res: return "-" return ",".join(res) def get_file_flags(flags): """Show flag names and handle dict size. """ res = render_flags(flags & ~rf.RAR_FILE_DICTMASK, file_bits) xf = (flags & rf.RAR_FILE_DICTMASK) >> 5 res += "," + file_parms[xf] return res def fmt_time(t): """Format time. """ if t is None: return "(-)" if isinstance(t, datetime): return t.isoformat("T") return "%04d-%02d-%02d %02d:%02d:%02d" % t def show_item(h): """Show any RAR3/5 record. """ if isinstance(h, rf.Rar3Info): show_item_v3(h) elif isinstance(h, rf.Rar5Info): show_item_v5(h) else: xprint("Unknown info record") def show_rftype(h): return "".join([ h.is_file() and "F" or "-", h.is_dir() and "D" or "-", h.is_symlink() and "L" or "-", ]) def modex3(v): return [v & 4 and "r" or "-", v & 2 and "w" or "-", v & 1 and "x" or "-"] def unix_mode(mode): perms = modex3(mode >> 6) + modex3(mode >> 3) + modex3(mode) if mode & 0x0800: perms[2] = perms[2] == "x" and "s" or "S" if mode & 0x0400: perms[5] = perms[5] == "x" and "s" or "S" if mode & 0x0200: perms[8] = perms[8] == "x" and "t" or "-" rest = mode & 0xF000 if rest == 0x4000: perms.insert(0, "d") elif rest == 0xA000: perms.insert(0, "l") elif rest == 0x8000: # common perms.insert(0, "-") elif rest == 0: perms.insert(0, "-") else: perms.insert(0, "?") perms.append("(0x%04x)" % rest) return "".join(perms) def show_mode(h): if h.host_os in (rf.RAR_OS_UNIX, rf.RAR_OS_BEOS): s_mode = unix_mode(h.mode) elif h.host_os in (rf.RAR_OS_MSDOS, rf.RAR_OS_WIN32, rf.RAR_OS_OS2): s_mode = render_flags(h.mode, dos_mode_bits) else: s_mode = "0x%x" % h.mode return s_mode def show_item_v3(h): """Show any RAR3 record. """ st = rar3_type(h.type) xprint("%s: hdrlen=%d datlen=%d is=%s", st, h.header_size, h.add_size, show_rftype(h)) if h.type in (rf.RAR_BLOCK_FILE, rf.RAR_BLOCK_SUB): s_mode = show_mode(h) xprint(" flags=0x%04x:%s", h.flags, get_file_flags(h.flags)) if h.host_os >= 0 and h.host_os < len(os_list): s_os = os_list[h.host_os] else: s_os = "?" if h.flags & rf.RAR_FILE_UNICODE: s_namecmp = " namecmp=%d/%d" % (len(h.orig_filename), h._name_size) else: s_namecmp = "" xprint(" os=%d:%s ver=%d mode=%s meth=%c cmp=%d dec=%d vol=%d%s", h.host_os, s_os, h.extract_version, s_mode, h.compress_type, h.compress_size, h.file_size, h.volume, s_namecmp) ucrc = (h.CRC + (1 << 32)) & ((1 << 32) - 1) xprint(" crc=0x%08x (%d) date_time=%s", ucrc, h.CRC, fmt_time(h.date_time)) xprint(" name=%s", h.filename) if h.mtime: xprint(" mtime=%s", fmt_time(h.mtime)) if h.ctime: xprint(" ctime=%s", fmt_time(h.ctime)) if h.atime: xprint(" atime=%s", fmt_time(h.atime)) if h.arctime: xprint(" arctime=%s", fmt_time(h.arctime)) elif h.type == rf.RAR_BLOCK_MAIN: xprint(" flags=0x%04x:%s", h.flags, render_flags(h.flags, main_bits)) elif h.type == rf.RAR_BLOCK_ENDARC: xprint(" flags=0x%04x:%s", h.flags, render_flags(h.flags, endarc_bits)) if h.flags & rf.RAR_ENDARC_DATACRC: xprint(" datacrc=0x%08x", h.endarc_datacrc) if h.flags & rf.RAR_ENDARC_DATACRC: xprint(" volnr=%d", h.endarc_volnr) elif h.type == rf.RAR_BLOCK_MARK: xprint(" flags=0x%04x:", h.flags) else: xprint(" flags=0x%04x:%s", h.flags, render_flags(h.flags, generic_bits)) if h.comment is not None: cm = repr(h.comment) if cm[0] == "u": cm = cm[1:] xprint(" comment=%s", cm) def show_item_v5(h): """Show any RAR5 record. """ st = rar5_type(h.block_type) xprint("%s: hdrlen=%d datlen=%d hdr_extra=%d is=%s", st, h.header_size, h.compress_size, h.block_extra_size, show_rftype(h)) xprint(" block_flags=0x%04x:%s", h.block_flags, render_flags(h.block_flags, r5_block_flags)) if h.block_type in (rf.RAR5_BLOCK_FILE, rf.RAR5_BLOCK_SERVICE): xprint(" name=%s", h.filename) s_mode = show_mode(h) if h.file_host_os == rf.RAR5_OS_UNIX: s_os = "UNIX" else: s_os = "WINDOWS" xprint(" file_flags=0x%04x:%s", h.file_flags, render_flags(h.file_flags, r5_file_flags)) cmp_flags = h.file_compress_flags xprint(" cmp_algo=%d cmp_meth=%d dict=%d solid=%r", cmp_flags & 0x3f, (cmp_flags >> 7) & 0x07, cmp_flags >> 10, cmp_flags & rf.RAR5_COMPR_SOLID > 0) xprint(" os=%d:%s mode=%s cmp=%r dec=%r vol=%r", h.file_host_os, s_os, s_mode, h.compress_size, h.file_size, h.volume) if h.CRC is not None: xprint(" crc=0x%08x (%d)", h.CRC, h.CRC) if h.blake2sp_hash is not None: xprint(" blake2sp=%s", tohex(h.blake2sp_hash)) if h.date_time is not None: xprint(" date_time=%s", fmt_time(h.date_time)) if h.mtime: xprint(" mtime=%s", fmt_time(h.mtime)) if h.ctime: xprint(" ctime=%s", fmt_time(h.ctime)) if h.atime: xprint(" atime=%s", fmt_time(h.atime)) if h.arctime: xprint(" arctime=%s", fmt_time(h.arctime)) if h.flags & rf.RAR_FILE_PASSWORD: enc_algo, enc_flags, kdf_count, salt, iv, checkval = h.file_encryption algo_name = "AES256" if enc_algo == rf.RAR5_XENC_CIPHER_AES256 else "UnknownAlgo" xprint(" algo=%d:%s enc_flags=%04x:%s kdf_lg=%d kdf_count=%d salt=%s iv=%s checkval=%s", enc_algo, algo_name, enc_flags, render_flags(enc_flags, r5_file_enc_flags), kdf_count, 1 << kdf_count, tohex(salt), tohex(iv), checkval and tohex(checkval) or "-") if h.file_redir: redir_type, redir_flags, redir_name = h.file_redir xprint(" redir: type=%s flags=%d:%s destination=%s", r5_file_redir_types.get(redir_type, "Unknown"), redir_flags, render_flags(redir_flags, r5_file_redir_flags), redir_name) if h.file_owner: uname, gname, uid, gid = h.file_owner xprint(" owner: name=%r group=%r uid=%r gid=%r", uname, gname, uid, gid) if h.file_version: flags, version = h.file_version xprint(" version: flags=%r version=%r", flags, version) elif h.block_type == rf.RAR5_BLOCK_MAIN: xprint(" flags=0x%04x:%s", h.flags, render_flags(h.main_flags, r5_main_flags)) elif h.block_type == rf.RAR5_BLOCK_ENDARC: xprint(" flags=0x%04x:%s", h.flags, render_flags(h.endarc_flags, r5_endarc_flags)) elif h.block_type == rf.RAR5_BLOCK_ENCRYPTION: algo_name = "AES256" if h.encryption_algo == rf.RAR5_XENC_CIPHER_AES256 else "UnknownAlgo" xprint(" algo=%d:%s flags=0x%04x:%s", h.encryption_algo, algo_name, h.flags, render_flags(h.encryption_flags, r5_enc_flags)) xprint(" kdf_lg=%d kdf_count=%d", h.encryption_kdf_count, 1 << h.encryption_kdf_count) xprint(" salt=%s", tohex(h.encryption_salt)) else: xprint(" - missing info -") if h.comment is not None: cm = repr(h.comment) if cm[0] == "u": cm = cm[1:] xprint(" comment=%s", cm) cf_show_comment = 0 cf_verbose = 0 cf_charset = None cf_extract = 0 cf_test_read = 0 cf_test_unrar = 0 cf_test_memory = 0 def check_crc(f, inf, desc): """Compare result crc to expected value. """ exp = inf._md_expect if exp is None: return ucrc = f._md_context.digest() if ucrc != exp: print("crc error - %s - exp=%r got=%r" % (desc, exp, ucrc)) def test_read_long(r, inf): """Test read and readinto. """ md_class = inf._md_class or rf.NoHashContext bctx = md_class() inf_orig = r.getinfo_orig(inf.filename) f = r.open(inf.filename) total = 0 while 1: data = f.read(8192) if not data: break bctx.update(data) total += len(data) if total != inf.file_size: xprint("\n *** %s has corrupt file: %s ***", r.rarfile, inf.filename) xprint(" *** short read: got=%d, need=%d ***\n", total, inf.file_size) check_crc(f, inf_orig, "read") bhash = bctx.hexdigest() if cf_verbose > 1: if f._md_context.digest() == inf_orig._md_expect: #xprint(" checkhash: %r", bhash) pass else: xprint(" checkhash: %r got=%r exp=%r cls=%r\n", bhash, f._md_context.digest(), inf._md_expect, inf._md_class) # test .seek() & .readinto() if cf_test_read > 1: f.seek(0, 0) total = 0 buf = bytearray(1024) while 1: res = f.readinto(buf) if not res: break total += res if inf.file_size != total: xprint(" *** readinto failed: got=%d, need=%d ***\n", total, inf.file_size) #check_crc(f, inf, "readinto") f.close() def test_read(r, inf): """Test file read.""" test_read_long(r, inf) def test_real(fn, pwd): """Actual archive processing. """ xprint("Archive: %s", fn) cb = None if cf_verbose > 1: cb = show_item rfarg = fn if cf_test_memory: rfarg = io.BytesIO(open(fn, "rb").read()) # check if rar if not rf.is_rarfile(rfarg): xprint(" --- %s is not a RAR file ---", fn) return # open r = rf.RarFile(rfarg, charset=cf_charset, info_callback=cb) # set password if r.needs_password(): if pwd: r.setpassword(pwd) else: xprint(" --- %s requires password ---", fn) return # show comment if cf_show_comment and r.comment: for ln in r.comment.split("\n"): xprint(" %s", ln) elif cf_verbose > 0 and r.comment: cm = repr(r.comment) if cm[0] == "u": cm = cm[1:] xprint(" comment=%s", cm) # process for n in r.namelist(): inf = r.getinfo(n) if cf_verbose == 1: show_item(inf) if cf_test_read and inf.is_file(): test_read(r, inf) if cf_extract: r.extractall() for inf in r.infolist(): r.extract(inf) if cf_test_unrar: r.testrar() def test(fn, pwd): """Process one archive with error handling. """ try: test_real(fn, pwd) except rf.NeedFirstVolume as ex: xprint(" --- %s is middle part of multi-vol archive (%s)---", fn, str(ex)) except rf.Error: exc, msg, tb = sys.exc_info() xprint("\n *** %s: %s ***\n", exc.__name__, msg) del tb except IOError: exc, msg, tb = sys.exc_info() xprint("\n *** %s: %s ***\n", exc.__name__, msg) del tb def main(): """Program entry point. """ global cf_verbose, cf_show_comment, cf_charset global cf_extract, cf_test_read, cf_test_unrar global cf_test_memory cf_backend = None pwd = None # parse args try: opts, args = getopt.getopt(sys.argv[1:], "p:C:hvcxtRMb:") except getopt.error as ex: print(str(ex), file=sys.stderr) sys.exit(1) for o, v in opts: if o == "-p": pwd = v elif o == "-h": xprint(usage) return elif o == "-v": cf_verbose += 1 elif o == "-c": cf_show_comment = 1 elif o == "-x": cf_extract = 1 elif o == "-t": cf_test_read += 1 elif o == "-T": cf_test_unrar = 1 elif o == "-M": cf_test_memory = 1 elif o == "-C": cf_charset = v elif o == "-b": cf_backend = v else: raise ValueError("unhandled switch: " + o) args2 = [] for a in args: if a[0] == "@": for ln in open(a[1:], "r", encoding="utf8"): fn = ln[:-1] args2.append(fn) else: args2.append(a) args = args2 if not args: xprint(usage) if cf_backend: cf_backend = {"7z": "sevenzip", "7zz": "sevenzip2"}.get(cf_backend, cf_backend) conf = {"unrar": False, "unar": False, "bsdtar": False, "sevenzip": False, "sevenzip2": False} assert cf_backend in conf, f"unknown backend: {cf_backend}" conf[cf_backend] = True rf.tool_setup(force=True, **conf) for fn in args: test(fn, pwd) if __name__ == "__main__": try: main() except KeyboardInterrupt: pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3855345 rarfile-4.1/etc/0000755000175100001770000000000014501653017013164 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/etc/requirements.build.txt0000644000175100001770000000006314501653005017542 0ustar00runnerdockersetuptools>=67 wheel>=0.41 twine==4.0.2 tox==4.8.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3855345 rarfile-4.1/rarfile.egg-info/0000755000175100001770000000000014501653017015527 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979599.0 rarfile-4.1/rarfile.egg-info/PKG-INFO0000644000175100001770000001040514501653017016624 0ustar00runnerdockerMetadata-Version: 2.1 Name: rarfile Version: 4.1 Summary: RAR archive reader for Python Home-page: https://github.com/markokr/rarfile Author: Marko Kreen Author-email: markokr@gmail.com License: ISC Keywords: rar,unrar,archive Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: ISC License (ISCL) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Archiving :: Compression Requires-Python: >=3.6 License-File: LICENSE rarfile - RAR archive reader for Python ======================================= This is Python module for RAR_ archive reading. The interface follows the style of zipfile_. Licensed under ISC_ license. Features: * Supports both RAR3 and RAR5 format archives. * Supports multi volume archives. * Supports Unicode filenames. * Supports password-protected archives. * Supports archive and file comments. * Archive parsing and non-compressed files are handled in pure Python code. * Compressed files are extracted by executing external tool: unrar_ (preferred), unar_, 7zip_ or bsdtar_. * Works with Python 3.6+. .. _RAR: https://en.wikipedia.org/wiki/RAR_%28file_format%29 .. _zipfile: https://docs.python.org/3/library/zipfile.html .. _ISC: https://en.wikipedia.org/wiki/ISC_license .. _bsdtar: https://github.com/libarchive/libarchive .. _unrar: https://www.rarlab.com/ .. _unar: https://theunarchiver.com/command-line .. _7zip: https://www.7-zip.org/ Backends: +-------------+----------------------+-----------------------------------------------------+ | Backend | Status | Notes | +=============+======================+=====================================================+ | unrar_ | Supported | * Recommended: full format support. | | | | * Non-free software, but free to use. | +-------------+----------------------+-----------------------------------------------------+ | unar_ | Supported | * Not usable on Windows: last build is from 2013 | | | | (v1.8.1) that does support output to stdout. | | | | * Does not support RAR2 locked files. | | | | * Does not support RAR5 Blake2 hash checking. | +-------------+----------------------+-----------------------------------------------------+ | 7zip_ | Supported | * RAR support not available on Debian/Ubuntu repos. | +-------------+----------------------+-----------------------------------------------------+ | p7zip_ | Supported | * Unmaintained? | | | | * Requires ``p7zip-rar`` package on Debian/Ubuntu. | +-------------+----------------------+-----------------------------------------------------+ | bsdtar_ | Supported | * Not recommended: limited RAR format support. | | | | * Does not support multi-volume archives. | | | | * Does not support solid archives. | | | | * Does not support password-protected archives. | | | | * Does not support RARVM-based compression filters. | +-------------+----------------------+-----------------------------------------------------+ | unrar-free_ | Not supported | * Unusable: Does not support output to stdout. | | | | * Based on libarchive so similar format support | | | | as ``bsdtar``. | +-------------+----------------------+-----------------------------------------------------+ .. _p7zip: https://sourceforge.net/projects/p7zip/ .. _unrar-free: https://gitlab.com/bgermann/unrar-free Links: - `Documentation`_ - `Downloads`_ - `Git`_ repo .. _Git: https://github.com/markokr/rarfile .. _Downloads: https://pypi.org/project/rarfile/#files .. _Documentation: https://rarfile.readthedocs.io/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979599.0 rarfile-4.1/rarfile.egg-info/SOURCES.txt0000644000175100001770000000717114501653017017421 0ustar00runnerdocker.coveragerc .pylintrc LICENSE MANIFEST.in Makefile README.rst dumprar.py rarfile.py setup.cfg setup.py tox.ini .github/workflows/ci.yml .github/workflows/release.yml doc/Makefile doc/api.rst doc/conf.py doc/faq.rst doc/index.rst doc/make.bat doc/news.rst doc/note.awk etc/requirements.build.txt rarfile.egg-info/PKG-INFO rarfile.egg-info/SOURCES.txt rarfile.egg-info/dependency_links.txt rarfile.egg-info/top_level.txt test/__init__.py test/run_dump.sh test/run_dump_all.sh test/test_api.py test/test_compat.py test/test_crypto.py test/test_extract.py test/test_format.py test/test_hashing.py test/test_korrupt.py test/test_reading.py test/test_seek.py test/test_tool.py test/test_util.py test/files/ctime0.rar test/files/ctime0.rar.exp test/files/ctime1.rar test/files/ctime1.rar.exp test/files/ctime2.rar test/files/ctime2.rar.exp test/files/ctime3.rar test/files/ctime3.rar.exp test/files/ctime4.rar test/files/ctime4.rar.exp test/files/ctime5.rar test/files/ctime5.rar.exp test/files/rar15-comment-lock.rar test/files/rar15-comment-lock.rar.exp test/files/rar15-comment.rar test/files/rar15-comment.rar.exp test/files/rar202-comment-nopsw.rar test/files/rar202-comment-nopsw.rar.exp test/files/rar202-comment-psw.rar test/files/rar202-comment-psw.rar.exp test/files/rar3-comment-hpsw.rar test/files/rar3-comment-hpsw.rar.exp test/files/rar3-comment-plain.rar test/files/rar3-comment-plain.rar.exp test/files/rar3-comment-psw.rar test/files/rar3-comment-psw.rar.exp test/files/rar3-old.r00 test/files/rar3-old.r01 test/files/rar3-old.rar test/files/rar3-old.rar.exp test/files/rar3-owner.rar test/files/rar3-owner.rar.exp test/files/rar3-readonly-unix.rar test/files/rar3-readonly-unix.rar.exp test/files/rar3-readonly-win.rar test/files/rar3-readonly-win.rar.exp test/files/rar3-seektest.sfx test/files/rar3-subdirs.rar test/files/rar3-subdirs.rar.exp test/files/rar3-symlink-unix.rar test/files/rar3-symlink-unix.rar.exp test/files/rar3-versions.rar test/files/rar3-versions.rar.exp test/files/rar3-vols.part1.rar test/files/rar3-vols.part1.rar.exp test/files/rar3-vols.part2.rar test/files/rar3-vols.part2.rar.exp test/files/rar3-vols.part3.rar test/files/rar3-vols.part3.rar.exp test/files/rar5-blake.rar test/files/rar5-blake.rar.exp test/files/rar5-crc.rar test/files/rar5-crc.rar.exp test/files/rar5-crc.sfx test/files/rar5-dups.rar test/files/rar5-dups.rar.exp test/files/rar5-hlink.rar test/files/rar5-hlink.rar.exp test/files/rar5-hpsw.rar test/files/rar5-hpsw.rar.exp test/files/rar5-owner.rar test/files/rar5-owner.rar.exp test/files/rar5-psw-blake.rar test/files/rar5-psw-blake.rar.exp test/files/rar5-psw.rar test/files/rar5-psw.rar.exp test/files/rar5-quick-open.rar test/files/rar5-quick-open.rar.exp test/files/rar5-readonly-unix.rar test/files/rar5-readonly-unix.rar.exp test/files/rar5-readonly-win.rar test/files/rar5-readonly-win.rar.exp test/files/rar5-solid-qo.rar test/files/rar5-solid-qo.rar.exp test/files/rar5-solid.rar test/files/rar5-solid.rar.exp test/files/rar5-subdirs.rar test/files/rar5-subdirs.rar.exp test/files/rar5-symlink-unix.rar test/files/rar5-symlink-unix.rar.exp test/files/rar5-symlink-win.rar test/files/rar5-symlink-win.rar.exp test/files/rar5-times.rar test/files/rar5-times.rar.exp test/files/rar5-times2.rar test/files/rar5-times2.rar.exp test/files/rar5-versions.rar test/files/rar5-versions.rar.exp test/files/rar5-vols.part1.rar test/files/rar5-vols.part1.rar.exp test/files/rar5-vols.part2.rar test/files/rar5-vols.part2.rar.exp test/files/rar5-vols.part3.rar test/files/rar5-vols.part3.rar.exp test/files/seektest.rar test/files/seektest.rar.exp test/files/unicode.rar test/files/unicode.rar.exp test/files/unicode2.rar test/files/unicode2.rar.exp././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979599.0 rarfile-4.1/rarfile.egg-info/dependency_links.txt0000644000175100001770000000000114501653017021575 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979599.0 rarfile-4.1/rarfile.egg-info/top_level.txt0000644000175100001770000000001014501653017020250 0ustar00runnerdockerrarfile ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/rarfile.py0000644000175100001770000031377214501653005014421 0ustar00runnerdocker# rarfile.py # # Copyright (c) 2005-2020 Marko Kreen # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """RAR archive reader. This is Python module for Rar archive reading. The interface is made as :mod:`zipfile`-like as possible. Basic logic: - Parse archive structure with Python. - Extract non-compressed files with Python - Extract compressed files with unrar. - Optionally write compressed data to temp file to speed up unrar, otherwise it needs to scan whole archive on each execution. Example:: import rarfile rf = rarfile.RarFile("myarchive.rar") for f in rf.infolist(): print(f.filename, f.file_size) if f.filename == "README": print(rf.read(f)) Archive files can also be accessed via file-like object returned by :meth:`RarFile.open`:: import rarfile with rarfile.RarFile("archive.rar") as rf: with rf.open("README") as f: for ln in f: print(ln.strip()) For decompression to work, either ``unrar`` or ``unar`` tool must be in PATH. """ import errno import io import os import re import shutil import struct import sys import warnings from binascii import crc32, hexlify from datetime import datetime, timezone from hashlib import blake2s, pbkdf2_hmac, sha1, sha256 from pathlib import Path from struct import Struct, pack, unpack from subprocess import DEVNULL, PIPE, STDOUT, Popen from tempfile import mkstemp AES = None # only needed for encrypted headers try: try: from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes, ) _have_crypto = 1 except ImportError: from Crypto.Cipher import AES _have_crypto = 2 except ImportError: _have_crypto = 0 class AES_CBC_Decrypt: """Decrypt API""" def __init__(self, key, iv): if _have_crypto == 2: self.decrypt = AES.new(key, AES.MODE_CBC, iv).decrypt else: ciph = Cipher(algorithms.AES(key), modes.CBC(iv), default_backend()) self.decrypt = ciph.decryptor().update __version__ = "4.1" # export only interesting items __all__ = ["get_rar_version", "is_rarfile", "is_rarfile_sfx", "RarInfo", "RarFile", "RarExtFile"] ## ## Module configuration. Can be tuned after importing. ## #: executable for unrar tool UNRAR_TOOL = "unrar" #: executable for unar tool UNAR_TOOL = "unar" #: executable for bsdtar tool BSDTAR_TOOL = "bsdtar" #: executable for p7zip/7z tool SEVENZIP_TOOL = "7z" #: executable for alternative 7z tool SEVENZIP2_TOOL = "7zz" #: default fallback charset DEFAULT_CHARSET = "windows-1252" #: list of encodings to try, with fallback to DEFAULT_CHARSET if none succeed TRY_ENCODINGS = ("utf8", "utf-16le") #: whether to speed up decompression by using tmp archive USE_EXTRACT_HACK = 1 #: limit the filesize for tmp archive usage HACK_SIZE_LIMIT = 20 * 1024 * 1024 #: set specific directory for mkstemp() used by hack dir usage HACK_TMP_DIR = None #: Separator for path name components. Always "/". PATH_SEP = "/" ## ## rar constants ## # block types RAR_BLOCK_MARK = 0x72 # r RAR_BLOCK_MAIN = 0x73 # s RAR_BLOCK_FILE = 0x74 # t RAR_BLOCK_OLD_COMMENT = 0x75 # u RAR_BLOCK_OLD_EXTRA = 0x76 # v RAR_BLOCK_OLD_SUB = 0x77 # w RAR_BLOCK_OLD_RECOVERY = 0x78 # x RAR_BLOCK_OLD_AUTH = 0x79 # y RAR_BLOCK_SUB = 0x7a # z RAR_BLOCK_ENDARC = 0x7b # { # flags for RAR_BLOCK_MAIN RAR_MAIN_VOLUME = 0x0001 RAR_MAIN_COMMENT = 0x0002 RAR_MAIN_LOCK = 0x0004 RAR_MAIN_SOLID = 0x0008 RAR_MAIN_NEWNUMBERING = 0x0010 RAR_MAIN_AUTH = 0x0020 RAR_MAIN_RECOVERY = 0x0040 RAR_MAIN_PASSWORD = 0x0080 RAR_MAIN_FIRSTVOLUME = 0x0100 RAR_MAIN_ENCRYPTVER = 0x0200 # flags for RAR_BLOCK_FILE RAR_FILE_SPLIT_BEFORE = 0x0001 RAR_FILE_SPLIT_AFTER = 0x0002 RAR_FILE_PASSWORD = 0x0004 RAR_FILE_COMMENT = 0x0008 RAR_FILE_SOLID = 0x0010 RAR_FILE_DICTMASK = 0x00e0 RAR_FILE_DICT64 = 0x0000 RAR_FILE_DICT128 = 0x0020 RAR_FILE_DICT256 = 0x0040 RAR_FILE_DICT512 = 0x0060 RAR_FILE_DICT1024 = 0x0080 RAR_FILE_DICT2048 = 0x00a0 RAR_FILE_DICT4096 = 0x00c0 RAR_FILE_DIRECTORY = 0x00e0 RAR_FILE_LARGE = 0x0100 RAR_FILE_UNICODE = 0x0200 RAR_FILE_SALT = 0x0400 RAR_FILE_VERSION = 0x0800 RAR_FILE_EXTTIME = 0x1000 RAR_FILE_EXTFLAGS = 0x2000 # flags for RAR_BLOCK_ENDARC RAR_ENDARC_NEXT_VOLUME = 0x0001 RAR_ENDARC_DATACRC = 0x0002 RAR_ENDARC_REVSPACE = 0x0004 RAR_ENDARC_VOLNR = 0x0008 # flags common to all blocks RAR_SKIP_IF_UNKNOWN = 0x4000 RAR_LONG_BLOCK = 0x8000 # Host OS types RAR_OS_MSDOS = 0 #: MSDOS (only in RAR3) RAR_OS_OS2 = 1 #: OS2 (only in RAR3) RAR_OS_WIN32 = 2 #: Windows RAR_OS_UNIX = 3 #: UNIX RAR_OS_MACOS = 4 #: MacOS (only in RAR3) RAR_OS_BEOS = 5 #: BeOS (only in RAR3) # Compression methods - "0".."5" RAR_M0 = 0x30 #: No compression. RAR_M1 = 0x31 #: Compression level `-m1` - Fastest compression. RAR_M2 = 0x32 #: Compression level `-m2`. RAR_M3 = 0x33 #: Compression level `-m3`. RAR_M4 = 0x34 #: Compression level `-m4`. RAR_M5 = 0x35 #: Compression level `-m5` - Maximum compression. # # RAR5 constants # RAR5_BLOCK_MAIN = 1 RAR5_BLOCK_FILE = 2 RAR5_BLOCK_SERVICE = 3 RAR5_BLOCK_ENCRYPTION = 4 RAR5_BLOCK_ENDARC = 5 RAR5_BLOCK_FLAG_EXTRA_DATA = 0x01 RAR5_BLOCK_FLAG_DATA_AREA = 0x02 RAR5_BLOCK_FLAG_SKIP_IF_UNKNOWN = 0x04 RAR5_BLOCK_FLAG_SPLIT_BEFORE = 0x08 RAR5_BLOCK_FLAG_SPLIT_AFTER = 0x10 RAR5_BLOCK_FLAG_DEPENDS_PREV = 0x20 RAR5_BLOCK_FLAG_KEEP_WITH_PARENT = 0x40 RAR5_MAIN_FLAG_ISVOL = 0x01 RAR5_MAIN_FLAG_HAS_VOLNR = 0x02 RAR5_MAIN_FLAG_SOLID = 0x04 RAR5_MAIN_FLAG_RECOVERY = 0x08 RAR5_MAIN_FLAG_LOCKED = 0x10 RAR5_FILE_FLAG_ISDIR = 0x01 RAR5_FILE_FLAG_HAS_MTIME = 0x02 RAR5_FILE_FLAG_HAS_CRC32 = 0x04 RAR5_FILE_FLAG_UNKNOWN_SIZE = 0x08 RAR5_COMPR_SOLID = 0x40 RAR5_ENC_FLAG_HAS_CHECKVAL = 0x01 RAR5_ENDARC_FLAG_NEXT_VOL = 0x01 RAR5_XFILE_ENCRYPTION = 1 RAR5_XFILE_HASH = 2 RAR5_XFILE_TIME = 3 RAR5_XFILE_VERSION = 4 RAR5_XFILE_REDIR = 5 RAR5_XFILE_OWNER = 6 RAR5_XFILE_SERVICE = 7 RAR5_XTIME_UNIXTIME = 0x01 RAR5_XTIME_HAS_MTIME = 0x02 RAR5_XTIME_HAS_CTIME = 0x04 RAR5_XTIME_HAS_ATIME = 0x08 RAR5_XTIME_UNIXTIME_NS = 0x10 RAR5_XENC_CIPHER_AES256 = 0 RAR5_XENC_CHECKVAL = 0x01 RAR5_XENC_TWEAKED = 0x02 RAR5_XHASH_BLAKE2SP = 0 RAR5_XREDIR_UNIX_SYMLINK = 1 RAR5_XREDIR_WINDOWS_SYMLINK = 2 RAR5_XREDIR_WINDOWS_JUNCTION = 3 RAR5_XREDIR_HARD_LINK = 4 RAR5_XREDIR_FILE_COPY = 5 RAR5_XREDIR_ISDIR = 0x01 RAR5_XOWNER_UNAME = 0x01 RAR5_XOWNER_GNAME = 0x02 RAR5_XOWNER_UID = 0x04 RAR5_XOWNER_GID = 0x08 RAR5_OS_WINDOWS = 0 RAR5_OS_UNIX = 1 DOS_MODE_ARCHIVE = 0x20 DOS_MODE_DIR = 0x10 DOS_MODE_SYSTEM = 0x04 DOS_MODE_HIDDEN = 0x02 DOS_MODE_READONLY = 0x01 RAR5_PW_CHECK_SIZE = 8 RAR5_PW_SUM_SIZE = 4 ## ## internal constants ## RAR_ID = b"Rar!\x1a\x07\x00" RAR5_ID = b"Rar!\x1a\x07\x01\x00" WIN32 = sys.platform == "win32" BSIZE = 512 * 1024 if WIN32 else 64 * 1024 SFX_MAX_SIZE = 2 * 1024 * 1024 RAR_V3 = 3 RAR_V5 = 5 _BAD_CHARS = r"""\x00-\x1F<>|"?*""" RC_BAD_CHARS_UNIX = re.compile(r"[%s]" % _BAD_CHARS) RC_BAD_CHARS_WIN32 = re.compile(r"[%s:^\\]" % _BAD_CHARS) FORCE_TOOL = False def _find_sfx_header(xfile): sig = RAR_ID[:-1] buf = io.BytesIO() steps = (64, SFX_MAX_SIZE) with XFile(xfile) as fd: for step in steps: data = fd.read(step) if not data: break buf.write(data) curdata = buf.getvalue() findpos = 0 while True: pos = curdata.find(sig, findpos) if pos < 0: break if curdata[pos:pos + len(RAR_ID)] == RAR_ID: return RAR_V3, pos if curdata[pos:pos + len(RAR5_ID)] == RAR5_ID: return RAR_V5, pos findpos = pos + len(sig) return 0, 0 ## ## Public interface ## def get_rar_version(xfile): """Check quickly whether file is rar archive. """ with XFile(xfile) as fd: buf = fd.read(len(RAR5_ID)) if buf.startswith(RAR_ID): return RAR_V3 elif buf.startswith(RAR5_ID): return RAR_V5 return 0 def is_rarfile(xfile): """Check quickly whether file is rar archive. """ try: return get_rar_version(xfile) > 0 except OSError: # File not found or not accessible, ignore return False def is_rarfile_sfx(xfile): """Check whether file is rar archive with support for SFX. It will read 2M from file. """ return _find_sfx_header(xfile)[0] > 0 class Error(Exception): """Base class for rarfile errors.""" class BadRarFile(Error): """Incorrect data in archive.""" class NotRarFile(Error): """The file is not RAR archive.""" class BadRarName(Error): """Cannot guess multipart name components.""" class NoRarEntry(Error): """File not found in RAR""" class PasswordRequired(Error): """File requires password""" class NeedFirstVolume(Error): """Need to start from first volume. Attributes: current_volume Volume number of current file or None if not known """ def __init__(self, msg, volume): super().__init__(msg) self.current_volume = volume class NoCrypto(Error): """Cannot parse encrypted headers - no crypto available.""" class RarExecError(Error): """Problem reported by unrar/rar.""" class RarWarning(RarExecError): """Non-fatal error""" class RarFatalError(RarExecError): """Fatal error""" class RarCRCError(RarExecError): """CRC error during unpacking""" class RarLockedArchiveError(RarExecError): """Must not modify locked archive""" class RarWriteError(RarExecError): """Write error""" class RarOpenError(RarExecError): """Open error""" class RarUserError(RarExecError): """User error""" class RarMemoryError(RarExecError): """Memory error""" class RarCreateError(RarExecError): """Create error""" class RarNoFilesError(RarExecError): """No files that match pattern were found""" class RarUserBreak(RarExecError): """User stop""" class RarWrongPassword(RarExecError): """Incorrect password""" class RarUnknownError(RarExecError): """Unknown exit code""" class RarSignalExit(RarExecError): """Unrar exited with signal""" class RarCannotExec(RarExecError): """Executable not found.""" class UnsupportedWarning(UserWarning): """Archive uses feature that are unsupported by rarfile. .. versionadded:: 4.0 """ class RarInfo: r"""An entry in rar archive. Timestamps as :class:`~datetime.datetime` are without timezone in RAR3, with UTC timezone in RAR5 archives. Attributes: filename File name with relative path. Path separator is "/". Always unicode string. date_time File modification timestamp. As tuple of (year, month, day, hour, minute, second). RAR5 allows archives where it is missing, it's None then. comment Optional file comment field. Unicode string. (RAR3-only) file_size Uncompressed size. compress_size Compressed size. compress_type Compression method: one of :data:`RAR_M0` .. :data:`RAR_M5` constants. extract_version Minimal Rar version needed for decompressing. As (major*10 + minor), so 2.9 is 29. RAR3: 10, 20, 29 RAR5 does not have such field in archive, it's simply set to 50. host_os Host OS type, one of RAR_OS_* constants. RAR3: :data:`RAR_OS_WIN32`, :data:`RAR_OS_UNIX`, :data:`RAR_OS_MSDOS`, :data:`RAR_OS_OS2`, :data:`RAR_OS_BEOS`. RAR5: :data:`RAR_OS_WIN32`, :data:`RAR_OS_UNIX`. mode File attributes. May be either dos-style or unix-style, depending on host_os. mtime File modification time. Same value as :attr:`date_time` but as :class:`~datetime.datetime` object with extended precision. ctime Optional time field: creation time. As :class:`~datetime.datetime` object. atime Optional time field: last access time. As :class:`~datetime.datetime` object. arctime Optional time field: archival time. As :class:`~datetime.datetime` object. (RAR3-only) CRC CRC-32 of uncompressed file, unsigned int. RAR5: may be None. blake2sp_hash Blake2SP hash over decompressed data. (RAR5-only) volume Volume nr, starting from 0. volume_file Volume file name, where file starts. file_redir If not None, file is link of some sort. Contains tuple of (type, flags, target). (RAR5-only) Type is one of constants: :data:`RAR5_XREDIR_UNIX_SYMLINK` Unix symlink. :data:`RAR5_XREDIR_WINDOWS_SYMLINK` Windows symlink. :data:`RAR5_XREDIR_WINDOWS_JUNCTION` Windows junction. :data:`RAR5_XREDIR_HARD_LINK` Hard link to target. :data:`RAR5_XREDIR_FILE_COPY` Current file is copy of another archive entry. Flags may contain bits: :data:`RAR5_XREDIR_ISDIR` Symlink points to directory. """ # zipfile-compatible fields filename = None file_size = None compress_size = None date_time = None CRC = None volume = None orig_filename = None # optional extended time fields, datetime() objects. mtime = None ctime = None atime = None extract_version = None mode = None host_os = None compress_type = None # rar3-only fields comment = None arctime = None # rar5-only fields blake2sp_hash = None file_redir = None # internal fields flags = 0 type = None # zipfile compat def is_dir(self): """Returns True if entry is a directory. .. versionadded:: 4.0 """ return False def is_symlink(self): """Returns True if entry is a symlink. .. versionadded:: 4.0 """ return False def is_file(self): """Returns True if entry is a normal file. .. versionadded:: 4.0 """ return False def needs_password(self): """Returns True if data is stored password-protected. """ if self.type == RAR_BLOCK_FILE: return (self.flags & RAR_FILE_PASSWORD) > 0 return False def isdir(self): """Returns True if entry is a directory. .. deprecated:: 4.0 """ return self.is_dir() class RarFile: """Parse RAR structure, provide access to files in archive. Parameters: file archive file name or file-like object. mode only "r" is supported. charset fallback charset to use, if filenames are not already Unicode-enabled. info_callback debug callback, gets to see all archive entries. crc_check set to False to disable CRC checks errors Either "stop" to quietly stop parsing on errors, or "strict" to raise errors. Default is "stop". part_only If True, read only single file and allow it to be middle-part of multi-volume archive. """ #: File name, if available. Unicode string or None. filename = None #: Archive comment. Unicode string or None. comment = None def __init__(self, file, mode="r", charset=None, info_callback=None, crc_check=True, errors="stop", part_only=False): if is_filelike(file): self.filename = getattr(file, "name", None) else: if isinstance(file, Path): file = str(file) self.filename = file self._rarfile = file self._charset = charset or DEFAULT_CHARSET self._info_callback = info_callback self._crc_check = crc_check self._part_only = part_only self._password = None self._file_parser = None if errors == "stop": self._strict = False elif errors == "strict": self._strict = True else: raise ValueError("Invalid value for errors= parameter.") if mode != "r": raise NotImplementedError("RarFile supports only mode=r") self._parse() def __enter__(self): """Open context.""" return self def __exit__(self, typ, value, traceback): """Exit context.""" self.close() def __iter__(self): """Iterate over members.""" return iter(self.infolist()) def setpassword(self, pwd): """Sets the password to use when extracting. """ self._password = pwd if self._file_parser: if self._file_parser.has_header_encryption(): self._file_parser = None if not self._file_parser: self._parse() else: self._file_parser.setpassword(self._password) def needs_password(self): """Returns True if any archive entries require password for extraction. """ return self._file_parser.needs_password() def namelist(self): """Return list of filenames in archive. """ return [f.filename for f in self.infolist()] def infolist(self): """Return RarInfo objects for all files/directories in archive. """ return self._file_parser.infolist() def volumelist(self): """Returns filenames of archive volumes. In case of single-volume archive, the list contains just the name of main archive file. """ return self._file_parser.volumelist() def getinfo(self, name): """Return RarInfo for file. """ return self._file_parser.getinfo(name) def getinfo_orig(self, name): """Return RarInfo for file source. RAR5: if name is hard-linked or copied file, returns original entry with original filename. """ return self._file_parser.getinfo_orig(name) def open(self, name, mode="r", pwd=None): """Returns file-like object (:class:`RarExtFile`) from where the data can be read. The object implements :class:`io.RawIOBase` interface, so it can be further wrapped with :class:`io.BufferedReader` and :class:`io.TextIOWrapper`. On older Python where io module is not available, it implements only .read(), .seek(), .tell() and .close() methods. The object is seekable, although the seeking is fast only on uncompressed files, on compressed files the seeking is implemented by reading ahead and/or restarting the decompression. Parameters: name file name or RarInfo instance. mode must be "r" pwd password to use for extracting. """ if mode != "r": raise NotImplementedError("RarFile.open() supports only mode=r") # entry lookup inf = self.getinfo(name) if inf.is_dir(): raise io.UnsupportedOperation("Directory does not have any data: " + inf.filename) # check password if inf.needs_password(): pwd = pwd or self._password if pwd is None: raise PasswordRequired("File %s requires password" % inf.filename) else: pwd = None return self._file_parser.open(inf, pwd) def read(self, name, pwd=None): """Return uncompressed data for archive entry. For longer files using :meth:`~RarFile.open` may be better idea. Parameters: name filename or RarInfo instance pwd password to use for extracting. """ with self.open(name, "r", pwd) as f: return f.read() def close(self): """Release open resources.""" pass def printdir(self, file=None): """Print archive file list to stdout or given file. """ if file is None: file = sys.stdout for f in self.infolist(): print(f.filename, file=file) def extract(self, member, path=None, pwd=None): """Extract single file into current directory. Parameters: member filename or :class:`RarInfo` instance path optional destination path pwd optional password to use """ inf = self.getinfo(member) return self._extract_one(inf, path, pwd, True) def extractall(self, path=None, members=None, pwd=None): """Extract all files into current directory. Parameters: path optional destination path members optional filename or :class:`RarInfo` instance list to extract pwd optional password to use """ if members is None: members = self.namelist() done = set() dirs = [] for m in members: inf = self.getinfo(m) dst = self._extract_one(inf, path, pwd, not inf.is_dir()) if inf.is_dir(): if dst not in done: dirs.append((dst, inf)) done.add(dst) if dirs: dirs.sort(reverse=True) for dst, inf in dirs: self._set_attrs(inf, dst) def testrar(self, pwd=None): """Read all files and test CRC. """ for member in self.infolist(): if member.is_file(): with self.open(member, 'r', pwd) as f: empty_read(f, member.file_size, BSIZE) def strerror(self): """Return error string if parsing failed or None if no problems. """ if not self._file_parser: return "Not a RAR file" return self._file_parser.strerror() ## ## private methods ## def _parse(self): """Run parser for file type """ ver, sfx_ofs = _find_sfx_header(self._rarfile) if ver == RAR_V3: p3 = RAR3Parser(self._rarfile, self._password, self._crc_check, self._charset, self._strict, self._info_callback, sfx_ofs, self._part_only) self._file_parser = p3 # noqa elif ver == RAR_V5: p5 = RAR5Parser(self._rarfile, self._password, self._crc_check, self._charset, self._strict, self._info_callback, sfx_ofs, self._part_only) self._file_parser = p5 # noqa else: raise NotRarFile("Not a RAR file") self._file_parser.parse() self.comment = self._file_parser.comment def _extract_one(self, info, path, pwd, set_attrs): fname = sanitize_filename( info.filename, os.path.sep, WIN32 ) if path is None: path = os.getcwd() else: path = os.fspath(path) dstfn = os.path.join(path, fname) dirname = os.path.dirname(dstfn) if dirname and dirname != ".": os.makedirs(dirname, exist_ok=True) if info.is_file(): return self._make_file(info, dstfn, pwd, set_attrs) if info.is_dir(): return self._make_dir(info, dstfn, pwd, set_attrs) if info.is_symlink(): return self._make_symlink(info, dstfn, pwd, set_attrs) return None def _create_helper(self, name, flags, info): return os.open(name, flags) def _make_file(self, info, dstfn, pwd, set_attrs): def helper(name, flags): return self._create_helper(name, flags, info) with self.open(info, "r", pwd) as src: with open(dstfn, "wb", opener=helper) as dst: shutil.copyfileobj(src, dst) if set_attrs: self._set_attrs(info, dstfn) return dstfn def _make_dir(self, info, dstfn, pwd, set_attrs): os.makedirs(dstfn, exist_ok=True) if set_attrs: self._set_attrs(info, dstfn) return dstfn def _make_symlink(self, info, dstfn, pwd, set_attrs): target_is_directory = False if info.host_os == RAR_OS_UNIX: link_name = self.read(info, pwd) target_is_directory = (info.flags & RAR_FILE_DIRECTORY) == RAR_FILE_DIRECTORY elif info.file_redir: redir_type, redir_flags, link_name = info.file_redir if redir_type == RAR5_XREDIR_WINDOWS_JUNCTION: warnings.warn(f"Windows junction not supported - {info.filename}", UnsupportedWarning) return None target_is_directory = (redir_type & RAR5_XREDIR_ISDIR) > 0 else: warnings.warn(f"Unsupported link type - {info.filename}", UnsupportedWarning) return None os.symlink(link_name, dstfn, target_is_directory=target_is_directory) return dstfn def _set_attrs(self, info, dstfn): if info.host_os == RAR_OS_UNIX: os.chmod(dstfn, info.mode & 0o777) elif info.host_os in (RAR_OS_WIN32, RAR_OS_MSDOS): # only keep R/O attr, except for dirs on win32 if info.mode & DOS_MODE_READONLY and (info.is_file() or not WIN32): st = os.stat(dstfn) new_mode = st.st_mode & ~0o222 os.chmod(dstfn, new_mode) if info.mtime: mtime_ns = to_nsecs(info.mtime) atime_ns = to_nsecs(info.atime) if info.atime else mtime_ns os.utime(dstfn, ns=(atime_ns, mtime_ns)) # # File format parsing # class CommonParser: """Shared parser parts.""" _main = None _hdrenc_main = None _needs_password = False _fd = None _expect_sig = None _parse_error = None _password = None comment = None def __init__(self, rarfile, password, crc_check, charset, strict, info_cb, sfx_offset, part_only): self._rarfile = rarfile self._password = password self._crc_check = crc_check self._charset = charset self._strict = strict self._info_callback = info_cb self._info_list = [] self._info_map = {} self._vol_list = [] self._sfx_offset = sfx_offset self._part_only = part_only def has_header_encryption(self): """Returns True if headers are encrypted """ if self._hdrenc_main: return True if self._main: if self._main.flags & RAR_MAIN_PASSWORD: return True return False def setpassword(self, pwd): """Set cached password.""" self._password = pwd def volumelist(self): """Volume files""" return self._vol_list def needs_password(self): """Is password required""" return self._needs_password def strerror(self): """Last error""" return self._parse_error def infolist(self): """List of RarInfo records. """ return self._info_list def getinfo(self, member): """Return RarInfo for filename """ if isinstance(member, RarInfo): fname = member.filename elif isinstance(member, Path): fname = str(member) else: fname = member if fname.endswith("/"): fname = fname.rstrip("/") try: return self._info_map[fname] except KeyError: raise NoRarEntry("No such file: %s" % fname) from None def getinfo_orig(self, member): inf = self.getinfo(member) if inf.file_redir: redir_type, redir_flags, redir_name = inf.file_redir # cannot leave to unrar as it expects copied file to exist if redir_type in (RAR5_XREDIR_FILE_COPY, RAR5_XREDIR_HARD_LINK): inf = self.getinfo(redir_name) return inf def parse(self): """Process file.""" self._fd = None try: self._parse_real() finally: if self._fd: self._fd.close() self._fd = None def _parse_real(self): """Actually read file. """ fd = XFile(self._rarfile) self._fd = fd fd.seek(self._sfx_offset, 0) sig = fd.read(len(self._expect_sig)) if sig != self._expect_sig: raise NotRarFile("Not a Rar archive") volume = 0 # first vol (.rar) is 0 more_vols = False endarc = False volfile = self._rarfile self._vol_list = [self._rarfile] raise_need_first_vol = False while True: if endarc: h = None # don"t read past ENDARC else: h = self._parse_header(fd) if not h: if raise_need_first_vol: # did not find ENDARC with VOLNR raise NeedFirstVolume("Need to start from first volume", None) if more_vols and not self._part_only: volume += 1 fd.close() try: volfile = self._next_volname(volfile) fd = XFile(volfile) except IOError: self._set_error("Cannot open next volume: %s", volfile) break self._fd = fd sig = fd.read(len(self._expect_sig)) if sig != self._expect_sig: self._set_error("Invalid volume sig: %s", volfile) break more_vols = False endarc = False self._vol_list.append(volfile) self._main = None self._hdrenc_main = None continue break h.volume = volume h.volume_file = volfile if h.type == RAR_BLOCK_MAIN and not self._main: self._main = h if volume == 0 and (h.flags & RAR_MAIN_NEWNUMBERING) and not self._part_only: # RAR 2.x does not set FIRSTVOLUME, # so check it only if NEWNUMBERING is used if (h.flags & RAR_MAIN_FIRSTVOLUME) == 0: if getattr(h, "main_volume_number", None) is not None: # rar5 may have more info raise NeedFirstVolume( "Need to start from first volume (current: %r)" % (h.main_volume_number,), h.main_volume_number ) # delay raise until we have volnr from ENDARC raise_need_first_vol = True if h.flags & RAR_MAIN_PASSWORD: self._needs_password = True if not self._password: break elif h.type == RAR_BLOCK_ENDARC: more_vols = (h.flags & RAR_ENDARC_NEXT_VOLUME) > 0 endarc = True if raise_need_first_vol and (h.flags & RAR_ENDARC_VOLNR) > 0: raise NeedFirstVolume( "Need to start from first volume (current: %r)" % (h.endarc_volnr,), h.endarc_volnr ) elif h.type == RAR_BLOCK_FILE: # RAR 2.x does not write RAR_BLOCK_ENDARC if h.flags & RAR_FILE_SPLIT_AFTER: more_vols = True # RAR 2.x does not set RAR_MAIN_FIRSTVOLUME if volume == 0 and h.flags & RAR_FILE_SPLIT_BEFORE: if not self._part_only: raise_need_first_vol = True if h.needs_password(): self._needs_password = True # store it self.process_entry(fd, h) if self._info_callback: self._info_callback(h) # go to next header if h.add_size > 0: fd.seek(h.data_offset + h.add_size, 0) def process_entry(self, fd, item): """Examine item, add into lookup cache.""" raise NotImplementedError() def _decrypt_header(self, fd): raise NotImplementedError("_decrypt_header") def _parse_block_header(self, fd): raise NotImplementedError("_parse_block_header") def _open_hack(self, inf, pwd): raise NotImplementedError("_open_hack") def _parse_header(self, fd): """Read single header """ try: # handle encrypted headers if (self._main and self._main.flags & RAR_MAIN_PASSWORD) or self._hdrenc_main: if not self._password: return None fd = self._decrypt_header(fd) # now read actual header return self._parse_block_header(fd) except struct.error: self._set_error("Broken header in RAR file") return None def _next_volname(self, volfile): """Given current vol name, construct next one """ if is_filelike(volfile): raise IOError("Working on single FD") if self._main.flags & RAR_MAIN_NEWNUMBERING: return _next_newvol(volfile) return _next_oldvol(volfile) def _set_error(self, msg, *args): if args: msg = msg % args self._parse_error = msg if self._strict: raise BadRarFile(msg) def open(self, inf, pwd): """Return stream object for file data.""" if inf.file_redir: redir_type, redir_flags, redir_name = inf.file_redir # cannot leave to unrar as it expects copied file to exist if redir_type in (RAR5_XREDIR_FILE_COPY, RAR5_XREDIR_HARD_LINK): inf = self.getinfo(redir_name) if not inf: raise BadRarFile("cannot find copied file") elif redir_type in ( RAR5_XREDIR_UNIX_SYMLINK, RAR5_XREDIR_WINDOWS_SYMLINK, RAR5_XREDIR_WINDOWS_JUNCTION, ): return io.BytesIO(redir_name.encode("utf8")) if inf.flags & RAR_FILE_SPLIT_BEFORE: raise NeedFirstVolume("Partial file, please start from first volume: " + inf.filename, None) # is temp write usable? use_hack = 1 if not self._main: use_hack = 0 elif self._main._must_disable_hack(): use_hack = 0 elif inf._must_disable_hack(): use_hack = 0 elif is_filelike(self._rarfile): pass elif inf.file_size > HACK_SIZE_LIMIT: use_hack = 0 elif not USE_EXTRACT_HACK: use_hack = 0 # now extract if inf.compress_type == RAR_M0 and (inf.flags & RAR_FILE_PASSWORD) == 0 and inf.file_redir is None: return self._open_clear(inf) elif use_hack: return self._open_hack(inf, pwd) elif is_filelike(self._rarfile): return self._open_unrar_membuf(self._rarfile, inf, pwd) else: return self._open_unrar(self._rarfile, inf, pwd) def _open_clear(self, inf): if FORCE_TOOL: return self._open_unrar(self._rarfile, inf) return DirectReader(self, inf) def _open_hack_core(self, inf, pwd, prefix, suffix): size = inf.compress_size + inf.header_size rf = XFile(inf.volume_file, 0) rf.seek(inf.header_offset) tmpfd, tmpname = mkstemp(suffix=".rar", dir=HACK_TMP_DIR) tmpf = os.fdopen(tmpfd, "wb") try: tmpf.write(prefix) while size > 0: if size > BSIZE: buf = rf.read(BSIZE) else: buf = rf.read(size) if not buf: raise BadRarFile("read failed: " + inf.filename) tmpf.write(buf) size -= len(buf) tmpf.write(suffix) tmpf.close() rf.close() except BaseException: rf.close() tmpf.close() os.unlink(tmpname) raise return self._open_unrar(tmpname, inf, pwd, tmpname) def _open_unrar_membuf(self, memfile, inf, pwd): """Write in-memory archive to temp file, needed for solid archives. """ tmpname = membuf_tempfile(memfile) return self._open_unrar(tmpname, inf, pwd, tmpname, force_file=True) def _open_unrar(self, rarfile, inf, pwd=None, tmpfile=None, force_file=False): """Extract using unrar """ setup = tool_setup() # not giving filename avoids encoding related problems fn = None if not tmpfile or force_file: fn = inf.filename.replace("/", os.path.sep) # read from unrar pipe cmd = setup.open_cmdline(pwd, rarfile, fn) return PipeReader(self, inf, cmd, tmpfile) # # RAR3 format # class Rar3Info(RarInfo): """RAR3 specific fields.""" extract_version = 15 salt = None add_size = 0 header_crc = None header_size = None header_offset = None data_offset = None _md_class = None _md_expect = None _name_size = None # make sure some rar5 fields are always present file_redir = None blake2sp_hash = None endarc_datacrc = None endarc_volnr = None def _must_disable_hack(self): if self.type == RAR_BLOCK_FILE: if self.flags & RAR_FILE_PASSWORD: return True elif self.flags & (RAR_FILE_SPLIT_BEFORE | RAR_FILE_SPLIT_AFTER): return True elif self.type == RAR_BLOCK_MAIN: if self.flags & (RAR_MAIN_SOLID | RAR_MAIN_PASSWORD): return True return False def is_dir(self): """Returns True if entry is a directory.""" if self.type == RAR_BLOCK_FILE and not self.is_symlink(): return (self.flags & RAR_FILE_DIRECTORY) == RAR_FILE_DIRECTORY return False def is_symlink(self): """Returns True if entry is a symlink.""" return ( self.type == RAR_BLOCK_FILE and self.host_os == RAR_OS_UNIX and self.mode & 0xF000 == 0xA000 ) def is_file(self): """Returns True if entry is a normal file.""" return ( self.type == RAR_BLOCK_FILE and not (self.is_dir() or self.is_symlink()) ) class RAR3Parser(CommonParser): """Parse RAR3 file format. """ _expect_sig = RAR_ID _last_aes_key = (None, None, None) # (salt, key, iv) def _decrypt_header(self, fd): if not _have_crypto: raise NoCrypto("Cannot parse encrypted headers - no crypto") salt = fd.read(8) if self._last_aes_key[0] == salt: key, iv = self._last_aes_key[1:] else: key, iv = rar3_s2k(self._password, salt) self._last_aes_key = (salt, key, iv) return HeaderDecrypt(fd, key, iv) def _parse_block_header(self, fd): """Parse common block header """ h = Rar3Info() h.header_offset = fd.tell() # read and parse base header buf = fd.read(S_BLK_HDR.size) if not buf: return None if len(buf) < S_BLK_HDR.size: self._set_error("Unexpected EOF when reading header") return None t = S_BLK_HDR.unpack_from(buf) h.header_crc, h.type, h.flags, h.header_size = t # read full header if h.header_size > S_BLK_HDR.size: hdata = buf + fd.read(h.header_size - S_BLK_HDR.size) else: hdata = buf h.data_offset = fd.tell() # unexpected EOF? if len(hdata) != h.header_size: self._set_error("Unexpected EOF when reading header") return None pos = S_BLK_HDR.size # block has data assiciated with it? if h.flags & RAR_LONG_BLOCK: h.add_size, pos = load_le32(hdata, pos) else: h.add_size = 0 # parse interesting ones, decide header boundaries for crc if h.type == RAR_BLOCK_MARK: return h elif h.type == RAR_BLOCK_MAIN: pos += 6 if h.flags & RAR_MAIN_ENCRYPTVER: pos += 1 crc_pos = pos if h.flags & RAR_MAIN_COMMENT: self._parse_subblocks(h, hdata, pos) elif h.type == RAR_BLOCK_FILE: pos = self._parse_file_header(h, hdata, pos - 4) crc_pos = pos if h.flags & RAR_FILE_COMMENT: pos = self._parse_subblocks(h, hdata, pos) elif h.type == RAR_BLOCK_SUB: pos = self._parse_file_header(h, hdata, pos - 4) crc_pos = h.header_size elif h.type == RAR_BLOCK_OLD_AUTH: pos += 8 crc_pos = pos elif h.type == RAR_BLOCK_OLD_EXTRA: pos += 7 crc_pos = pos elif h.type == RAR_BLOCK_ENDARC: if h.flags & RAR_ENDARC_DATACRC: h.endarc_datacrc, pos = load_le32(hdata, pos) if h.flags & RAR_ENDARC_VOLNR: h.endarc_volnr = S_SHORT.unpack_from(hdata, pos)[0] pos += 2 crc_pos = h.header_size else: crc_pos = h.header_size # check crc if h.type == RAR_BLOCK_OLD_SUB: crcdat = hdata[2:] + fd.read(h.add_size) else: crcdat = hdata[2:crc_pos] calc_crc = crc32(crcdat) & 0xFFFF # return good header if h.header_crc == calc_crc: return h # header parsing failed. self._set_error("Header CRC error (%02x): exp=%x got=%x (xlen = %d)", h.type, h.header_crc, calc_crc, len(crcdat)) # instead panicing, send eof return None def _parse_file_header(self, h, hdata, pos): """Read file-specific header """ fld = S_FILE_HDR.unpack_from(hdata, pos) pos += S_FILE_HDR.size h.compress_size = fld[0] h.file_size = fld[1] h.host_os = fld[2] h.CRC = fld[3] h.date_time = parse_dos_time(fld[4]) h.mtime = to_datetime(h.date_time) h.extract_version = fld[5] h.compress_type = fld[6] h._name_size = name_size = fld[7] h.mode = fld[8] h._md_class = CRC32Context h._md_expect = h.CRC if h.flags & RAR_FILE_LARGE: h1, pos = load_le32(hdata, pos) h2, pos = load_le32(hdata, pos) h.compress_size |= h1 << 32 h.file_size |= h2 << 32 h.add_size = h.compress_size name, pos = load_bytes(hdata, name_size, pos) if h.flags & RAR_FILE_UNICODE and b"\0" in name: # stored in custom encoding nul = name.find(b"\0") h.orig_filename = name[:nul] u = UnicodeFilename(h.orig_filename, name[nul + 1:]) h.filename = u.decode() # if parsing failed fall back to simple name if u.failed: h.filename = self._decode(h.orig_filename) elif h.flags & RAR_FILE_UNICODE: # stored in UTF8 h.orig_filename = name h.filename = name.decode("utf8", "replace") else: # stored in random encoding h.orig_filename = name h.filename = self._decode(name) # change separator, set dir suffix h.filename = h.filename.replace("\\", "/").rstrip("/") if h.is_dir(): h.filename = h.filename + "/" if h.flags & RAR_FILE_SALT: h.salt, pos = load_bytes(hdata, 8, pos) else: h.salt = None # optional extended time stamps if h.flags & RAR_FILE_EXTTIME: pos = _parse_ext_time(h, hdata, pos) else: h.mtime = h.atime = h.ctime = h.arctime = None return pos def _parse_subblocks(self, h, hdata, pos): """Find old-style comment subblock """ while pos < len(hdata): # ordinary block header t = S_BLK_HDR.unpack_from(hdata, pos) ___scrc, stype, sflags, slen = t pos_next = pos + slen pos += S_BLK_HDR.size # corrupt header if pos_next < pos: break # followed by block-specific header if stype == RAR_BLOCK_OLD_COMMENT and pos + S_COMMENT_HDR.size <= pos_next: declen, ver, meth, crc = S_COMMENT_HDR.unpack_from(hdata, pos) pos += S_COMMENT_HDR.size data = hdata[pos: pos_next] cmt = rar3_decompress(ver, meth, data, declen, sflags, crc, self._password) if not self._crc_check or (crc32(cmt) & 0xFFFF == crc): h.comment = self._decode_comment(cmt) pos = pos_next return pos def _read_comment_v3(self, inf, pwd=None): # read data with XFile(inf.volume_file) as rf: rf.seek(inf.data_offset) data = rf.read(inf.compress_size) # decompress cmt = rar3_decompress(inf.extract_version, inf.compress_type, data, inf.file_size, inf.flags, inf.CRC, pwd, inf.salt) # check crc if self._crc_check: crc = crc32(cmt) if crc != inf.CRC: return None return self._decode_comment(cmt) def _decode(self, val): for c in TRY_ENCODINGS: try: return val.decode(c) except UnicodeError: pass return val.decode(self._charset, "replace") def _decode_comment(self, val): return self._decode(val) def process_entry(self, fd, item): if item.type == RAR_BLOCK_FILE: # use only first part if item.flags & RAR_FILE_VERSION: pass # skip old versions elif (item.flags & RAR_FILE_SPLIT_BEFORE) == 0: self._info_map[item.filename.rstrip("/")] = item self._info_list.append(item) elif len(self._info_list) > 0: # final crc is in last block old = self._info_list[-1] old.CRC = item.CRC old._md_expect = item._md_expect old.compress_size += item.compress_size # parse new-style comment if item.type == RAR_BLOCK_SUB and item.filename == "CMT": if item.flags & (RAR_FILE_SPLIT_BEFORE | RAR_FILE_SPLIT_AFTER): pass elif item.flags & RAR_FILE_SOLID: # file comment cmt = self._read_comment_v3(item, self._password) if len(self._info_list) > 0: old = self._info_list[-1] old.comment = cmt else: # archive comment cmt = self._read_comment_v3(item, self._password) self.comment = cmt if item.type == RAR_BLOCK_MAIN: if item.flags & RAR_MAIN_COMMENT: self.comment = item.comment if item.flags & RAR_MAIN_PASSWORD: self._needs_password = True # put file compressed data into temporary .rar archive, and run # unrar on that, thus avoiding unrar going over whole archive def _open_hack(self, inf, pwd): # create main header: crc, type, flags, size, res1, res2 prefix = RAR_ID + S_BLK_HDR.pack(0x90CF, 0x73, 0, 13) + b"\0" * (2 + 4) return self._open_hack_core(inf, pwd, prefix, b"") # # RAR5 format # class Rar5Info(RarInfo): """Shared fields for RAR5 records. """ extract_version = 50 header_crc = None header_size = None header_offset = None data_offset = None # type=all block_type = None block_flags = None add_size = 0 block_extra_size = 0 # type=MAIN volume_number = None _md_class = None _md_expect = None def _must_disable_hack(self): return False class Rar5BaseFile(Rar5Info): """Shared sturct for file & service record. """ type = -1 file_flags = None file_encryption = (0, 0, 0, b"", b"", b"") file_compress_flags = None file_redir = None file_owner = None file_version = None blake2sp_hash = None def _must_disable_hack(self): if self.flags & RAR_FILE_PASSWORD: return True if self.block_flags & (RAR5_BLOCK_FLAG_SPLIT_BEFORE | RAR5_BLOCK_FLAG_SPLIT_AFTER): return True if self.file_compress_flags & RAR5_COMPR_SOLID: return True if self.file_redir: return True return False class Rar5FileInfo(Rar5BaseFile): """RAR5 file record. """ type = RAR_BLOCK_FILE def is_symlink(self): """Returns True if entry is a symlink.""" # pylint: disable=unsubscriptable-object return ( self.file_redir is not None and self.file_redir[0] in ( RAR5_XREDIR_UNIX_SYMLINK, RAR5_XREDIR_WINDOWS_SYMLINK, RAR5_XREDIR_WINDOWS_JUNCTION, ) ) def is_file(self): """Returns True if entry is a normal file.""" return not (self.is_dir() or self.is_symlink()) def is_dir(self): """Returns True if entry is a directory.""" if not self.file_redir: if self.file_flags & RAR5_FILE_FLAG_ISDIR: return True return False class Rar5ServiceInfo(Rar5BaseFile): """RAR5 service record. """ type = RAR_BLOCK_SUB class Rar5MainInfo(Rar5Info): """RAR5 archive main record. """ type = RAR_BLOCK_MAIN main_flags = None main_volume_number = None def _must_disable_hack(self): if self.main_flags & RAR5_MAIN_FLAG_SOLID: return True return False class Rar5EncryptionInfo(Rar5Info): """RAR5 archive header encryption record. """ type = RAR5_BLOCK_ENCRYPTION encryption_algo = None encryption_flags = None encryption_kdf_count = None encryption_salt = None encryption_check_value = None def needs_password(self): return True class Rar5EndArcInfo(Rar5Info): """RAR5 end of archive record. """ type = RAR_BLOCK_ENDARC endarc_flags = None class RAR5Parser(CommonParser): """Parse RAR5 format. """ _expect_sig = RAR5_ID _hdrenc_main = None # AES encrypted headers _last_aes256_key = (-1, None, None) # (kdf_count, salt, key) def _get_utf8_password(self): pwd = self._password if isinstance(pwd, str): return pwd.encode("utf8") return pwd def _gen_key(self, kdf_count, salt): if self._last_aes256_key[:2] == (kdf_count, salt): return self._last_aes256_key[2] if kdf_count > 24: raise BadRarFile("Too large kdf_count") pwd = self._get_utf8_password() key = pbkdf2_hmac("sha256", pwd, salt, 1 << kdf_count) self._last_aes256_key = (kdf_count, salt, key) return key def _decrypt_header(self, fd): if not _have_crypto: raise NoCrypto("Cannot parse encrypted headers - no crypto") h = self._hdrenc_main key = self._gen_key(h.encryption_kdf_count, h.encryption_salt) iv = fd.read(16) return HeaderDecrypt(fd, key, iv) def _parse_block_header(self, fd): """Parse common block header """ header_offset = fd.tell() preload = 4 + 1 start_bytes = fd.read(preload) if len(start_bytes) < preload: self._set_error("Unexpected EOF when reading header") return None while start_bytes[-1] & 0x80: b = fd.read(1) if not b: self._set_error("Unexpected EOF when reading header") return None start_bytes += b header_crc, pos = load_le32(start_bytes, 0) hdrlen, pos = load_vint(start_bytes, pos) if hdrlen > 2 * 1024 * 1024: return None header_size = pos + hdrlen # read full header, check for EOF hdata = start_bytes + fd.read(header_size - len(start_bytes)) if len(hdata) != header_size: self._set_error("Unexpected EOF when reading header") return None data_offset = fd.tell() calc_crc = crc32(memoryview(hdata)[4:]) if header_crc != calc_crc: # header parsing failed. self._set_error("Header CRC error: exp=%x got=%x (xlen = %d)", header_crc, calc_crc, len(hdata)) return None block_type, pos = load_vint(hdata, pos) if block_type == RAR5_BLOCK_MAIN: h, pos = self._parse_block_common(Rar5MainInfo(), hdata) h = self._parse_main_block(h, hdata, pos) elif block_type == RAR5_BLOCK_FILE: h, pos = self._parse_block_common(Rar5FileInfo(), hdata) h = self._parse_file_block(h, hdata, pos) elif block_type == RAR5_BLOCK_SERVICE: h, pos = self._parse_block_common(Rar5ServiceInfo(), hdata) h = self._parse_file_block(h, hdata, pos) elif block_type == RAR5_BLOCK_ENCRYPTION: h, pos = self._parse_block_common(Rar5EncryptionInfo(), hdata) h = self._parse_encryption_block(h, hdata, pos) elif block_type == RAR5_BLOCK_ENDARC: h, pos = self._parse_block_common(Rar5EndArcInfo(), hdata) h = self._parse_endarc_block(h, hdata, pos) else: h = None if h: h.header_offset = header_offset h.data_offset = data_offset return h def _parse_block_common(self, h, hdata): h.header_crc, pos = load_le32(hdata, 0) hdrlen, pos = load_vint(hdata, pos) h.header_size = hdrlen + pos h.block_type, pos = load_vint(hdata, pos) h.block_flags, pos = load_vint(hdata, pos) if h.block_flags & RAR5_BLOCK_FLAG_EXTRA_DATA: h.block_extra_size, pos = load_vint(hdata, pos) if h.block_flags & RAR5_BLOCK_FLAG_DATA_AREA: h.add_size, pos = load_vint(hdata, pos) h.compress_size = h.add_size if h.block_flags & RAR5_BLOCK_FLAG_SKIP_IF_UNKNOWN: h.flags |= RAR_SKIP_IF_UNKNOWN if h.block_flags & RAR5_BLOCK_FLAG_DATA_AREA: h.flags |= RAR_LONG_BLOCK return h, pos def _parse_main_block(self, h, hdata, pos): h.main_flags, pos = load_vint(hdata, pos) if h.main_flags & RAR5_MAIN_FLAG_HAS_VOLNR: h.main_volume_number, pos = load_vint(hdata, pos) h.flags |= RAR_MAIN_NEWNUMBERING if h.main_flags & RAR5_MAIN_FLAG_SOLID: h.flags |= RAR_MAIN_SOLID if h.main_flags & RAR5_MAIN_FLAG_ISVOL: h.flags |= RAR_MAIN_VOLUME if h.main_flags & RAR5_MAIN_FLAG_RECOVERY: h.flags |= RAR_MAIN_RECOVERY if self._hdrenc_main: h.flags |= RAR_MAIN_PASSWORD if h.main_flags & RAR5_MAIN_FLAG_HAS_VOLNR == 0: h.flags |= RAR_MAIN_FIRSTVOLUME return h def _parse_file_block(self, h, hdata, pos): h.file_flags, pos = load_vint(hdata, pos) h.file_size, pos = load_vint(hdata, pos) h.mode, pos = load_vint(hdata, pos) if h.file_flags & RAR5_FILE_FLAG_HAS_MTIME: h.mtime, pos = load_unixtime(hdata, pos) h.date_time = h.mtime.timetuple()[:6] if h.file_flags & RAR5_FILE_FLAG_HAS_CRC32: h.CRC, pos = load_le32(hdata, pos) h._md_class = CRC32Context h._md_expect = h.CRC h.file_compress_flags, pos = load_vint(hdata, pos) h.file_host_os, pos = load_vint(hdata, pos) h.orig_filename, pos = load_vstr(hdata, pos) h.filename = h.orig_filename.decode("utf8", "replace").rstrip("/") # use compatible values if h.file_host_os == RAR5_OS_WINDOWS: h.host_os = RAR_OS_WIN32 else: h.host_os = RAR_OS_UNIX h.compress_type = RAR_M0 + ((h.file_compress_flags >> 7) & 7) if h.block_extra_size: # allow 1 byte of garbage while pos < len(hdata) - 1: xsize, pos = load_vint(hdata, pos) xdata, pos = load_bytes(hdata, xsize, pos) self._process_file_extra(h, xdata) if h.block_flags & RAR5_BLOCK_FLAG_SPLIT_BEFORE: h.flags |= RAR_FILE_SPLIT_BEFORE if h.block_flags & RAR5_BLOCK_FLAG_SPLIT_AFTER: h.flags |= RAR_FILE_SPLIT_AFTER if h.file_flags & RAR5_FILE_FLAG_ISDIR: h.flags |= RAR_FILE_DIRECTORY if h.file_compress_flags & RAR5_COMPR_SOLID: h.flags |= RAR_FILE_SOLID if h.is_dir(): h.filename = h.filename + "/" return h def _parse_endarc_block(self, h, hdata, pos): h.endarc_flags, pos = load_vint(hdata, pos) if h.endarc_flags & RAR5_ENDARC_FLAG_NEXT_VOL: h.flags |= RAR_ENDARC_NEXT_VOLUME return h def _check_password(self, check_value, kdf_count_shift, salt): if len(check_value) != RAR5_PW_CHECK_SIZE + RAR5_PW_SUM_SIZE: return hdr_check = check_value[:RAR5_PW_CHECK_SIZE] hdr_sum = check_value[RAR5_PW_CHECK_SIZE:] sum_hash = sha256(hdr_check).digest() if sum_hash[:RAR5_PW_SUM_SIZE] != hdr_sum: return kdf_count = (1 << kdf_count_shift) + 32 pwd = self._get_utf8_password() pwd_hash = pbkdf2_hmac("sha256", pwd, salt, kdf_count) pwd_check = bytearray(RAR5_PW_CHECK_SIZE) len_mask = RAR5_PW_CHECK_SIZE - 1 for i, v in enumerate(pwd_hash): pwd_check[i & len_mask] ^= v if pwd_check != hdr_check: raise RarWrongPassword() def _parse_encryption_block(self, h, hdata, pos): h.encryption_algo, pos = load_vint(hdata, pos) h.encryption_flags, pos = load_vint(hdata, pos) h.encryption_kdf_count, pos = load_byte(hdata, pos) h.encryption_salt, pos = load_bytes(hdata, 16, pos) if h.encryption_flags & RAR5_ENC_FLAG_HAS_CHECKVAL: h.encryption_check_value, pos = load_bytes(hdata, 12, pos) if h.encryption_algo != RAR5_XENC_CIPHER_AES256: raise BadRarFile("Unsupported header encryption cipher") if h.encryption_check_value and self._password: self._check_password(h.encryption_check_value, h.encryption_kdf_count, h.encryption_salt) self._hdrenc_main = h return h def _process_file_extra(self, h, xdata): xtype, pos = load_vint(xdata, 0) if xtype == RAR5_XFILE_TIME: self._parse_file_xtime(h, xdata, pos) elif xtype == RAR5_XFILE_ENCRYPTION: self._parse_file_encryption(h, xdata, pos) elif xtype == RAR5_XFILE_HASH: self._parse_file_hash(h, xdata, pos) elif xtype == RAR5_XFILE_VERSION: self._parse_file_version(h, xdata, pos) elif xtype == RAR5_XFILE_REDIR: self._parse_file_redir(h, xdata, pos) elif xtype == RAR5_XFILE_OWNER: self._parse_file_owner(h, xdata, pos) elif xtype == RAR5_XFILE_SERVICE: pass else: pass # extra block for file time record def _parse_file_xtime(self, h, xdata, pos): tflags, pos = load_vint(xdata, pos) ldr = load_windowstime if tflags & RAR5_XTIME_UNIXTIME: ldr = load_unixtime if tflags & RAR5_XTIME_HAS_MTIME: h.mtime, pos = ldr(xdata, pos) h.date_time = h.mtime.timetuple()[:6] if tflags & RAR5_XTIME_HAS_CTIME: h.ctime, pos = ldr(xdata, pos) if tflags & RAR5_XTIME_HAS_ATIME: h.atime, pos = ldr(xdata, pos) if tflags & RAR5_XTIME_UNIXTIME_NS: if tflags & RAR5_XTIME_HAS_MTIME: nsec, pos = load_le32(xdata, pos) h.mtime = to_nsdatetime(h.mtime, nsec) if tflags & RAR5_XTIME_HAS_CTIME: nsec, pos = load_le32(xdata, pos) h.ctime = to_nsdatetime(h.ctime, nsec) if tflags & RAR5_XTIME_HAS_ATIME: nsec, pos = load_le32(xdata, pos) h.atime = to_nsdatetime(h.atime, nsec) # just remember encryption info def _parse_file_encryption(self, h, xdata, pos): algo, pos = load_vint(xdata, pos) flags, pos = load_vint(xdata, pos) kdf_count, pos = load_byte(xdata, pos) salt, pos = load_bytes(xdata, 16, pos) iv, pos = load_bytes(xdata, 16, pos) checkval = None if flags & RAR5_XENC_CHECKVAL: checkval, pos = load_bytes(xdata, 12, pos) if flags & RAR5_XENC_TWEAKED: h._md_expect = None h._md_class = NoHashContext h.file_encryption = (algo, flags, kdf_count, salt, iv, checkval) h.flags |= RAR_FILE_PASSWORD def _parse_file_hash(self, h, xdata, pos): hash_type, pos = load_vint(xdata, pos) if hash_type == RAR5_XHASH_BLAKE2SP: h.blake2sp_hash, pos = load_bytes(xdata, 32, pos) if (h.file_encryption[1] & RAR5_XENC_TWEAKED) == 0: h._md_class = Blake2SP h._md_expect = h.blake2sp_hash def _parse_file_version(self, h, xdata, pos): flags, pos = load_vint(xdata, pos) version, pos = load_vint(xdata, pos) h.file_version = (flags, version) def _parse_file_redir(self, h, xdata, pos): redir_type, pos = load_vint(xdata, pos) redir_flags, pos = load_vint(xdata, pos) redir_name, pos = load_vstr(xdata, pos) redir_name = redir_name.decode("utf8", "replace") h.file_redir = (redir_type, redir_flags, redir_name) def _parse_file_owner(self, h, xdata, pos): user_name = group_name = user_id = group_id = None flags, pos = load_vint(xdata, pos) if flags & RAR5_XOWNER_UNAME: user_name, pos = load_vstr(xdata, pos) if flags & RAR5_XOWNER_GNAME: group_name, pos = load_vstr(xdata, pos) if flags & RAR5_XOWNER_UID: user_id, pos = load_vint(xdata, pos) if flags & RAR5_XOWNER_GID: group_id, pos = load_vint(xdata, pos) h.file_owner = (user_name, group_name, user_id, group_id) def process_entry(self, fd, item): if item.block_type == RAR5_BLOCK_FILE: if item.file_version: pass # skip old versions elif (item.block_flags & RAR5_BLOCK_FLAG_SPLIT_BEFORE) == 0: # use only first part self._info_map[item.filename.rstrip("/")] = item self._info_list.append(item) elif len(self._info_list) > 0: # final crc is in last block old = self._info_list[-1] old.CRC = item.CRC old._md_expect = item._md_expect old.blake2sp_hash = item.blake2sp_hash old.compress_size += item.compress_size elif item.block_type == RAR5_BLOCK_SERVICE: if item.filename == "CMT": self._load_comment(fd, item) def _load_comment(self, fd, item): if item.block_flags & (RAR5_BLOCK_FLAG_SPLIT_BEFORE | RAR5_BLOCK_FLAG_SPLIT_AFTER): return None if item.compress_type != RAR_M0: return None if item.flags & RAR_FILE_PASSWORD: algo, ___flags, kdf_count, salt, iv, ___checkval = item.file_encryption if algo != RAR5_XENC_CIPHER_AES256: return None key = self._gen_key(kdf_count, salt) f = HeaderDecrypt(fd, key, iv) cmt = f.read(item.file_size) else: # archive comment with self._open_clear(item) as cmtstream: cmt = cmtstream.read() # rar bug? - appends zero to comment cmt = cmt.split(b"\0", 1)[0] self.comment = cmt.decode("utf8") return None def _open_hack(self, inf, pwd): # len, type, blk_flags, flags main_hdr = b"\x03\x01\x00\x00" endarc_hdr = b"\x03\x05\x00\x00" main_hdr = S_LONG.pack(crc32(main_hdr)) + main_hdr endarc_hdr = S_LONG.pack(crc32(endarc_hdr)) + endarc_hdr return self._open_hack_core(inf, pwd, RAR5_ID + main_hdr, endarc_hdr) ## ## Utility classes ## class UnicodeFilename: """Handle RAR3 unicode filename decompression. """ def __init__(self, name, encdata): self.std_name = bytearray(name) self.encdata = bytearray(encdata) self.pos = self.encpos = 0 self.buf = bytearray() self.failed = 0 def enc_byte(self): """Copy encoded byte.""" try: c = self.encdata[self.encpos] self.encpos += 1 return c except IndexError: self.failed = 1 return 0 def std_byte(self): """Copy byte from 8-bit representation.""" try: return self.std_name[self.pos] except IndexError: self.failed = 1 return ord("?") def put(self, lo, hi): """Copy 16-bit value to result.""" self.buf.append(lo) self.buf.append(hi) self.pos += 1 def decode(self): """Decompress compressed UTF16 value.""" hi = self.enc_byte() flagbits = 0 while self.encpos < len(self.encdata): if flagbits == 0: flags = self.enc_byte() flagbits = 8 flagbits -= 2 t = (flags >> flagbits) & 3 if t == 0: self.put(self.enc_byte(), 0) elif t == 1: self.put(self.enc_byte(), hi) elif t == 2: self.put(self.enc_byte(), self.enc_byte()) else: n = self.enc_byte() if n & 0x80: c = self.enc_byte() for _ in range((n & 0x7f) + 2): lo = (self.std_byte() + c) & 0xFF self.put(lo, hi) else: for _ in range(n + 2): self.put(self.std_byte(), 0) return self.buf.decode("utf-16le", "replace") class RarExtFile(io.RawIOBase): """Base class for file-like object that :meth:`RarFile.open` returns. Provides public methods and common crc checking. Behaviour: - no short reads - .read() and .readinfo() read as much as requested. - no internal buffer, use io.BufferedReader for that. """ name = None #: Filename of the archive entry mode = "rb" _parser = None _inf = None _fd = None _remain = 0 _returncode = 0 _md_context = None _seeking = False def _open_extfile(self, parser, inf): self.name = inf.filename self._parser = parser self._inf = inf if self._fd: self._fd.close() if self._seeking: md_class = NoHashContext else: md_class = self._inf._md_class or NoHashContext self._md_context = md_class() self._fd = None self._remain = self._inf.file_size def read(self, n=-1): """Read all or specified amount of data from archive entry.""" # sanitize count if n is None or n < 0: n = self._remain elif n > self._remain: n = self._remain if n == 0: return b"" buf = [] orig = n while n > 0: # actual read data = self._read(n) if not data: break buf.append(data) self._md_context.update(data) self._remain -= len(data) n -= len(data) data = b"".join(buf) if n > 0: raise BadRarFile("Failed the read enough data: req=%d got=%d" % (orig, len(data))) # done? if not data or self._remain == 0: # self.close() self._check() return data def _check(self): """Check final CRC.""" final = self._md_context.digest() exp = self._inf._md_expect if exp is None: return if final is None: return if self._returncode: check_returncode(self._returncode, "", tool_setup().get_errmap()) if self._remain != 0: raise BadRarFile("Failed the read enough data") if final != exp: raise BadRarFile("Corrupt file - CRC check failed: %s - exp=%r got=%r" % ( self._inf.filename, exp, final)) def _read(self, cnt): """Actual read that gets sanitized cnt.""" raise NotImplementedError("_read") def close(self): """Close open resources.""" super().close() if self._fd: self._fd.close() self._fd = None def __del__(self): """Hook delete to make sure tempfile is removed.""" self.close() def readinto(self, buf): """Zero-copy read directly into buffer. Returns bytes read. """ raise NotImplementedError("readinto") def tell(self): """Return current reading position in uncompressed data.""" return self._inf.file_size - self._remain def seek(self, offset, whence=0): """Seek in data. On uncompressed files, the seeking works by actual seeks so it's fast. On compresses files its slow - forward seeking happends by reading ahead, backwards by re-opening and decompressing from the start. """ # disable crc check when seeking if not self._seeking: self._md_context = NoHashContext() self._seeking = True fsize = self._inf.file_size cur_ofs = self.tell() if whence == 0: # seek from beginning of file new_ofs = offset elif whence == 1: # seek from current position new_ofs = cur_ofs + offset elif whence == 2: # seek from end of file new_ofs = fsize + offset else: raise ValueError("Invalid value for whence") # sanity check if new_ofs < 0: new_ofs = 0 elif new_ofs > fsize: new_ofs = fsize # do the actual seek if new_ofs >= cur_ofs: self._skip(new_ofs - cur_ofs) else: # reopen and seek self._open_extfile(self._parser, self._inf) self._skip(new_ofs) return self.tell() def _skip(self, cnt): """Read and discard data""" empty_read(self, cnt, BSIZE) def readable(self): """Returns True""" return True def writable(self): """Returns False. Writing is not supported. """ return False def seekable(self): """Returns True. Seeking is supported, although it's slow on compressed files. """ return True def readall(self): """Read all remaining data""" # avoid RawIOBase default impl return self.read() class PipeReader(RarExtFile): """Read data from pipe, handle tempfile cleanup.""" def __init__(self, parser, inf, cmd, tempfile=None): super().__init__() self._cmd = cmd self._proc = None self._tempfile = tempfile self._open_extfile(parser, inf) def _close_proc(self): if not self._proc: return for f in (self._proc.stdout, self._proc.stderr, self._proc.stdin): if f: f.close() self._proc.wait() self._returncode = self._proc.returncode self._proc = None def _open_extfile(self, parser, inf): super()._open_extfile(parser, inf) # stop old process self._close_proc() # launch new process self._returncode = 0 self._proc = custom_popen(self._cmd) self._fd = self._proc.stdout def _read(self, cnt): """Read from pipe.""" # normal read is usually enough data = self._fd.read(cnt) if len(data) == cnt or not data: return data # short read, try looping buf = [data] cnt -= len(data) while cnt > 0: data = self._fd.read(cnt) if not data: break cnt -= len(data) buf.append(data) return b"".join(buf) def close(self): """Close open resources.""" self._close_proc() super().close() if self._tempfile: try: os.unlink(self._tempfile) except OSError: pass self._tempfile = None def readinto(self, buf): """Zero-copy read directly into buffer.""" cnt = len(buf) if cnt > self._remain: cnt = self._remain vbuf = memoryview(buf) res = got = 0 while got < cnt: res = self._fd.readinto(vbuf[got: cnt]) if not res: break self._md_context.update(vbuf[got: got + res]) self._remain -= res got += res return got class DirectReader(RarExtFile): """Read uncompressed data directly from archive. """ _cur = None _cur_avail = None _volfile = None def __init__(self, parser, inf): super().__init__() self._open_extfile(parser, inf) def _open_extfile(self, parser, inf): super()._open_extfile(parser, inf) self._volfile = self._inf.volume_file self._fd = XFile(self._volfile, 0) self._fd.seek(self._inf.header_offset, 0) self._cur = self._parser._parse_header(self._fd) self._cur_avail = self._cur.add_size def _skip(self, cnt): """RAR Seek, skipping through rar files to get to correct position """ while cnt > 0: # next vol needed? if self._cur_avail == 0: if not self._open_next(): break # fd is in read pos, do the read if cnt > self._cur_avail: cnt -= self._cur_avail self._remain -= self._cur_avail self._cur_avail = 0 else: self._fd.seek(cnt, 1) self._cur_avail -= cnt self._remain -= cnt cnt = 0 def _read(self, cnt): """Read from potentially multi-volume archive.""" pos = self._fd.tell() need = self._cur.data_offset + self._cur.add_size - self._cur_avail if pos != need: self._fd.seek(need, 0) buf = [] while cnt > 0: # next vol needed? if self._cur_avail == 0: if not self._open_next(): break # fd is in read pos, do the read if cnt > self._cur_avail: data = self._fd.read(self._cur_avail) else: data = self._fd.read(cnt) if not data: break # got some data cnt -= len(data) self._cur_avail -= len(data) buf.append(data) if len(buf) == 1: return buf[0] return b"".join(buf) def _open_next(self): """Proceed to next volume.""" # is the file split over archives? if (self._cur.flags & RAR_FILE_SPLIT_AFTER) == 0: return False if self._fd: self._fd.close() self._fd = None # open next part self._volfile = self._parser._next_volname(self._volfile) fd = open(self._volfile, "rb", 0) self._fd = fd sig = fd.read(len(self._parser._expect_sig)) if sig != self._parser._expect_sig: raise BadRarFile("Invalid signature") # loop until first file header while True: cur = self._parser._parse_header(fd) if not cur: raise BadRarFile("Unexpected EOF") if cur.type in (RAR_BLOCK_MARK, RAR_BLOCK_MAIN): if cur.add_size: fd.seek(cur.add_size, 1) continue if cur.orig_filename != self._inf.orig_filename: raise BadRarFile("Did not found file entry") self._cur = cur self._cur_avail = cur.add_size return True def readinto(self, buf): """Zero-copy read directly into buffer.""" got = 0 vbuf = memoryview(buf) while got < len(buf): # next vol needed? if self._cur_avail == 0: if not self._open_next(): break # length for next read cnt = len(buf) - got if cnt > self._cur_avail: cnt = self._cur_avail # read into temp view res = self._fd.readinto(vbuf[got: got + cnt]) if not res: break self._md_context.update(vbuf[got: got + res]) self._cur_avail -= res self._remain -= res got += res return got class HeaderDecrypt: """File-like object that decrypts from another file""" def __init__(self, f, key, iv): self.f = f self.ciph = AES_CBC_Decrypt(key, iv) self.buf = b"" def tell(self): """Current file pos - works only on block boundaries.""" return self.f.tell() def read(self, cnt=None): """Read and decrypt.""" if cnt > 8 * 1024: raise BadRarFile("Bad count to header decrypt - wrong password?") # consume old data if cnt <= len(self.buf): res = self.buf[:cnt] self.buf = self.buf[cnt:] return res res = self.buf self.buf = b"" cnt -= len(res) # decrypt new data blklen = 16 while cnt > 0: enc = self.f.read(blklen) if len(enc) < blklen: break dec = self.ciph.decrypt(enc) if cnt >= len(dec): res += dec cnt -= len(dec) else: res += dec[:cnt] self.buf = dec[cnt:] cnt = 0 return res class XFile: """Input may be filename or file object. """ __slots__ = ("_fd", "_need_close") def __init__(self, xfile, bufsize=1024): if is_filelike(xfile): self._need_close = False self._fd = xfile self._fd.seek(0) else: self._need_close = True self._fd = open(xfile, "rb", bufsize) def read(self, n=None): """Read from file.""" return self._fd.read(n) def tell(self): """Return file pos.""" return self._fd.tell() def seek(self, ofs, whence=0): """Move file pos.""" return self._fd.seek(ofs, whence) def readinto(self, buf): """Read into buffer.""" return self._fd.readinto(buf) def close(self): """Close file object.""" if self._need_close: self._fd.close() def __enter__(self): return self def __exit__(self, typ, val, tb): self.close() class NoHashContext: """No-op hash function.""" def __init__(self, data=None): """Initialize""" def update(self, data): """Update data""" def digest(self): """Final hash""" def hexdigest(self): """Hexadecimal digest.""" class CRC32Context: """Hash context that uses CRC32.""" __slots__ = ["_crc"] def __init__(self, data=None): self._crc = 0 if data: self.update(data) def update(self, data): """Process data.""" self._crc = crc32(data, self._crc) def digest(self): """Final hash.""" return self._crc def hexdigest(self): """Hexadecimal digest.""" return "%08x" % self.digest() class Blake2SP: """Blake2sp hash context. """ __slots__ = ["_thread", "_buf", "_cur", "_digest"] digest_size = 32 block_size = 64 parallelism = 8 def __init__(self, data=None): self._buf = b"" self._cur = 0 self._digest = None self._thread = [] for i in range(self.parallelism): ctx = self._blake2s(i, 0, i == (self.parallelism - 1)) self._thread.append(ctx) if data: self.update(data) def _blake2s(self, ofs, depth, is_last): return blake2s(node_offset=ofs, node_depth=depth, last_node=is_last, depth=2, inner_size=32, fanout=self.parallelism) def _add_block(self, blk): self._thread[self._cur].update(blk) self._cur = (self._cur + 1) % self.parallelism def update(self, data): """Hash data. """ view = memoryview(data) bs = self.block_size if self._buf: need = bs - len(self._buf) if len(view) < need: self._buf += view.tobytes() return self._add_block(self._buf + view[:need].tobytes()) view = view[need:] while len(view) >= bs: self._add_block(view[:bs]) view = view[bs:] self._buf = view.tobytes() def digest(self): """Return final digest value. """ if self._digest is None: if self._buf: self._add_block(self._buf) self._buf = b"" ctx = self._blake2s(0, 1, True) for t in self._thread: ctx.update(t.digest()) self._digest = ctx.digest() return self._digest def hexdigest(self): """Hexadecimal digest.""" return hexlify(self.digest()).decode("ascii") class Rar3Sha1: """Emulate buggy SHA1 from RAR3. """ digest_size = 20 block_size = 64 _BLK_BE = struct.Struct(b">16L") _BLK_LE = struct.Struct(b"<16L") __slots__ = ("_nbytes", "_md", "_rarbug") def __init__(self, data=b"", rarbug=False): self._md = sha1() self._nbytes = 0 self._rarbug = rarbug self.update(data) def update(self, data): """Process more data.""" self._md.update(data) bufpos = self._nbytes & 63 self._nbytes += len(data) if self._rarbug and len(data) > 64: dpos = self.block_size - bufpos while dpos + self.block_size <= len(data): self._corrupt(data, dpos) dpos += self.block_size def digest(self): """Return final state.""" return self._md.digest() def hexdigest(self): """Return final state as hex string.""" return self._md.hexdigest() def _corrupt(self, data, dpos): """Corruption from SHA1 core.""" ws = list(self._BLK_BE.unpack_from(data, dpos)) for t in range(16, 80): tmp = ws[(t - 3) & 15] ^ ws[(t - 8) & 15] ^ ws[(t - 14) & 15] ^ ws[(t - 16) & 15] ws[t & 15] = ((tmp << 1) | (tmp >> (32 - 1))) & 0xFFFFFFFF self._BLK_LE.pack_into(data, dpos, *ws) ## ## Utility functions ## S_LONG = Struct(" len(buf): raise BadRarFile("cannot load byte") return S_BYTE.unpack_from(buf, pos)[0], end def load_le32(buf, pos): """Load little-endian 32-bit integer""" end = pos + 4 if end > len(buf): raise BadRarFile("cannot load le32") return S_LONG.unpack_from(buf, pos)[0], end def load_bytes(buf, num, pos): """Load sequence of bytes""" end = pos + num if end > len(buf): raise BadRarFile("cannot load bytes") return buf[pos: end], end def load_vstr(buf, pos): """Load bytes prefixed by vint length""" slen, pos = load_vint(buf, pos) return load_bytes(buf, slen, pos) def load_dostime(buf, pos): """Load LE32 dos timestamp""" stamp, pos = load_le32(buf, pos) tup = parse_dos_time(stamp) return to_datetime(tup), pos def load_unixtime(buf, pos): """Load LE32 unix timestamp""" secs, pos = load_le32(buf, pos) dt = datetime.fromtimestamp(secs, timezone.utc) return dt, pos def load_windowstime(buf, pos): """Load LE64 windows timestamp""" # unix epoch (1970) in seconds from windows epoch (1601) unix_epoch = 11644473600 val1, pos = load_le32(buf, pos) val2, pos = load_le32(buf, pos) secs, n1secs = divmod((val2 << 32) | val1, 10000000) dt = datetime.fromtimestamp(secs - unix_epoch, timezone.utc) dt = to_nsdatetime(dt, n1secs * 100) return dt, pos # # volume numbering # _rc_num = re.compile('^[0-9]+$') def _next_newvol(volfile): """New-style next volume """ name, ext = os.path.splitext(volfile) if ext.lower() in ("", ".exe", ".sfx"): volfile = name + ".rar" i = len(volfile) - 1 while i >= 0: if "0" <= volfile[i] <= "9": return _inc_volname(volfile, i, False) if volfile[i] in ("/", os.sep): break i -= 1 raise BadRarName("Cannot construct volume name: " + volfile) def _next_oldvol(volfile): """Old-style next volume """ name, ext = os.path.splitext(volfile) if ext.lower() in ("", ".exe", ".sfx"): ext = ".rar" sfx = ext[2:] if _rc_num.match(sfx): ext = _inc_volname(ext, len(ext) - 1, True) else: # .rar -> .r00 ext = ext[:2] + "00" return name + ext def _inc_volname(volfile, i, inc_chars): """increase digits with carry, otherwise just increment char """ fn = list(volfile) while i >= 0: if fn[i] == "9": fn[i] = "0" i -= 1 if i < 0: fn.insert(0, "1") elif "0" <= fn[i] < "9" or inc_chars: fn[i] = chr(ord(fn[i]) + 1) break else: fn.insert(i + 1, "1") break return "".join(fn) def _parse_ext_time(h, data, pos): """Parse all RAR3 extended time fields """ # flags and rest of data can be missing flags = 0 if pos + 2 <= len(data): flags = S_SHORT.unpack_from(data, pos)[0] pos += 2 mtime, pos = _parse_xtime(flags >> 3 * 4, data, pos, h.mtime) h.ctime, pos = _parse_xtime(flags >> 2 * 4, data, pos) h.atime, pos = _parse_xtime(flags >> 1 * 4, data, pos) h.arctime, pos = _parse_xtime(flags >> 0 * 4, data, pos) if mtime: h.mtime = mtime h.date_time = mtime.timetuple()[:6] return pos def _parse_xtime(flag, data, pos, basetime=None): """Parse one RAR3 extended time field """ res = None if flag & 8: if not basetime: basetime, pos = load_dostime(data, pos) # load second fractions of 100ns units rem = 0 cnt = flag & 3 for _ in range(cnt): b, pos = load_byte(data, pos) rem = (b << 16) | (rem >> 8) # dostime has room for 30 seconds only, correct if needed if flag & 4 and basetime.second < 59: basetime = basetime.replace(second=basetime.second + 1) res = to_nsdatetime(basetime, rem * 100) return res, pos def is_filelike(obj): """Filename or file object? """ if isinstance(obj, (bytes, str, Path)): return False res = True for a in ("read", "tell", "seek"): res = res and hasattr(obj, a) if not res: raise ValueError("Invalid object passed as file") return True def rar3_s2k(pwd, salt): """String-to-key hash for RAR3. """ if not isinstance(pwd, str): pwd = pwd.decode("utf8") seed = bytearray(pwd.encode("utf-16le") + salt) h = Rar3Sha1(rarbug=True) iv = b"" for i in range(16): for j in range(0x4000): cnt = S_LONG.pack(i * 0x4000 + j) h.update(seed) h.update(cnt[:3]) if j == 0: iv += h.digest()[19:20] key_be = h.digest()[:16] key_le = pack("LLLL", key_be)) return key_le, iv def rar3_decompress(vers, meth, data, declen=0, flags=0, crc=0, pwd=None, salt=None): """Decompress blob of compressed data. Used for data with non-standard header - eg. comments. """ # already uncompressed? if meth == RAR_M0 and (flags & RAR_FILE_PASSWORD) == 0: return data # take only necessary flags flags = flags & (RAR_FILE_PASSWORD | RAR_FILE_SALT | RAR_FILE_DICTMASK) flags |= RAR_LONG_BLOCK # file header fname = b"data" date = ((2010 - 1980) << 25) + (12 << 21) + (31 << 16) mode = DOS_MODE_ARCHIVE fhdr = S_FILE_HDR.pack(len(data), declen, RAR_OS_MSDOS, crc, date, vers, meth, len(fname), mode) fhdr += fname if salt: fhdr += salt # full header hlen = S_BLK_HDR.size + len(fhdr) hdr = S_BLK_HDR.pack(0, RAR_BLOCK_FILE, flags, hlen) + fhdr hcrc = crc32(hdr[2:]) & 0xFFFF hdr = S_BLK_HDR.pack(hcrc, RAR_BLOCK_FILE, flags, hlen) + fhdr # archive main header mh = S_BLK_HDR.pack(0x90CF, RAR_BLOCK_MAIN, 0, 13) + b"\0" * (2 + 4) # decompress via temp rar setup = tool_setup() tmpfd, tmpname = mkstemp(suffix=".rar", dir=HACK_TMP_DIR) tmpf = os.fdopen(tmpfd, "wb") try: tmpf.write(RAR_ID + mh + hdr + data) tmpf.close() curpwd = (flags & RAR_FILE_PASSWORD) and pwd or None cmd = setup.open_cmdline(curpwd, tmpname) p = custom_popen(cmd) return p.communicate()[0] finally: tmpf.close() os.unlink(tmpname) def sanitize_filename(fname, pathsep, is_win32): """Simulate unrar sanitization. """ if is_win32: if len(fname) > 1 and fname[1] == ":": fname = fname[2:] rc = RC_BAD_CHARS_WIN32 else: rc = RC_BAD_CHARS_UNIX if rc.search(fname): fname = rc.sub("_", fname) parts = [] for seg in fname.split("/"): if seg in ("", ".", ".."): continue if is_win32 and seg[-1] in (" ", "."): seg = seg[:-1] + "_" parts.append(seg) return pathsep.join(parts) def empty_read(src, size, blklen): """Read and drop fixed amount of data. """ while size > 0: if size > blklen: res = src.read(blklen) else: res = src.read(size) if not res: raise BadRarFile("cannot load data") size -= len(res) def to_datetime(t): """Convert 6-part time tuple into datetime object. """ # extract values year, mon, day, h, m, s = t # assume the values are valid try: return datetime(year, mon, day, h, m, s) except ValueError: pass # sanitize invalid values mday = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) mon = max(1, min(mon, 12)) day = max(1, min(day, mday[mon])) h = min(h, 23) m = min(m, 59) s = min(s, 59) return datetime(year, mon, day, h, m, s) def parse_dos_time(stamp): """Parse standard 32-bit DOS timestamp. """ sec, stamp = stamp & 0x1F, stamp >> 5 mn, stamp = stamp & 0x3F, stamp >> 6 hr, stamp = stamp & 0x1F, stamp >> 5 day, stamp = stamp & 0x1F, stamp >> 5 mon, stamp = stamp & 0x0F, stamp >> 4 yr = (stamp & 0x7F) + 1980 return (yr, mon, day, hr, mn, sec * 2) # pylint: disable=arguments-differ,signature-differs class nsdatetime(datetime): """Datetime that carries nanoseconds. Arithmetic not supported, will lose nanoseconds. .. versionadded:: 4.0 """ __slots__ = ("nanosecond",) nanosecond: int #: Number of nanoseconds, 0 <= nanosecond < 999999999 def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0, nanosecond=0): usec, mod = divmod(nanosecond, 1000) if nanosecond else (microsecond, 0) if mod == 0: return datetime(year, month, day, hour, minute, second, usec, tzinfo, fold=fold) self = super().__new__(cls, year, month, day, hour, minute, second, usec, tzinfo, fold=fold) self.nanosecond = nanosecond return self def isoformat(self, sep="T", timespec="auto"): """Formats with nanosecond precision by default. """ if timespec == "auto": pre, post = super().isoformat(sep, "microseconds").split(".", 1) return f"{pre}.{self.nanosecond:09d}{post[6:]}" return super().isoformat(sep, timespec) def astimezone(self, tz=None): """Convert to new timezone. """ tmp = super().astimezone(tz) return self.__class__(tmp.year, tmp.month, tmp.day, tmp.hour, tmp.minute, tmp.second, nanosecond=self.nanosecond, tzinfo=tmp.tzinfo, fold=tmp.fold) def replace(self, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, tzinfo=None, *, fold=None, nanosecond=None): """Return new timestamp with specified fields replaced. """ return self.__class__( self.year if year is None else year, self.month if month is None else month, self.day if day is None else day, self.hour if hour is None else hour, self.minute if minute is None else minute, self.second if second is None else second, nanosecond=((self.nanosecond if microsecond is None else microsecond * 1000) if nanosecond is None else nanosecond), tzinfo=self.tzinfo if tzinfo is None else tzinfo, fold=self.fold if fold is None else fold) def __hash__(self): return hash((super().__hash__(), self.nanosecond)) if self.nanosecond else super().__hash__() def __eq__(self, other): return super().__eq__(other) and self.nanosecond == ( other.nanosecond if isinstance(other, nsdatetime) else other.microsecond * 1000) def __gt__(self, other): return super().__gt__(other) or (super().__eq__(other) and self.nanosecond > ( other.nanosecond if isinstance(other, nsdatetime) else other.microsecond * 1000)) def __lt__(self, other): return not (self > other or self == other) def __ge__(self, other): return not self < other def __le__(self, other): return not self > other def __ne__(self, other): return not self == other def to_nsdatetime(dt, nsec): """Apply nanoseconds to datetime. """ if not nsec: return dt return nsdatetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, tzinfo=dt.tzinfo, fold=dt.fold, nanosecond=nsec) def to_nsecs(dt): """Convert datatime instance to nanoseconds. """ secs = int(dt.timestamp()) nsecs = dt.nanosecond if isinstance(dt, nsdatetime) else dt.microsecond * 1000 return secs * 1000000000 + nsecs def custom_popen(cmd): """Disconnect cmd from parent fds, read only from stdout. """ creationflags = 0x08000000 if WIN32 else 0 # CREATE_NO_WINDOW try: p = Popen(cmd, bufsize=0, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL, creationflags=creationflags) except OSError as ex: if ex.errno == errno.ENOENT: raise RarCannotExec("Unrar not installed?") from None if ex.errno == errno.EACCES or ex.errno == errno.EPERM: raise RarCannotExec("Cannot execute unrar") from None raise return p def check_returncode(code, out, errmap): """Raise exception according to unrar exit code. """ if code == 0: return if code > 0 and code < len(errmap): exc = errmap[code] elif code == 255: exc = RarUserBreak elif code < 0: exc = RarSignalExit else: exc = RarUnknownError # format message if out: msg = "%s [%d]: %s" % (exc.__doc__, code, out) else: msg = "%s [%d]" % (exc.__doc__, code) raise exc(msg) def membuf_tempfile(memfile): """Write in-memory file object to real file. """ memfile.seek(0, 0) tmpfd, tmpname = mkstemp(suffix=".rar", dir=HACK_TMP_DIR) tmpf = os.fdopen(tmpfd, "wb") try: shutil.copyfileobj(memfile, tmpf, BSIZE) tmpf.close() except BaseException: tmpf.close() os.unlink(tmpname) raise return tmpname # # Find working command-line tool # class ToolSetup: def __init__(self, setup): self.setup = setup def check(self): cmdline = self.get_cmdline("check_cmd", None) try: p = custom_popen(cmdline) out, _ = p.communicate() return p.returncode == 0 except RarCannotExec: return False def open_cmdline(self, pwd, rarfn, filefn=None): cmdline = self.get_cmdline("open_cmd", pwd) cmdline.append(rarfn) if filefn: self.add_file_arg(cmdline, filefn) return cmdline def get_errmap(self): return self.setup["errmap"] def get_cmdline(self, key, pwd, nodash=False): cmdline = list(self.setup[key]) cmdline[0] = globals()[cmdline[0]] if key == "check_cmd": return cmdline self.add_password_arg(cmdline, pwd) if not nodash: cmdline.append("--") return cmdline def add_file_arg(self, cmdline, filename): cmdline.append(filename) def add_password_arg(self, cmdline, pwd): """Append password switch to commandline. """ if pwd is not None: if not isinstance(pwd, str): pwd = pwd.decode("utf8") args = self.setup["password"] if args is None: tool = self.setup["open_cmd"][0] raise RarCannotExec(f"{tool} does not support passwords") elif isinstance(args, str): cmdline.append(args + pwd) else: cmdline.extend(args) cmdline.append(pwd) else: cmdline.extend(self.setup["no_password"]) UNRAR_CONFIG = { "open_cmd": ("UNRAR_TOOL", "p", "-inul"), "check_cmd": ("UNRAR_TOOL", "-inul"), "password": "-p", "no_password": ("-p-",), # map return code to exception class, codes from rar.txt "errmap": [None, RarWarning, RarFatalError, RarCRCError, RarLockedArchiveError, # 1..4 RarWriteError, RarOpenError, RarUserError, RarMemoryError, # 5..8 RarCreateError, RarNoFilesError, RarWrongPassword] # 9..11 } # Problems with unar RAR backend: # - Does not support RAR2 locked files [fails to read] # - Does not support RAR5 Blake2sp hash [reading works] UNAR_CONFIG = { "open_cmd": ("UNAR_TOOL", "-q", "-o", "-"), "check_cmd": ("UNAR_TOOL", "-version"), "password": ("-p",), "no_password": ("-p", ""), "errmap": [None], } # Problems with libarchive RAR backend: # - Does not support solid archives. # - Does not support password-protected archives. # - Does not support RARVM-based compression filters. BSDTAR_CONFIG = { "open_cmd": ("BSDTAR_TOOL", "-x", "--to-stdout", "-f"), "check_cmd": ("BSDTAR_TOOL", "--version"), "password": None, "no_password": (), "errmap": [None], } SEVENZIP_CONFIG = { "open_cmd": ("SEVENZIP_TOOL", "e", "-so", "-bb0"), "check_cmd": ("SEVENZIP_TOOL", "i"), "password": "-p", "no_password": ("-p",), "errmap": [None, RarWarning, RarFatalError, None, None, # 1..4 None, None, RarUserError, RarMemoryError] # 5..8 } SEVENZIP2_CONFIG = { "open_cmd": ("SEVENZIP2_TOOL", "e", "-so", "-bb0"), "check_cmd": ("SEVENZIP2_TOOL", "i"), "password": "-p", "no_password": ("-p",), "errmap": [None, RarWarning, RarFatalError, None, None, # 1..4 None, None, RarUserError, RarMemoryError] # 5..8 } CURRENT_SETUP = None def tool_setup(unrar=True, unar=True, bsdtar=True, sevenzip=True, sevenzip2=True, force=False): """Pick a tool, return cached ToolSetup. """ global CURRENT_SETUP if force: CURRENT_SETUP = None if CURRENT_SETUP is not None: return CURRENT_SETUP lst = [] if unrar: lst.append(UNRAR_CONFIG) if unar: lst.append(UNAR_CONFIG) if sevenzip: lst.append(SEVENZIP_CONFIG) if sevenzip2: lst.append(SEVENZIP2_CONFIG) if bsdtar: lst.append(BSDTAR_CONFIG) for conf in lst: setup = ToolSetup(conf) if setup.check(): CURRENT_SETUP = setup break if CURRENT_SETUP is None: raise RarCannotExec("Cannot find working tool") return CURRENT_SETUP def main(args): """Minimal command-line interface for rarfile module. """ import argparse p = argparse.ArgumentParser(description=main.__doc__) g = p.add_mutually_exclusive_group(required=True) g.add_argument("-l", "--list", metavar="", help="Show archive listing") g.add_argument("-e", "--extract", nargs=2, metavar=("", ""), help="Extract archive into target dir") g.add_argument("-t", "--test", metavar="", help="Test if a archive is valid") cmd = p.parse_args(args) if cmd.list: with RarFile(cmd.list) as rf: rf.printdir() elif cmd.test: with RarFile(cmd.test) as rf: rf.testrar() elif cmd.extract: with RarFile(cmd.extract[0]) as rf: rf.extractall(cmd.extract[1]) if __name__ == "__main__": main(sys.argv[1:]) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3975348 rarfile-4.1/setup.cfg0000644000175100001770000000014314501653017014230 0ustar00runnerdocker[bdist_wheel] universal = 0 [tool:pytest] testpaths = test [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/setup.py0000644000175100001770000000177114501653005014126 0ustar00runnerdocker"""Setup script for rarfile. """ import re from setuptools import setup vrx = r"""^__version__ *= *['"]([^'"]+)['"]""" src = open("rarfile.py").read() ver = re.search(vrx, src, re.M).group(1) ldesc = open("README.rst").read().strip() sdesc = ldesc.split('\n')[0].split(' - ')[1].strip() setup( name="rarfile", version=ver, description=sdesc, long_description=ldesc, author="Marko Kreen", license="ISC", author_email="markokr@gmail.com", url="https://github.com/markokr/rarfile", py_modules=['rarfile'], keywords=['rar', 'unrar', 'archive'], python_requires=">=3.6", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: ISC License (ISCL)", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Archiving :: Compression", ] ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3855345 rarfile-4.1/test/0000755000175100001770000000000014501653017013370 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/__init__.py0000644000175100001770000000000114501653005015465 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1694979599.3975348 rarfile-4.1/test/files/0000755000175100001770000000000014501653017014472 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime0.rar0000644000175100001770000000011114501653005016347 0ustar00runnerdockerRar!ϐs It .>0 afile.txt:={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime0.rar.exp0000644000175100001770000000040214501653005017145 0ustar00runnerdockerArchive: test/files/ctime0.rar FILE: hdrlen=46 datlen=0 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2011-05-10 21:28:47 name=afile.txt mtime=2011-05-10T21:28:47.899345100 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime1.rar0000644000175100001770000000011514501653005016354 0ustar00runnerdockerRar!ϐs t 2>0 afile.txt:>={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime1.rar.exp0000644000175100001770000000043614501653005017155 0ustar00runnerdockerArchive: test/files/ctime1.rar FILE: hdrlen=50 datlen=0 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2011-05-10 21:28:47 name=afile.txt mtime=2011-05-10T21:28:47.899345100 ctime=2011-05-10T21:28:47 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime2.rar0000644000175100001770000000011614501653005016356 0ustar00runnerdockerRar!ϐs ҅t 3>0 afile.txt:>={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime2.rar.exp0000644000175100001770000000045014501653005017152 0ustar00runnerdockerArchive: test/files/ctime2.rar FILE: hdrlen=51 datlen=0 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2011-05-10 21:28:47 name=afile.txt mtime=2011-05-10T21:28:47.899345100 ctime=2011-05-10T21:28:47.897843200 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime3.rar0000644000175100001770000000011714501653005016360 0ustar00runnerdockerRar!ϐs vt 4>0 afile.txt:>:={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime3.rar.exp0000644000175100001770000000044514501653005017157 0ustar00runnerdockerArchive: test/files/ctime3.rar FILE: hdrlen=52 datlen=0 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2011-05-10 21:28:47 name=afile.txt mtime=2011-05-10T21:28:47.899345100 ctime=2011-05-10T21:28:47.899328 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime4.rar0000644000175100001770000000012014501653005016353 0ustar00runnerdockerRar!ϐs t 5>0 afile.txt:>:={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime4.rar.exp0000644000175100001770000000045014501653005017154 0ustar00runnerdockerArchive: test/files/ctime4.rar FILE: hdrlen=53 datlen=0 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2011-05-10 21:28:47 name=afile.txt mtime=2011-05-10T21:28:47.899345100 ctime=2011-05-10T21:28:47.899345100 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime5.rar0000644000175100001770000000013514501653005016362 0ustar00runnerdockerRar!3 |7G_ timed.txt-#_c-#_-#_d(=P9t wVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/ctime5.rar.exp0000644000175100001770000000066514501653005017165 0ustar00runnerdockerArchive: test/files/ctime5.rar R5_FILE: hdrlen=60 datlen=2 hdr_extra=27 is=F-- block_flags=0x0003:EXTRA,DATA name=timed.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=2 dec=2 vol=0 crc=0xea5f4713 (3932112659) date_time=2020-07-30 20:26:59 mtime=2020-07-30T20:26:59.677675904+00:00 ctime=2020-07-30T20:28:19.398867888+00:00 atime=2020-07-30T20:27:10.121196721+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar15-comment-lock.rar0000644000175100001770000000032214501653005020512 0ustar00runnerdockerRar!@s,bu4J]4@tH0c=3 FILE1.TXTu0file1comment -----ztHC<3c=0 FILE2.TXT'u0pfile2comment -----baaaar ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar15-comment-lock.rar.exp0000644000175100001770000000102014501653005021301 0ustar00runnerdockerArchive: test/files/rar15-comment-lock.rar comment='RARcomment -----' FILE: hdrlen=72 datlen=7 is=F-- flags=0x8008:COMMENT,LONG,D64 os=0:DOS ver=15 mode=ARCHIVE meth=3 cmp=7 dec=7 vol=0 crc=0xe27f07a9 (3799975849) date_time=2010-11-03 19:49:32 name=FILE1.TXT comment='file1comment -----' FILE: hdrlen=72 datlen=8 is=F-- flags=0x8008:COMMENT,LONG,D64 os=0:DOS ver=15 mode=ARCHIVE meth=0 cmp=8 dec=8 vol=0 crc=0x3c4306f7 (1011025655) date_time=2010-11-03 19:49:38 name=FILE2.TXT comment='file2comment -----' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar15-comment.rar0000644000175100001770000000032214501653005017564 0ustar00runnerdockerRar!:"s,bu4J]4@tH0c=3 FILE1.TXTu0file1comment -----ztHC<3c=0 FILE2.TXT'u0pfile2comment -----baaaar ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar15-comment.rar.exp0000644000175100001770000000101314501653005020355 0ustar00runnerdockerArchive: test/files/rar15-comment.rar comment='RARcomment -----' FILE: hdrlen=72 datlen=7 is=F-- flags=0x8008:COMMENT,LONG,D64 os=0:DOS ver=15 mode=ARCHIVE meth=3 cmp=7 dec=7 vol=0 crc=0xe27f07a9 (3799975849) date_time=2010-11-03 19:49:32 name=FILE1.TXT comment='file1comment -----' FILE: hdrlen=72 datlen=8 is=F-- flags=0x8008:COMMENT,LONG,D64 os=0:DOS ver=15 mode=ARCHIVE meth=0 cmp=8 dec=8 vol=0 crc=0x3c4306f7 (1011025655) date_time=2010-11-03 19:49:38 name=FILE2.TXT comment='file2comment -----' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar202-comment-nopsw.rar0000644000175100001770000000031414501653005021007 0ustar00runnerdockerRar!s3u& 4PL m+mtB}znc=0 FILE1.TXT!Qu 0Yfile1commentfile1 X/tB_xqc=0 FILE2.TXTdu 0=^file2commentfile2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar202-comment-nopsw.rar.exp0000644000175100001770000000100014501653005021573 0ustar00runnerdockerArchive: test/files/rar202-comment-nopsw.rar comment='RARcomment' FILE: hdrlen=66 datlen=7 is=F-- flags=0x8008:COMMENT,LONG,D64 os=0:DOS ver=20 mode=ARCHIVE meth=0 cmp=7 dec=7 vol=0 crc=0x7a197dba (2048490938) date_time=2010-11-03 00:27:28 name=FILE1.TXT comment='file1comment' FILE: hdrlen=66 datlen=7 is=F-- flags=0x8008:COMMENT,LONG,D64 os=0:DOS ver=20 mode=ARCHIVE meth=0 cmp=7 dec=7 vol=0 crc=0x785fc3e3 (2019541987) date_time=2010-11-03 00:27:34 name=FILE2.TXT comment='file2comment' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar202-comment-psw.rar0000644000175100001770000000037614501653005020462 0ustar00runnerdockerRar!s3u& 4PL m+t B }znc=3 FILE1.TXT!Qu 0Yfile1commentS}~s+*L-5g5/Ƽ%t B _xqc=3 FILE2.TXTdu 0=^file2commentӐCԿyZ|-Iַw^././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar202-comment-psw.rar.exp0000644000175100001770000000102414501653005021244 0ustar00runnerdockerArchive: test/files/rar202-comment-psw.rar comment='RARcomment' FILE: hdrlen=66 datlen=32 is=F-- flags=0x800c:PASSWORD,COMMENT,LONG,D64 os=0:DOS ver=20 mode=ARCHIVE meth=3 cmp=32 dec=7 vol=0 crc=0x7a197dba (2048490938) date_time=2010-11-03 00:27:28 name=FILE1.TXT comment='file1comment' FILE: hdrlen=66 datlen=32 is=F-- flags=0x800c:PASSWORD,COMMENT,LONG,D64 os=0:DOS ver=20 mode=ARCHIVE meth=3 cmp=32 dec=7 vol=0 crc=0x785fc3e3 (2019541987) date_time=2010-11-03 00:27:34 name=FILE2.TXT comment='file2comment' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-comment-hpsw.rar0000644000175100001770000000074414501653005020470 0ustar00runnerdockerRar!Ιs :zT$pzs!))@5r=@.a 1[>$咐&dA.B."P]L\r?w ZJ: :zY$HD&VmȗYOA j 4q[idsYnwR5{20t^(:zt5?Na&4Έ6 [U6Zɨx$WtBb);ޚ{xa.Y ɂY! 'Sɘ:z!IʡZZYwQwbAML1ךa YN9(8$Q=wR5{20t^(:z+>Z!4-&X)0mY="s4&O MfgŲt}D.)p7F:z.΅gjd|././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-comment-hpsw.rar.exp0000644000175100001770000000111714501653005021256 0ustar00runnerdockerArchive: test/files/rar3-comment-hpsw.rar comment='RARcomment\n' FILE: hdrlen=51 datlen=16 is=F-- flags=0x9424:PASSWORD,SALT,EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=3 cmp=16 dec=0 vol=0 crc=0x00000000 (0) date_time=2010-11-02 10:03:25 name=file1.txt mtime=2010-11-02T10:03:25 comment='Comment1v2\n' FILE: hdrlen=51 datlen=16 is=F-- flags=0x9424:PASSWORD,SALT,EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=3 cmp=16 dec=0 vol=0 crc=0x00000000 (0) date_time=2010-11-02 10:03:25 name=file2.txt mtime=2010-11-02T10:03:25 comment='Comment2v2\n' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-comment-plain.rar0000644000175100001770000000045414501653005020610 0ustar00runnerdockerRar!ϐs ҙz# Pu3CMT VH)kjvz t +lPb=3 file1.txtgAz# H?o3CMT 6V,x&oԋ½st +lPb=3 file2.txtg|z# 3CMTsAH'끏W*={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-comment-plain.rar.exp0000644000175100001770000000106014501653005021375 0ustar00runnerdockerArchive: test/files/rar3-comment-plain.rar comment='RARcomment\n' FILE: hdrlen=43 datlen=8 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=3 cmp=8 dec=0 vol=0 crc=0x00000000 (0) date_time=2010-11-02 10:03:25 name=file1.txt mtime=2010-11-02T10:03:25 comment='Comment1v2\n' FILE: hdrlen=43 datlen=8 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=3 cmp=8 dec=0 vol=0 crc=0x00000000 (0) date_time=2010-11-02 10:03:25 name=file2.txt mtime=2010-11-02T10:03:25 comment='Comment2v2\n' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-comment-psw.rar0000644000175100001770000000051414501653005020313 0ustar00runnerdockerRar!ϐs ҙz# Pu3CMT VH)kjvzmt$3lPb=3 file1.txt/e'1xlmMjmAz# H?o3CMT 6V,x&oԋ½t$3lPb=3 file2.txt/e'1xlmMjm|z# 3CMTsAH'끏W*={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-comment-psw.rar.exp0000644000175100001770000000111614501653005021105 0ustar00runnerdockerArchive: test/files/rar3-comment-psw.rar comment='RARcomment\n' FILE: hdrlen=51 datlen=16 is=F-- flags=0x9424:PASSWORD,SALT,EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=3 cmp=16 dec=0 vol=0 crc=0x00000000 (0) date_time=2010-11-02 10:03:25 name=file1.txt mtime=2010-11-02T10:03:25 comment='Comment1v2\n' FILE: hdrlen=51 datlen=16 is=F-- flags=0x9424:PASSWORD,SALT,EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=3 cmp=16 dec=0 vol=0 crc=0x00000000 (0) date_time=2010-11-02 10:03:25 name=file2.txt mtime=2010-11-02T10:03:25 comment='Comment2v2\n' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-old.r000000644000175100001770000031000014501653005016427 0ustar00runnerdockerRar!s  t#2 PR]H0vols\bigfile.txt 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 x]{@?@O././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-old.r010000644000175100001770000000501414501653005016436 0ustar00runnerdockerRar!s 5t!2| LךPR]H0vols\bigfile.txt 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 Xt 4U]H0vols\smallfile.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 {@`c././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-old.rar0000644000175100001770000031000014501653005016612 0ustar00runnerdockerRar!s ct"2 g R]H0vols\bigfile.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 H{@5././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-old.rar.exp0000644000175100001770000000104114501653005017407 0ustar00runnerdockerArchive: test/files/rar3-old.rar FILE: hdrlen=50 datlen=102310 is=F-- flags=0x9022:SPLIT_AFTER,EXTTIME,LONG,D128 os=3:UNIX ver=20 mode=-rw-rw-r-- meth=0 cmp=205000 dec=205000 vol=0 crc=0x509ad74c (1352324940) date_time=2016-05-24 11:42:37 name=vols/bigfile.txt mtime=2016-05-24T11:42:37 FILE: hdrlen=52 datlen=2050 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=20 mode=-rw-rw-r-- meth=0 cmp=2050 dec=2050 vol=2 crc=0xd08a1f86 (3498712966) date_time=2016-05-24 11:42:43 name=vols/smallfile.txt mtime=2016-05-24T11:42:43 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-owner.rar0000644000175100001770000000024714501653005017177 0ustar00runnerdockerRar!ϐs Mdt /SQgP0 owner1.txtխ71 z*CP0UOWbinsyst /|LP0 owner2.txt> 52 ={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-owner.rar.exp0000644000175100001770000000100214501653005017760 0ustar00runnerdockerArchive: test/files/rar3-owner.rar FILE: hdrlen=47 datlen=2 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=2 dec=2 vol=0 crc=0x6751fc53 (1733426259) date_time=2020-07-30 22:48:11 name=owner1.txt mtime=2020-07-30T22:48:11.364898100 FILE: hdrlen=47 datlen=2 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=2 dec=2 vol=0 crc=0x4c7caf90 (1283239824) date_time=2020-07-30 22:48:16 name=owner2.txt mtime=2020-07-30T22:48:16.347603 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-readonly-unix.rar0000644000175100001770000000020614501653005020636 0ustar00runnerdockerRar!ϐs fkt 7 v"uP0$ro_dir\ro_file.txt/readonly t+uP0mAro_dir$2={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-readonly-unix.rar.exp0000644000175100001770000000100514501653005021427 0ustar00runnerdockerArchive: test/files/rar3-readonly-unix.rar FILE: hdrlen=55 datlen=9 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-r--r--r-- meth=0 cmp=9 dec=9 vol=0 crc=0x818d2276 (2173510262) date_time=2020-07-26 22:11:42 name=ro_dir/ro_file.txt mtime=2020-07-26T22:11:42.312616300 FILE: hdrlen=43 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=dr-xr-xr-x meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-26 22:11:42 name=ro_dir/ mtime=2020-07-26T22:11:42.328617 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-readonly-win.rar0000644000175100001770000000020614501653005020450 0ustar00runnerdockerRar!ϐs t 7 v"uP0!ro_dir\ro_file.txt/readonly qGt+uP0ro_dir$2={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-readonly-win.rar.exp0000644000175100001770000000102014501653005021236 0ustar00runnerdockerArchive: test/files/rar3-readonly-win.rar FILE: hdrlen=55 datlen=9 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=READONLY,ARCHIVE meth=0 cmp=9 dec=9 vol=0 crc=0x818d2276 (2173510262) date_time=2020-07-26 22:11:42 name=ro_dir/ro_file.txt mtime=2020-07-26T22:11:42.312616300 FILE: hdrlen=43 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=2:WIN ver=20 mode=READONLY,DIRECTORY meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-26 22:11:42 name=ro_dir/ mtime=2020-07-26T22:11:42.328617 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-seektest.sfx0000644000175100001770000262221514501653005017717 0ustar00runnerdockerRar!ϐs t ,ZŰf>5 stest1.txt ޯ_5uefVH,WF@0 stest2.txt000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 ={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-subdirs.rar0000644000175100001770000000113614501653005017516 0ustar00runnerdockerRar!ϐs t 7Ǥ6P0sub\dir2\file2.txt|0file2 Qt ?}$qHP0sub\with space\long fn.txtGLlong fn #t W/P02sub\üȵĩöḋè\file.txt5) \file.txtrfile \t 7)0P0sub\dir1\file1.txtfile1 ut-6P0Asub\dir2&3t3HP0Asub\with spaceNt.$P0 Asub\emptypGtCP0Asub\üȵĩöḋè5) 4vkt-0P0Asub\dir1XRt(ըP0Asub$={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-subdirs.rar.exp0000644000175100001770000000466014501653005020316 0ustar00runnerdockerArchive: test/files/rar3-subdirs.rar FILE: hdrlen=55 datlen=6 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=6 dec=6 vol=0 crc=0xc904a4c7 (3372524743) date_time=2020-07-20 21:01:44 name=sub/dir2/file2.txt mtime=2020-07-20T21:01:44.319218800 FILE: hdrlen=63 datlen=8 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=8 dec=8 vol=0 crc=0x71b7247d (1907827837) date_time=2020-07-20 21:02:17 name=sub/with space/long fn.txt mtime=2020-07-20T21:02:17.499892 FILE: hdrlen=87 datlen=5 is=F-- flags=0x9220:UNICODE,EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=5 dec=5 vol=0 namecmp=26/50 crc=0x2fec89c1 (804030913) date_time=2020-07-20 21:07:00 name=sub/üȵĩöḋè/file.txt mtime=2020-07-20T21:07:00.141758600 FILE: hdrlen=55 datlen=6 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=6 dec=6 vol=0 crc=0xe229f704 (3794401028) date_time=2020-07-20 21:01:33 name=sub/dir1/file1.txt mtime=2020-07-20T21:01:33.875008200 FILE: hdrlen=45 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=drwxr-xr-x meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-20 21:01:44 name=sub/dir2/ mtime=2020-07-20T21:01:44.335219100 FILE: hdrlen=51 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=drwxr-xr-x meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-20 21:02:17 name=sub/with space/ mtime=2020-07-20T21:02:17.511892300 FILE: hdrlen=46 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=drwxr-xr-x meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-20 21:01:09 name=sub/empty/ mtime=2020-07-20T21:01:09.182513600 FILE: hdrlen=67 datlen=0 is=-D- flags=0x92e0:UNICODE,EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=drwxr-xr-x meth=0 cmp=0 dec=0 vol=0 namecmp=17/30 crc=0x00000000 (0) date_time=2020-07-20 21:07:00 name=sub/üȵĩöḋè/ mtime=2020-07-20T21:07:00.153758800 FILE: hdrlen=45 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=drwxr-xr-x meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-20 21:01:33 name=sub/dir1/ mtime=2020-07-20T21:01:33.887008500 FILE: hdrlen=40 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=3:UNIX ver=20 mode=drwxr-xr-x meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-20 21:06:42 name=sub/ mtime=2020-07-20T21:06:42.241383800 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-symlink-unix.rar0000644000175100001770000000027714501653005020517 0ustar00runnerdockerRar!ϐs &t. y8P0 data_link$data.txt֜t-氹P0data.txtVdata Tct0 vP0 random_link~Έ../random123={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-symlink-unix.rar.exp0000644000175100001770000000140114501653005021300 0ustar00runnerdockerArchive: test/files/rar3-symlink-unix.rar FILE: hdrlen=46 datlen=8 is=--L flags=0x90c0:EXTTIME,LONG,D4096 os=3:UNIX ver=20 mode=lrwxrwxrwx meth=0 cmp=8 dec=8 vol=0 crc=0x8b387909 (2335734025) date_time=2020-07-26 23:13:58 name=data_link mtime=2020-07-26T23:13:58.125453100 FILE: hdrlen=45 datlen=5 is=F-- flags=0x90c0:EXTTIME,LONG,D4096 os=3:UNIX ver=29 mode=-rw-rw-r-- meth=0 cmp=5 dec=5 vol=0 crc=0xe6c1c582 (3871458690) date_time=2020-07-26 23:13:33 name=data.txt mtime=2020-07-26T23:13:33.568312800 FILE: hdrlen=48 datlen=12 is=--L flags=0x90c0:EXTTIME,LONG,D4096 os=3:UNIX ver=20 mode=lrwxrwxrwx meth=0 cmp=12 dec=12 vol=0 crc=0xcfb67605 (3484841477) date_time=2020-07-26 23:32:08 name=random_link mtime=2020-07-26T23:32:08.896575800 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-versions.rar0000644000175100001770000000027314501653005017714 0ustar00runnerdockerRar!ϐs \t 4SQgP0versioned.txt;1<1 t 4|LP0versioned.txt;2?2 1(t 2ўgUP0 versioned.txtB3 ={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-versions.rar.exp0000644000175100001770000000043214501653005020504 0ustar00runnerdockerArchive: test/files/rar3-versions.rar FILE: hdrlen=50 datlen=2 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=0 cmp=2 dec=2 vol=0 crc=0x55679ed1 (1432854225) date_time=2020-07-30 22:52:46 name=versioned.txt mtime=2020-07-30T22:52:46.436647500 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-vols.part1.rar0000644000175100001770000031000014501653005020045 0ustar00runnerdockerRar!Zns ct"2 g R]H0vols\bigfile.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 k{@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-vols.part1.rar.exp0000644000175100001770000000105014501653005020642 0ustar00runnerdockerArchive: test/files/rar3-vols.part1.rar FILE: hdrlen=50 datlen=102310 is=F-- flags=0x9022:SPLIT_AFTER,EXTTIME,LONG,D128 os=3:UNIX ver=20 mode=-rw-rw-r-- meth=0 cmp=205000 dec=205000 vol=0 crc=0x509ad74c (1352324940) date_time=2016-05-24 11:42:37 name=vols/bigfile.txt mtime=2016-05-24T11:42:37 FILE: hdrlen=52 datlen=2050 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=20 mode=-rw-rw-r-- meth=0 cmp=2050 dec=2050 vol=2 crc=0xd08a1f86 (3498712966) date_time=2016-05-24 11:42:43 name=vols/smallfile.txt mtime=2016-05-24T11:42:43 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-vols.part2.rar0000644000175100001770000031000014501653005020046 0ustar00runnerdockerRar!zs  t#2 PR]H0vols\bigfile.txt 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 [{@C;D././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-vols.part2.rar.exp0000644000175100001770000000024214501653005020645 0ustar00runnerdockerArchive: test/files/rar3-vols.part2.rar --- test/files/rar3-vols.part2.rar is middle part of multi-vol archive (Need to start from first volume (current: 1))--- ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-vols.part3.rar0000644000175100001770000000501414501653005020055 0ustar00runnerdockerRar!zs 5t!2| LךPR]H0vols\bigfile.txt 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 Xt 4U]H0vols\smallfile.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 t{@tD././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar3-vols.part3.rar.exp0000644000175100001770000000024214501653005020646 0ustar00runnerdockerArchive: test/files/rar3-vols.part3.rar --- test/files/rar3-vols.part3.rar is middle part of multi-vol archive (Need to start from first volume (current: 2))--- ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-blake.rar0000644000175100001770000000445514501653005017132 0ustar00runnerdockerRar! +uݾCMTRAR5 archive - blake fYSG. stest1.txt"|1XJWrGhV|!9  (Ī4D4$2GM} *"P@@`6T*dN|IcW> stest2.txt"|1XJWrGhV|!9 ( pE 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 wVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-blake.rar.exp0000644000175100001770000000152614501653005017721 0ustar00runnerdockerArchive: test/files/rar5-blake.rar comment='RAR5 archive - blake\n' R5_FILE: hdrlen=76 datlen=55 hdr_extra=46 is=F-- block_flags=0x0003:EXTRA,DATA name=stest1.txt file_flags=0x0000:- cmp_algo=0 cmp_meth=3 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=55 dec=2048 vol=0 blake2sp=7cd5c1ac31f0cf58844a57fb9072c44768dbea1456e37c21e491f4853982ede0 date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 R5_FILE: hdrlen=92 datlen=2048 hdr_extra=62 is=F-- block_flags=0x0003:EXTRA,DATA name=stest2.txt file_flags=0x0000:- cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=2048 dec=2048 vol=0 blake2sp=7cd5c1ac31f0cf58844a57fb9072c44768dbea1456e37c21e491f4853982ede0 date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 ctime=2016-05-22T09:12:33+00:00 atime=2016-05-22T09:12:37+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-crc.rar0000644000175100001770000000435514501653005016622 0ustar00runnerdockerRar! &8꥕CMTRAR5 archive - crc ( ŀ stest1.txt  (Ī4D4$2GM} *"P@@`6T*dN|68ŀ stest2.txt ( pE 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 wVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-crc.rar.exp0000644000175100001770000000137614501653005017415 0ustar00runnerdockerArchive: test/files/rar5-crc.rar comment='RAR5 archive - crc\n' R5_FILE: hdrlen=45 datlen=55 hdr_extra=11 is=F-- block_flags=0x0003:EXTRA,DATA name=stest1.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=3 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=55 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 R5_FILE: hdrlen=61 datlen=2048 hdr_extra=27 is=F-- block_flags=0x0003:EXTRA,DATA name=stest2.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=2048 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 ctime=2016-05-22T09:12:33+00:00 atime=2016-05-22T09:12:37+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-crc.sfx0000644000175100001770000037633514501653005016650 0ustar00runnerdockerRar! &8꥕CMTRAR5 archive - crc XG$ŀ stest1.txtMĪ4D4$2GM} *"P@@`6T*dN|ܦ,ŀ stest2.txtMxAWxAW000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 wVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-dups.rar0000644000175100001770000000112214501653005017013 0ustar00runnerdockerRar! w&  ŀ stest1.txt  (Ī4D4$2GM} *"P@@`6T*dN| 5 stest2.txt  ( stest1.txtE5 stest3.txt  ( stest1.txtr[5 stest4.txt  ( stest1.txtf5 stest5.txt  ( stest1.txt_5 stest6.txt  ( stest1.txts5 stest7.txt  ( stest1.txtk5 stest8.txt  ( stest1.txto5 stest9.txt  ( stest1.txtwVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-dups.rar.exp0000644000175100001770000000623414501653005017617 0ustar00runnerdockerArchive: test/files/rar5-dups.rar R5_FILE: hdrlen=43 datlen=55 hdr_extra=11 is=F-- block_flags=0x0003:EXTRA,DATA name=stest1.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=3 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=55 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest2.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest3.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest4.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest5.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest6.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest7.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest8.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt R5_FILE: hdrlen=58 datlen=0 hdr_extra=26 is=F-- block_flags=0x0003:EXTRA,DATA name=stest9.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=0:WINDOWS mode=ARCHIVE cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=FILE_COPY flags=0:- destination=stest1.txt ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-hlink.rar0000644000175100001770000000034614501653005017154 0ustar00runnerdockerRar! a Mŀ stest1.txtĪ4D4$2GM} *"P@@`6T*dN|t0M stest2.txt stest1.txtt0M stest3.txt stest1.txtwVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-hlink.rar.exp0000644000175100001770000000207014501653005017743 0ustar00runnerdockerArchive: test/files/rar5-hlink.rar R5_FILE: hdrlen=37 datlen=55 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest1.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=0 solid=False os=1:UNIX mode=-rw-rw-r-- cmp=55 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 R5_FILE: hdrlen=53 datlen=0 hdr_extra=15 is=F-- block_flags=0x0003:EXTRA,DATA name=stest2.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-rw-r-- cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=HARD_LINK flags=0:- destination=stest1.txt R5_FILE: hdrlen=53 datlen=0 hdr_extra=15 is=F-- block_flags=0x0003:EXTRA,DATA name=stest3.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-rw-r-- cmp=0 dec=2048 vol=0 crc=0x00000000 (0) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 redir: type=HARD_LINK flags=0:- destination=stest1.txt ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-hpsw.rar0000644000175100001770000000503614501653005017031 0ustar00runnerdockerRar!iE!\T B‡')cJ_@\RM';c&!ՠ/D {v#:z [2XcUj㚙򫮮xuw@{Ϊ CQ紃Th-̥_QoCm2y(05:Dm"J F UQa14ԧQI*W"өӽFγv$KygN}? wb!_Z1 ")mv@@A4 )I[_A 7zuT 㪏UfarxmѪ? \j1?]х )lqt8L=JfIC B{9Eʏ^ Uc>AFJǑ'I !\PeN^jvI*J-+Qym56m ? ?5\`s׮Yh@y7?&Ol<=3>z y偁ѰʣDGӢyu2]NʺbZ0 |Ko" f ǵj7xՙ?d|Ø pG$J'K]4apr7ׁw LZTH]K[*|^{E}p7,:J*MaxR MJgkM<`3pFz(aNǖ2KyMQ+A1#gre[~5 D xh==F.ޙ39COߛ~MH"48i-'`TT Nn] pŌ*]ߨPDHt-'=܊5q 9dzfcdo3umBQ/caNXՃfG2⼸4)|},c.p7P@okDRtO~6@} cl wM$[vPppC4c iZQ[5@FPu zlT 5*9z1STB~7t#gpt6A?vבW[R5䄴AK>h\|@RloGHN%+MWIt9뱕\B Β:M&/5~]Yp&62 Wb 9./iIll;W}z~CnbŔ.s:EDWymnv:+/)?(] tTͦ& Ǐ7LLY@`!)2SV ? uIrmNG ֫>RR`7-iV_ߓYNQI|S!vNe?]Rr{U6>\lT1 -7p.P#bI*tc$v}cJgy's^S=4!Z\ٷUd58cYxJ'԰И)#ӏU>MP< ;)re8+LB*`tNk7֐7I)9 q3 m7@$X4v0:MeS 2o}Gv(p cqvac1b&Rm}[+ 3d#X>?oIflvX,*KIb2݈@tד.^Jz -q."A jN6*1^-lkyAJLtm5שbHh%IYz" % 6 e"p+PKɆu"9X&;zQk?9Un*xwmNf5. wBvnv]ԫ924!XOW͊B*`V\. av闟CsqE] > ܛ>` VS?5/;tr-)Fۘυ"O) /<} vB?iFȃԪb5cB «k. |TΟt~ySpX[-M5z9$TwnfrQfstӫ`9x "\YJ5<;dۣh%K^  (g .m{abn&}XC񧸭a l]%%Xou o stest2.txt0t Q@sF U 4 A9x "\YJ5<;dۣh%K^ ( pE 3ZBp?2 x8}%;!xu &`K.zad7W I ) i:gk,(nMrDW<͖>foܡOn\OR3P9EՓ굹4x#GC2,aX7Oal{R[yn~ [J;=]&kfSs D\}, &@ʯB! zƼdjPDtYQ^ .2+~XNMBCe}5x-׊f1u\FC_f@/I . %hΛ.]\.t0㯫t8F˿l֙0Q(:\5'4o۫!R5_7G@K\ )Akt_fKNj[;ܶvv%L苕xPм:u%7gir% @n>ǵO}r#xIW0ጥKζ e͡dKOJBv|[gxmm0A+ *&C?ޙNU믬5: Clt!Ç6&J*+|dZ7OR 7K@xG ktm>LZ|tg&+{Th=pƒWyjѨDE P8}fJ,a-=zlp0'"zqw009| Nྠ$0T,b(F]!DK3,z$Z4z s^<+28;ФGJ \mw_Ly6Za1[<","n|U4D^spyRXQB;yIx;DRn'")1ܪeh]Vea,^/ $a8؎ztL4aGottSB~im҂uzf,6,IڤNoˢ"̹)f kg39^LQbnW$jM%$#+45g90NiB9C3B4_SSwiNT۫PW ~Uw%*`Q$[fΔ.}ܹ'(}1xOrI 0v?]n&!Q1N$|h'A='&J#3X܇|քxdjI@}YYׂ g:"ॖ,7%mJXQr s^9 Ҭ!(gRE6A&U!jWKwyp]&տ|Z#! Pix 6'݄J"} \h,=9T0,Yݺ>T#Dv̊O!3 W!K0mi^mHa &nZjz!+3zR6["ɑ!^])SMbes+AHTR7u:iL( stest2.txt0~,6ǣڍh߃ nQF}yIҁQ6Inj" ( pE I8qeCW%hv0):gک`͎7Zc{ /rC~H@Q /aTm/a pv25B1,)*߀ \1o<%}zw5guCyȁhV"AńHk,Oz fo$X"ŗOׇr}ǦpA9[6_$A sB9q7aG  zC߷U tc{m +Qg NDHtaqR~廂ZDl?@1-!I* |V}{4҃B`]gCZz1ɤ 9`^c :wLB&'OeN! ]jX{)#Ӊj;q֝zRmT]_;snR Ètdx;gS|!сw@/.RS#Djp Ma}9-J@%UކhjX*ԛWnҋ|t +!Ǵoi,+yQ; UFPj9s*qdP} [Ԡigác&S[6&z_'ouĴQrZSPD/s+fcGLSNl!)񪲶ADljɅ<$Oნ,I/]2O 튵U_j^6s##1UxGBږԺ^ u2υPç +3 I1 7W}P*+ES䖀8NTp ct0"D ҒgRp$} 𭀂G b2lz]# w5=)'md5.!'tS6_&Z"_ X4 : . `\>&9ANO(|V 8ߩGF,EE7|d;i4?y۰5Y+mP~YEs,kl^İ6a}]U]*jq:2;N'By%>;,o;QKDžb8n@:BH'hCcEz!3 1!S0?#Q  @^ l|,՚TE&&~fʚRfXrx퇜tx!sAڞT{1ҎM%"ˑ?)rj$ KMCgN ׮a3L8'3oeB:)G*@p2FY$.%.^ h1INmV[pn Y3InW.C[`WHv;!a䀄Xz`e-Bm(]]7n]߅V+ &_[26 #R9D/fQ<`Em51hӻ8z4nĵ7{oB}]=IkOc1aX<GwpA;ӀN_;U%^\R!_TDWG$-;l -:hP`h_Ntb%t<%U2کZ6pDŽ]6>JpT *wpGV˃Pz;N 9 A4icdV="ӥM)~J?%az5-q4ZUadY0ΥO&CZ;P۪Rg\ "*k mggTNI7ǻw{BXpRLjG/w7h㞸 ,șS;Gq[>GJ3g}ۓ]#t1D~5CWf#Vua<v.tY $+RaʰBwVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-psw.rar.exp0000644000175100001770000000216614501653005017455 0ustar00runnerdockerArchive: test/files/rar5-psw.rar comment='RAR5 archive - nohdr-password\n' R5_FILE: hdrlen=94 datlen=64 hdr_extra=60 is=F-- block_flags=0x0003:EXTRA,DATA name=stest1.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=3 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=64 dec=2048 vol=0 crc=0xba28eeea (3123244778) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 algo=0:AES256 enc_flags=0003:CHECKVAL,TWEAKED kdf_lg=15 kdf_count=32768 salt=7e982cdd1ae21c36c7a391da8d088a68 iv=a03aad26f4827b87d54c725ce73b6967 checkval=8151cff63649c16e186a220f R5_FILE: hdrlen=110 datlen=2048 hdr_extra=76 is=F-- block_flags=0x0003:EXTRA,DATA name=stest2.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=2048 dec=2048 vol=0 crc=0xba28eeea (3123244778) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 ctime=2016-05-22T09:12:33+00:00 atime=2016-05-22T09:12:37+00:00 algo=0:AES256 enc_flags=0003:CHECKVAL,TWEAKED kdf_lg=15 kdf_count=32768 salt=7e982cdd1ae21c36c7a391da8d088a68 iv=df83fa0cd86e88b8b6f851467d7949d2 checkval=8151cff63649c16e186a220f ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-quick-open.rar0000644000175100001770000000050614501653005020120 0ustar00runnerdockerRar! ȁ; Mŀ stest1.txtĪ4D4$2GM} *"P@@`6T*dN|AB Mŀ stest2.txtĪ4D4$2GM} *"P@@`6T*dN|U8QOP)%; Mŀ stest1.txtX(\%AB Mŀ stest2.txtwVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-quick-open.rar.exp0000644000175100001770000000123214501653005020710 0ustar00runnerdockerArchive: test/files/rar5-quick-open.rar R5_FILE: hdrlen=37 datlen=55 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest1.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=55 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 R5_FILE: hdrlen=37 datlen=55 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest2.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=0 solid=False os=1:UNIX mode=-rw-r--r-- cmp=55 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-readonly-unix.rar0000644000175100001770000000020514501653005020637 0ustar00runnerdockerRar! 0 v"ro_dir/ro_file.txt n_%readonly {" ro_dir n_zLwVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-readonly-unix.rar.exp0000644000175100001770000000125114501653005021434 0ustar00runnerdockerArchive: test/files/rar5-readonly-unix.rar R5_FILE: hdrlen=53 datlen=9 hdr_extra=11 is=F-- block_flags=0x0003:EXTRA,DATA name=ro_dir/ro_file.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-r--r--r-- cmp=9 dec=9 vol=0 crc=0x818d2276 (2173510262) date_time=2020-07-26 19:11:42 mtime=2020-07-26T19:11:42.312616322+00:00 R5_FILE: hdrlen=39 datlen=0 hdr_extra=11 is=-D- block_flags=0x0003:EXTRA,DATA name=ro_dir/ file_flags=0x0005:DIR,CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=dr-xr-xr-x cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-26 19:11:42 mtime=2020-07-26T19:11:42.328617082+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-readonly-win.rar0000644000175100001770000000020614501653005020452 0ustar00runnerdockerRar!ϐs t 7 v"uP0!ro_dir\ro_file.txt/readonly qGt+uP0ro_dir$2={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-readonly-win.rar.exp0000644000175100001770000000102014501653005021240 0ustar00runnerdockerArchive: test/files/rar5-readonly-win.rar FILE: hdrlen=55 datlen=9 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=2:WIN ver=29 mode=READONLY,ARCHIVE meth=0 cmp=9 dec=9 vol=0 crc=0x818d2276 (2173510262) date_time=2020-07-26 22:11:42 name=ro_dir/ro_file.txt mtime=2020-07-26T22:11:42.312616300 FILE: hdrlen=43 datlen=0 is=-D- flags=0x90e0:EXTTIME,LONG,DIR os=2:WIN ver=20 mode=READONLY,DIRECTORY meth=0 cmp=0 dec=0 vol=0 crc=0x00000000 (0) date_time=2020-07-26 22:11:42 name=ro_dir/ mtime=2020-07-26T22:11:42.328617 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-solid-qo.rar0000644000175100001770000000077414501653005017603 0ustar00runnerdockerRar!.  y(tAWŀsomedir/stest1.txt 8SSB#46G#&'& _c4'яVƼ M stest1.txtF `}~}~i(tAWsomedir/stest2.txtF `}~}~ M stest2.txtF `}~}~?QOq1- y(tAWŀsomedir/stest1.txtcѲ)%VƼ M stest1.txtH{0j-i(tAWsomedir/stest2.txtqk(1% M stest2.txtwVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-solid-qo.rar.exp0000644000175100001770000000242714501653005020373 0ustar00runnerdockerArchive: test/files/rar5-solid-qo.rar R5_FILE: hdrlen=45 datlen=59 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=somedir/stest1.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=3 solid=False os=1:UNIX mode=-rw-r--r-- cmp=59 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2016-05-22 09:48:36 mtime=2016-05-22T09:48:36+00:00 R5_FILE: hdrlen=37 datlen=12 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest1.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=3 solid=True os=1:UNIX mode=-rw-r--r-- cmp=12 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 R5_FILE: hdrlen=45 datlen=12 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=somedir/stest2.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=3 solid=True os=1:UNIX mode=-rw-r--r-- cmp=12 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2016-05-22 09:48:36 mtime=2016-05-22T09:48:36+00:00 R5_FILE: hdrlen=37 datlen=12 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest2.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=3 dict=3 solid=True os=1:UNIX mode=-rw-r--r-- cmp=12 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 09:53:33 mtime=2011-06-12T09:53:33+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-solid.rar0000644000175100001770000000025114501653005017154 0ustar00runnerdockerRar! o prŀ stest1.txt7DD##bSQLAy\G-6ݠX@Pv22׃- stest2.txtE `߷wVQ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-solid.rar.exp0000644000175100001770000000100414501653005017744 0ustar00runnerdockerArchive: test/files/rar5-solid.rar R5_FILE: hdrlen=33 datlen=58 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest1.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=3 dict=3 solid=False os=1:UNIX mode=-rw-rw-rw- cmp=58 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) R5_FILE: hdrlen=33 datlen=13 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=stest2.txt file_flags=0x0004:CRC32 cmp_algo=0 cmp_meth=3 dict=3 solid=True os=1:UNIX mode=-rw-rw-rw- cmp=13 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-subdirs.rar0000644000175100001770000000103614501653005017517 0ustar00runnerdockerRar! [*0 Ǥɀsub/dir2/file2.txt _file2 $4y 8 }$qsub/with space/long fn.txt )_flong fn  Ƃ( DW7H@[vols/bigfile.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 lk*QO7K2-( DW7H@[vols/bigfile.txt6RR{RB}lOrBHNBaK"2@WqvYLTrأ$\A$[y<0zwl I4S`> c ԍ;Jcu5:=qv‘C7Aq/^2"*F`?ZcHQPoQ /b. .%-kn LP hUwяl;$ QdS1 OOIrJ}tI#pW@hl< 2]-'R=SNN*j!a %]Gef<2ZqZFwC[(jn=iTtrwp'2J7daH9҆ޝ? [P9'<}$z @CHi04s$hӬuXD' BJA ŴunEfVɞU8Mvs4gx;" Akuq~G w'vk =0 05( ĎRcdュTx|vzpglerǂ}*tc9R;9k,BAi\c9Kr 8}>[)kˢx'U,Ӛn9 ?0[$w 6`z.):O5Z]GRW2/`]\uGJn秌.(Ufe}0.njEFA>̚pK|.ݴnA14:v,Ж$T62WN V&@l7Lx$=h8K0 1+4ۼAnus?g*TkSA ~ni7"g„L xqp )iPՎW 2孛{>RS<7\kQ:ʣժ;ujk*I)#y12Ip7&^)$ԨP,rH'>)) /[q[:l2oJf|3Ĭly{/ 7oꃚ9Oqr%7 }Ps ?zSDKəW߄ߝ@Ac [ ' _ޡVBSxQ/s#f &H<= BJ>|p@yO`&"ׇDm?m=b^/U2tᮭk F#-Y{4{ _ψf}1^JCieY G=(BnIƹk:]=I2?+JnVPTmsWqj-8kW"5Ď`XcOY3yBtЄMK\ ϭ{RB}Lj1YhBHNBaK"2@WqvYLTrأ$\A$[y<0zwl I4S`> c ԍ;Jcu5:=qv‘C7Aq/^2"*F`?ZcHQPoQ /b. .%-kn LP hUwяl;$ QdS1 OOIrJ}tI#pW@hl< 2]-'R=SNN*j!a %]Gef<2ZqZFwC[(jn=iTtrwp'2J7daH9҆ޝ? [P9'<}$z @CHi04s$hӬuXD' BJA ŴunEfVɞU8Mvs4gx;" Akuq~G w'vk =0 05( ĎRcdュTx|vzpglerǂ}*tc9R;9k,BAi\c9Kr 8}>[)kˢx'U,Ӛn9 ?0[$Kߘ` bM,:g_'9qd)xFh_c(}!plStj|"Ԡ[);C']J Tuo[{}tsId :ХeOuGHFX_lXjV].߈lb%NES t@!BlÑ/h?dY@[;T\{KoI͏BI12 `匨xzd4bQ8ِjBqz!1H+$$CZtXo fQK$'cp _M.b=ގL98cĬ2rPN~ٔZ}#*Gؕ Y3noxd;2|xXd;uUc=,Xԗ/F,éh:@Hzń]xaGCZ;6, O'%$RM^N{FU)Z*| ᑞ>z|Ʌ?iL( MMM(]+_hqܿ?26~nT~˪&Қ #^<2, th!5p@a!Z71e 6Ii1KlH% JW>iȽ71.Q0#y= Yŭ|ѹ=kgXтC"Cp,A&2VāH6;I s?໗7<B\7( vl*Heg۝fhC?c"jB852<#?ܪZt#a`[BqÙ]I>*DJdHB"I+D|+Q]DqrZ?ڠ4OB7t0)=82Ш!8M<Ewea*Dvnwhnv/c n #z 0 [3=VW6Aʐ>qi87a ,@}/ċGQ&././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-vols.part1.rar.exp0000644000175100001770000000130214501653005020644 0ustar00runnerdockerArchive: test/files/rar5-vols.part1.rar R5_FILE: hdrlen=45 datlen=205000 hdr_extra=0 is=F-- block_flags=0x0012:DATA,SPLIT_AFTER name=vols/bigfile.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-rw-r-- cmp=205000 dec=205000 vol=0 crc=0x509ad74c (1352324940) date_time=2016-05-24 08:42:37 mtime=2016-05-24T08:42:37+00:00 R5_FILE: hdrlen=45 datlen=2050 hdr_extra=0 is=F-- block_flags=0x0002:DATA name=vols/smallfile.txt file_flags=0x0006:MTIME,CRC32 cmp_algo=0 cmp_meth=0 dict=0 solid=False os=1:UNIX mode=-rw-rw-r-- cmp=2050 dec=2050 vol=2 crc=0xd08a1f86 (3498712966) date_time=2016-05-24 08:42:43 mtime=2016-05-24T08:42:43+00:00 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/rar5-vols.part2.rar0000644000175100001770000031000014501653005020050 0ustar00runnerdockerRar!l  Ƃ:( DW̠vols/bigfile.txt 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 lk*QO2-:( DW̠vols/bigfile.txt6RR{RB},߰BHNBau zkZk4=Eʑ:(U)Txi8M3 2QWtɾ ]8<g>‚-{ 87^+7xBU׌aw|n`^ЪgB DkGg&* r ֗,:=AG|(v'Mq~}˰GҼ'y<@^A7VFֻSҲg|Ԇ*MMZs8vui y5ΐ&;aO2=_T/%qP2Ő2]q7.x2VuoU'BjM& nd%enFVfum4ḳ6e`dy{HyjlDsd.$\",;}m9+B+PelI ]66 u^vQ9AC%N(LV²=dԌU0R^Blee-iϛϚ0aC9A5RDhD*d'_S }7s[ڃY]ཱྀL ^G&-PQ`U=j蜆W2uxT? Xtm|_-XR"k|cj_c3i^bF#|g<$*F!NQ93x,g>‚-{ 87^+7xBU׌aw|n`^ЪgB DkGg&* r ֗,:=AG|(v'Mq~}˰GҼ'y<@^A7VFֻSҲg|Ԇ*MMZs8G! q:&C=/I1"!.bdǷj|\ }`]R3X2o$`PHO6bk6DTo2]8q\ yV ge۾WH\璒_@b|U(Lh";~k#p5}Ԋg*/˂<#8߼HMF _.%:/5ި㐩I{Ģ]I}e׍,) ܥ+j{"~\b"|ND+#d͠* S|y2Mn;dF:u5G̭clBJ5AQNXPUړ.n#p|ĽHXW %B sphv35)iџdÏ\SZln_< NBc; 2 5ԔW:R|4|^T׭;Kx{}L).dY8.X& Weڎ* n:2_nVK!jŸ]lH.4% ۾$)Iz/p1Bsף֧-c]@=4Yz S0"c7[1MnųFiq<`*{ ²/ذb\(> e YJ{ 0HOˁӳ،4Yc҄f$gsg(M]*lHaYH"E`~#_QgX Z?t}a >,Xr8; 9tjk nn)T#5xA *m 54_ &'_Nv^ ˜q^‡әĘrs ֋iU^ r __Fȓb 5 4_tֈ'_L2D ˜='Ϊә,rpg iR^Z ryK _ȕ 54_ ''_KU=^ ˜9p_kMәCKv N_iP^8 rs! _Q 54_ '^NvUϓ _9qvUFyKs ֎_i^8 rn _FQb 5g4_pb'^L2UDϧ? _cFy,Kpg _Rw 6]>lunYkA3󕦕4N4R5aeah _9bo"tFy[Kr ^ ] 1 rRs٨ _FQW 5A4_'^H ] ]Ϯ a_ŎFyD u  ]Z rW _Q 5x4_^'.^I ] ]G K`pXm-}Vh//,<5 stest1.txt ޯ_5uefVH,WF@0 stest2.txt000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 ={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/seektest.rar.exp0000644000175100001770000000077514501653005017630 0ustar00runnerdockerArchive: test/files/seektest.rar FILE: hdrlen=44 datlen=90 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=29 mode=-rw-r--r-- meth=5 cmp=90 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 12:53:33 name=stest1.txt mtime=2011-06-12T12:53:33 FILE: hdrlen=44 datlen=2048 is=F-- flags=0x9020:EXTTIME,LONG,D128 os=3:UNIX ver=20 mode=-rw-r--r-- meth=0 cmp=2048 dec=2048 vol=0 crc=0xc5b7e6a2 (3317163682) date_time=2011-06-12 12:53:33 name=stest2.txt mtime=2011-06-12T12:53:33 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/unicode.rar0000644000175100001770000000024314501653005016622 0ustar00runnerdockerRar!;s t6SQg>5уииоотивл.txt0#gt4 SQg>5𝐀𝐁𝐁𝐂.txtwg={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/unicode.rar.exp0000644000175100001770000000071014501653005017414 0ustar00runnerdockerArchive: test/files/unicode.rar FILE: hdrlen=54 datlen=17 is=F-- flags=0x8080:LONG,D1024 os=3:UNIX ver=29 mode=-rw-r--r-- meth=5 cmp=17 dec=2 vol=0 crc=0x6751fc53 (1733426259) date_time=2011-07-06 16:48:04 name=уииоотивл.txt FILE: hdrlen=52 datlen=13 is=F-- flags=0x8090:SOLID,LONG,D1024 os=3:UNIX ver=29 mode=-rw-r--r-- meth=5 cmp=13 dec=2 vol=0 crc=0x6751fc53 (1733426259) date_time=2011-07-06 16:48:04 name=𝐀𝐁𝐁𝐂.txt ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/unicode2.rar0000644000175100001770000000023014501653005016700 0ustar00runnerdockerRar!ϐs u]t >SQg>0 ????????.txtf55f551 9t ;SQg>0 ?????????.txt}CBW82;1 ={@././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/files/unicode2.rar.exp0000644000175100001770000000074114501653005017502 0ustar00runnerdockerArchive: test/files/unicode2.rar FILE: hdrlen=62 datlen=2 is=F-- flags=0x8220:UNICODE,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=2 dec=2 vol=0 namecmp=12/30 crc=0x6751fc53 (1733426259) date_time=2011-07-06 16:48:04 name=𝐀𝐁𝐁𝐂.txt FILE: hdrlen=59 datlen=2 is=F-- flags=0x8220:UNICODE,LONG,D128 os=2:WIN ver=29 mode=ARCHIVE meth=0 cmp=2 dec=2 vol=0 namecmp=13/27 crc=0x6751fc53 (1733426259) date_time=2011-07-06 16:48:04 name=уииоотивл.txt ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/run_dump.sh0000755000175100001770000000172314501653005015560 0ustar00runnerdocker#! /bin/sh PYTHON="$1" tag="$2" test -n "$tag" || { echo "usage: $0 PY TAG"; exit 1; } PYTHONIOENCODING=utf8; export PYTHONIOENCODING #PYTHONUTF8=1; export PYTHONUTF8 mkdir -p tmp diffs="tmp/output.$tag.diffs" rm -f "$diffs" quiet="" quiet="1" vprintf=printf vecho=echo if test -n "$quiet"; then echo "[$tag] testing structure dump" vprintf=true vecho=true fi result=0 for f in test/files/*.rar; do $vprintf "%s -> %-30s .. " "$tag" "$f" "$PYTHON" dumprar.py -v -ppassword "$f" > "$f.$tag" if diff -uw "$f.exp" "$f.$tag" > /dev/null; then $vecho "ok" rm -f "$f.$tag" else $vecho "FAIL" errmsg="FAILED" case "$f" in *-hpsw.rar) errmsg="failed-nocrypto";; *) result=1;; esac if test -n "$quiet"; then printf "[%s] %-30s .. ${errmsg}\n" "$tag" "$f" fi echo "#### $py ####" >> "$diffs" diff -uw "$f.exp" "$f.$tag" >> "$diffs" fi done test "$result" = "0" || echo "Diffs: ${diffs}" exit $result ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/run_dump_all.sh0000755000175100001770000000052314501653005016405 0ustar00runnerdocker#! /bin/sh JAVA_OPTIONS="-Dpython.path=`pwd`/.." export JAVA_OPTIONS plist="python3.7 python3.8 python3.9 python3.10 python3.11 python3.12 pypy3.9 pypy3.10" result=0 for py in $plist; do if which $py > /dev/null; then ./test/run_dump.sh "$py" "$py" || result=1 echo "" else echo $py not available echo "" fi done ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_api.py0000644000175100001770000002610014501653005015546 0ustar00runnerdocker"""API tests. """ import io import os from pathlib import Path import pytest import rarfile # # test start # def test_not_rar(): with pytest.raises(rarfile.NotRarFile): rarfile.RarFile("rarfile.py", "r") with pytest.raises(rarfile.NotRarFile): with open("rarfile.py", "rb") as f: rarfile.RarFile(f, "r") def test_bad_arc_mode_w(): with pytest.raises(NotImplementedError): rarfile.RarFile("test/files/rar3-comment-plain.rar", "w") def test_bad_arc_mode_rb(): with pytest.raises(NotImplementedError): rarfile.RarFile("test/files/rar3-comment-plain.rar", "rb") def test_bad_errs(): with pytest.raises(ValueError): rarfile.RarFile("test/files/rar3-comment-plain.rar", "r", errors="foo") def test_errors_param(): with open("test/files/rar3-comment-plain.rar", "rb") as f: data = f.read() buf = io.BytesIO(data[:17]) with rarfile.RarFile(buf, "r", errors="stop") as rf: assert rf.namelist() == [] with pytest.raises(rarfile.BadRarFile): rarfile.RarFile(buf, "r", errors="strict") def test_bad_open_mode_w(): rf = rarfile.RarFile("test/files/rar3-comment-plain.rar") with pytest.raises(NotImplementedError): rf.open("qwe", "w") def test_bad_open_psw(): rf = rarfile.RarFile("test/files/rar3-comment-psw.rar") with pytest.raises(rarfile.PasswordRequired): rf.open("file1.txt") def test_bad_filelike(): with pytest.raises(ValueError): rarfile.is_rarfile(bytearray(10)) def test_open_psw_late_rar3(): rf = rarfile.RarFile("test/files/rar3-comment-psw.rar") d1 = rf.open("file1.txt", "r", "password").read() d2 = rf.open("file1.txt", "r", b"password").read() assert d1 == d2 def test_open_psw_late_rar5(): rf = rarfile.RarFile("test/files/rar5-psw.rar") rf.open("stest1.txt", "r", "password").read() rf.open("stest1.txt", "r", b"password").read() def test_open_pathlib_path(): rf = rarfile.RarFile("test/files/rar5-psw.rar") rf.open(Path("stest1.txt"), "r", "password").read() def test_read_psw_late_rar3(): rf = rarfile.RarFile("test/files/rar3-comment-psw.rar") rf.read("file1.txt", "password") rf.read("file1.txt", b"password") def test_read_psw_late_rar5(): rf = rarfile.RarFile("test/files/rar5-psw.rar") rf.read("stest1.txt", "password") rf.read("stest1.txt", b"password") def test_open_psw_late(): rf = rarfile.RarFile("test/files/rar5-psw.rar") with pytest.raises(rarfile.BadRarFile): rf.read("stest1.txt", "password222") def test_create_from_pathlib_path(): # Make sure we can open both relative and absolute Paths rarfile.RarFile(Path("test/files/rar5-psw.rar")) rarfile.RarFile(Path("test/files/rar5-psw.rar").resolve()) def test_detection(): assert rarfile.is_rarfile("test/files/ctime4.rar.exp") is False assert rarfile.is_rarfile("test/files/ctime4.rar") is True assert rarfile.is_rarfile("test/files/rar5-crc.rar") is True assert rarfile.is_rarfile(Path("test/files/rar5-crc.rar")) is True assert rarfile.is_rarfile("test/files/_missing_.rar") is False def test_getinfo(): with rarfile.RarFile("test/files/rar5-crc.rar") as rf: inf = rf.getinfo("stest1.txt") assert isinstance(inf, rarfile.RarInfo) assert rf.getinfo(inf) is inf with pytest.raises(rarfile.NoRarEntry): rf.getinfo("missing.txt") def test_signature_error(): with pytest.raises(rarfile.NotRarFile): rarfile.RarFile("test/files/ctime4.rar.exp") def test_signature_error_mem(): data = io.BytesIO(b"x" * 40) with pytest.raises(rarfile.NotRarFile): rarfile.RarFile(data) def test_with(): with rarfile.RarFile("test/files/rar5-crc.rar") as rf: data = rf.read("stest1.txt") with rf.open("stest1.txt") as f: dst = io.BytesIO() while True: buf = f.read(7) if not buf: break dst.write(buf) assert dst.getvalue() == data def test_readline(): def load_readline(rf, fn): with rf.open(fn) as f: tr = io.TextIOWrapper(io.BufferedReader(f)) res = [] while True: ln = tr.readline() if not ln: break res.append(ln) return res rf = rarfile.RarFile("test/files/seektest.rar") v1 = load_readline(rf, "stest1.txt") v2 = load_readline(rf, "stest2.txt") assert len(v1) == 512 assert v1 == v2 def run_parallel(rfile, entry): buf1, buf2 = [], [] rf = rarfile.RarFile(rfile) count = 0 with rf.open(entry) as f1: with rf.open(entry) as f2: for _ in range(10000): res1 = f1.read(10) res2 = f2.read(10) if res1: buf1.append(res1) count += len(res1) if res2: buf2.append(res2) count += len(res2) if not res1 and not res2: break assert buf1 assert buf1 == buf2 def test_parallel_file_compressed(): run_parallel("test/files/seektest.rar", "stest1.txt") def test_parallel_file_direct(): run_parallel("test/files/seektest.rar", "stest2.txt") def test_parallel_fd_compressed(): with open("test/files/seektest.rar", "rb") as f: memfile = io.BytesIO(f.read()) run_parallel(memfile, "stest1.txt") def test_parallel_fd_direct(): with open("test/files/seektest.rar", "rb") as f: memfile = io.BytesIO(f.read()) run_parallel(memfile, "stest2.txt") def test_printdir(capsys): rf = rarfile.RarFile("test/files/seektest.rar") rf.printdir() res = capsys.readouterr() assert res.out == "stest1.txt\nstest2.txt\n" def test_testrar(): rf = rarfile.RarFile("test/files/seektest.rar") rf.testrar() def test_iter(): rf = rarfile.RarFile("test/files/seektest.rar") n1 = rf.namelist() n2 = [m.filename for m in rf] assert n1 == n2 def test_testrar_mem(): with open("test/files/seektest.rar", "rb") as f: arc = f.read() rf = rarfile.RarFile(io.BytesIO(arc)) rf.testrar() def test_extract(tmp_path): ex1 = tmp_path / "extract1" ex2 = tmp_path / "extract2" ex3 = tmp_path / "extract3" os.makedirs(str(ex1)) os.makedirs(str(ex2)) os.makedirs(str(ex3)) rf = rarfile.RarFile("test/files/seektest.rar") rf.extractall(str(ex1)) assert os.path.isfile(str(ex1 / "stest1.txt")) is True assert os.path.isfile(str(ex1 / "stest2.txt")) is True rf.extract("stest1.txt", str(ex2)) assert os.path.isfile(str(ex2 / "stest1.txt")) is True assert os.path.isfile(str(ex2 / "stest2.txt")) is False inf = rf.getinfo("stest2.txt") rf.extract(inf, str(ex3)) assert os.path.isfile(str(ex3 / "stest1.txt")) is False assert os.path.isfile(str(ex3 / "stest2.txt")) is True rf.extractall(str(ex2), ["stest1.txt"]) assert os.path.isfile(str(ex2 / "stest1.txt")) is True rf.extractall(str(ex3), [rf.getinfo("stest2.txt")]) assert os.path.isfile(str(ex3 / "stest2.txt")) is True ex4 = tmp_path / "extract4" os.makedirs(str(ex4)) rf.extractall(ex4) assert os.path.isfile(str(ex4 / "stest1.txt")) is True assert os.path.isfile(str(ex4 / "stest2.txt")) is True def test_extract_mem(tmp_path): ex1 = tmp_path / "extract11" ex2 = tmp_path / "extract22" ex3 = tmp_path / "extract33" os.makedirs(str(ex1)) os.makedirs(str(ex2)) os.makedirs(str(ex3)) with open("test/files/seektest.rar", "rb") as f: arc = f.read() rf = rarfile.RarFile(io.BytesIO(arc)) rf.extractall(str(ex1)) assert os.path.isfile(str(ex1 / "stest1.txt")) is True assert os.path.isfile(str(ex1 / "stest2.txt")) is True rf.extract("stest1.txt", str(ex2)) assert os.path.isfile(str(ex2 / "stest1.txt")) is True assert os.path.isfile(str(ex2 / "stest2.txt")) is False inf = rf.getinfo("stest2.txt") rf.extract(inf, str(ex3)) assert os.path.isfile(str(ex3 / "stest1.txt")) is False assert os.path.isfile(str(ex3 / "stest2.txt")) is True def get_rftype(h): assert h.is_dir() == h.isdir() return "".join([ h.is_file() and "F" or "-", h.is_dir() and "D" or "-", h.is_symlink() and "L" or "-", ]) def test_infocb(): infos = [] def info_cb(info): infos.append((info.type, info.needs_password(), get_rftype(info), info._must_disable_hack())) rf = rarfile.RarFile("test/files/seektest.rar", info_callback=info_cb) assert infos == [ (rarfile.RAR_BLOCK_MAIN, False, "---", False), (rarfile.RAR_BLOCK_FILE, False, "F--", False), (rarfile.RAR_BLOCK_FILE, False, "F--", False), (rarfile.RAR_BLOCK_ENDARC, False, "---", False)] rf.close() infos = [] rf = rarfile.RarFile("test/files/rar5-solid-qo.rar", info_callback=info_cb) assert infos == [ (rarfile.RAR_BLOCK_MAIN, False, "---", True), (rarfile.RAR_BLOCK_FILE, False, "F--", False), (rarfile.RAR_BLOCK_FILE, False, "F--", True), (rarfile.RAR_BLOCK_FILE, False, "F--", True), (rarfile.RAR_BLOCK_FILE, False, "F--", True), (rarfile.RAR_BLOCK_SUB, False, "---", False), (rarfile.RAR_BLOCK_ENDARC, False, "---", False)] rf.close() # pylint: disable=singleton-comparison def test_rarextfile(): with rarfile.RarFile("test/files/seektest.rar") as rf: for fn in ("stest1.txt", "stest2.txt"): with rf.open(fn) as f: assert f.tell() == 0 assert f.writable() == False assert f.seekable() == True assert f.readable() == True assert f.readall() == rf.read(fn) def test_is_rarfile(): with rarfile.RarFile("test/files/seektest.rar") as rf: for fn in ("stest1.txt", "stest2.txt"): with rf.open(fn) as f: assert f.tell() == 0 assert f.writable() == False assert f.seekable() == True assert f.readable() == True assert f.readall() == rf.read(fn) def test_part_only(): info_list = [] def info_cb(info): info_list.append(info) with pytest.raises(rarfile.NeedFirstVolume): with rarfile.RarFile("test/files/rar3-vols.part2.rar") as rf: pass with rarfile.RarFile("test/files/rar3-vols.part2.rar", part_only=True, info_callback=info_cb) as rf: assert len(info_list) == 3 with pytest.raises(rarfile.NeedFirstVolume): with rarfile.RarFile("test/files/rar5-vols.part2.rar") as rf: pass info_list = [] with rarfile.RarFile("test/files/rar5-vols.part2.rar", part_only=True, info_callback=info_cb) as rf: assert len(info_list) == 5 def test_volume_info(): info_list = [] def info_cb(info): info_list.append(info) with rarfile.RarFile("test/files/rar3-vols.part1.rar", info_callback=info_cb) as rf: assert len(info_list) == 10 info_list = [] with rarfile.RarFile("test/files/rar5-vols.part1.rar", info_callback=info_cb) as rf: assert len(info_list) == 16 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_compat.py0000644000175100001770000000363014501653005016263 0ustar00runnerdocker"""Test zipfile compat. """ import inspect import sys import zipfile import pytest import rarfile # dont fail on new python by default _VERS = [(3, 6), (3, 7), (3, 8)] _UNSUPPORTED = sys.version_info[:2] not in _VERS _ignore = set([ "detach", "peek", "read1", "readinto1", "seek", # no kwargs "readinto", "readline", "truncate", "write", # random "FileHeader", "from_file", "testzip", "writestr", ]) def load_cls_names(maincls): assert inspect.isclass(maincls) res = {} for cls in inspect.getmro(maincls): for name, val in inspect.getmembers(cls): if name not in res: res[name] = val return res def cleansig(sig): res = str(sig).replace(", /", "") if "*" in res: res = res.split(", *", 1)[0] + ")" return res def compare(rmaincls, zmaincls): znames = load_cls_names(zmaincls) rnames = load_cls_names(rmaincls) for name, zval in znames.items(): if not inspect.isroutine(zval) or name[0] == "_" or name in _ignore: continue assert name in rnames, "member not found: \"%s\"" % name rval = rnames[name] zsig = inspect.signature(zval) rsig = inspect.signature(rval) zsigstr = cleansig(zsig) rsigstr = cleansig(rsig) assert zsigstr == rsigstr, "sig differs: %s.%s%s != %s.%s%s" % ( rmaincls.__name__, name, rsigstr, zmaincls.__name__, name, zsigstr) @pytest.mark.skipif(_UNSUPPORTED, reason="Unsupported for sig checks") def test_cmp_zipfile(): compare(rarfile.RarFile, zipfile.ZipFile) @pytest.mark.skipif(_UNSUPPORTED, reason="Unsupported for sig checks") def test_cmp_zipextfile(): compare(rarfile.RarExtFile, zipfile.ZipExtFile) @pytest.mark.skipif(_UNSUPPORTED, reason="Unsupported for sig checks") def test_cmp_zipinfo(): compare(rarfile.RarInfo, zipfile.ZipInfo) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_crypto.py0000644000175100001770000000240414501653005016316 0ustar00runnerdocker"""Crypto tests. """ from __future__ import division, print_function from binascii import unhexlify import pytest import rarfile try: from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes, ) def aes_encrypt(key, iv, data): ciph = Cipher(algorithms.AES(key), modes.CBC(iv), default_backend()) enc = ciph.encryptor() return enc.update(data) except ImportError: pass @pytest.mark.skipif(not rarfile._have_crypto, reason="No crypto") def test_aes128_cbc(): data = b"0123456789abcdef" * 2 key = b"\x02" * 16 iv = b"\x80" * 16 #encdata = aes_encrypt(key, iv, data) encdata = unhexlify("4b0d438b4a1b972bd4ab81cd64674dcce4b0158090fbe616f455354284d53502") ctx = rarfile.AES_CBC_Decrypt(key, iv) assert ctx.decrypt(encdata) == data @pytest.mark.skipif(not rarfile._have_crypto, reason="No crypto") def test_aes256_cbc(): data = b"0123456789abcdef" * 2 key = b"\x52" * 32 iv = b"\x70" * 16 #encdata = aes_encrypt(key, iv, data) encdata = unhexlify("24988f387592e4d95b6eaab013137a221f81b25aa7ecde0ef4f4d7a95f92c250") ctx = rarfile.AES_CBC_Decrypt(key, iv) assert ctx.decrypt(encdata) == data ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_extract.py0000644000175100001770000001554414501653005016461 0ustar00runnerdocker"""Extract tests. """ import io import os import sys from datetime import datetime import pytest import rarfile def get_props(rf, name): inf = rf.getinfo(name) return "".join([ inf.is_file() and "F" or "-", inf.is_dir() and "D" or "-", inf.is_symlink() and "L" or "-", ]) def san_unix(fn): return rarfile.sanitize_filename(fn, "/", False) def san_win32(fn): return rarfile.sanitize_filename(fn, "/", True) def test_sanitize_unix(): assert san_unix("asd/asd") == "asd/asd" assert san_unix("asd/../asd") == "asd/asd" assert san_unix("c:/a/x") == r"c:/a/x" assert san_unix("z/./../a /b./c") == "z/a /b./c" assert san_unix("z<>*?:") == "z____:" def test_sanitize_win32(): assert san_win32("asd/asd") == "asd/asd" assert san_win32("asd/../asd") == "asd/asd" assert san_win32("c:/a/x") == "a/x" assert san_win32("z/./../a /b./c") == "z/a_/b_/c" assert san_win32("z<>*?:\\^") == "z_______" def checktime(fn, exp_mtime): # cannot check subsecond precision as filesystem may not support it cut = len("0000-00-00 00:00:00") st = os.stat(fn) got_mtime = datetime.fromtimestamp(st.st_mtime, exp_mtime.tzinfo) exp_stamp = exp_mtime.isoformat(" ", "seconds")[:cut] got_stamp = got_mtime.isoformat(" ", "seconds")[:cut] assert exp_stamp == got_stamp def checkfile(fn, data, mtime): with open(fn, "r", encoding="utf8") as f: got = f.read() assert got.strip() == data checktime(fn, mtime) def check_subdir(rf, tmp_path): # pre-mkdir ext1 = tmp_path / "ext1" inf = rf.getinfo("sub/dir1/file1.txt") os.mkdir(ext1) rf.extract(inf, ext1) assert sorted(os.listdir(tmp_path)) == ["ext1"] assert os.listdir(ext1 / "sub") == ["dir1"] checkfile(ext1 / "sub/dir1/file1.txt", "file1", inf.mtime) # no mkdir ext2 = tmp_path / "ext2" inf = rf.getinfo("sub/dir2/file2.txt") rf.extract("sub/dir2/file2.txt", ext2) assert sorted(os.listdir(tmp_path)) == ["ext1", "ext2"] assert os.listdir(ext2 / "sub") == ["dir2"] checkfile(ext2 / "sub/dir2/file2.txt", "file2", inf.mtime) # spaced ext3 = tmp_path / "ext3" inf = rf.getinfo("sub/with space/long fn.txt") rf.extract("sub/with space/long fn.txt", ext3) checkfile(ext3 / "sub/with space/long fn.txt", "long fn", inf.mtime) # unicode ext4 = tmp_path / "ext4" inf = rf.getinfo("sub/üȵĩöḋè/file.txt") rf.extract("sub/üȵĩöḋè/file.txt", ext4) checkfile(ext4 / "sub/üȵĩöḋè/file.txt", "file", inf.mtime) # dir only ext5 = tmp_path / "ext5" inf = rf.getinfo("sub/dir2") rf.extract("sub/dir2", ext5) assert os.listdir(ext5 / "sub") == ["dir2"] assert os.listdir(ext5 / "sub/dir2") == [] checktime(ext5 / "sub/dir2", inf.mtime) # cwd ext6 = tmp_path / "ext6" os.mkdir(ext6) old = os.getcwd() try: os.chdir(ext6) rf.extract("sub/dir1") assert os.listdir(".") == ["sub"] assert os.listdir("sub") == ["dir1"] assert os.listdir("sub/dir1") == [] finally: os.chdir(old) # errors with pytest.raises(io.UnsupportedOperation): rf.open("sub/dir1") @pytest.mark.parametrize("fn", [ "test/files/rar3-subdirs.rar", "test/files/rar5-subdirs.rar", ]) def test_subdirs(fn, tmp_path): with rarfile.RarFile(fn) as rf: check_subdir(rf, tmp_path) @pytest.mark.parametrize("fn", [ "test/files/rar3-readonly-unix.rar", "test/files/rar3-readonly-win.rar", "test/files/rar5-readonly-unix.rar", "test/files/rar5-readonly-win.rar", ]) def test_readonly(fn, tmp_path): with rarfile.RarFile(fn) as rf: assert get_props(rf, "ro_dir") == "-D-" assert get_props(rf, "ro_dir/ro_file.txt") == "F--" rf.extractall(tmp_path) assert os.access(tmp_path / "ro_dir/ro_file.txt", os.R_OK) assert not os.access(tmp_path / "ro_dir/ro_file.txt", os.W_OK) if sys.platform != "win32": assert os.access(tmp_path / "ro_dir", os.R_OK) assert not os.access(tmp_path / "ro_dir", os.W_OK) @pytest.mark.parametrize("fn", [ "test/files/rar3-symlink-unix.rar", "test/files/rar5-symlink-unix.rar", ]) def test_symlink(fn, tmp_path): with rarfile.RarFile(fn) as rf: assert get_props(rf, "data.txt") == "F--" assert get_props(rf, "data_link") == "--L" assert get_props(rf, "random_link") == "--L" rf.extractall(tmp_path) assert sorted(os.listdir(tmp_path)) == ["data.txt", "data_link", "random_link"] data = rf.getinfo("data.txt") data_link = rf.getinfo("data_link") random_link = rf.getinfo("random_link") assert not data.is_symlink() assert data_link.is_symlink() assert random_link.is_symlink() assert rf.read(data) == b"data\n" assert rf.read(data_link) == b"data.txt" assert rf.read(random_link) == b"../random123" assert os.path.isfile(tmp_path / "data.txt") assert os.path.islink(tmp_path / "data_link") assert os.path.islink(tmp_path / "random_link") # str - work around pypy3 bug assert os.readlink(str(tmp_path / "data_link")) == "data.txt" assert os.readlink(str(tmp_path / "random_link")) == "../random123" def test_symlink_win(tmp_path): fn = "test/files/rar5-symlink-win.rar" with rarfile.RarFile(fn) as rf: assert get_props(rf, "content/dir1") == "-D-" assert get_props(rf, "content/dir2") == "-D-" assert get_props(rf, "content/file.txt") == "F--" assert get_props(rf, "links/bad_link") == "--L" assert get_props(rf, "links/dir_junction") == "--L" assert get_props(rf, "links/dir_link") == "--L" assert get_props(rf, "links/file_link") == "--L" with pytest.warns(rarfile.UnsupportedWarning): rf.extractall(tmp_path) assert sorted(os.listdir(tmp_path)) == ["content", "links"] assert sorted(os.listdir(tmp_path / "content")) == ["dir1", "dir2", "file.txt"] assert sorted(os.listdir(tmp_path / "links")) == ["bad_link", "dir_link", "file_link"] assert os.path.islink(tmp_path / "links/bad_link") assert os.path.islink(tmp_path / "links/dir_link") assert os.path.islink(tmp_path / "links/file_link") @pytest.mark.parametrize("fn", [ "test/files/rar3-old.rar", "test/files/rar3-vols.part1.rar", "test/files/rar5-vols.part1.rar", ]) def test_vols(fn, tmp_path): with rarfile.RarFile(fn) as rf: rarfile.FORCE_TOOL = True try: rf.extractall(str(tmp_path)) finally: rarfile.FORCE_TOOL = False assert sorted(os.listdir(tmp_path)) == ["vols"] assert sorted(os.listdir(tmp_path / "vols")) == ["bigfile.txt", "smallfile.txt"] assert os.path.isfile(tmp_path / "vols" / "bigfile.txt") assert os.path.isfile(tmp_path / "vols" / "smallfile.txt") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_format.py0000644000175100001770000002106414501653005016271 0ustar00runnerdocker"""Format details. """ from datetime import datetime import pytest import rarfile def render_date(dt): if isinstance(dt, datetime): return dt.isoformat("T") elif isinstance(dt, tuple): return "%04d-%02d-%02d %02d:%02d:%02d" % dt else: return dt def mkitem(**kwargs): res = {} for k, v in kwargs.items(): if v is not None: res[k] = v return res def dumparc(rf): res = [] for item in rf.infolist(): info = mkitem(fn=item.filename, file_size=item.file_size, compress_size=item.compress_size, CRC=item.CRC, date_time=render_date(item.date_time), arctime=render_date(item.arctime), mtime=render_date(item.mtime), atime=render_date(item.atime), ctime=render_date(item.ctime), comment=item.comment, extract_version=item.extract_version, compress_type=item.compress_type, mode=item.mode, host_os=item.host_os) res.append(info) return res def diffs(a, b): if len(a) != len(b): return "Different lengths" problems = [] for i, xa in enumerate(a): xb = b[i] for k in xa: if k not in xb: problems.append("NewKey(%d,%s)=%r" % (i, k, xa[k])) for k in xb: if k not in xa: problems.append("MissingKey(%d,%s)=%r" % (i, k, xb[k])) for k in xa: if k in xb and xa[k] != xb[k]: problems.append("ErrValue(%d,%s):got=%r/exp=%r" % (i, k, xa[k], xb[k])) return "; ".join(problems) def cmp_struct(a, b): assert a == b, diffs(a, b) # # test start # @pytest.mark.skipif(not rarfile._have_crypto, reason="No crypto") def test_rar3_header_encryption(): r = rarfile.RarFile("test/files/rar3-comment-hpsw.rar", "r") assert r.needs_password() is True assert r.comment is None assert r.namelist() == [] r.setpassword("password") assert r.needs_password() is True assert r.namelist() == ["file1.txt", "file2.txt"] assert r.comment is not None assert r.comment == "RARcomment\n" @pytest.mark.skipif(not rarfile._have_crypto, reason="No crypto") def test_rar5_header_encryption(): r = rarfile.RarFile("test/files/rar5-hpsw.rar") assert r.needs_password() is True assert r.comment is None assert r.namelist() == [] r.setpassword("password") assert r.needs_password() is True assert r.namelist() == ["stest1.txt", "stest2.txt"] assert r.comment is not None assert r.comment == "RAR5 archive - hdr-password\n" r.close() def get_vol_info(extver=20, tz="", hr="11"): return [ mkitem(CRC=1352324940, date_time="2016-05-24 %s:42:37%s" % (hr, ""), mtime="2016-05-24T%s:42:37%s" % (hr, tz), compress_type=48, compress_size=205000, extract_version=extver, file_size=205000, mode=33204, host_os=3, fn="vols/bigfile.txt"), mkitem(CRC=3498712966, date_time="2016-05-24 %s:42:43%s" % (hr, ""), mtime="2016-05-24T%s:42:43%s" % (hr, tz), extract_version=extver, compress_type=48, compress_size=2050, file_size=2050, mode=33204, host_os=3, fn="vols/smallfile.txt")] def test_rar3_vols(): r = rarfile.RarFile("test/files/rar3-vols.part1.rar") assert r.needs_password() is False assert r.comment is None assert r.strerror() is None cmp_struct(dumparc(r), get_vol_info()) assert r.volumelist() == [ "test/files/rar3-vols.part1.rar", "test/files/rar3-vols.part2.rar", "test/files/rar3-vols.part3.rar"] with pytest.raises(rarfile.NeedFirstVolume): rarfile.RarFile("test/files/rar3-vols.part2.rar") def test_rar3_oldvols(): r = rarfile.RarFile("test/files/rar3-old.rar") assert r.needs_password() is False assert r.comment is None assert r.strerror() is None cmp_struct(dumparc(r), get_vol_info()) assert r.volumelist() == [ "test/files/rar3-old.rar", "test/files/rar3-old.r00", "test/files/rar3-old.r01"] with pytest.raises(rarfile.NeedFirstVolume): rarfile.RarFile("test/files/rar3-old.r00") def test_rar5_vols(): r = rarfile.RarFile("test/files/rar5-vols.part1.rar") assert r.needs_password() is False assert r.comment is None assert r.strerror() is None cmp_struct(dumparc(r), get_vol_info(50, "+00:00", "08")) assert r.volumelist() == [ "test/files/rar5-vols.part1.rar", "test/files/rar5-vols.part2.rar", "test/files/rar5-vols.part3.rar"] with pytest.raises(rarfile.NeedFirstVolume): rarfile.RarFile("test/files/rar5-vols.part2.rar") def expect_ctime(mtime, ctime): return [mkitem( mtime=mtime, date_time=mtime.split(".")[0].replace("T", " "), ctime=ctime, compress_size=0, file_size=0, CRC=0, fn="afile.txt", extract_version=29, compress_type=48, mode=32, host_os=2)] def test_rar3_ctime0(): r = rarfile.RarFile("test/files/ctime0.rar") cmp_struct(dumparc(r), expect_ctime("2011-05-10T21:28:47.899345100", None)) def test_rar3_ctime1(): r = rarfile.RarFile("test/files/ctime1.rar") cmp_struct(dumparc(r), expect_ctime("2011-05-10T21:28:47.899345100", "2011-05-10T21:28:47")) def test_rar3_ctime2(): r = rarfile.RarFile("test/files/ctime2.rar") cmp_struct(dumparc(r), expect_ctime("2011-05-10T21:28:47.899345100", "2011-05-10T21:28:47.897843200")) def test_rar3_ctime3(): r = rarfile.RarFile("test/files/ctime3.rar") cmp_struct(dumparc(r), expect_ctime("2011-05-10T21:28:47.899345100", "2011-05-10T21:28:47.899328")) def test_rar3_ctime4(): r = rarfile.RarFile("test/files/ctime4.rar") cmp_struct(dumparc(r), expect_ctime("2011-05-10T21:28:47.899345100", "2011-05-10T21:28:47.899345100")) def test_rar5_ctime5(): r = rarfile.RarFile("test/files/ctime5.rar") inf = r.getinfo("timed.txt") assert inf.mtime.isoformat() == "2020-07-30T20:26:59.677675904+00:00" assert inf.ctime.isoformat() == "2020-07-30T20:28:19.398867888+00:00" assert inf.atime.isoformat() == "2020-07-30T20:27:10.121196721+00:00" def test_rar5_times(): r = rarfile.RarFile("test/files/rar5-times.rar") cmp_struct(dumparc(r), [mkitem( fn="stest1.txt", file_size=2048, compress_size=55, compress_type=rarfile.RAR_M3, extract_version=50, host_os=rarfile.RAR_OS_UNIX, mode=33188, date_time="2011-06-12 09:53:33", mtime="2011-06-12T09:53:33+00:00", atime="2016-05-22T09:12:36+00:00", CRC=3317163682 )]) def test_oldvols(): assert rarfile._next_oldvol("archive") == "archive.r00" assert rarfile._next_oldvol("archive.rar/foo") == "archive.rar/foo.r00" assert rarfile._next_oldvol("archive.arr") == "archive.a00" assert rarfile._next_oldvol("archive.brar") == "archive.b00" assert rarfile._next_oldvol("qq00.part0.rar") == "qq00.part0.r00" assert rarfile._next_oldvol("qq00.part0.r00") == "qq00.part0.r01" assert rarfile._next_oldvol("qq00.part0.r29") == "qq00.part0.r30" assert rarfile._next_oldvol("qq00.part0.r99") == "qq00.part0.s00" def test_newvols(): assert rarfile._next_newvol("qq00.part0.rar") == "qq00.part1.rar" assert rarfile._next_newvol("qq00.part09.rar") == "qq00.part10.rar" assert rarfile._next_newvol("qq00.part99.rar") == "qq00.part100.rar" assert rarfile._next_newvol("part20") == "part21.rar" assert rarfile._next_newvol("qq00.part3.exe") == "qq00.part4.rar" assert rarfile._next_newvol("qq00.part5.sfx") == "qq00.part6.rar" assert rarfile._next_newvol("qq00.part6.bin") == "qq00.part7.bin" assert rarfile._next_newvol("99") == "100.rar" assert rarfile._next_newvol("dir/99.rar") == "dir/100.rar" with pytest.raises(rarfile.BadRarName): rarfile._next_newvol("qq00.part7.rar/foo") with pytest.raises(rarfile.BadRarName): rarfile._next_newvol("foo") def test_newvols_err(): with pytest.raises(rarfile.BadRarName): rarfile._next_newvol("xx.rar") @pytest.mark.parametrize("fn", ["test/files/rar3-versions.rar", "test/files/rar5-versions.rar"]) def test_versions(fn): with rarfile.RarFile(fn) as rf: assert rf.namelist() == ["versioned.txt"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_hashing.py0000644000175100001770000000637714501653005016434 0ustar00runnerdocker"""Hashing tests. """ import hashlib from binascii import hexlify, unhexlify import rarfile from rarfile import Blake2SP, CRC32Context, NoHashContext, Rar3Sha1 def tohex(data): """Return hex string.""" return hexlify(data).decode("ascii") def test_nohash(): assert NoHashContext("").hexdigest() is None assert NoHashContext("asd").hexdigest() is None md = NoHashContext() md.update("asd") assert md.digest() is None def test_crc32(): assert CRC32Context(b"").hexdigest() == "00000000" assert CRC32Context(b"Hello").hexdigest() == "f7d18982" assert CRC32Context(b"Bye").hexdigest() == "4f7ad7d4" md = CRC32Context() md.update(b"He") md.update(b"ll") md.update(b"o") assert md.hexdigest() == "f7d18982" def xblake2sp(xdata): data = unhexlify(xdata) md = Blake2SP() md.update(data) return md.hexdigest() def xblake2sp_slow(xdata): data = unhexlify(xdata) md = Blake2SP() buf = memoryview(data) pos = 0 while pos < len(buf): md.update(buf[pos: pos + 3]) pos += 3 return md.hexdigest() def test_blake2sp(): assert Blake2SP(b"").hexdigest() == "dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f" assert Blake2SP(b"Hello").hexdigest() == "0d6bae0db99f99183d060f7994bb94b45c6490b2a0a628b8b1346ebea8ec1d66" assert xblake2sp("") == "dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f" assert xblake2sp("00") == "a6b9eecc25227ad788c99d3f236debc8da408849e9a5178978727a81457f7239" long1 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031" assert xblake2sp(long1) == "270affa6426f1a515c9b76dfc27d181fc2fd57d082a3ba2c1eef071533a6dfb7" long2 = long1 * 20 assert xblake2sp(long2) == "24a78d92592d0761a3681f32935225ca55ffb8eb16b55ab9481c89c59a985ff3" assert xblake2sp_slow(long2) == "24a78d92592d0761a3681f32935225ca55ffb8eb16b55ab9481c89c59a985ff3" def test_rar3_sha1(): for n in range(0, 200): data = bytearray(range(n)) h1 = hashlib.sha1(data).hexdigest() h2 = Rar3Sha1(data).hexdigest() assert h1 == h2 data = bytearray([(i & 255) for i in range(2000)]) x1 = hashlib.sha1() x2 = Rar3Sha1() for step in (3, 17, 67, 128, 157): pos = 0 while pos < len(data): pos2 = pos + step if pos2 > len(data): pos2 = len(data) x1.update(data[pos:pos2]) x2.update(data[pos:pos2]) assert x1.hexdigest() == x2.hexdigest() pos = pos2 def test_rar3_s2k(): exp = ("a160cb31cb262e9231c0b6fc984fbb0d", "aa54a659fb0c359b30f353a6343fb11d") key, iv = rarfile.rar3_s2k(b"password", unhexlify("00FF00")) assert (tohex(key), tohex(iv)) == exp key, iv = rarfile.rar3_s2k("password", unhexlify("00FF00")) assert (tohex(key), tohex(iv)) == exp exp = ("ffff33ffaf31987c899ccc2f965a8927", "bdff6873721b247afa4f978448a5aeef") key, iv = rarfile.rar3_s2k("p" * 28, unhexlify("1122334455667788")) assert (tohex(key), tohex(iv)) == exp exp = ("306cafde28f1ea78c9427c3ec642c0db", "173ecdf574c0bfe9e7c23bdfd96fa435") key, iv = rarfile.rar3_s2k("p" * 29, unhexlify("1122334455667788")) assert (tohex(key), tohex(iv)) == exp ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_korrupt.py0000644000175100001770000000252714501653005016512 0ustar00runnerdocker"""test corrupt file parsing. """ import glob import io import rarfile def try_read(tmpfn): if not rarfile.is_rarfile(tmpfn): return rarfile.RarFile(tmpfn, errors="stop") try: rf = rarfile.RarFile(tmpfn, errors="strict") if rf.needs_password(): rf.setpassword("password") except rarfile.Error: return for fn in rf.namelist(): try: rf.read(fn) except rarfile.Error: pass def process_rar(rarfn, quick=False): with open(rarfn, "rb") as f: data = f.read() for n in range(len(data)): bad = io.BytesIO(data[:n]) if not rarfile.is_rarfile(bad): return try_read(bad) crap = b"\x00\xff\x01\x80\x7f" if quick: crap = b"\xff" for n in range(1, len(data)): for i in range(len(crap)): c = crap[i:i + 1] bad = data[:n - 1] + c + data[n:] try_read(io.BytesIO(bad)) def test_corrupt_quick_rar3(): process_rar("test/files/rar3-comment-plain.rar", True) def test_corrupt_quick_rar5(): process_rar("test/files/rar5-times.rar", True) def test_corrupt_all(): test_rar_list = glob.glob("test/files/*.rar") test_rar_list = [] for rar in test_rar_list: process_rar(rar) if __name__ == "__main__": test_corrupt_quick_rar5() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_reading.py0000644000175100001770000000704314501653005016413 0ustar00runnerdocker"""Read all test files. """ import io from glob import glob import pytest import rarfile ARCHIVE_COMMENTS = { "rar15-comment-lock.rar": "RARcomment -----", "rar15-comment.rar": "RARcomment -----", "rar202-comment-nopsw.rar": "RARcomment", "rar202-comment-psw.rar": "RARcomment", "rar3-comment-hpsw.rar": "RARcomment\n", "rar3-comment-plain.rar": "RARcomment\n", "rar3-comment-psw.rar": "RARcomment\n", "rar5-blake.rar": "RAR5 archive - blake\n", "rar5-crc.rar": "RAR5 archive - crc\n", "rar5-crc.sfx": "RAR5 archive - crc\n", "rar5-hpsw.rar": "RAR5 archive - hdr-password\n", "rar5-psw-blake.rar": "RAR5 archive - nohdr-password-blake\n", "rar5-psw.rar": "RAR5 archive - nohdr-password\n", } ARCHIVE_FILES = [ f.replace("\\", "/") for f in sorted(glob("test/files/*.rar")) if "hpsw" not in f and "unicode.rar" not in f ] def run_reading_normal(fn, comment): try: rf = rarfile.RarFile(fn) except rarfile.NeedFirstVolume: return if rf.needs_password(): rf.setpassword("password") assert rf.strerror() is None assert rf.comment == comment for ifn in rf.namelist(): if ifn.endswith("/"): continue info = rf.getinfo(ifn) if info.is_dir(): continue if info.is_symlink(): continue # full read rf.read(ifn) # read from stream item = rf.getinfo(ifn) f = rf.open(ifn) total = 0 while True: buf = f.read(1024) if not buf: break total += len(buf) f.close() assert total == item.file_size, ifn # read from stream with readinto bbuf = bytearray(1024) with rf.open(ifn) as f: res = f.readinto(memoryview(bbuf)) if res == 0: break def run_reading_inmem(fn, comment): try: rf = rarfile.RarFile(fn) except rarfile.NeedFirstVolume: return if len(rf.volumelist()) > 1: return with io.open(fn, "rb") as f: buf = f.read() run_reading_normal(io.BytesIO(buf), comment) def run_reading(fn): basename = fn.split("/")[-1] comment = ARCHIVE_COMMENTS.get(basename) run_reading_normal(fn, comment) run_reading_inmem(fn, comment) @pytest.mark.parametrize("fn", ARCHIVE_FILES) def test_reading(fn): run_reading(fn) @pytest.mark.skipif(not rarfile._have_crypto, reason="No crypto") def test_reading_rar3_hpsw(): run_reading("test/files/rar3-comment-hpsw.rar") @pytest.mark.skipif(rarfile._have_crypto, reason="Has crypto") def test_reading_rar3_hpsw_nocrypto(): with pytest.raises(rarfile.NoCrypto): run_reading("test/files/rar3-comment-hpsw.rar") @pytest.mark.skipif(not rarfile._have_crypto, reason="No crypto") def test_reading_rar5_hpsw(): run_reading("test/files/rar5-hpsw.rar") @pytest.mark.skipif(rarfile._have_crypto, reason="Has crypto") def test_reading_rar5_hpsw_nocrypto(): with pytest.raises(rarfile.NoCrypto): run_reading("test/files/rar5-hpsw.rar") def test_reading_rar3_sfx(): assert rarfile.is_rarfile("test/files/rar3-seektest.sfx") is False assert rarfile.is_rarfile_sfx("test/files/rar3-seektest.sfx") is True run_reading("test/files/rar3-seektest.sfx") run_reading("test/files/rar3-seektest.sfx") def test_reading_rar5_crc_sfx(): assert rarfile.is_rarfile("test/files/rar5-crc.sfx") is False assert rarfile.is_rarfile_sfx("test/files/rar5-crc.sfx") is True run_reading("test/files/rar5-crc.sfx") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_seek.py0000644000175100001770000000522214501653005015726 0ustar00runnerdocker"""Test seeking on files. """ import io import pytest import rarfile ARC = "test/files/seektest.rar" _WHENCE = 0 def do_seek(f, pos, lim, size=None): global _WHENCE ofs = pos * 4 fsize = lim * 4 if ofs < 0: exp = 0 elif ofs > fsize: exp = fsize else: exp = ofs if size: cur = f.tell() if _WHENCE == 0: f.seek(ofs, _WHENCE) elif _WHENCE == 1: f.seek(ofs - cur, _WHENCE) else: assert _WHENCE == 2 f.seek(ofs - size, _WHENCE) _WHENCE = (_WHENCE + 1) % 3 else: f.seek(ofs) got = f.tell() assert got == exp ln = f.read(4) if got == fsize and ln: raise ValueError("unexpected read") if not ln and got < fsize: raise ValueError("unexpected read failure") if ln: spos = int(ln) assert spos * 4 == got def run_seek(rf, fn): inf = rf.getinfo(fn) cnt = int(inf.file_size / 4) f = rf.open(fn) with pytest.raises(ValueError): f.seek(0, -1) with pytest.raises(ValueError): f.seek(0, 3) do_seek(f, int(cnt / 2), cnt) do_seek(f, 0, cnt) for i in range(int(cnt / 2)): do_seek(f, i * 2, cnt, inf.file_size) for i in range(cnt): do_seek(f, i * 2 - int(cnt / 2), cnt, inf.file_size) for i in range(cnt + 10): do_seek(f, cnt - i - 5, cnt, inf.file_size) f.close() def run_arc(arc, desc): files = ["stest1.txt", "stest2.txt"] rf = rarfile.RarFile(arc) for fn in files: run_seek(rf, fn) def test_seek_filename(): run_arc(ARC, "fn") def test_seek_bytesio(): # filelike: io.BytesIO, io.open() with open(ARC, "rb") as f: data = f.read() run_arc(io.BytesIO(data), "io.BytesIO") def test_seek_open(): # filelike: file() with open(ARC, "rb") as f: run_arc(f, "open") def test_seek_ioopen(): # filelike: io.open() with io.open(ARC, "rb") as f: run_arc(f, "io.open") def run_seek_middle(fn, entry): rar = rarfile.RarFile(fn) file = rar.open(entry) assert file.read(1) == b"0" assert file.read(1) == b"0" assert file.read(1) == b"0" assert file.read(1) == b"\n" file.read() file.seek(0) assert file.read(1) == b"0" assert file.read(1) == b"0" assert file.read(1) == b"0" assert file.read(1) == b"\n" file.read() file.seek(2) assert file.read(1) == b"0" assert file.read(1) == b"\n" file.read() def test_seek_middle1(): run_seek_middle("test/files/seektest.rar", "stest1.txt") def test_seek_middle2(): run_seek_middle("test/files/seektest.rar", "stest2.txt") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_tool.py0000644000175100001770000001344514501653005015762 0ustar00runnerdocker"""Alt tool tests """ import sys import os import pytest import rarfile def have_tool(name): for dn in os.get_exec_path(): if os.path.isfile(os.path.join(dn, name)): return True if os.path.isfile(os.path.join(dn, name + ".exe")): return True return False def tool_setup(unrar=False, unar=False, bsdtar=False, sevenzip=False, sevenzip2=False): rarfile.FORCE_TOOL = True rarfile.tool_setup(unrar=unrar, unar=unar, bsdtar=bsdtar, sevenzip=sevenzip, sevenzip2=sevenzip2, force=True) def install_unrar_tool(): tool_setup(unrar=True) def install_unar_tool(): tool_setup(unar=True) def install_bsdtar_tool(): tool_setup(bsdtar=True) def install_7z_tool(): tool_setup(sevenzip=True) def install_7zz_tool(): tool_setup(sevenzip2=True) def uninstall_alt_tool(): rarfile.FORCE_TOOL = False rarfile.tool_setup(force=True) def test_read_rar3(): with rarfile.RarFile("test/files/seektest.rar") as rf: for fn in rf.namelist(): rf.read(fn) def test_read_vols(): with rarfile.RarFile("test/files/rar3-old.rar") as rf: for fn in rf.namelist(): rf.read(fn) # old with rarfile.RarFile("test/files/rar3-vols.part1.rar") as rf: for fn in rf.namelist(): rf.read(fn) # rar3-new with rarfile.RarFile("test/files/rar5-vols.part1.rar") as rf: for fn in rf.namelist(): rf.read(fn) # rar5 def test_unrar_tool(): install_unrar_tool() try: test_read_rar3() test_read_vols() with rarfile.RarFile("test/files/rar3-comment-plain.rar") as rf: rf.read("file1.txt") rf.read("file2.txt") with rarfile.RarFile("test/files/rar3-comment-psw.rar") as rf: rf.setpassword("password") rf.read("file1.txt") finally: uninstall_alt_tool() @pytest.mark.skipif(sys.platform == "win32", reason="unar not available on Windows") @pytest.mark.skipif(not have_tool(rarfile.UNAR_TOOL), reason="unar not installed") def test_unar_tool(): install_unar_tool() try: test_read_rar3() test_read_vols() with rarfile.RarFile("test/files/rar3-comment-plain.rar") as rf: rf.read("file1.txt") rf.read("file2.txt") with rarfile.RarFile("test/files/rar3-comment-psw.rar") as rf: rf.setpassword("password") rf.read("file1.txt") finally: uninstall_alt_tool() @pytest.mark.skipif(not have_tool(rarfile.BSDTAR_TOOL), reason="bsdtar not installed") def test_bsdtar_tool(): install_bsdtar_tool() try: #test_read_rar3() #test_read_vols() with rarfile.RarFile("test/files/rar3-comment-plain.rar") as rf: rf.read("file1.txt") rf.read("file2.txt") with pytest.raises(rarfile.RarCannotExec): with rarfile.RarFile("test/files/rar3-comment-psw.rar") as rf: rf.setpassword("password") rf.read("file1.txt") finally: uninstall_alt_tool() @pytest.mark.skipif(not have_tool(rarfile.SEVENZIP_TOOL), reason="7z not installed") def test_7z_tool(): install_7z_tool() try: #test_read_rar3() test_read_vols() with rarfile.RarFile("test/files/rar3-comment-plain.rar") as rf: rf.read("file1.txt") rf.read("file2.txt") with rarfile.RarFile("test/files/rar3-comment-psw.rar") as rf: rf.setpassword("password") rf.read("file1.txt") finally: uninstall_alt_tool() @pytest.mark.skipif(not have_tool(rarfile.SEVENZIP2_TOOL), reason="7zz not installed") def test_7zz_tool(): install_7zz_tool() try: #test_read_rar3() test_read_vols() with rarfile.RarFile("test/files/rar3-comment-plain.rar") as rf: rf.read("file1.txt") rf.read("file2.txt") with rarfile.RarFile("test/files/rar3-comment-psw.rar") as rf: rf.setpassword("password") rf.read("file1.txt") finally: uninstall_alt_tool() # test popen errors def test_popen_fail(): with pytest.raises(rarfile.RarCannotExec): rarfile.custom_popen(["missing-unrar-exe"]) if sys.platform != "win32": with pytest.raises(rarfile.RarCannotExec): rarfile.custom_popen(["./test/files/rar5-blake.rar.exp"]) def test_check_returncode(): errmap = rarfile.UNRAR_CONFIG["errmap"] assert not rarfile.check_returncode(0, "", errmap) with pytest.raises(rarfile.RarFatalError): rarfile.check_returncode(2, "x", errmap) with pytest.raises(rarfile.RarUnknownError): rarfile.check_returncode(100, "", errmap) with pytest.raises(rarfile.RarUserBreak): rarfile.check_returncode(255, "", errmap) with pytest.raises(rarfile.RarSignalExit): rarfile.check_returncode(-11, "", errmap) errmap = rarfile.UNAR_CONFIG["errmap"] with pytest.raises(rarfile.RarUnknownError): rarfile.check_returncode(2, "", errmap) # own cli tests def cli(*args): try: rarfile.main(args) return 0 except SystemExit as ex: return int(ex.code) except Exception as ex: sys.stderr.write(str(ex) + "\n") return 1 def test_cli_list(capsys): assert cli("-l", "test/files/rar3-old.rar") == 0 res = capsys.readouterr() assert "bigfile" in res.out def test_cli_testrar(capsys): assert cli("-t", "test/files/rar3-old.rar") == 0 res = capsys.readouterr() assert not res.err def test_cli_extract(capsys, tmp_path): assert cli("-e", "test/files/rar3-old.rar", str(tmp_path)) == 0 res = capsys.readouterr() assert not res.err def test_cli_help(capsys): assert cli("--help") == 0 res = capsys.readouterr() assert "option" in res.out ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/test/test_util.py0000644000175100001770000000662614501653005015765 0ustar00runnerdocker # pylint: disable=comparison-with-itself,unneeded-not from datetime import datetime, timedelta, timezone import rarfile def test_load_vint(): assert rarfile.load_vint(b"\x00", 0) == (0, 1) assert rarfile.load_vint(b"\x80\x01", 0) == (1 << 7, 2) assert rarfile.load_vint(b"\x80\x80\x01", 0) == (1 << 14, 3) assert rarfile.load_vint(b"\x80\x80\x80\x01", 0) == (1 << 21, 4) assert rarfile.load_vint(b"\x80\x80\x80\x80\x01", 0) == (1 << 28, 5) assert rarfile.load_vint(b"\x80\x80\x80\x80\x80\x01", 0) == (1 << 35, 6) assert rarfile.load_vint(b"\x80" * 10 + b"\x01", 0) == (1 << 70, 11) def test_to_datetime(): assert rarfile.to_datetime((2020, 0, 0, 0, 0, 0)) == datetime(2020, 1, 1, 0, 0, 0) assert rarfile.to_datetime((2020, 60, 60, 60, 60, 60)) == datetime(2020, 12, 31, 23, 59, 59) assert rarfile.to_datetime((2020, 2, 30, 60, 60, 60)) == datetime(2020, 2, 28, 23, 59, 59) assert rarfile.to_datetime((2021, 2, 30, 60, 60, 60)) == datetime(2021, 2, 28, 23, 59, 59) def test_to_nsdatetime(): base = datetime(2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc) assert rarfile.to_nsdatetime(base, 0) is base res = rarfile.to_nsdatetime(base, 1000) assert res == base.replace(microsecond=1) assert isinstance(res, datetime) assert res.isoformat(" ") == "2020-01-01 00:00:00.000001+00:00" res = rarfile.to_nsdatetime(base, 1001) assert isinstance(res, datetime) assert isinstance(res, rarfile.nsdatetime) assert res.microsecond == 1 assert res.nanosecond == 1001 assert res.isoformat(" ") == "2020-01-01 00:00:00.000001001+00:00" assert res.isoformat(" ", "auto") == "2020-01-01 00:00:00.000001001+00:00" assert res.isoformat(" ", "microseconds") == "2020-01-01 00:00:00.000001+00:00" def test_nsdatetime_cmp(): nsdatetime = rarfile.nsdatetime n1 = nsdatetime(2000, 1, 1, 9, 15, 30, nanosecond=100200300, tzinfo=timezone.utc) n2 = nsdatetime(2000, 1, 1, 9, 15, 30, nanosecond=100200301, tzinfo=timezone.utc) n3 = nsdatetime(2000, 1, 1, 9, 15, 30, nanosecond=100200402, tzinfo=timezone.utc) d1 = datetime(2000, 1, 1, 9, 15, 30, 100100, timezone.utc) d2 = datetime(2000, 1, 1, 9, 15, 30, 100200, timezone.utc) d3 = datetime(2000, 1, 1, 9, 15, 30, 100300, timezone.utc) n2x = n2 + timedelta(seconds=0) assert not isinstance(n2x, nsdatetime) assert not hasattr(n2x, "_nanoseconds") assert n2x == d2 assert hash(n2x) == hash(d2) assert hash(n2) != hash(d2) # compare nsdatetime only n1c = n1.replace() assert n1 == n1 assert n1 == n1c assert n1 <= n1c assert n1 >= n1c assert n1 < n2 assert n1 <= n2 assert n1 != n2 assert not n1 == n2 assert n2 > n1 assert n2 >= n1 assert not n2 < n1 assert not n1 > n2 # mixed eq assert not d2 == n2 assert not n2 == d2 assert d2 != n2 assert n2 != d2 # mixed gt assert n2 > d2 assert d3 > n2 assert not d2 > n3 assert not n2 > d3 # mixed lt assert d1 < n2 < d3 def test_nsdatetime_astimezone(): nsdatetime = rarfile.nsdatetime X1 = timezone(timedelta(hours=1), "X1") n1 = nsdatetime(2000, 1, 1, 9, 15, 30, nanosecond=100200402, tzinfo=timezone.utc) n2 = n1.astimezone(X1) assert n2.nanosecond == n1.nanosecond assert (n1.year, n1.month, n1.day) == (n2.year, n2.month, n2.day) assert (n1.hour, n1.minute, n1.second) == (n2.hour - 1, n2.minute, n2.second) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1694979589.0 rarfile-4.1/tox.ini0000644000175100001770000000166314501653005013727 0ustar00runnerdocker [tox] envlist = lint,docs,py3-pycryptodome,py3-cryptography,py3 [package] name = rarfile deps = pycryptodome: pycryptodome==3.15.0 cryptography: cryptography==41.0.3 test_deps = #coverage==7.3.1 coverage==7.2.7 pytest==7.4.2 pytest-cov==4.1.0 pytest-xdist==3.3.1 doc_deps = sphinx==7.2.6 docutils==0.20.1 lint_deps = pylint==2.17.5 [testenv] deps = {[package]deps} {[package]test_deps} commands = pytest --cov=rarfile --cov-report=term --cov-report=html:{toxinidir}/cover/{envname} {posargs} sh ./test/run_dump.sh {envpython} {envname} allowlist_externals = sh [testenv:lint] basepython = python3 deps = {[package]deps} {[package]lint_deps} {[package]test_deps} commands = pylint rarfile.py dumprar.py test [testenv:docs] basepython = python3 deps = {[package]doc_deps} changedir = doc commands = sphinx-build -q -W -b html -d {envtmpdir}/doctrees . ../tmp/dochtml