Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

432 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

desync

Distribute large files and images by transferring only the parts that changed.

Go ReferenceCILicense

desync splits a file into content-defined chunks, stores each distinct chunk once, and writes an index listing the chunks that make up the file. A client that already holds an older version reuses the chunks it has and downloads only the ones it is missing. Chunks are ordinary files addressed by their hash, so a chunk store is any static file host: a web server, an S3 bucket, an OCI registry, or a directory on disk. Nothing on the server computes a delta, which means one published copy serves every client no matter which version they are coming from.

It implements the casync format and interoperates with it — same index files, archives and chunk stores — with parallel chunking, more store backends and a Go library API. It is not a drop-in replacement on the command line: the options differ, and desync has commands casync doesn't.

What it's for

  • A/B image updates for appliances and embedded devices. The device has the running partition on disk. It seeds from that and pulls only the difference.
  • VM and container image distribution. Publish each build to the same chunk store; unchanged parts of the filesystem are stored and transferred once across all of them.
  • Shipping large assets over a CDN. Chunks are immutable, hash-named static files, which is the friendliest possible thing to cache.
  • CI artifact caching. Deduplicate build outputs and toolchains between runs instead of re-fetching whole tarballs.

What it saves

Two adjacent Debian point releases, exported as container root filesystems and published to the same chunk store. The client already has 12.7 on disk and uses it as a seed:

Image size (12.8, uncompressed)125.2 MB
Full download, compressed50.4 MB
Download with 12.7 as a seed18.4 MB
Chunks reused from 12.71121 of 1570
Store holding both versions68.8 MB, against 100.8 MB for two independent copies
mkdir store
desync make -s store v12.7.caibx v12.7.tar # publish the old version
desync make -s store v12.8.caibx v12.8.tar # publish the new one
desync inspect-chunks -s store v12.8.caibx > chunks.json
desync info --seed v12.7.caibx --chunks-info chunks.json -s store v12.8.caibx

How much you save depends entirely on how much actually changed between versions; a rebuild that shifts every file will save nothing. Measure your own data with desync info before committing to a design — that is what the command is for.

How it compares

desynccasyncrsynczsyncOCI / ORAS
Reuses local data as a seedyesyesyes, the destination fileyesno
Server-side work per clientnonenonedelta computed per transfernonenone
Server requirementany static file hostany static file hostrsync daemon or SSHstatic host with range requestsregistry
Deduplication across versions in the storeyesyesnonowhole layers only
Directory treescatar archivescatar archivesyesno, single fileyes, as layers
FUSE mount of a published imageyesyesnonono

rsync is the right tool when both ends are machines you control and the destination is a live filesystem. desync and casync are for publishing an artifact once to a dumb file host and letting many clients, at many different starting versions, update from it. bita solves a similar problem in Rust with self-contained archives rather than a shared chunk store.

Key Features

  • Parallel chunking — byte-identical output to casync, several times faster given enough cores
  • Multiple store backends — local, HTTP(S), S3/GCS, SFTP, SSH, OCI registries
  • Store chaining and caching — combine stores with failover groups
  • Seeds and reflinks — clone blocks from existing files on Btrfs/XFS
  • Built-in servers — HTTP(S) chunk server and index server with proxy support
  • FUSE mounting — mount blob indexes as files
  • Tar interoperability — create/extract catar from standard tar streams
  • Chunk encryption — optional store encryption with XChaCha20-Poly1305 or AES-256-GCM
  • Cross-platform — Linux, macOS, Windows (subset), BSD

Documentation

ConceptsChunking, seeds and reflinks, how the pieces fit together
Store backendsCapabilities, chaining, caching, failover groups
S3 storesBucket URLs, addressing styles, credentials
OCI registry storesChunks and indexes in a container registry
Chunk encryptionEncrypting a store at rest
ConfigurationConfig file, store options, dynamic reload
CLI referenceEvery command and flag
CookbookWorked examples for extraction, chunking, servers, archives

Installation

Download an archive for your platform from the releases page, unpack it, and put the desync binary somewhere on your PATH. Archives are published per operating system and architecture; see Platform Support for what is covered. Each release also carries a checksums.txt to verify the download against.

To build from the latest source instead, into $HOME/go/bin:

go install -v github.com/folbricht/desync/cmd/desync@latest

Or from a clone, which is also what you want for working on desync:

git clone https://github.com/folbricht/desync.git
cd desync/cmd/desync && go install

Quick Start

Chunk a file — split a blob into chunks and create an index:

desync make -s /tmp/store index.caibx /path/to/largefile

Extract a file — reassemble a blob from its index and chunk store:

desync extract -s /tmp/store index.caibx /path/to/largefile

Extract with remote store and local cache — fetch chunks over HTTP, cache locally:

desync extract -s http://server/store -c /tmp/cache index.caibx /path/to/largefile

Platform Support

PlatformStatusNotes
LinuxFull supportAll features including FUSE, reflinks (Btrfs/XFS)
macOSSupportedMinor incompatibilities possible when exchanging catar files with Linux (filemodes)
WindowsPartialSubset of commands. No mount-index. Device entries unsupported in tar; --no-same-owner, --no-same-permissions and --no-same-xattrs ignored in untar, which never applies extended attributes there.
FreeBSDSupportedTested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
NetBSDSupportedNo mount-index. Extended attributes work only on filesystems that implement them; tar skips them elsewhere and untar needs --no-same-xattrs there. Tested in CI in a VM and release binaries are published, but it sees far less real-world use than Linux.
OpenBSDSupportedNo mount-index. Extended attributes are unavailable: tar records none, and untar refuses an archive that carries them unless --no-same-xattrs is given. Otherwise as NetBSD.
DragonFlySupportedNo mount-index. Extended attributes as on OpenBSD. untar also refuses device entries: mknod reports success there but doesn't record the device number, so the node is rejected rather than written with the wrong device. Otherwise as NetBSD.

Design Philosophy

  • Performance over storage efficiency — where upstream casync optimizes for storage efficiency (e.g. using local files as seeds, building temporary indexes), desync optimizes for runtime performance (maintaining a local explicit chunk store, avoiding the need to reindex) at the cost of storage efficiency.
  • Cross-platform over platform-specific features — where upstream casync takes full advantage of Linux platform features, desync implements a minimum feature set. High-value platform-specific features (such as Btrfs reflinks) are added while maintaining the ability to build on other platforms.
  • Hash functions — both SHA512/256 and SHA256 are supported.
  • Compression — only zstd compression and uncompressed stores are supported.
  • Serving casync clients — desync can stand in for the casync binary on SSH servers for read-only chunk serving. Set CASYNC_REMOTE_PATH=desync on the client.
  • catar limitations — SELinux and ACLs in existing catar files are ignored and won't be present in newly created catars. FCAPs are supported only as a verbatim copy of the security.capability XAttr.
  • FUSE mountingmount-index needs the FUSE bindings, which cover Linux, macOS and FreeBSD. Elsewhere the command exists but reports that it's unavailable.

Links

About

Alternative casync implementation

Topics

Resources

Stars

425 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages