Skip to content

Commit af18542

Browse files
committed
docs: Add sections on operations, index, recovery, drive management and embedding
1 parent 68fbf0e commit af18542

File tree

1 file changed

+233
-3
lines changed

1 file changed

+233
-3
lines changed

README.md

Lines changed: 233 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Simple Tape File System (STFS), a file system for tapes and tar files.
55
⚠️ STFS has not yet been audited! While we try to make it as secure as possible, it has not yet undergone a formal security audit by a third party. Please keep this in mind if you use it for security-critical applications. ⚠️
66

77
[![hydrun CI](https://github.com/pojntfx/stfs/actions/workflows/hydrun.yaml/badge.svg)](https://github.com/pojntfx/stfs/actions/workflows/hydrun.yaml)
8+
![Go Version](https://img.shields.io/badge/go%20version-%3E=1.17-61CFDD.svg)
89
[![Go Reference](https://pkg.go.dev/badge/github.com/pojntfx/stfs.svg)](https://pkg.go.dev/github.com/pojntfx/stfs)
910
[![Matrix](https://img.shields.io/matrix/stfs:matrix.org)](https://matrix.to/#/#stfs:matrix.org?via=matrix.org)
1011
[![Binary Downloads](https://img.shields.io/github/downloads/pojntfx/stfs/total?label=binary%20downloads)](https://github.com/pojntfx/stfs/releases)
@@ -42,6 +43,8 @@ You can find binaries for more operating systems and architectures on [GitHub re
4243

4344
## Usage
4445

46+
> Please note that this is only a short overview and does not explain all configuration options. To get more info on available commands or options, use `--help`.
47+
4548
### 1. Generating Keys with `stfs keygen`
4649

4750
While not strictly required, it is recommended to generate keys to sign and encrypt your data on tape. There are multiple methods available; `PGP` and [age](https://github.com/FiloSottile/age) for encryption, and `PGP` as well as [Minisign](https://github.com/aead/minisign) for signatures. In most cases, using age for encryption and PGP for signatures is the best option. To generate the appropriate keys, run the following; make sure to save the keys in a secure location and use a secure password:
@@ -119,15 +122,242 @@ For more information, see the [servers reference](#servers).
119122

120123
### 4. Using Optimized Operations with `stfs operation`
121124

125+
While the file system API is convenient because of its similarity to most filesystems, it also can't be used without a write cache. While this isn't an issue for most applications, it requires you to have a disk that is at least as large as the largest file you want to add to the tape. To get around these limitations, STFS also provides a `tar`-like interface for interacting with the tape. Please note that these operations should be used carefully, as the usual checks (such as checking if a parent directory exists before adding files to it) don't apply.
126+
127+
First, initialize an empty tape:
128+
129+
```shell
130+
# Use `-d /dev/nst0` for your primary tape drive instead
131+
$ stfs operation initialize \
132+
-d ~/Downloads/drive.tar \
133+
-m ~/Downloads/metadata.sqlite \
134+
-e age \
135+
--recipient ~/.stfs-age.pub \
136+
-s pgp \
137+
--identity ~/.stfs-pgp.priv \
138+
--password mysecuresignaturepassword \
139+
--compression zstandard
140+
type,indexed,record,lastknownrecord,block,lastknownblock,typeflag,name,linkname,size,mode,uid,gid,uname,gname,modtime,accesstime,changetime,devmajor,devminor,paxrecords,format
141+
archive,false,-1,-1,-1,-1,53,/,,0,511,1000,1000,pojntfx,1000,2022-05-16T22:24:13+02:00,0001-01-01T00:00:00Z,0001-01-01T00:00:00Z,0,0,null,4
142+
archive,true,0,-1,0,-1,53,/,,0,511,1000,1000,pojntfx,1000,2022-05-16T22:24:13+02:00,0001-01-01T00:00:00Z,0001-01-01T00:00:00Z,0,0,null,4
143+
```
144+
145+
You can now add files to it:
146+
147+
```shell
148+
# Use `-d /dev/nst0` for your primary tape drive instead
149+
$ stfs operation archive \
150+
-d ~/Downloads/drive.tar \
151+
-m ~/Downloads/metadata.sqlite \
152+
-e age \
153+
--recipient ~/.stfs-age.pub \
154+
-s pgp \
155+
--identity ~/.stfs-pgp.priv \
156+
--password mysecuresignaturepassword \
157+
--compression zstandard \
158+
.
159+
# ...
160+
archive,true,1480,-1,9,-1,48,pkg/tape/write.go,,1544,420,1000,1000,pojntfx,pojntfx,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,0,0,"{""STFS.Signature"":""wnUEABYIACcFAmKCsyUJkGA0c/4XcV5qFqEEjWKRLHhppJ6S+ZJlYDRz/hdxXmoAAF5mAP95DKo/r136fL/SKuBwmxoMNfGZ+v61bwk/xcOBQk5vrwEAs07QV2RF6h/FME+/nXxjZrbBWmFWg8pC4IGdScnJbQ4="",""STFS.UncompressedSize"":""1544""}",4
161+
archive,true,1480,-1,17,-1,53,pkg/utility,,0,509,1000,1000,pojntfx,pojntfx,2022-04-18T20:19:52+02:00,2022-05-15T23:36:33+02:00,2022-04-23T16:08:59+02:00,0,0,null,4
162+
# ...
163+
```
164+
165+
Full CRUD support is implemented, so you can `delete`, `move`, `restore` and `update` files like this as well. For example, to restore `pkg/tape/write.go`, run the following:
166+
167+
```shell
168+
# Use `-d /dev/nst0` for your primary tape drive instead
169+
$ stfs operation restore \
170+
-d ~/Downloads/drive.tar \
171+
-m ~/Downloads/metadata.sqlite \
172+
-e age \
173+
--identity ~/.stfs-age.priv \
174+
--password mysecureencryptionpassword \
175+
-s pgp \
176+
--recipient ~/.stfs-pgp.pub \
177+
--compression zstandard \
178+
--flatten \
179+
--from pkg/tape/write.go \
180+
--to write.go
181+
type,indexed,record,lastknownrecord,block,lastknownblock,typeflag,name,linkname,size,mode,uid,gid,uname,gname,modtime,accesstime,changetime,devmajor,devminor,paxrecords,format
182+
restore,true,1480,1480,9,9,48,/pkg/tape/write.go,,1544,420,1000,1000,pojntfx,pojntfx,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,0,0,"{""STFS.Signature"":""wnUEABYIACcFAmKCsyUJkGA0c/4XcV5qFqEEjWKRLHhppJ6S+ZJlYDRz/hdxXmoAAF5mAP95DKo/r136fL/SKuBwmxoMNfGZ+v61bwk/xcOBQk5vrwEAs07QV2RF6h/FME+/nXxjZrbBWmFWg8pC4IGdScnJbQ4="",""STFS.UncompressedSize"":""1544""}",4
183+
$ file write.go
184+
write.go: ASCII text
185+
```
186+
187+
For more information, see the [operations reference](#operations).
188+
122189
### 5. Managing the Index with `stfs inventory`
123190

191+
For similar reasons as described in [Using Optimized Operations with `stfs operation`](#4-using-optimized-operations-with-stfs-operation), it can make sense to take advantage of the index in order to quickly find a file or directory. For example, to list all files in the `pkg` directory, run the following:
192+
193+
```shell
194+
$ stfs inventory list \
195+
-m ~/Downloads/metadata.sqlite \
196+
--name pkg
197+
record,lastknownrecord,block,lastknownblock,typeflag,name,linkname,size,mode,uid,gid,uname,gname,modtime,accesstime,changetime,devmajor,devminor,paxrecords,format
198+
1454,1454,14,14,53,/pkg/cache,,0,493,1000,1000,pojntfx,pojntfx,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,0,0,null,4
199+
# ...
200+
```
201+
202+
It is also possible to search for a file by regex with `stfs inventory find`:
203+
204+
```shell
205+
$ stfs inventory find \
206+
-m ~/Downloads/metadata.sqlite \
207+
--expression '(.*).yaml'
208+
record,lastknownrecord,block,lastknownblock,typeflag,name,linkname,size,mode,uid,gid,uname,gname,modtime,accesstime,changetime,devmajor,devminor,paxrecords,format
209+
118,118,11,11,48,/.github/workflows/hydrun.yaml,,3000,420,1000,1000,pojntfx,pojntfx,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,0,0,"{""STFS.Signature"":""wnUEABYIACcFAmKCsyMJkGA0c/4XcV5qFqEEjWKRLHhppJ6S+ZJlYDRz/hdxXmoAAF9nAP98fVspytLtKjTATbtH7hoVaK7tyVGKVDabY4OkOnYiygD/QcTtdWR48Eq5pIT0bR2M9u168aXTbWoWX8JVXcm7uwg="",""STFS.UncompressedSize"":""3000""}",4
210+
# ...
211+
```
212+
213+
It is also possible to get information on a single file or directory using `stfs inventory stat`. For more information, see the [inventory reference](#inventory).
214+
124215
### 6. Recovering Data with `stfs recovery`
125216

217+
In case of unfinished write operations, sudden power losses or other forms of data corruption, the integrated recovery tools can help. For example, to query a tape starting from a specific record and block, use `stfs query`:
218+
219+
```shell
220+
# Use `-d /dev/nst0` for your primary tape drive instead
221+
$ stfs recovery query \
222+
-d ~/Downloads/drive.tar \
223+
-e age \
224+
--identity ~/.stfs-age.priv \
225+
--password mysecureencryptionpassword \
226+
-s pgp \
227+
--recipient ~/.stfs-pgp.pub \
228+
--compression zstandard \
229+
--record 118 \
230+
--block 11
231+
118,-1,11,-1,48,.github/workflows/hydrun.yaml.zst.age,,1272,420,1000,1000,pojntfx,pojntfx,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,0,0,"{""STFS.Signature"":""wnUEABYIACcFAmKCsyMJkGA0c/4XcV5qFqEEjWKRLHhppJ6S+ZJlYDRz/hdxXmoAAF9nAP98fVspytLtKjTATbtH7hoVaK7tyVGKVDabY4OkOnYiygD/QcTtdWR48Eq5pIT0bR2M9u168aXTbWoWX8JVXcm7uwg="",""STFS.UncompressedSize"":""3000""}",4
232+
119,-1,0,-1,48,.gitignore.zst.age,,220,436,1000,1000,pojntfx,pojntfx,2022-04-18T20:19:52+02:00,2022-05-15T23:38:41+02:00,2022-04-23T16:08:59+02:00,0,0,"{""STFS.Signature"":""wnUEABYIACcFAmKCsyMJkGA0c/4XcV5qFqEEjWKRLHhppJ6S+ZJlYDRz/hdxXmoAAGAmAP9G6z9HSr5puQjDMRpYZ11Jge95wG2g3LSetF+ts4CG7wEA38qbJx92BbQN4tWmm5G3dXg+PAnGKONAkc0IU9dmtgA="",""STFS.UncompressedSize"":""4""}",4
233+
# ...
234+
```
235+
236+
If you know the record and block of a file (which you can get from the index with the `inventory` commands), you can also recover it directly:
237+
238+
```shell
239+
# Use `-d /dev/nst0` for your primary tape drive instead
240+
$ stfs recovery fetch \
241+
-d ~/Downloads/drive.tar \
242+
-e age \
243+
--identity ~/.stfs-age.priv \
244+
--password mysecureencryptionpassword \
245+
-s pgp \
246+
--recipient ~/.stfs-pgp.pub \
247+
--compression zstandard \
248+
--record 118 \
249+
--block 11 \
250+
--to hydrun.yaml
251+
record,lastknownrecord,block,lastknownblock,typeflag,name,linkname,size,mode,uid,gid,uname,gname,modtime,accesstime,changetime,devmajor,devminor,paxrecords,format
252+
118,-1,11,-1,48,.github/workflows/hydrun.yaml.zst.age,,1272,420,1000,1000,pojntfx,pojntfx,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,2022-05-15T23:41:54+02:00,0,0,"{""STFS.Signature"":""wnUEABYIACcFAmKCsyMJkGA0c/4XcV5qFqEEjWKRLHhppJ6S+ZJlYDRz/hdxXmoAAF9nAP98fVspytLtKjTATbtH7hoVaK7tyVGKVDabY4OkOnYiygD/QcTtdWR48Eq5pIT0bR2M9u168aXTbWoWX8JVXcm7uwg="",""STFS.UncompressedSize"":""3000""}",4
253+
$ file hydrun.yaml
254+
hydrun.yaml: ASCII text
255+
```
256+
257+
It is also possible to restore a broken index from scratch with `stfs recovery index`. For more information, see the [recovery reference](#recovery).
258+
126259
### 7. Managing the Drive with `stfs drive`
127260

261+
STFS can also manage the physical tape drive directly without having to rely on external tools. For example, to eject a tape from the drive, use `stfs drive eject`:
262+
263+
```shell
264+
$ stfs drive eject \
265+
-d /dev/nst0
266+
```
267+
268+
It is also possible to get the current tape position with `stfs drive tell`. For more information, see the [drive management reference](#drive-management).
269+
128270
### 8. Embedding STFS with `fs.STFS`
129271

130-
🚀 **That's it!** We hope you enjoy using stfs.
272+
STFS at its core provides quite a few public APIs, but the easiest way to embed it is to use it's provided [`afero.FS implementation`](https://github.com/spf13/afero). This makes it possible to easily swap out the filesystem implementation with a native one, layer caching implementations and decouple your storage layer.
273+
274+
Using this API is fairly straightforward:
275+
276+
```go
277+
// ...
278+
stfs := fs.NewSTFS(
279+
readOps,
280+
writeOps,
281+
282+
config.MetadataConfig{
283+
Metadata: metadataPersister,
284+
},
285+
286+
config.CompressionLevelFastestKey,
287+
func() (cache.WriteCache, func() error, error) {
288+
return cache.NewCacheWrite(
289+
*writeCacheFlag,
290+
config.WriteCacheTypeFile,
291+
)
292+
},
293+
false,
294+
false,
295+
296+
func(hdr *config.Header) {
297+
l.Trace("Header transform", hdr)
298+
},
299+
l,
300+
)
301+
302+
root, err := stfs.Initialize("/", os.ModePerm)
303+
if err != nil {
304+
panic(err)
305+
}
306+
307+
fs, err := cache.NewCacheFilesystem(
308+
stfs,
309+
root,
310+
config.NoneKey,
311+
0,
312+
"",
313+
)
314+
if err != nil {
315+
panic(err)
316+
}
317+
```
318+
319+
You can now use the Afero APIs to interact with the filesystem; if you've worked with Go's `fs` package before, they should be very familiar:
320+
321+
```go
322+
log.Println("stat /")
323+
324+
stat, err := fs.Stat("/")
325+
if err != nil {
326+
panic(err)
327+
}
328+
329+
log.Println("Result of stat /:", stat)
330+
331+
log.Println("create /test.txt")
332+
333+
file, err := fs.Create("/test.txt")
334+
if err != nil {
335+
panic(err)
336+
}
337+
338+
log.Println("Result of create /test.txt:", file)
339+
340+
log.Println("writeString /test.txt")
341+
342+
n, err := file.WriteString("Hello, world!")
343+
if err != nil {
344+
panic(err)
345+
}
346+
347+
log.Println("Result of writeString /test.txt:", n)
348+
349+
if err := file.Close(); err != nil {
350+
panic(err)
351+
}
352+
353+
// ...
354+
```
355+
356+
Note that STFS also implements `afero.Symlinker`, so symlinks are available as well.
357+
358+
For more information, check out the [Go API](https://pkg.go.dev/github.com/pojntfx/stfs) and take a look at the provided [examples](./examples), utilities, services and tests in the package for examples.
359+
360+
🚀 **That's it!** We hope you enjoy using STFS.
131361

132362
## Reference
133363

@@ -370,14 +600,14 @@ All command line arguments described above can also be set using environment var
370600
371601
To contribute, please use the [GitHub flow](https://guides.github.com/introduction/flow/) and follow our [Code of Conduct](./CODE_OF_CONDUCT.md).
372602
373-
To build and start a development version of stfs locally, run the following:
603+
To build and start a development version of STFS locally, run the following:
374604
375605
```shell
376606
$ git clone https://github.com/pojntfx/stfs.git
377607
$ cd stfs
378608
$ make depend
379609
$ make && sudo make install
380-
$ stfs serve ftp -d /tmp/drive.tar -m /tmp/dev.sqlite # Now point Nautilus to `ftp://localhost:1337`
610+
$ stfs serve ftp -d /tmp/drive.tar -m /tmp/dev.sqlite # Now point your file explorer to `ftp://localhost:1337`
381611
```
382612
383613
Have any questions or need help? Chat with us [on Matrix](https://matrix.to/#/#stfs:matrix.org?via=matrix.org)!

0 commit comments

Comments
 (0)