archive
Make and open .zip, .tar(.gz) and .gz files. Extraction is safe by default: members that would land outside the destination (zip-slip), absolute paths, links and device files are refused, and archives that would unpack to more than 2 GB (or compress suspiciously well) are stopped. archive.list(path) shows what is inside without extracting.
import archive
Example
import archive
import fs
fs.write("evidence.txt", "auth.log excerpt")
say(archive.zip("evidence.zip", ["evidence.txt"]))
for entry in archive.list("evidence.zip") {
say(entry.name, entry.size)
}
# unzip refuses entries that would land outside the target folder.
say(archive.unzip("evidence.zip", "out"))
Functions
zip(target, paths, options?)
returns numberMake a .zip file holding the files and folders in paths. Folders are added with everything inside. Replaces an existing target. Gives back the number of files added.
Options
basea folder. Paths in the zip are kept relative to it. Without it, names in the zip are just the file or folder names.
Visualizehow archive.zip works
archive.zip("notes.zip", ["notes.txt", "logs"])
Real result: worked out by running this example with TB while the site was built.
unzip(path, dest, options?)
returns listExtract a .zip into the folder dest (made if needed) and give back the paths written. It is safe by default.
Refused by default
- Members with absolute paths or '..' in them (zip-slip).
- Links.
- Archives that unpack to more than 2 GB.
Options
safefalse only skips the dangerous members, instead of stopping.overwritefalse keeps files that already exist.max_sizethe most bytes the archive may unpack to.membersa list of names, to extract only some.
Visualizehow archive.unzip works
archive.unzip("bundle.zip", "unpacked") gives ["/home/you/project/unpacked/notes.txt", "/home/you/project/unpacked/logs/app.log", "/hom…
Real result: worked out by running this example with TB while the site was built.
tar(target, paths, options?)
returns numberMake a .tar file. Links are skipped. Gives back the number of files added.
It is compressed when the name ends in .tar.gz or .tgz, .tar.bz2 or .tar.xz.
Options
compresslike "gz", to compress whatever the name is.baseworks like in zip(), and so do paths.
Visualizehow archive.tar works
archive.tar("logs.tar.gz", ["logs"])archive.tar("logs.tar", ["logs"])archive.tar("logs.tar.xz", ["logs"])
Drawing…
Real result: worked out by running this example with TB while the site was built.
untar(path, dest, options?)
returns listExtract a .tar / .tar.gz / .tar.bz2 / .tar.xz into dest and give the paths written. Same safety and options as unzip(); links and device files are refused (or skipped with {"safe": false}).
Visualizehow archive.untar works
archive.untar("backup.tar.gz", "restored") gives ["/home/you/project/restored/logs/app.log", "/home/you/project/restored/logs/old/2025.log…
Real result: worked out by running this example with TB while the site was built.
gzip(path, target?)
returns textCompress one file with gzip. target defaults to path + ".gz". Gives the target path.
Visualizehow archive.gzip works
archive.gzip("big.log")
Real result: worked out by running this example with TB while the site was built.
gunzip(path, target?)
returns textUncompress a .gz file. target defaults to the name without ".gz". Stops if the result would be bigger than 2 GB. Gives the target path.
Visualizehow archive.gunzip works
archive.gunzip("day.log.gz") gives "day.log"
Real result: worked out by running this example with TB while the site was built.
list(path)
returns listWhat is inside a .zip or .tar archive, without extracting: maps with "name", "size" (unpacked bytes), "compressed" (zip only), "is_dir" and "modified".
Visualizehow archive.list works
archive.list("site.zip") gives [{"name": "notes.txt", "size": 30, "compressed": 32, "is_dir": false, "modified": "2026-1…
Real result: worked out by running this example with TB while the site was built.
kind(path)
returns text"zip", "tar", "gzip" or "unknown", by looking at the file's first bytes.
Visualizehow archive.kind works
archive.kind("k.zip") gives "zip"archive.kind("k.tar") gives "tar"archive.kind("k.txt.gz") gives "gzip"archive.kind("notes.txt") gives "unknown"
Real result: worked out by running this example with TB while the site was built.
extract(path, dest, options?)
returns listunzip() or untar() depending on what the file is (gunzip for a lone .gz).
Visualizehow archive.extract works
archive.extract("mixed.tgz", "out") gives ["/home/you/project/out/logs/app.log", "/home/you/project/out/logs/old/2025.log"]
Real result: worked out by running this example with TB while the site was built.
Values
| Name | Value | What it is |
|---|---|---|
archive.max_size | 2147483648 | How many unpacked bytes an extraction allows by default (2 GB). Visualizehow archive.max_size works
No inputs: call it as it is. Real value, read from TB while the site was built. |