Skip to content
YadeWira edited this page Oct 29, 2026 · 5 revisions

Usage

syc is two tools in one program: an archiver (.syc: files and directories, versions, deduplication) and a compressor of single files (.sylz streams, gzip/zstd style). syc h lists the commands, and syc h CMD (or syc CMD -h) lists a command's options.

syc a [options] ARCHIVE PATH...      add: a new archive, or a new version of one
syc x [options] ARCHIVE [FILTER...]  extract
syc l [options] ARCHIVE [FILTER...]  list
syc i ARCHIVE                        versions, sizes, deduplication
syc t [options] [FILE...]            check archives and streams, write nothing
syc c [options] [FILE...]            compress each FILE to FILE.sylz
syc d [options] [FILE...]            decompress each FILE.sylz to FILE
syc k [options] FILE...              change the password of encrypted ones

Options, in general

  • Short and long forms: -t 4, -t4, --threads 4 and --threads=4 all mean the same.
  • Short options are not grouped: -ec is one option, not -e -c.
  • Position: options may come before or after the operands; -- ends them.
  • Levels: -0 .. -10, or --level N. The default is 1.
    • 0 and 1 use a single hash;
    • 2 and 3 use two hashes;
    • 4 to 8 use hash chains;
    • 9 and 10 use optimal parsing.
  • -ec (extra compression): literals are Huffman-coded (sylz format v3).
    • Smaller output, about 2/3 of the decoding speed.
    • Levels 0..10: 0–8 parse as v2's levels 2–10, while 9 and 10 price each literal by its code.
  • -t N: N threads, default 1. The output is the same bytes whatever N.
  • -q / -v: only errors / more detail (a and x name each entry).
  • --progress / --no-progress: a progress line on stderr. By default it appears when stderr is a terminal.

Archives

syc a backup.syc docs/ photos/       # a new archive
syc a backup.syc docs/ photos/       # later: a new version with what changed
syc l backup.syc                     # what is in it (the last version)
syc l -l backup.syc docs/            # with permissions, size, date; only under docs/
syc l --all backup.syc docs/a.txt    # every version of a path
syc i backup.syc                     # one line per version
syc t -t 4 backup.syc                # check everything
syc x backup.syc -o restore/         # extract everything under restore/
syc x backup.syc 'docs/**.txt'       # only what a filter selects
syc x -u 3 backup.syc -o v3/         # as it was in version 3
syc x -u 2026-10-24T18:00 backup.syc # as it was at that date (local time)
syc x -O backup.syc docs/a.txt > a.txt   # one file to stdout
syc a - docs/ | ssh host 'cat > docs.syc'  # a new archive to stdout
ssh host 'cat docs.syc' | syc x -       # an archive from stdin

syc a

  • Paths: each PATH is added recursively. Paths are stored as given, relative.
    • A leading / or drive letter is dropped.
    • A path with .. is refused; use -C DIR to start from another directory.
  • A new archive is written to ARCHIVE.syc-partial and renamed when complete.
  • An existing archive gets a new version with what changed since its last version:
    • An entry whose type, size, mtime, attributes, owner and link target are unchanged is not read again. As in zpaq, a change that keeps size and mtime is not seen.
    • A path that was under one of the PATHs and is gone is marked deleted in the new version; older versions keep it. --no-delete keeps it in the new version too.
    • Paths that are excluded or could not be read are never marked deleted.
    • If nothing changed, no version is written.
  • Deduplication: files are cut into content-defined fragments (16 KiB / 64 KiB / 512 KiB) identified by BLAKE2s-256. A fragment already in the archive, from any version or file, is not stored again. --no-dedup turns this off for one version.
  • Blocks: new fragments are packed in solid blocks (-b MIB, default 16) compressed at the level given.
  • Exclusions: -X PATTERN skips matches, and the option can be repeated.
    • * and ? match within a name, ** across directories.
    • A pattern without / matches names; with /, whole paths.
  • Interrupted syc a: a power cut or a full disk leaves bytes after the last complete version. Readers ignore them with a warning (exit 1), and the next syc a cuts them. Old versions are never rewritten.

syc x

  • What is extracted: everything, or what the FILTERs select. A filter is a path, a directory (with everything under it), or a pattern as in -X. -X excludes.
  • Destination: -o DIR, by default the current directory.
  • An existing file is left in place with a warning (exit 1). -f replaces it, and --skip leaves it silently.
  • Integrity: each fragment is checked against its BLAKE2s-256 as it is extracted. Damage stops with exit 3, and no partial file is left.
  • Metadata restored: mtime (to the nanosecond on Linux), permissions (--no-perms skips them), symlinks, empty directories, and Windows attributes. The owner is restored only when running as root (--no-owner skips it).
  • Symlinks: syc never writes through a symlink. The archive's symlinks are made after every file, and a directory on the way that is already a symlink makes syc skip the entry.

stdin and stdout

  • Reading from stdin: x -, l -, i - and t - read an archive through a temporary copy, because the index of each version comes after its data.
  • Writing to stdout: a - writes a new archive; appending needs a file.

Encryption (-p)

syc a -p backup.syc docs/             # asks for the password twice, without echo
syc a -p --visible-names b.syc docs/  # the data encrypted, names and sizes listable
syc l backup.syc                      # asks for it (or -pPASSWORD, --password-file, SYC_PASSWORD)
syc x --password-file key.txt backup.syc -o restore/
syc c -p secret.bin                   # an encrypted .sylz stream
SYC_PASSWORD=... syc d secret.bin.sylz
  • Algorithms: XChaCha20-Poly1305 for the data and the index, with a key from Argon2id (64 MiB by default; --kdf-mem MIB when creating).

  • Hidden in the default mode: contents, names, sizes, dates, attributes and the directory tree. With --visible-names (chosen when the archive is created) only the data is hidden, and syc l / syc i work without the password.

  • Detected: any change, a block moved or swapped, a stream cut short. All of these exit with 3, and so does a wrong password.

  • Not hidden:

    • the number of versions;
    • each block's size, and with it roughly how much each version added;
    • an archive cut back to an earlier version (it reads as one with fewer versions).
  • Where the password comes from, in order:

    1. -pPASSWORD / --password=PASSWORD (other users can see it in the process list: avoid it);
    2. --password-file FILE (its first line);
    3. SYC_PASSWORD;
    4. else the terminal.

    Reading never needs -p. With no password and no terminal, syc exits with 2.

  • Adding a version to an encrypted archive needs its password and keeps its mode. A plain archive cannot get a password added to it.

  • Changing the password: syc k (below).

  • The code is syc's own. The algorithms are standard, and the code is checked against the RFCs' test vectors and against libsodium, OpenSSL and hashlib. An outside review is still welcome before relying on it for anything critical. Format: syc encryption.

syc k: a new password

syc k backup.syc                      # asks for the current one, then the new one twice
syc k -pOLD --new-password-file new.txt backup.syc secret.bin.sylz
SYC_PASSWORD=... SYC_NEW_PASSWORD=... syc k backup.syc
  • Archives and streams, in place: the data is not recompressed or encrypted again, so the time is three Argon2id runs whatever the size (under a second at 64 MiB on a recent PC). The data key stays the same and is wrapped again with the new password; only the 216-byte key record at the start of the file changes.
  • Safe if interrupted: syc writes the new password into the key record's free slot and flushes the file to the disk. Only then does it erase the old slot and flush again. A crash or power cut in between leaves a file that opens with the old password or the new one, never neither.
  • The new password comes from, in order: --new-password=PASSWORD (visible to other users, like -p), --new-password-file FILE, SYC_NEW_PASSWORD, else the terminal (twice). The current one comes from the usual sources (-pPASSWORD, --password-file, SYC_PASSWORD, the terminal). With several FILEs, the same two passwords serve them all.
  • --kdf-mem MIB sets Argon2id's memory for the new password (default: the current one's).
  • Exits: a wrong current password exits with 3 and leaves the file as it was; a file that is not encrypted exits with 2; stdin is refused (2).
  • What it cannot do: anyone who had the old password and a copy of the file (or of its data key) can still read that copy, and the data key, unchanged, still opens the new file's data. To lock out a person who knew the old password, recompress: syc x, then syc a -p into a new archive.

Single files: syc c / d

syc c -6 big.log                 # -> big.log.sylz (the input stays; --rm deletes it)
syc d big.log.sylz               # -> big.log
syc c -o out.sylz in.bin         # an explicit output
tar c dir | syc c > dir.tar.sylz # no FILE: stdin -> stdout
syc d -O dir.tar.sylz | tar x
syc c a b c                      # several files, each to its own .sylz
  • Existing output: an existing output is skipped with a warning; -f overwrites it.
  • Terminals: c does not write compressed data to a terminal unless -f is given, and no command reads its input from a terminal.
  • Blocks: -b MIB sets the block size (default 4); each block carries a CRC-32.

Bare sylz blocks: --raw

syc c --raw -9 data.bin            # -> data.bin.sylzraw: one sylz v2 block
syc c --raw -ec -9 data.bin        # the same in format v3
syc d --raw --size 123456 data.bin.sylzraw   # back: the decoded size must be given
syc t --raw --size 123456 data.bin.sylzraw
  • What it writes: one sylz block exactly as the zpaq-std plugins' compress() writes it, with no header, sizes or CRC-32.
  • Size limit: the input can be up to 512 MiB.
  • Decoding: the block does not hold its decoded size, so d and t need --size. c prints that size.
  • Checking: a wrong size or a damaged block is refused (exit 3), but nothing checks the data itself: there is no CRC.
  • What it is for: feeding or testing other sylz decoders. For files, the .sylz stream is the safer choice.

Exit status

status meaning
0 ok
1 finished, but something was skipped or unreadable (an existing file, an unreadable input, bytes after the last complete version)
2 usage: unknown option, bad value, missing operand
3 corrupt data: a checksum, a hash or the structure is wrong
4 I/O error or out of memory

Windows notes

  • Names: Unicode names work. The archive stores paths as UTF-8.
  • Attributes: read-only, hidden, system and archive are kept.
  • Symlinks: file and directory symlinks are stored and recreated. Making one needs developer mode or administrator rights; without them syc warns and exits with 1. Junctions are skipped.
  • Archives from Unix: extract with times and symlinks. Unix permissions become read-only when nobody may write.

Clone this wiki locally