{"id":7360,"library":"libarchive-c","title":"libarchive-c Python Interface","description":"libarchive-c is a Python interface to the C library libarchive, allowing users to read, write, and extract various archive formats like tar, zip, and 7z. It leverages `ctypes` for dynamic loading and is actively maintained, with regular releases (e.g., v5.3 released May 22, 2025). It is currently tested with Python 3.12 and 3.13.","status":"active","version":"5.3","language":"en","source_language":"en","source_url":"https://github.com/Changaco/python-libarchive-c","tags":["archive","compression","tar","zip","7zip","libarchive","cffi","ctypes"],"install":[{"cmd":"pip install libarchive-c","lang":"bash","label":"Install Python package"}],"dependencies":[{"reason":"Required for `libarchive-c` to function as it's a CFFI binding. Users often need to install this separately via system package managers (e.g., `apt`, `brew`) or by providing its path via the `LIBARCHIVE` environment variable.","package":"libarchive (C library)","optional":false}],"imports":[{"symbol":"extract_file","correct":"import libarchive\nlibarchive.extract_file(...)"},{"symbol":"file_reader","correct":"import libarchive\nwith libarchive.file_reader(...) as archive:"},{"symbol":"file_writer","correct":"import libarchive\nwith libarchive.file_writer(...) as archive:"},{"note":"While technically possible, the typical high-level API usage involves iterating `file_reader` which yields `ArchiveEntry` objects, rather than importing and instantiating directly.","wrong":"from libarchive import ArchiveEntry","symbol":"ArchiveEntry","correct":"import libarchive\nentry = libarchive.ArchiveEntry(...)"}],"quickstart":{"code":"import libarchive\nimport os\n\n# Create a dummy file\nwith open('test_file.txt', 'w') as f:\n    f.write('Hello, libarchive-c!')\n\n# Create an archive\narchive_name = 'my_archive.tar'\nwith libarchive.file_writer(archive_name, 'tar') as archive:\n    archive.add_files('test_file.txt')\nprint(f\"Archive '{archive_name}' created.\")\n\n# Clean up the dummy file\nos.remove('test_file.txt')\n\n# Read and extract the archive\nextracted_dir = 'extracted_content'\nos.makedirs(extracted_dir, exist_ok=True)\n\nos.chdir(extracted_dir)\nlibarchive.extract_file(os.path.join('..', archive_name)) # Extract from parent dir\nos.chdir('..')\n\n# Verify extraction\nextracted_path = os.path.join(extracted_dir, 'test_file.txt')\nif os.path.exists(extracted_path):\n    with open(extracted_path, 'r') as f:\n        content = f.read()\n    print(f\"Content extracted: {content}\")\nelse:\n    print(\"Extraction failed.\")\n\n# Clean up archive and extracted directory\nos.remove(archive_name)\nos.remove(extracted_path)\nos.rmdir(extracted_dir)","lang":"python","description":"This quickstart demonstrates how to create a simple 'tar' archive with a file, and then extract its contents using the high-level `file_writer` and `extract_file` functions."},"warnings":[{"fix":"Update custom class constructors to accept `codec` argument: `__init__(self, obj, codec)`.","message":"If you use the `archive_read_class` or `archive_write_class` arguments for custom archive handling, the classes you provide will now receive a `codec` name as a second positional argument.","severity":"breaking","affected_versions":"5.0+"},{"fix":"Review extraction logic, especially when dealing with potentially malicious archives or specific path structures. Explicitly pass desired `flags` to extraction functions if default behavior is not suitable.","message":"Archive extraction functions now pass `SECURE_NODOTDOT`, `SECURE_NOABSOLUTEPATHS`, and `SECURE_SYMLINKS` flags by default, unless extracting to the root directory. This enhances security but might alter behavior for paths containing '..' or absolute paths within archives, or symbolic links.","severity":"breaking","affected_versions":"4.0+"},{"fix":"Update code that checks these properties to explicitly handle `None` values (e.g., `if entry.size is not None: ...`).","message":"The `ArchiveEntry` properties `atime`, `mtime`, `ctime`, `birthtime`, and `size` now return `None` instead of `0` when the corresponding metadata is unset in the archive.","severity":"breaking","affected_versions":"4.0+"},{"fix":"When reading archives with non-UTF-8 metadata, specify the correct `header_codec` argument to `file_reader` (e.g., `libarchive.file_reader('archive.zip', header_codec='cp437')`).","message":"The `ArchiveEntry.pathname` property now attempts to decode bytes using UTF-8 by default, which may break reading archives containing non-UTF-8 filenames that coincidentally resemble UTF-8.","severity":"breaking","affected_versions":"4.0+"},{"fix":"Migrate your project to Python 3.","message":"Support for Python 2.7 has been dropped.","severity":"breaking","affected_versions":"3.0+"},{"fix":"Install `libarchive` via your system's package manager (e.g., `sudo apt-get install libarchive-dev` on Debian/Ubuntu, `brew install libarchive` on macOS). On Windows, you may need to download the `libarchive.dll` and its dependencies and ensure it's in your system PATH or specified via the `LIBARCHIVE` environment variable.","message":"The `libarchive-c` Python package is a wrapper around the native `libarchive` C library. This C library must be installed on your system for `libarchive-c` to function.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure you have a recent version of the `libarchive` C library installed. If issues persist, consider installing a newer version via `brew` (macOS) or compiling from source, and point `libarchive-c` to it using the `LIBARCHIVE` environment variable.","message":"Older or obsolete versions of the `libarchive` C library (especially those bundled with some operating systems like macOS) may not work correctly or support all features. Python `libarchive-c` is tested against newer versions.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"1. Install the `libarchive` C library for your system. 2. For Windows, ensure `libarchive.dll` and its dependencies (like `libcrypto-1_1-x64.dll`, `VCRUNTIME140.dll`) are either in your system PATH or in the same directory as your Python script, or explicitly set the `LIBARCHIVE` environment variable to the full path of `libarchive.dll` before running your Python script.","cause":"The native `libarchive` C library (e.g., `archive.dll` on Windows) or one of its dependencies cannot be found by Python's `ctypes`.","error":"OSError: [WinError 126] The specified module could not be found\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"...\\libarchive\\__init__.py\", line 45, in <module>\n    libarchive = ctypes.cdll.LoadLibrary(libarchive_path)\n  File \"C:\\Python3x\\lib\\ctypes\\__init__.py\", line xxx, in LoadLibrary\n    return self._dlltype(name)"},{"fix":"Use the recommended high-level functions. Instead of `from libarchive import ArchiveRead`, use `import libarchive` and then `with libarchive.file_reader(...) as archive:` to get an archive object. `ArchiveEntry` objects are yielded by iterating the archive object.","cause":"The high-level API of `libarchive-c` primarily exposes functions like `file_reader`, `file_writer`, and `extract_file` directly under the `libarchive` module. The `ArchiveRead` and `ArchiveWrite` classes are part of the lower-level FFI or internal implementation and not directly exposed for top-level import in the current recommended API.","error":"ImportError: cannot import name 'ArchiveRead' from 'libarchive' (<path_to_site-packages>/libarchive/__init__.py)"}]}