-
Notifications
You must be signed in to change notification settings - Fork 2
/
cafs.go
138 lines (115 loc) · 4.32 KB
/
cafs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// BitWrk - A Bitcoin-friendly, anonymous marketplace for computing power
// Copyright (C) 2013-2017 Jonas Eschenburg <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Package cafs specifies a content-addressable file storage with support
// for de-duplication and remote syncing.
package cafs
import (
"encoding/hex"
"errors"
"io"
)
var ErrNotFound = errors.New("Not found")
var ErrStillOpen = errors.New("Temporary still open")
var ErrInvalidState = errors.New("Invalid temporary state")
var ErrNotEnoughSpace = errors.New("Not enough space")
var LoggingEnabled = false
type SKey [32]byte
type FileStorage interface {
// Creates a new temporary that can be written into. The info string will stick
// with the temporary and also with the file, should it be created, and serves only
// informational purposes.
Create(info string) Temporary
// Queries a file from the storage that can be read from. If the file exists, a File
// interface is returned that has been locked once and that must be released correctly.
// If the file does not exist, then (nil, ErrNotFound) is returned.
Get(key *SKey) (File, error)
DumpStatistics(log Printer)
}
type File interface {
// Signals that this file handle is no longer in use.
// If no handles exist on a file anymore, the storage space
// bound by it can ce reclaimed by the garbage collector.
// It is an error to call Open() or Duplicate() after Dispose().
// It is ok to call Dispose() more than once.
Dispose()
Key() SKey
Open() io.ReadCloser
Size() int64
// Creates a new handle to the same file that must be Dispose()'d
// independently.
Duplicate() File
// Returns true if the file is stored in chunks internally.
// It is an error to call this function after Dispose().
IsChunked() bool
// Returns an iterator to the chunks of the file. The iterator must be disposed after use.
Chunks() FileIterator
// Returns the number of chunks in this file, or 1 if file is not chunked
NumChunks() int64
}
// Iterate over a set of files or chunks.
type FileIterator interface {
// Must be called after using this iterator.
Dispose()
// Returns a copy of this iterator that must be Dispose()'d independently.
Duplicate() FileIterator
// Advances the iterator and returns true if successful, or false if no further chunks
// could be read.
// Must be called before calling File().
Next() bool
// Returns the key of the last file or chunk successfully read by Next().
// Before calling this function, Next() must have been called and returned true.
Key() SKey
// Returns the size of the last file or chunk successfully read by Next().
// Before calling this function, Next() must have been called and returned true.
Size() int64
// Returns the last file or chunk successfully read by Next() as a file.
// The received File must be Dispose()'d.
// Before calling this function, Next() must have been called and returned true.
File() File
}
type Temporary interface {
// Stores the temporary file into the FileStorage, where it
// can be retrieved by key - after Close() has been called.
io.WriteCloser
// Returns a handle to the stored file, once Close() has been
// called and no error occurred. Otherwise, panics.
File() File
// Must be called when the temporary is no longer needed.
// It's ok to call Dispose() more than once.
Dispose()
}
func (k SKey) String() string {
return hex.EncodeToString(k[:])
}
func ParseKey(s string) (*SKey, error) {
if len(s) != 64 {
return nil, errors.New("Invalid key length")
}
var result SKey
if b, err := hex.DecodeString(s); err != nil {
return nil, err
} else {
copy(result[:], b)
}
return &result, nil
}
func MustParseKey(s string) *SKey {
if key, err := ParseKey(s); err != nil {
panic(err)
} else {
return key
}
}