Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symlinks #52

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/words-to-ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ codec
backlink like link
prepend like append
preimage like image
UTF
URI

# rationale
Combinatoric
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The WNFS spec is a suite of specifications consisting of public WNFS, private WN
The specifications are:
- [Public WNFS](/spec/public-wnfs.md)
- [Private WNFS](/spec/private-wnfs.md)
- [Symlinks in WNFS](/spec/symlinks.md)
- [Namefilters](/spec/namefilter.md)
- [Skip Ratchet](/spec/skip-ratchet.md)
## Editors
Expand Down
10 changes: 3 additions & 7 deletions spec/public-wnfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ Nodes need to be encoded as dag-cbor.
A directory node contains a map of entry names to either symlinks or CIDs that resolve to another directory or to a file.

```typescript
type PublicRoot = CBOR<PublicDirectory>

type PublicNode
= PublicDirectory
| PublicFile
Expand All @@ -21,11 +19,7 @@ type PublicDirectory = {
previous: Array<CID<CBOR<PublicDirectory>>>
// userland:
metadata: Metadata
entries: Record<string, CID<CBOR<PublicNode>> | PublicSymlink>
}

type PublicSymlink = {
ipns: string // e.g. alice.files.fission.name/public/<public-key>
entries: Record<string, CID<CBOR<PublicNode>> | Symlink>
}

type PublicFile = {
Expand All @@ -38,6 +32,8 @@ type PublicFile = {
}
```

Symbolic links (`Symlink`s) are described in the [Symlink Specification](/spec/symlinks.md).

## Metadata

The metadata field MUST be a CBOR map. It is in userland, and contains arbitrary keys and values.
Expand Down
118 changes: 118 additions & 0 deletions spec/symlinks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Symlink Specification

Symlink is short for "Symbolic Link".

# 0 Abstract

Symlinks are a tool for users to organize their file system:
- They allow linking to the same directory from different places in their file system
- They enable linking out to other user's file systems from your own file system
- They enable linking between public and private parts of file systems

While hard links (`CID`s or private references) conceptually are supposed to work like 'copying' the linked data, a symlink is meant to work differently:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code-wise, do you see any aliasing needed for hardlinks now (vs symlinks)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I don't think so.

I'm still thinking idly about the symlinking stuff in WNFS.
Only in the public file system hard-links correspond directly to CIDs.
In the private file system, that's not quite the case.

If our "own" version of hard-links doesn't become a thing, this will probably be a comment on the cp function of the public file system, as it doesn't actually need to copy anything, it's similar to a hard link.

- It won't guarantee availability.
- It's mutable: Resolving the same link twice may result in different results.
- It doesn't provide integrity of the linked data on its own.

Symlinks shouldn't be confused with a key management mechanism: Knowing a symlink doesn't provide additional read or write access. This ensures the conceptual invariant that giving someone read or write access to a directory will only give them access to that directory and anything contained in it. Symlinks are not meant to 'contain' the data they link to, as that may change over time.

# 1 Layout

Because of differences in addressing between public and private WNFS, symlinks have different formats depending on whether you're linking into public or linking into private data.

```ts
type Symlink = PublicSymlink | PrivateSymlink
```

Symlinks are objects containing a `type` key set to either `"wnfs/sym/pub"`, if it's a public symlink or `"wnfs/sym/priv"`, if it's a private symlink.

We call symlinks that refer to some data that is external to the current WNFS 'foreign'. Foreign symlinks MUST include a `root` pointer to the root they're relative to.

## 1.1 Public Symlink

```ts
type PublicSymlink = {
type: "wnfs/sym/pub"
root?: string
path: string[]
}
```

Public data is symlinked via a list of [UTF-8](https://www.rfc-editor.org/rfc/rfc3629) path segment strings.

If the symlink is not linking relative to the same file system, it can provide a `root` parameter: An [`ipns://` URI](https://github.com/ipfs/in-web-browsers/blob/master/ADDRESSING.md) to the public root that the path is relative to.

A foreign public symlink's `root` MUST point to a [public directory](/spec/public-wnfs.md).

### 1.1.1 Public Symlink Examples

```json
{
"type": "wnfs/sym/pub",
"root": "ipns://matheus23.files.fission.name/public/",
"path": ["Profile", "Avatar.jpg"]
}
```

```json
{
"type": "wnfs/sym/pub",
"path": ["Documents", "Notes.md"]
}
```

```json
{
"type": "wnfs/sym/pub",
"root": "ipns://matheus23.files.fission.name/public/",
"path": []
}
```

```json
{
"type": "wnfs/sym/pub",
"root": "ipns://k51qzi5uqu5dgutdk6i1ynyzgkqngpha5xpgia3a5qqp4jsh0u4csozksxel2r/public/",
"path": []
}
```

## 1.2 Private Symlink

```ts
type PrivateSymlink = {
type: "wnfs/sym/priv"
root?: string
inumber: Inumber

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dumb q alert: guessing this Inumber is always unique (after looking at the current code too)? Do we have anything like an Inode for filesystems in wnfs? https://en.wikipedia.org/wiki/Inode.

Copy link
Member Author

@matheus23 matheus23 Dec 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this number should be unique (unless there's a malicious peer with write permissions or a buggy implementation). You could think of files and directories at inodes. The term inumber also appears in the linked articles. It would then be the number that refers to a certain inode.
However, in our case the inumber is persistent across revisions. This is where the analogy kind-of breaks down. I'm not super sure whether inumbers change between revisions in traditional file systems, or whether everything basically happens via in-place mutation.

}
```

A private symlink identifies a private node via its `inumber`.

A foreign private symlink's `root` MUST point to a [private forest](/spec/private-wnfs.md#21-ciphertext-blocks).

### 1.2.1 Private Symlink Examples

```json
{
"type": "wnfs/sym/priv",
"root": "ipns://matheus23.files.fission.name/private",
"inumber": <CBOR-encoded 32 byte array>
}
```

```json
{
"type": "wnfs/sym/priv",
"inumber": <CBOR-encoded 32 byte array>
}
```

```json
{
"type": "wnfs/sym/priv",
"root": "ipns://k51qzi5uqu5dgutdk6i1ynyzgkqngpha5xpgia3a5qqp4jsh0u4csozksxel2r/private/",
"inumber": <CBOR-encoded 32 byte array>
}
```