/
inodes.go
70 lines (56 loc) · 1.42 KB
/
inodes.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
// Package inodes contains the logic for allocating inode numbers.
//
// We just store each inode as a key in the database. The overhead is
// roughly 8 bytes per inode. Inodes are never freed, currently. 2**64
// files oughta be enough for a while.
package inodes
import (
"encoding/binary"
"syscall"
"bazil.org/bazil/tokens"
"bazil.org/fuse"
"github.com/boltdb/bolt"
)
func inodeToBytes(inode uint64, buf []byte) {
binary.BigEndian.PutUint64(buf, inode)
}
func bytesToInode(buf []byte) uint64 {
return binary.BigEndian.Uint64(buf)
}
type outOfInodesError struct{}
var _ error = outOfInodesError{}
var _ fuse.ErrorNumber = outOfInodesError{}
func (outOfInodesError) Error() string {
return "out of inodes"
}
func (outOfInodesError) Errno() fuse.Errno {
return fuse.Errno(syscall.ENOSPC)
}
var ErrOutOfInodes = outOfInodesError{}
// Allocate returns the next available inode number, and marks it
// used.
//
// Returns ErrOutOfInodes if there are no free inodes.
func Allocate(bucket *bolt.Bucket) (uint64, error) {
c := bucket.Cursor()
var i uint64
k, _ := c.Last()
if k != nil {
i = bytesToInode(k)
}
// reserve a few inodes for internal use
if i < tokens.MaxReservedInode {
i = tokens.MaxReservedInode
}
i++
if i&tokens.InodeKindMask != tokens.InodeKindNormal {
return 0, ErrOutOfInodes
}
var buf [8]byte
inodeToBytes(i, buf[:])
err := bucket.Put(buf[:], nil)
if err != nil {
return 0, err
}
return i, nil
}