C.W.K.
Stream
Lesson 03 of 05 · published

Packages Are Atomic, Symlinks Are Links

~12 min · packages, symlinks, traversal

Level 0Lost in Finder
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"The question a copy has to answer over and over is: do I go inside this, or treat it as one thing? Guess wrong and you corrupt an app or duplicate a terabyte."

A Package Looks Like a Folder and Isn't

A .app, a .rtfd, many document formats — these are packages: directories on disk that the system and the user treat as a single item. If Waygate copied one by descending into it and copying each internal file separately, an interruption could leave a half-populated .app that looks installed but is broken. So the default is: a package is atomic — copied as one unit, not traversed. "Show Package Contents" lets you browse inside when you choose to, but that changes browsing, not the default copy graph.

A Symlink Is a Pointer, Copy It as One

A symlink is a tiny file that points at another path. Copy it as a link and you preserve its meaning — the copy points where the original pointed. Blindly follow it instead, and two disasters wait: you might duplicate the entire multi-gigabyte target the link pointed at, or you might hit a symlink loop and recurse forever. So the default is conservative: symlinks are copied as links, never recursively followed to their targets.

The Rule Underneath Both

Packages and symlinks are two faces of one principle: traversal is a decision that changes what the operation means, so it must be explicit. Descending into a package changes 'copy this app' into 'copy these hundred files.' Following a symlink changes 'copy this pointer' into 'copy whatever it aims at.' Waygate's default is always the conservative reading — treat it as the single thing it appears to be — and any deeper traversal is a deliberate, named choice, not an accident of a recursive loop that didn't check.

Packages are atomic by default; symlinks are copied as links, not followed. Traversal changes what an operation means, so it is always explicit and conservative. Descending into a package or following a symlink is a named choice — never the accidental behavior of a recursive copy that forgot to ask what kind of thing it was looking at.
The symlink loop and the accidental terabyte. Two classic file-tool catastrophes: a symlink that points into its own ancestor makes a naive recursive copy run forever, and a symlink to a huge external volume makes 'copy this folder' silently copy a terabyte you didn't mean to. Both come from following links by default. Copying links as links makes both impossible.

Code

Classify before you traverse·swift
func copyGraph(for url: URL) throws -> CopyNode {
    let vals = try url.resourceValues(forKeys: [.isSymbolicLinkKey, .isPackageKey,
                                                .isDirectoryKey])
    if vals.isSymbolicLink == true {
        return .link(url)                 // copy the POINTER, don't follow it
    }
    if vals.isPackage == true {
        return .atomicItem(url)           // copy WHOLE, don't descend
    }
    if vals.isDirectory == true {
        return .directory(url)            // real folder: traverse (bounded, lazy)
    }
    return .file(url)
}
// The default at every node is the CONSERVATIVE reading. Descending into a
// package or following a link is a separate, explicit code path -- never the
// fall-through behavior of a recursive walk that didn't classify first.

External links

Exercise

Create a folder containing a symlink that points back up to the folder itself, then imagine a file tool that copies by recursively following links. Trace what happens. Now create a symlink to your entire home folder inside a folder you're about to copy elsewhere — what does a follow-links copy do? Explain why 'copy links as links' makes both cases safe and boring.
Hint
The self-pointing symlink makes a follow-links copy recurse infinitely (or until it runs out of names/disk). The home-folder symlink makes 'copy this small folder' balloon into copying your whole home directory. Copying links as links stores each symlink as a tiny pointer file — no recursion, no ballooning. Both catastrophes become non-events because you never dereferenced.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.