-
Notifications
You must be signed in to change notification settings - Fork 10
/
util.go
180 lines (156 loc) · 4.59 KB
/
util.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright (c) 2016 Intel Corporation. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package fs
import (
"fmt"
"os"
"path"
"path/filepath"
"syscall"
"github.com/intel-hpdd/go-lustre/luser"
)
// Version returns the current Lustre version string.
func Version() (string, error) {
v, err := luser.GetVersion()
if err != nil {
return "", fmt.Errorf("GetVersion() failed: %s", err)
}
return v.Lustre, nil
}
// RootDir represent a the mount point of a Lustre filesystem.
type RootDir struct {
path string
}
// IsValid indicates whether or not the RootDir is actually the
// root of a Lustre filesystem.
func (root RootDir) IsValid() bool {
return isDotLustre(path.Join(root.path, ".lustre"))
}
// Join args with root dir to create an absolute path.
// FIXME: replace this with OpenAt and friends
func (root RootDir) Join(args ...string) string {
return path.Join(root.path, path.Join(args...))
}
func (root RootDir) String() string {
return root.path
}
// Path returns the path for the root
func (root RootDir) Path() string {
return root.path
}
// Open returns open handle for the root directory
func (root RootDir) Open() (*os.File, error) {
return os.Open(root.path)
}
// ID should be a unique identifier for a filesystem. For now just use RootDir
type ID RootDir
func (id ID) String() string {
return id.path
}
// Path returns the path for the root
func (id ID) Path() (string, error) {
return id.path, nil
}
// Root returns the root dir for the root
func (id ID) Root() (RootDir, error) {
return RootDir(id), nil
}
// GetID returns the filesystem's ID. For the moment, this is the root path, but in
// the future it could be something more globally unique (uuid?).
func GetID(p string) (ID, error) {
r, err := MountRoot(p)
if err != nil {
return ID(r), err
}
return ID(r), nil
}
// Determine if given directory is the one true magical DOT_LUSTRE directory.
func isDotLustre(dir string) bool {
fi, err := os.Lstat(dir)
if err != nil {
return false
}
if fi.IsDir() {
fid, err := LookupFid(dir)
if err == nil && fid.IsDotLustre() {
return true
}
}
return false
}
// Return root device from the struct stat embedded in FileInfo
func rootDevice(fi os.FileInfo) uint64 {
stat, ok := fi.Sys().(*syscall.Stat_t)
if ok {
return uint64(stat.Dev)
}
panic("no stat available")
}
// findRoot returns the root directory for the lustre filesystem containing
// the pathname. If the the filesystem is not lustre, then error is returned.
func findRoot(dev uint64, pathname string) string {
parent := path.Dir(pathname)
fi, err := os.Lstat(parent)
if err != nil {
return ""
}
// If "/" is lustre then we won't see the device change
if rootDevice(fi) != dev || pathname == "/" {
if isDotLustre(path.Join(pathname, ".lustre")) {
return pathname
}
return ""
}
return findRoot(dev, parent)
}
// MountRoot returns the Lustre filesystem mountpoint for path
// or returns an error if the path is not on a Lustre filesystem.
func MountRoot(path string) (RootDir, error) {
absPath, err := filepath.Abs(path)
if err != nil {
return RootDir{}, err
}
fi, err := os.Lstat(absPath)
if err != nil {
return RootDir{}, err
}
mnt := findRoot(rootDevice(fi), absPath)
if mnt == "" {
return RootDir{}, fmt.Errorf("%s not a Lustre filesystem", path)
}
return RootDir{path: mnt}, nil
}
// findRelPah returns pathname relative to root directory for the lustre filesystem containing
// the pathname. If no Lustre root was found, then empty strings are returned.
func findRelPath(dev uint64, pathname string, relPath []string) (string, string) {
parent := path.Dir(pathname)
fi, err := os.Lstat(parent)
if err != nil {
return "", ""
}
// If "/" is lustre then we won't see the device change
if rootDevice(fi) != dev || pathname == "/" {
if isDotLustre(path.Join(pathname, ".lustre")) {
return pathname, path.Join(relPath...)
}
return "", ""
}
return findRelPath(dev, parent, append([]string{path.Base(pathname)}, relPath...))
}
// MountRelPath returns the lustre mountpoint, and remaing path for
// the given pathname. The remaining path is relative to the mount
// point. Returns an error if pathname is not valid or does not refer
// to a Lustre fs.
func MountRelPath(pathname string) (RootDir, string, error) {
pathname = filepath.Clean(pathname)
fi, err := os.Lstat(pathname)
if err != nil {
return RootDir{}, "", err
}
root, relPath := findRelPath(rootDevice(fi), pathname, []string{})
if root == "" {
return RootDir{}, "", fmt.Errorf("%s not a Lustre filesystem", pathname)
}
return RootDir{path: root}, relPath, nil
}