Skip to main content

Archive Management

To handle compressed archives in this project, use the unified API provided by django.utils.archive. This utility allows you to extract and list the contents of both Tar and Zip files without needing to interface directly with the Python standard library's tarfile or zipfile modules.

Extracting an Archive

The simplest way to unpack an archive is to use the extract() function. It automatically detects the archive format based on the file extension and extracts the contents to the specified directory.

from django.utils import archive

# Extract a zip file to a specific directory
archive.extract('/path/to/project_template.zip', '/tmp/extracted_files/')

# Extract a tar.gz file
archive.extract('my_app.tar.gz', './my_app_contents/')

Listing and Managing Archives

For more control, such as listing contents before extraction or ensuring file handles are properly closed, use the Archive class as a context manager.

from django.utils.archive import Archive

with Archive('backup.tar.bz2') as a:
# Print the list of files in the archive to stdout
a.list()

# Extract the contents
a.extract('/home/user/backups/latest/')

The Archive class uses TarArchive or ZipArchive internally depending on the file extension.

Working with File-like Objects

If you are working with a file-like object (such as a BytesIO stream or a Django UploadedFile), the object must have a .name attribute with a valid extension for the format detection to work.

from io import BytesIO
from django.utils.archive import Archive

# Mocking a file-like object with a .name attribute
archive_data = BytesIO(b"...")
archive_data.name = "data.zip"

with Archive(archive_data) as a:
a.extract('/tmp/data/')

Supported Formats

The Archive API supports a wide range of extensions through its internal extension_map:

  • Zip: .zip
  • Tar: .tar, .tar.gz, .tgz, .tar.bz2, .tbz2, .tbz, .tz2, .taz, .tar.lzma, .tlz, .tar.xz, .txz

Security and Path Handling

The archive utility includes built-in protections and convenience features for path management:

Path Traversal Protection

The BaseArchive.target_filename method prevents path traversal attacks. If an archive contains files with paths like ../../etc/passwd or absolute paths that would escape the target directory, the utility raises a django.core.exceptions.SuspiciousOperation.

Leading Directory Stripping

If an archive contains all its files within a single top-level directory (a common pattern in source code distributions), the utility automatically strips that leading directory during extraction. This is handled by BaseArchive.has_leading_dir and BaseArchive.split_leading_dir.

Permission Preservation

The utility attempts to preserve file permissions. BaseArchive._copy_permissions checks if the archived file has "read" permissions for "others" (stat.S_IROTH) and applies the mode to the extracted file using os.chmod.

Troubleshooting

Unrecognized Archive Format

If you pass a file with an unsupported extension or a file-like object without a .name attribute, the utility raises an UnrecognizedArchiveFormat exception.

from django.utils.archive import Archive, UnrecognizedArchiveFormat

try:
with Archive('unsupported_file.rar') as a:
a.extract('/tmp/')
except UnrecognizedArchiveFormat as e:
print(f"Error: {e}")

Corrupt Tar Members

When extracting Tar archives, if a member is invalid (often due to bad symlinks in corrupt files), TarArchive.extract will catch the KeyError or AttributeError, print a warning to stdout, and continue with the remaining files.