1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage fs 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "bytes" 19*333d2b36SAndroid Build Coastguard Worker "errors" 20*333d2b36SAndroid Build Coastguard Worker "fmt" 21*333d2b36SAndroid Build Coastguard Worker "io" 22*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 23*333d2b36SAndroid Build Coastguard Worker "os" 24*333d2b36SAndroid Build Coastguard Worker "os/user" 25*333d2b36SAndroid Build Coastguard Worker "path/filepath" 26*333d2b36SAndroid Build Coastguard Worker "sync" 27*333d2b36SAndroid Build Coastguard Worker "time" 28*333d2b36SAndroid Build Coastguard Worker) 29*333d2b36SAndroid Build Coastguard Worker 30*333d2b36SAndroid Build Coastguard Workervar OsFs FileSystem = osFs{} 31*333d2b36SAndroid Build Coastguard Worker 32*333d2b36SAndroid Build Coastguard Workerfunc NewMockFs(files map[string][]byte) *MockFs { 33*333d2b36SAndroid Build Coastguard Worker workDir := "/cwd" 34*333d2b36SAndroid Build Coastguard Worker fs := &MockFs{ 35*333d2b36SAndroid Build Coastguard Worker Clock: NewClock(time.Unix(2, 2)), 36*333d2b36SAndroid Build Coastguard Worker workDir: workDir, 37*333d2b36SAndroid Build Coastguard Worker } 38*333d2b36SAndroid Build Coastguard Worker fs.root = *fs.newDir() 39*333d2b36SAndroid Build Coastguard Worker fs.MkDirs(workDir) 40*333d2b36SAndroid Build Coastguard Worker 41*333d2b36SAndroid Build Coastguard Worker for path, bytes := range files { 42*333d2b36SAndroid Build Coastguard Worker dir := filepath.Dir(path) 43*333d2b36SAndroid Build Coastguard Worker fs.MkDirs(dir) 44*333d2b36SAndroid Build Coastguard Worker fs.WriteFile(path, bytes, 0777) 45*333d2b36SAndroid Build Coastguard Worker } 46*333d2b36SAndroid Build Coastguard Worker 47*333d2b36SAndroid Build Coastguard Worker return fs 48*333d2b36SAndroid Build Coastguard Worker} 49*333d2b36SAndroid Build Coastguard Worker 50*333d2b36SAndroid Build Coastguard Workertype FileSystem interface { 51*333d2b36SAndroid Build Coastguard Worker // getting information about files 52*333d2b36SAndroid Build Coastguard Worker Open(name string) (file io.ReadCloser, err error) 53*333d2b36SAndroid Build Coastguard Worker Lstat(path string) (stats os.FileInfo, err error) 54*333d2b36SAndroid Build Coastguard Worker Stat(path string) (stats os.FileInfo, err error) 55*333d2b36SAndroid Build Coastguard Worker ReadDir(path string) (contents []DirEntryInfo, err error) 56*333d2b36SAndroid Build Coastguard Worker 57*333d2b36SAndroid Build Coastguard Worker InodeNumber(info os.FileInfo) (number uint64, err error) 58*333d2b36SAndroid Build Coastguard Worker DeviceNumber(info os.FileInfo) (number uint64, err error) 59*333d2b36SAndroid Build Coastguard Worker PermTime(info os.FileInfo) (time time.Time, err error) 60*333d2b36SAndroid Build Coastguard Worker 61*333d2b36SAndroid Build Coastguard Worker // changing contents of the filesystem 62*333d2b36SAndroid Build Coastguard Worker Rename(oldPath string, newPath string) (err error) 63*333d2b36SAndroid Build Coastguard Worker WriteFile(path string, data []byte, perm os.FileMode) (err error) 64*333d2b36SAndroid Build Coastguard Worker Remove(path string) (err error) 65*333d2b36SAndroid Build Coastguard Worker RemoveAll(path string) (err error) 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Worker // metadata about the filesystem 68*333d2b36SAndroid Build Coastguard Worker ViewId() (id string) // Some unique id of the user accessing the filesystem 69*333d2b36SAndroid Build Coastguard Worker} 70*333d2b36SAndroid Build Coastguard Worker 71*333d2b36SAndroid Build Coastguard Worker// DentryInfo is a subset of the functionality available through os.FileInfo that might be able 72*333d2b36SAndroid Build Coastguard Worker// to be gleaned through only a syscall.Getdents without requiring a syscall.Lstat of every file. 73*333d2b36SAndroid Build Coastguard Workertype DirEntryInfo interface { 74*333d2b36SAndroid Build Coastguard Worker Name() string 75*333d2b36SAndroid Build Coastguard Worker Mode() os.FileMode // the file type encoded as an os.FileMode 76*333d2b36SAndroid Build Coastguard Worker IsDir() bool 77*333d2b36SAndroid Build Coastguard Worker} 78*333d2b36SAndroid Build Coastguard Worker 79*333d2b36SAndroid Build Coastguard Workertype dirEntryInfo struct { 80*333d2b36SAndroid Build Coastguard Worker name string 81*333d2b36SAndroid Build Coastguard Worker mode os.FileMode 82*333d2b36SAndroid Build Coastguard Worker modeExists bool 83*333d2b36SAndroid Build Coastguard Worker} 84*333d2b36SAndroid Build Coastguard Worker 85*333d2b36SAndroid Build Coastguard Workervar _ DirEntryInfo = os.FileInfo(nil) 86*333d2b36SAndroid Build Coastguard Worker 87*333d2b36SAndroid Build Coastguard Workerfunc (d *dirEntryInfo) Name() string { return d.name } 88*333d2b36SAndroid Build Coastguard Workerfunc (d *dirEntryInfo) Mode() os.FileMode { return d.mode } 89*333d2b36SAndroid Build Coastguard Workerfunc (d *dirEntryInfo) IsDir() bool { return d.mode.IsDir() } 90*333d2b36SAndroid Build Coastguard Workerfunc (d *dirEntryInfo) String() string { return d.name + ": " + d.mode.String() } 91*333d2b36SAndroid Build Coastguard Worker 92*333d2b36SAndroid Build Coastguard Worker// osFs implements FileSystem using the local disk. 93*333d2b36SAndroid Build Coastguard Workertype osFs struct{} 94*333d2b36SAndroid Build Coastguard Worker 95*333d2b36SAndroid Build Coastguard Workervar _ FileSystem = (*osFs)(nil) 96*333d2b36SAndroid Build Coastguard Worker 97*333d2b36SAndroid Build Coastguard Workerfunc (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) } 98*333d2b36SAndroid Build Coastguard Worker 99*333d2b36SAndroid Build Coastguard Workerfunc (osFs) Lstat(path string) (stats os.FileInfo, err error) { 100*333d2b36SAndroid Build Coastguard Worker return os.Lstat(path) 101*333d2b36SAndroid Build Coastguard Worker} 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Workerfunc (osFs) Stat(path string) (stats os.FileInfo, err error) { 104*333d2b36SAndroid Build Coastguard Worker return os.Stat(path) 105*333d2b36SAndroid Build Coastguard Worker} 106*333d2b36SAndroid Build Coastguard Worker 107*333d2b36SAndroid Build Coastguard Workerfunc (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) { 108*333d2b36SAndroid Build Coastguard Worker entries, err := readdir(path) 109*333d2b36SAndroid Build Coastguard Worker if err != nil { 110*333d2b36SAndroid Build Coastguard Worker return nil, err 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker for _, entry := range entries { 113*333d2b36SAndroid Build Coastguard Worker contents = append(contents, entry) 114*333d2b36SAndroid Build Coastguard Worker } 115*333d2b36SAndroid Build Coastguard Worker 116*333d2b36SAndroid Build Coastguard Worker return contents, nil 117*333d2b36SAndroid Build Coastguard Worker} 118*333d2b36SAndroid Build Coastguard Worker 119*333d2b36SAndroid Build Coastguard Workerfunc (osFs) Rename(oldPath string, newPath string) error { 120*333d2b36SAndroid Build Coastguard Worker return os.Rename(oldPath, newPath) 121*333d2b36SAndroid Build Coastguard Worker} 122*333d2b36SAndroid Build Coastguard Worker 123*333d2b36SAndroid Build Coastguard Workerfunc (osFs) WriteFile(path string, data []byte, perm os.FileMode) error { 124*333d2b36SAndroid Build Coastguard Worker return ioutil.WriteFile(path, data, perm) 125*333d2b36SAndroid Build Coastguard Worker} 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Workerfunc (osFs) Remove(path string) error { 128*333d2b36SAndroid Build Coastguard Worker return os.Remove(path) 129*333d2b36SAndroid Build Coastguard Worker} 130*333d2b36SAndroid Build Coastguard Worker 131*333d2b36SAndroid Build Coastguard Workerfunc (osFs) RemoveAll(path string) error { 132*333d2b36SAndroid Build Coastguard Worker return os.RemoveAll(path) 133*333d2b36SAndroid Build Coastguard Worker} 134*333d2b36SAndroid Build Coastguard Worker 135*333d2b36SAndroid Build Coastguard Workerfunc (osFs) ViewId() (id string) { 136*333d2b36SAndroid Build Coastguard Worker user, err := user.Current() 137*333d2b36SAndroid Build Coastguard Worker if err != nil { 138*333d2b36SAndroid Build Coastguard Worker return "" 139*333d2b36SAndroid Build Coastguard Worker } 140*333d2b36SAndroid Build Coastguard Worker username := user.Username 141*333d2b36SAndroid Build Coastguard Worker 142*333d2b36SAndroid Build Coastguard Worker hostname, err := os.Hostname() 143*333d2b36SAndroid Build Coastguard Worker if err != nil { 144*333d2b36SAndroid Build Coastguard Worker return "" 145*333d2b36SAndroid Build Coastguard Worker } 146*333d2b36SAndroid Build Coastguard Worker 147*333d2b36SAndroid Build Coastguard Worker return username + "@" + hostname 148*333d2b36SAndroid Build Coastguard Worker} 149*333d2b36SAndroid Build Coastguard Worker 150*333d2b36SAndroid Build Coastguard Workertype Clock struct { 151*333d2b36SAndroid Build Coastguard Worker time time.Time 152*333d2b36SAndroid Build Coastguard Worker} 153*333d2b36SAndroid Build Coastguard Worker 154*333d2b36SAndroid Build Coastguard Workerfunc NewClock(startTime time.Time) *Clock { 155*333d2b36SAndroid Build Coastguard Worker return &Clock{time: startTime} 156*333d2b36SAndroid Build Coastguard Worker 157*333d2b36SAndroid Build Coastguard Worker} 158*333d2b36SAndroid Build Coastguard Worker 159*333d2b36SAndroid Build Coastguard Workerfunc (c *Clock) Tick() { 160*333d2b36SAndroid Build Coastguard Worker c.time = c.time.Add(time.Microsecond) 161*333d2b36SAndroid Build Coastguard Worker} 162*333d2b36SAndroid Build Coastguard Worker 163*333d2b36SAndroid Build Coastguard Workerfunc (c *Clock) Time() time.Time { 164*333d2b36SAndroid Build Coastguard Worker return c.time 165*333d2b36SAndroid Build Coastguard Worker} 166*333d2b36SAndroid Build Coastguard Worker 167*333d2b36SAndroid Build Coastguard Worker// given "/a/b/c/d", pathSplit returns ("/a/b/c", "d") 168*333d2b36SAndroid Build Coastguard Workerfunc pathSplit(path string) (dir string, leaf string) { 169*333d2b36SAndroid Build Coastguard Worker dir, leaf = filepath.Split(path) 170*333d2b36SAndroid Build Coastguard Worker if dir != "/" && len(dir) > 0 { 171*333d2b36SAndroid Build Coastguard Worker dir = dir[:len(dir)-1] 172*333d2b36SAndroid Build Coastguard Worker } 173*333d2b36SAndroid Build Coastguard Worker return dir, leaf 174*333d2b36SAndroid Build Coastguard Worker} 175*333d2b36SAndroid Build Coastguard Worker 176*333d2b36SAndroid Build Coastguard Worker// MockFs supports singlethreaded writes and multithreaded reads 177*333d2b36SAndroid Build Coastguard Workertype MockFs struct { 178*333d2b36SAndroid Build Coastguard Worker // configuration 179*333d2b36SAndroid Build Coastguard Worker viewId string // 180*333d2b36SAndroid Build Coastguard Worker deviceNumber uint64 181*333d2b36SAndroid Build Coastguard Worker 182*333d2b36SAndroid Build Coastguard Worker // implementation 183*333d2b36SAndroid Build Coastguard Worker root mockDir 184*333d2b36SAndroid Build Coastguard Worker Clock *Clock 185*333d2b36SAndroid Build Coastguard Worker workDir string 186*333d2b36SAndroid Build Coastguard Worker nextInodeNumber uint64 187*333d2b36SAndroid Build Coastguard Worker 188*333d2b36SAndroid Build Coastguard Worker // history of requests, for tests to check 189*333d2b36SAndroid Build Coastguard Worker StatCalls []string 190*333d2b36SAndroid Build Coastguard Worker ReadDirCalls []string 191*333d2b36SAndroid Build Coastguard Worker aggregatesLock sync.Mutex 192*333d2b36SAndroid Build Coastguard Worker} 193*333d2b36SAndroid Build Coastguard Worker 194*333d2b36SAndroid Build Coastguard Workervar _ FileSystem = (*MockFs)(nil) 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Workertype mockInode struct { 197*333d2b36SAndroid Build Coastguard Worker modTime time.Time 198*333d2b36SAndroid Build Coastguard Worker permTime time.Time 199*333d2b36SAndroid Build Coastguard Worker sys interface{} 200*333d2b36SAndroid Build Coastguard Worker inodeNumber uint64 201*333d2b36SAndroid Build Coastguard Worker readErr error 202*333d2b36SAndroid Build Coastguard Worker} 203*333d2b36SAndroid Build Coastguard Worker 204*333d2b36SAndroid Build Coastguard Workerfunc (m mockInode) ModTime() time.Time { 205*333d2b36SAndroid Build Coastguard Worker return m.modTime 206*333d2b36SAndroid Build Coastguard Worker} 207*333d2b36SAndroid Build Coastguard Worker 208*333d2b36SAndroid Build Coastguard Workerfunc (m mockInode) Sys() interface{} { 209*333d2b36SAndroid Build Coastguard Worker return m.sys 210*333d2b36SAndroid Build Coastguard Worker} 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Workertype mockFile struct { 213*333d2b36SAndroid Build Coastguard Worker bytes []byte 214*333d2b36SAndroid Build Coastguard Worker 215*333d2b36SAndroid Build Coastguard Worker mockInode 216*333d2b36SAndroid Build Coastguard Worker} 217*333d2b36SAndroid Build Coastguard Worker 218*333d2b36SAndroid Build Coastguard Workertype mockLink struct { 219*333d2b36SAndroid Build Coastguard Worker target string 220*333d2b36SAndroid Build Coastguard Worker 221*333d2b36SAndroid Build Coastguard Worker mockInode 222*333d2b36SAndroid Build Coastguard Worker} 223*333d2b36SAndroid Build Coastguard Worker 224*333d2b36SAndroid Build Coastguard Workertype mockDir struct { 225*333d2b36SAndroid Build Coastguard Worker mockInode 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Worker subdirs map[string]*mockDir 228*333d2b36SAndroid Build Coastguard Worker files map[string]*mockFile 229*333d2b36SAndroid Build Coastguard Worker symlinks map[string]*mockLink 230*333d2b36SAndroid Build Coastguard Worker} 231*333d2b36SAndroid Build Coastguard Worker 232*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) resolve(path string, followLastLink bool) (result string, err error) { 233*333d2b36SAndroid Build Coastguard Worker if !filepath.IsAbs(path) { 234*333d2b36SAndroid Build Coastguard Worker path = filepath.Join(m.workDir, path) 235*333d2b36SAndroid Build Coastguard Worker } 236*333d2b36SAndroid Build Coastguard Worker path = filepath.Clean(path) 237*333d2b36SAndroid Build Coastguard Worker 238*333d2b36SAndroid Build Coastguard Worker return m.followLinks(path, followLastLink, 10) 239*333d2b36SAndroid Build Coastguard Worker} 240*333d2b36SAndroid Build Coastguard Worker 241*333d2b36SAndroid Build Coastguard Worker// note that followLinks can return a file path that doesn't exist 242*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) followLinks(path string, followLastLink bool, count int) (canonicalPath string, err error) { 243*333d2b36SAndroid Build Coastguard Worker if path == "/" { 244*333d2b36SAndroid Build Coastguard Worker return path, nil 245*333d2b36SAndroid Build Coastguard Worker } 246*333d2b36SAndroid Build Coastguard Worker 247*333d2b36SAndroid Build Coastguard Worker parentPath, leaf := pathSplit(path) 248*333d2b36SAndroid Build Coastguard Worker if parentPath == path { 249*333d2b36SAndroid Build Coastguard Worker err = fmt.Errorf("Internal error: %v yields itself as a parent", path) 250*333d2b36SAndroid Build Coastguard Worker panic(err.Error()) 251*333d2b36SAndroid Build Coastguard Worker } 252*333d2b36SAndroid Build Coastguard Worker 253*333d2b36SAndroid Build Coastguard Worker parentPath, err = m.followLinks(parentPath, true, count) 254*333d2b36SAndroid Build Coastguard Worker if err != nil { 255*333d2b36SAndroid Build Coastguard Worker return "", err 256*333d2b36SAndroid Build Coastguard Worker } 257*333d2b36SAndroid Build Coastguard Worker 258*333d2b36SAndroid Build Coastguard Worker parentNode, err := m.getDir(parentPath, false) 259*333d2b36SAndroid Build Coastguard Worker if err != nil { 260*333d2b36SAndroid Build Coastguard Worker return "", err 261*333d2b36SAndroid Build Coastguard Worker } 262*333d2b36SAndroid Build Coastguard Worker if parentNode.readErr != nil { 263*333d2b36SAndroid Build Coastguard Worker return "", &os.PathError{ 264*333d2b36SAndroid Build Coastguard Worker Op: "read", 265*333d2b36SAndroid Build Coastguard Worker Path: path, 266*333d2b36SAndroid Build Coastguard Worker Err: parentNode.readErr, 267*333d2b36SAndroid Build Coastguard Worker } 268*333d2b36SAndroid Build Coastguard Worker } 269*333d2b36SAndroid Build Coastguard Worker 270*333d2b36SAndroid Build Coastguard Worker link, isLink := parentNode.symlinks[leaf] 271*333d2b36SAndroid Build Coastguard Worker if isLink && followLastLink { 272*333d2b36SAndroid Build Coastguard Worker if count <= 0 { 273*333d2b36SAndroid Build Coastguard Worker // probably a loop 274*333d2b36SAndroid Build Coastguard Worker return "", &os.PathError{ 275*333d2b36SAndroid Build Coastguard Worker Op: "read", 276*333d2b36SAndroid Build Coastguard Worker Path: path, 277*333d2b36SAndroid Build Coastguard Worker Err: fmt.Errorf("too many levels of symbolic links"), 278*333d2b36SAndroid Build Coastguard Worker } 279*333d2b36SAndroid Build Coastguard Worker } 280*333d2b36SAndroid Build Coastguard Worker 281*333d2b36SAndroid Build Coastguard Worker if link.readErr != nil { 282*333d2b36SAndroid Build Coastguard Worker return "", &os.PathError{ 283*333d2b36SAndroid Build Coastguard Worker Op: "read", 284*333d2b36SAndroid Build Coastguard Worker Path: path, 285*333d2b36SAndroid Build Coastguard Worker Err: link.readErr, 286*333d2b36SAndroid Build Coastguard Worker } 287*333d2b36SAndroid Build Coastguard Worker } 288*333d2b36SAndroid Build Coastguard Worker 289*333d2b36SAndroid Build Coastguard Worker target := m.followLink(link, parentPath) 290*333d2b36SAndroid Build Coastguard Worker return m.followLinks(target, followLastLink, count-1) 291*333d2b36SAndroid Build Coastguard Worker } 292*333d2b36SAndroid Build Coastguard Worker return path, nil 293*333d2b36SAndroid Build Coastguard Worker} 294*333d2b36SAndroid Build Coastguard Worker 295*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) followLink(link *mockLink, parentPath string) (result string) { 296*333d2b36SAndroid Build Coastguard Worker return filepath.Clean(filepath.Join(parentPath, link.target)) 297*333d2b36SAndroid Build Coastguard Worker} 298*333d2b36SAndroid Build Coastguard Worker 299*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) getFile(parentDir *mockDir, fileName string) (file *mockFile, err error) { 300*333d2b36SAndroid Build Coastguard Worker file, isFile := parentDir.files[fileName] 301*333d2b36SAndroid Build Coastguard Worker if !isFile { 302*333d2b36SAndroid Build Coastguard Worker _, isDir := parentDir.subdirs[fileName] 303*333d2b36SAndroid Build Coastguard Worker _, isLink := parentDir.symlinks[fileName] 304*333d2b36SAndroid Build Coastguard Worker if isDir || isLink { 305*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 306*333d2b36SAndroid Build Coastguard Worker Op: "open", 307*333d2b36SAndroid Build Coastguard Worker Path: fileName, 308*333d2b36SAndroid Build Coastguard Worker Err: os.ErrInvalid, 309*333d2b36SAndroid Build Coastguard Worker } 310*333d2b36SAndroid Build Coastguard Worker } 311*333d2b36SAndroid Build Coastguard Worker 312*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 313*333d2b36SAndroid Build Coastguard Worker Op: "open", 314*333d2b36SAndroid Build Coastguard Worker Path: fileName, 315*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 316*333d2b36SAndroid Build Coastguard Worker } 317*333d2b36SAndroid Build Coastguard Worker } 318*333d2b36SAndroid Build Coastguard Worker if file.readErr != nil { 319*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 320*333d2b36SAndroid Build Coastguard Worker Op: "open", 321*333d2b36SAndroid Build Coastguard Worker Path: fileName, 322*333d2b36SAndroid Build Coastguard Worker Err: file.readErr, 323*333d2b36SAndroid Build Coastguard Worker } 324*333d2b36SAndroid Build Coastguard Worker } 325*333d2b36SAndroid Build Coastguard Worker return file, nil 326*333d2b36SAndroid Build Coastguard Worker} 327*333d2b36SAndroid Build Coastguard Worker 328*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) getInode(parentDir *mockDir, name string) (inode *mockInode, err error) { 329*333d2b36SAndroid Build Coastguard Worker file, isFile := parentDir.files[name] 330*333d2b36SAndroid Build Coastguard Worker if isFile { 331*333d2b36SAndroid Build Coastguard Worker return &file.mockInode, nil 332*333d2b36SAndroid Build Coastguard Worker } 333*333d2b36SAndroid Build Coastguard Worker link, isLink := parentDir.symlinks[name] 334*333d2b36SAndroid Build Coastguard Worker if isLink { 335*333d2b36SAndroid Build Coastguard Worker return &link.mockInode, nil 336*333d2b36SAndroid Build Coastguard Worker } 337*333d2b36SAndroid Build Coastguard Worker dir, isDir := parentDir.subdirs[name] 338*333d2b36SAndroid Build Coastguard Worker if isDir { 339*333d2b36SAndroid Build Coastguard Worker return &dir.mockInode, nil 340*333d2b36SAndroid Build Coastguard Worker } 341*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 342*333d2b36SAndroid Build Coastguard Worker Op: "stat", 343*333d2b36SAndroid Build Coastguard Worker Path: name, 344*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 345*333d2b36SAndroid Build Coastguard Worker } 346*333d2b36SAndroid Build Coastguard Worker 347*333d2b36SAndroid Build Coastguard Worker} 348*333d2b36SAndroid Build Coastguard Worker 349*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) Open(path string) (io.ReadCloser, error) { 350*333d2b36SAndroid Build Coastguard Worker path, err := m.resolve(path, true) 351*333d2b36SAndroid Build Coastguard Worker if err != nil { 352*333d2b36SAndroid Build Coastguard Worker return nil, err 353*333d2b36SAndroid Build Coastguard Worker } 354*333d2b36SAndroid Build Coastguard Worker 355*333d2b36SAndroid Build Coastguard Worker if err != nil { 356*333d2b36SAndroid Build Coastguard Worker return nil, err 357*333d2b36SAndroid Build Coastguard Worker } 358*333d2b36SAndroid Build Coastguard Worker 359*333d2b36SAndroid Build Coastguard Worker parentPath, base := pathSplit(path) 360*333d2b36SAndroid Build Coastguard Worker parentDir, err := m.getDir(parentPath, false) 361*333d2b36SAndroid Build Coastguard Worker if err != nil { 362*333d2b36SAndroid Build Coastguard Worker return nil, err 363*333d2b36SAndroid Build Coastguard Worker } 364*333d2b36SAndroid Build Coastguard Worker file, err := m.getFile(parentDir, base) 365*333d2b36SAndroid Build Coastguard Worker if err != nil { 366*333d2b36SAndroid Build Coastguard Worker return nil, err 367*333d2b36SAndroid Build Coastguard Worker } 368*333d2b36SAndroid Build Coastguard Worker return struct { 369*333d2b36SAndroid Build Coastguard Worker io.Closer 370*333d2b36SAndroid Build Coastguard Worker *bytes.Reader 371*333d2b36SAndroid Build Coastguard Worker }{ 372*333d2b36SAndroid Build Coastguard Worker ioutil.NopCloser(nil), 373*333d2b36SAndroid Build Coastguard Worker bytes.NewReader(file.bytes), 374*333d2b36SAndroid Build Coastguard Worker }, nil 375*333d2b36SAndroid Build Coastguard Worker 376*333d2b36SAndroid Build Coastguard Worker} 377*333d2b36SAndroid Build Coastguard Worker 378*333d2b36SAndroid Build Coastguard Worker// a mockFileInfo is for exporting file stats in a way that satisfies the FileInfo interface 379*333d2b36SAndroid Build Coastguard Workertype mockFileInfo struct { 380*333d2b36SAndroid Build Coastguard Worker path string 381*333d2b36SAndroid Build Coastguard Worker size int64 382*333d2b36SAndroid Build Coastguard Worker modTime time.Time // time at which the inode's contents were modified 383*333d2b36SAndroid Build Coastguard Worker permTime time.Time // time at which the inode's permissions were modified 384*333d2b36SAndroid Build Coastguard Worker mode os.FileMode 385*333d2b36SAndroid Build Coastguard Worker inodeNumber uint64 386*333d2b36SAndroid Build Coastguard Worker deviceNumber uint64 387*333d2b36SAndroid Build Coastguard Worker} 388*333d2b36SAndroid Build Coastguard Worker 389*333d2b36SAndroid Build Coastguard Workerfunc (m *mockFileInfo) Name() string { 390*333d2b36SAndroid Build Coastguard Worker return m.path 391*333d2b36SAndroid Build Coastguard Worker} 392*333d2b36SAndroid Build Coastguard Worker 393*333d2b36SAndroid Build Coastguard Workerfunc (m *mockFileInfo) Size() int64 { 394*333d2b36SAndroid Build Coastguard Worker return m.size 395*333d2b36SAndroid Build Coastguard Worker} 396*333d2b36SAndroid Build Coastguard Worker 397*333d2b36SAndroid Build Coastguard Workerfunc (m *mockFileInfo) Mode() os.FileMode { 398*333d2b36SAndroid Build Coastguard Worker return m.mode 399*333d2b36SAndroid Build Coastguard Worker} 400*333d2b36SAndroid Build Coastguard Worker 401*333d2b36SAndroid Build Coastguard Workerfunc (m *mockFileInfo) ModTime() time.Time { 402*333d2b36SAndroid Build Coastguard Worker return m.modTime 403*333d2b36SAndroid Build Coastguard Worker} 404*333d2b36SAndroid Build Coastguard Worker 405*333d2b36SAndroid Build Coastguard Workerfunc (m *mockFileInfo) IsDir() bool { 406*333d2b36SAndroid Build Coastguard Worker return m.mode&os.ModeDir != 0 407*333d2b36SAndroid Build Coastguard Worker} 408*333d2b36SAndroid Build Coastguard Worker 409*333d2b36SAndroid Build Coastguard Workerfunc (m *mockFileInfo) Sys() interface{} { 410*333d2b36SAndroid Build Coastguard Worker return nil 411*333d2b36SAndroid Build Coastguard Worker} 412*333d2b36SAndroid Build Coastguard Worker 413*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) dirToFileInfo(d *mockDir, path string) (info *mockFileInfo) { 414*333d2b36SAndroid Build Coastguard Worker return &mockFileInfo{ 415*333d2b36SAndroid Build Coastguard Worker path: filepath.Base(path), 416*333d2b36SAndroid Build Coastguard Worker size: 1, 417*333d2b36SAndroid Build Coastguard Worker modTime: d.modTime, 418*333d2b36SAndroid Build Coastguard Worker permTime: d.permTime, 419*333d2b36SAndroid Build Coastguard Worker mode: os.ModeDir, 420*333d2b36SAndroid Build Coastguard Worker inodeNumber: d.inodeNumber, 421*333d2b36SAndroid Build Coastguard Worker deviceNumber: m.deviceNumber, 422*333d2b36SAndroid Build Coastguard Worker } 423*333d2b36SAndroid Build Coastguard Worker 424*333d2b36SAndroid Build Coastguard Worker} 425*333d2b36SAndroid Build Coastguard Worker 426*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) fileToFileInfo(f *mockFile, path string) (info *mockFileInfo) { 427*333d2b36SAndroid Build Coastguard Worker return &mockFileInfo{ 428*333d2b36SAndroid Build Coastguard Worker path: filepath.Base(path), 429*333d2b36SAndroid Build Coastguard Worker size: 1, 430*333d2b36SAndroid Build Coastguard Worker modTime: f.modTime, 431*333d2b36SAndroid Build Coastguard Worker permTime: f.permTime, 432*333d2b36SAndroid Build Coastguard Worker mode: 0, 433*333d2b36SAndroid Build Coastguard Worker inodeNumber: f.inodeNumber, 434*333d2b36SAndroid Build Coastguard Worker deviceNumber: m.deviceNumber, 435*333d2b36SAndroid Build Coastguard Worker } 436*333d2b36SAndroid Build Coastguard Worker} 437*333d2b36SAndroid Build Coastguard Worker 438*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) linkToFileInfo(l *mockLink, path string) (info *mockFileInfo) { 439*333d2b36SAndroid Build Coastguard Worker return &mockFileInfo{ 440*333d2b36SAndroid Build Coastguard Worker path: filepath.Base(path), 441*333d2b36SAndroid Build Coastguard Worker size: 1, 442*333d2b36SAndroid Build Coastguard Worker modTime: l.modTime, 443*333d2b36SAndroid Build Coastguard Worker permTime: l.permTime, 444*333d2b36SAndroid Build Coastguard Worker mode: os.ModeSymlink, 445*333d2b36SAndroid Build Coastguard Worker inodeNumber: l.inodeNumber, 446*333d2b36SAndroid Build Coastguard Worker deviceNumber: m.deviceNumber, 447*333d2b36SAndroid Build Coastguard Worker } 448*333d2b36SAndroid Build Coastguard Worker} 449*333d2b36SAndroid Build Coastguard Worker 450*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) Lstat(path string) (stats os.FileInfo, err error) { 451*333d2b36SAndroid Build Coastguard Worker // update aggregates 452*333d2b36SAndroid Build Coastguard Worker m.aggregatesLock.Lock() 453*333d2b36SAndroid Build Coastguard Worker m.StatCalls = append(m.StatCalls, path) 454*333d2b36SAndroid Build Coastguard Worker m.aggregatesLock.Unlock() 455*333d2b36SAndroid Build Coastguard Worker 456*333d2b36SAndroid Build Coastguard Worker // resolve symlinks 457*333d2b36SAndroid Build Coastguard Worker path, err = m.resolve(path, false) 458*333d2b36SAndroid Build Coastguard Worker if err != nil { 459*333d2b36SAndroid Build Coastguard Worker return nil, err 460*333d2b36SAndroid Build Coastguard Worker } 461*333d2b36SAndroid Build Coastguard Worker 462*333d2b36SAndroid Build Coastguard Worker // special case for root dir 463*333d2b36SAndroid Build Coastguard Worker if path == "/" { 464*333d2b36SAndroid Build Coastguard Worker return m.dirToFileInfo(&m.root, "/"), nil 465*333d2b36SAndroid Build Coastguard Worker } 466*333d2b36SAndroid Build Coastguard Worker 467*333d2b36SAndroid Build Coastguard Worker // determine type and handle appropriately 468*333d2b36SAndroid Build Coastguard Worker parentPath, baseName := pathSplit(path) 469*333d2b36SAndroid Build Coastguard Worker dir, err := m.getDir(parentPath, false) 470*333d2b36SAndroid Build Coastguard Worker if err != nil { 471*333d2b36SAndroid Build Coastguard Worker return nil, err 472*333d2b36SAndroid Build Coastguard Worker } 473*333d2b36SAndroid Build Coastguard Worker subdir, subdirExists := dir.subdirs[baseName] 474*333d2b36SAndroid Build Coastguard Worker if subdirExists { 475*333d2b36SAndroid Build Coastguard Worker return m.dirToFileInfo(subdir, path), nil 476*333d2b36SAndroid Build Coastguard Worker } 477*333d2b36SAndroid Build Coastguard Worker file, fileExists := dir.files[baseName] 478*333d2b36SAndroid Build Coastguard Worker if fileExists { 479*333d2b36SAndroid Build Coastguard Worker return m.fileToFileInfo(file, path), nil 480*333d2b36SAndroid Build Coastguard Worker } 481*333d2b36SAndroid Build Coastguard Worker link, linkExists := dir.symlinks[baseName] 482*333d2b36SAndroid Build Coastguard Worker if linkExists { 483*333d2b36SAndroid Build Coastguard Worker return m.linkToFileInfo(link, path), nil 484*333d2b36SAndroid Build Coastguard Worker } 485*333d2b36SAndroid Build Coastguard Worker // not found 486*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 487*333d2b36SAndroid Build Coastguard Worker Op: "stat", 488*333d2b36SAndroid Build Coastguard Worker Path: path, 489*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 490*333d2b36SAndroid Build Coastguard Worker } 491*333d2b36SAndroid Build Coastguard Worker} 492*333d2b36SAndroid Build Coastguard Worker 493*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) Stat(path string) (stats os.FileInfo, err error) { 494*333d2b36SAndroid Build Coastguard Worker // resolve symlinks 495*333d2b36SAndroid Build Coastguard Worker path, err = m.resolve(path, true) 496*333d2b36SAndroid Build Coastguard Worker if err != nil { 497*333d2b36SAndroid Build Coastguard Worker return nil, err 498*333d2b36SAndroid Build Coastguard Worker } 499*333d2b36SAndroid Build Coastguard Worker 500*333d2b36SAndroid Build Coastguard Worker return m.Lstat(path) 501*333d2b36SAndroid Build Coastguard Worker} 502*333d2b36SAndroid Build Coastguard Worker 503*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) InodeNumber(info os.FileInfo) (number uint64, err error) { 504*333d2b36SAndroid Build Coastguard Worker mockInfo, ok := info.(*mockFileInfo) 505*333d2b36SAndroid Build Coastguard Worker if ok { 506*333d2b36SAndroid Build Coastguard Worker return mockInfo.inodeNumber, nil 507*333d2b36SAndroid Build Coastguard Worker } 508*333d2b36SAndroid Build Coastguard Worker return 0, fmt.Errorf("%v is not a mockFileInfo", info) 509*333d2b36SAndroid Build Coastguard Worker} 510*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) DeviceNumber(info os.FileInfo) (number uint64, err error) { 511*333d2b36SAndroid Build Coastguard Worker mockInfo, ok := info.(*mockFileInfo) 512*333d2b36SAndroid Build Coastguard Worker if ok { 513*333d2b36SAndroid Build Coastguard Worker return mockInfo.deviceNumber, nil 514*333d2b36SAndroid Build Coastguard Worker } 515*333d2b36SAndroid Build Coastguard Worker return 0, fmt.Errorf("%v is not a mockFileInfo", info) 516*333d2b36SAndroid Build Coastguard Worker} 517*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) PermTime(info os.FileInfo) (when time.Time, err error) { 518*333d2b36SAndroid Build Coastguard Worker mockInfo, ok := info.(*mockFileInfo) 519*333d2b36SAndroid Build Coastguard Worker if ok { 520*333d2b36SAndroid Build Coastguard Worker return mockInfo.permTime, nil 521*333d2b36SAndroid Build Coastguard Worker } 522*333d2b36SAndroid Build Coastguard Worker return time.Date(0, 0, 0, 0, 0, 0, 0, nil), 523*333d2b36SAndroid Build Coastguard Worker fmt.Errorf("%v is not a mockFileInfo", info) 524*333d2b36SAndroid Build Coastguard Worker} 525*333d2b36SAndroid Build Coastguard Worker 526*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) ReadDir(path string) (contents []DirEntryInfo, err error) { 527*333d2b36SAndroid Build Coastguard Worker // update aggregates 528*333d2b36SAndroid Build Coastguard Worker m.aggregatesLock.Lock() 529*333d2b36SAndroid Build Coastguard Worker m.ReadDirCalls = append(m.ReadDirCalls, path) 530*333d2b36SAndroid Build Coastguard Worker m.aggregatesLock.Unlock() 531*333d2b36SAndroid Build Coastguard Worker 532*333d2b36SAndroid Build Coastguard Worker // locate directory 533*333d2b36SAndroid Build Coastguard Worker path, err = m.resolve(path, true) 534*333d2b36SAndroid Build Coastguard Worker if err != nil { 535*333d2b36SAndroid Build Coastguard Worker return nil, err 536*333d2b36SAndroid Build Coastguard Worker } 537*333d2b36SAndroid Build Coastguard Worker results := []DirEntryInfo{} 538*333d2b36SAndroid Build Coastguard Worker dir, err := m.getDir(path, false) 539*333d2b36SAndroid Build Coastguard Worker if err != nil { 540*333d2b36SAndroid Build Coastguard Worker return nil, err 541*333d2b36SAndroid Build Coastguard Worker } 542*333d2b36SAndroid Build Coastguard Worker if dir.readErr != nil { 543*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 544*333d2b36SAndroid Build Coastguard Worker Op: "read", 545*333d2b36SAndroid Build Coastguard Worker Path: path, 546*333d2b36SAndroid Build Coastguard Worker Err: dir.readErr, 547*333d2b36SAndroid Build Coastguard Worker } 548*333d2b36SAndroid Build Coastguard Worker } 549*333d2b36SAndroid Build Coastguard Worker // describe its contents 550*333d2b36SAndroid Build Coastguard Worker for name, subdir := range dir.subdirs { 551*333d2b36SAndroid Build Coastguard Worker dirInfo := m.dirToFileInfo(subdir, name) 552*333d2b36SAndroid Build Coastguard Worker results = append(results, dirInfo) 553*333d2b36SAndroid Build Coastguard Worker } 554*333d2b36SAndroid Build Coastguard Worker for name, file := range dir.files { 555*333d2b36SAndroid Build Coastguard Worker info := m.fileToFileInfo(file, name) 556*333d2b36SAndroid Build Coastguard Worker results = append(results, info) 557*333d2b36SAndroid Build Coastguard Worker } 558*333d2b36SAndroid Build Coastguard Worker for name, link := range dir.symlinks { 559*333d2b36SAndroid Build Coastguard Worker info := m.linkToFileInfo(link, name) 560*333d2b36SAndroid Build Coastguard Worker results = append(results, info) 561*333d2b36SAndroid Build Coastguard Worker } 562*333d2b36SAndroid Build Coastguard Worker return results, nil 563*333d2b36SAndroid Build Coastguard Worker} 564*333d2b36SAndroid Build Coastguard Worker 565*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) Rename(sourcePath string, destPath string) error { 566*333d2b36SAndroid Build Coastguard Worker // validate source parent exists 567*333d2b36SAndroid Build Coastguard Worker sourcePath, err := m.resolve(sourcePath, false) 568*333d2b36SAndroid Build Coastguard Worker if err != nil { 569*333d2b36SAndroid Build Coastguard Worker return err 570*333d2b36SAndroid Build Coastguard Worker } 571*333d2b36SAndroid Build Coastguard Worker sourceParentPath := filepath.Dir(sourcePath) 572*333d2b36SAndroid Build Coastguard Worker sourceParentDir, err := m.getDir(sourceParentPath, false) 573*333d2b36SAndroid Build Coastguard Worker if err != nil { 574*333d2b36SAndroid Build Coastguard Worker return err 575*333d2b36SAndroid Build Coastguard Worker } 576*333d2b36SAndroid Build Coastguard Worker if sourceParentDir == nil { 577*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 578*333d2b36SAndroid Build Coastguard Worker Op: "move", 579*333d2b36SAndroid Build Coastguard Worker Path: sourcePath, 580*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 581*333d2b36SAndroid Build Coastguard Worker } 582*333d2b36SAndroid Build Coastguard Worker } 583*333d2b36SAndroid Build Coastguard Worker if sourceParentDir.readErr != nil { 584*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 585*333d2b36SAndroid Build Coastguard Worker Op: "move", 586*333d2b36SAndroid Build Coastguard Worker Path: sourcePath, 587*333d2b36SAndroid Build Coastguard Worker Err: sourceParentDir.readErr, 588*333d2b36SAndroid Build Coastguard Worker } 589*333d2b36SAndroid Build Coastguard Worker } 590*333d2b36SAndroid Build Coastguard Worker 591*333d2b36SAndroid Build Coastguard Worker // validate dest parent exists 592*333d2b36SAndroid Build Coastguard Worker destPath, err = m.resolve(destPath, false) 593*333d2b36SAndroid Build Coastguard Worker destParentPath := filepath.Dir(destPath) 594*333d2b36SAndroid Build Coastguard Worker destParentDir, err := m.getDir(destParentPath, false) 595*333d2b36SAndroid Build Coastguard Worker if err != nil { 596*333d2b36SAndroid Build Coastguard Worker return err 597*333d2b36SAndroid Build Coastguard Worker } 598*333d2b36SAndroid Build Coastguard Worker if destParentDir == nil { 599*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 600*333d2b36SAndroid Build Coastguard Worker Op: "move", 601*333d2b36SAndroid Build Coastguard Worker Path: destParentPath, 602*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 603*333d2b36SAndroid Build Coastguard Worker } 604*333d2b36SAndroid Build Coastguard Worker } 605*333d2b36SAndroid Build Coastguard Worker if destParentDir.readErr != nil { 606*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 607*333d2b36SAndroid Build Coastguard Worker Op: "move", 608*333d2b36SAndroid Build Coastguard Worker Path: destParentPath, 609*333d2b36SAndroid Build Coastguard Worker Err: destParentDir.readErr, 610*333d2b36SAndroid Build Coastguard Worker } 611*333d2b36SAndroid Build Coastguard Worker } 612*333d2b36SAndroid Build Coastguard Worker // check the source and dest themselves 613*333d2b36SAndroid Build Coastguard Worker sourceBase := filepath.Base(sourcePath) 614*333d2b36SAndroid Build Coastguard Worker destBase := filepath.Base(destPath) 615*333d2b36SAndroid Build Coastguard Worker 616*333d2b36SAndroid Build Coastguard Worker file, sourceIsFile := sourceParentDir.files[sourceBase] 617*333d2b36SAndroid Build Coastguard Worker dir, sourceIsDir := sourceParentDir.subdirs[sourceBase] 618*333d2b36SAndroid Build Coastguard Worker link, sourceIsLink := sourceParentDir.symlinks[sourceBase] 619*333d2b36SAndroid Build Coastguard Worker 620*333d2b36SAndroid Build Coastguard Worker // validate that the source exists 621*333d2b36SAndroid Build Coastguard Worker if !sourceIsFile && !sourceIsDir && !sourceIsLink { 622*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 623*333d2b36SAndroid Build Coastguard Worker Op: "move", 624*333d2b36SAndroid Build Coastguard Worker Path: sourcePath, 625*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 626*333d2b36SAndroid Build Coastguard Worker } 627*333d2b36SAndroid Build Coastguard Worker 628*333d2b36SAndroid Build Coastguard Worker } 629*333d2b36SAndroid Build Coastguard Worker 630*333d2b36SAndroid Build Coastguard Worker // validate the destination doesn't already exist as an incompatible type 631*333d2b36SAndroid Build Coastguard Worker _, destWasFile := destParentDir.files[destBase] 632*333d2b36SAndroid Build Coastguard Worker _, destWasDir := destParentDir.subdirs[destBase] 633*333d2b36SAndroid Build Coastguard Worker _, destWasLink := destParentDir.symlinks[destBase] 634*333d2b36SAndroid Build Coastguard Worker 635*333d2b36SAndroid Build Coastguard Worker if destWasDir { 636*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 637*333d2b36SAndroid Build Coastguard Worker Op: "move", 638*333d2b36SAndroid Build Coastguard Worker Path: destPath, 639*333d2b36SAndroid Build Coastguard Worker Err: errors.New("destination exists as a directory"), 640*333d2b36SAndroid Build Coastguard Worker } 641*333d2b36SAndroid Build Coastguard Worker } 642*333d2b36SAndroid Build Coastguard Worker 643*333d2b36SAndroid Build Coastguard Worker if sourceIsDir && (destWasFile || destWasLink) { 644*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 645*333d2b36SAndroid Build Coastguard Worker Op: "move", 646*333d2b36SAndroid Build Coastguard Worker Path: destPath, 647*333d2b36SAndroid Build Coastguard Worker Err: errors.New("destination exists as a file"), 648*333d2b36SAndroid Build Coastguard Worker } 649*333d2b36SAndroid Build Coastguard Worker } 650*333d2b36SAndroid Build Coastguard Worker 651*333d2b36SAndroid Build Coastguard Worker if destWasFile { 652*333d2b36SAndroid Build Coastguard Worker delete(destParentDir.files, destBase) 653*333d2b36SAndroid Build Coastguard Worker } 654*333d2b36SAndroid Build Coastguard Worker if destWasDir { 655*333d2b36SAndroid Build Coastguard Worker delete(destParentDir.subdirs, destBase) 656*333d2b36SAndroid Build Coastguard Worker } 657*333d2b36SAndroid Build Coastguard Worker if destWasLink { 658*333d2b36SAndroid Build Coastguard Worker delete(destParentDir.symlinks, destBase) 659*333d2b36SAndroid Build Coastguard Worker } 660*333d2b36SAndroid Build Coastguard Worker 661*333d2b36SAndroid Build Coastguard Worker if sourceIsFile { 662*333d2b36SAndroid Build Coastguard Worker destParentDir.files[destBase] = file 663*333d2b36SAndroid Build Coastguard Worker delete(sourceParentDir.files, sourceBase) 664*333d2b36SAndroid Build Coastguard Worker } 665*333d2b36SAndroid Build Coastguard Worker if sourceIsDir { 666*333d2b36SAndroid Build Coastguard Worker destParentDir.subdirs[destBase] = dir 667*333d2b36SAndroid Build Coastguard Worker delete(sourceParentDir.subdirs, sourceBase) 668*333d2b36SAndroid Build Coastguard Worker } 669*333d2b36SAndroid Build Coastguard Worker if sourceIsLink { 670*333d2b36SAndroid Build Coastguard Worker destParentDir.symlinks[destBase] = link 671*333d2b36SAndroid Build Coastguard Worker delete(destParentDir.symlinks, sourceBase) 672*333d2b36SAndroid Build Coastguard Worker } 673*333d2b36SAndroid Build Coastguard Worker 674*333d2b36SAndroid Build Coastguard Worker destParentDir.modTime = m.Clock.Time() 675*333d2b36SAndroid Build Coastguard Worker sourceParentDir.modTime = m.Clock.Time() 676*333d2b36SAndroid Build Coastguard Worker return nil 677*333d2b36SAndroid Build Coastguard Worker} 678*333d2b36SAndroid Build Coastguard Worker 679*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) newInodeNumber() uint64 { 680*333d2b36SAndroid Build Coastguard Worker result := m.nextInodeNumber 681*333d2b36SAndroid Build Coastguard Worker m.nextInodeNumber++ 682*333d2b36SAndroid Build Coastguard Worker return result 683*333d2b36SAndroid Build Coastguard Worker} 684*333d2b36SAndroid Build Coastguard Worker 685*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) WriteFile(filePath string, data []byte, perm os.FileMode) error { 686*333d2b36SAndroid Build Coastguard Worker filePath, err := m.resolve(filePath, true) 687*333d2b36SAndroid Build Coastguard Worker if err != nil { 688*333d2b36SAndroid Build Coastguard Worker return err 689*333d2b36SAndroid Build Coastguard Worker } 690*333d2b36SAndroid Build Coastguard Worker parentPath := filepath.Dir(filePath) 691*333d2b36SAndroid Build Coastguard Worker parentDir, err := m.getDir(parentPath, false) 692*333d2b36SAndroid Build Coastguard Worker if err != nil || parentDir == nil { 693*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 694*333d2b36SAndroid Build Coastguard Worker Op: "write", 695*333d2b36SAndroid Build Coastguard Worker Path: parentPath, 696*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 697*333d2b36SAndroid Build Coastguard Worker } 698*333d2b36SAndroid Build Coastguard Worker } 699*333d2b36SAndroid Build Coastguard Worker if parentDir.readErr != nil { 700*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 701*333d2b36SAndroid Build Coastguard Worker Op: "write", 702*333d2b36SAndroid Build Coastguard Worker Path: parentPath, 703*333d2b36SAndroid Build Coastguard Worker Err: parentDir.readErr, 704*333d2b36SAndroid Build Coastguard Worker } 705*333d2b36SAndroid Build Coastguard Worker } 706*333d2b36SAndroid Build Coastguard Worker 707*333d2b36SAndroid Build Coastguard Worker baseName := filepath.Base(filePath) 708*333d2b36SAndroid Build Coastguard Worker _, exists := parentDir.files[baseName] 709*333d2b36SAndroid Build Coastguard Worker if !exists { 710*333d2b36SAndroid Build Coastguard Worker parentDir.modTime = m.Clock.Time() 711*333d2b36SAndroid Build Coastguard Worker parentDir.files[baseName] = m.newFile() 712*333d2b36SAndroid Build Coastguard Worker } else { 713*333d2b36SAndroid Build Coastguard Worker readErr := parentDir.files[baseName].readErr 714*333d2b36SAndroid Build Coastguard Worker if readErr != nil { 715*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 716*333d2b36SAndroid Build Coastguard Worker Op: "write", 717*333d2b36SAndroid Build Coastguard Worker Path: filePath, 718*333d2b36SAndroid Build Coastguard Worker Err: readErr, 719*333d2b36SAndroid Build Coastguard Worker } 720*333d2b36SAndroid Build Coastguard Worker } 721*333d2b36SAndroid Build Coastguard Worker } 722*333d2b36SAndroid Build Coastguard Worker file := parentDir.files[baseName] 723*333d2b36SAndroid Build Coastguard Worker file.bytes = data 724*333d2b36SAndroid Build Coastguard Worker file.modTime = m.Clock.Time() 725*333d2b36SAndroid Build Coastguard Worker return nil 726*333d2b36SAndroid Build Coastguard Worker} 727*333d2b36SAndroid Build Coastguard Worker 728*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) newFile() *mockFile { 729*333d2b36SAndroid Build Coastguard Worker newFile := &mockFile{} 730*333d2b36SAndroid Build Coastguard Worker newFile.inodeNumber = m.newInodeNumber() 731*333d2b36SAndroid Build Coastguard Worker newFile.modTime = m.Clock.Time() 732*333d2b36SAndroid Build Coastguard Worker newFile.permTime = newFile.modTime 733*333d2b36SAndroid Build Coastguard Worker return newFile 734*333d2b36SAndroid Build Coastguard Worker} 735*333d2b36SAndroid Build Coastguard Worker 736*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) newDir() *mockDir { 737*333d2b36SAndroid Build Coastguard Worker newDir := &mockDir{ 738*333d2b36SAndroid Build Coastguard Worker subdirs: make(map[string]*mockDir, 0), 739*333d2b36SAndroid Build Coastguard Worker files: make(map[string]*mockFile, 0), 740*333d2b36SAndroid Build Coastguard Worker symlinks: make(map[string]*mockLink, 0), 741*333d2b36SAndroid Build Coastguard Worker } 742*333d2b36SAndroid Build Coastguard Worker newDir.inodeNumber = m.newInodeNumber() 743*333d2b36SAndroid Build Coastguard Worker newDir.modTime = m.Clock.Time() 744*333d2b36SAndroid Build Coastguard Worker newDir.permTime = newDir.modTime 745*333d2b36SAndroid Build Coastguard Worker return newDir 746*333d2b36SAndroid Build Coastguard Worker} 747*333d2b36SAndroid Build Coastguard Worker 748*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) newLink(target string) *mockLink { 749*333d2b36SAndroid Build Coastguard Worker newLink := &mockLink{ 750*333d2b36SAndroid Build Coastguard Worker target: target, 751*333d2b36SAndroid Build Coastguard Worker } 752*333d2b36SAndroid Build Coastguard Worker newLink.inodeNumber = m.newInodeNumber() 753*333d2b36SAndroid Build Coastguard Worker newLink.modTime = m.Clock.Time() 754*333d2b36SAndroid Build Coastguard Worker newLink.permTime = newLink.modTime 755*333d2b36SAndroid Build Coastguard Worker 756*333d2b36SAndroid Build Coastguard Worker return newLink 757*333d2b36SAndroid Build Coastguard Worker} 758*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) MkDirs(path string) error { 759*333d2b36SAndroid Build Coastguard Worker _, err := m.getDir(path, true) 760*333d2b36SAndroid Build Coastguard Worker return err 761*333d2b36SAndroid Build Coastguard Worker} 762*333d2b36SAndroid Build Coastguard Worker 763*333d2b36SAndroid Build Coastguard Worker// getDir doesn't support symlinks 764*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) getDir(path string, createIfMissing bool) (dir *mockDir, err error) { 765*333d2b36SAndroid Build Coastguard Worker cleanedPath := filepath.Clean(path) 766*333d2b36SAndroid Build Coastguard Worker if cleanedPath == "/" { 767*333d2b36SAndroid Build Coastguard Worker return &m.root, nil 768*333d2b36SAndroid Build Coastguard Worker } 769*333d2b36SAndroid Build Coastguard Worker 770*333d2b36SAndroid Build Coastguard Worker parentPath, leaf := pathSplit(cleanedPath) 771*333d2b36SAndroid Build Coastguard Worker if len(parentPath) >= len(path) { 772*333d2b36SAndroid Build Coastguard Worker return &m.root, nil 773*333d2b36SAndroid Build Coastguard Worker } 774*333d2b36SAndroid Build Coastguard Worker parent, err := m.getDir(parentPath, createIfMissing) 775*333d2b36SAndroid Build Coastguard Worker if err != nil { 776*333d2b36SAndroid Build Coastguard Worker return nil, err 777*333d2b36SAndroid Build Coastguard Worker } 778*333d2b36SAndroid Build Coastguard Worker if parent.readErr != nil { 779*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 780*333d2b36SAndroid Build Coastguard Worker Op: "stat", 781*333d2b36SAndroid Build Coastguard Worker Path: path, 782*333d2b36SAndroid Build Coastguard Worker Err: parent.readErr, 783*333d2b36SAndroid Build Coastguard Worker } 784*333d2b36SAndroid Build Coastguard Worker } 785*333d2b36SAndroid Build Coastguard Worker childDir, dirExists := parent.subdirs[leaf] 786*333d2b36SAndroid Build Coastguard Worker if !dirExists { 787*333d2b36SAndroid Build Coastguard Worker if createIfMissing { 788*333d2b36SAndroid Build Coastguard Worker // confirm that a file with the same name doesn't already exist 789*333d2b36SAndroid Build Coastguard Worker _, fileExists := parent.files[leaf] 790*333d2b36SAndroid Build Coastguard Worker if fileExists { 791*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 792*333d2b36SAndroid Build Coastguard Worker Op: "mkdir", 793*333d2b36SAndroid Build Coastguard Worker Path: path, 794*333d2b36SAndroid Build Coastguard Worker Err: os.ErrExist, 795*333d2b36SAndroid Build Coastguard Worker } 796*333d2b36SAndroid Build Coastguard Worker } 797*333d2b36SAndroid Build Coastguard Worker // create this directory 798*333d2b36SAndroid Build Coastguard Worker childDir = m.newDir() 799*333d2b36SAndroid Build Coastguard Worker parent.subdirs[leaf] = childDir 800*333d2b36SAndroid Build Coastguard Worker parent.modTime = m.Clock.Time() 801*333d2b36SAndroid Build Coastguard Worker } else { 802*333d2b36SAndroid Build Coastguard Worker return nil, &os.PathError{ 803*333d2b36SAndroid Build Coastguard Worker Op: "stat", 804*333d2b36SAndroid Build Coastguard Worker Path: path, 805*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 806*333d2b36SAndroid Build Coastguard Worker } 807*333d2b36SAndroid Build Coastguard Worker } 808*333d2b36SAndroid Build Coastguard Worker } 809*333d2b36SAndroid Build Coastguard Worker return childDir, nil 810*333d2b36SAndroid Build Coastguard Worker 811*333d2b36SAndroid Build Coastguard Worker} 812*333d2b36SAndroid Build Coastguard Worker 813*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) Remove(path string) (err error) { 814*333d2b36SAndroid Build Coastguard Worker path, err = m.resolve(path, false) 815*333d2b36SAndroid Build Coastguard Worker parentPath, leaf := pathSplit(path) 816*333d2b36SAndroid Build Coastguard Worker if len(leaf) == 0 { 817*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("Cannot remove %v\n", path) 818*333d2b36SAndroid Build Coastguard Worker } 819*333d2b36SAndroid Build Coastguard Worker parentDir, err := m.getDir(parentPath, false) 820*333d2b36SAndroid Build Coastguard Worker if err != nil { 821*333d2b36SAndroid Build Coastguard Worker return err 822*333d2b36SAndroid Build Coastguard Worker } 823*333d2b36SAndroid Build Coastguard Worker if parentDir == nil { 824*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 825*333d2b36SAndroid Build Coastguard Worker Op: "remove", 826*333d2b36SAndroid Build Coastguard Worker Path: path, 827*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 828*333d2b36SAndroid Build Coastguard Worker } 829*333d2b36SAndroid Build Coastguard Worker } 830*333d2b36SAndroid Build Coastguard Worker if parentDir.readErr != nil { 831*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 832*333d2b36SAndroid Build Coastguard Worker Op: "remove", 833*333d2b36SAndroid Build Coastguard Worker Path: path, 834*333d2b36SAndroid Build Coastguard Worker Err: parentDir.readErr, 835*333d2b36SAndroid Build Coastguard Worker } 836*333d2b36SAndroid Build Coastguard Worker } 837*333d2b36SAndroid Build Coastguard Worker _, isDir := parentDir.subdirs[leaf] 838*333d2b36SAndroid Build Coastguard Worker if isDir { 839*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 840*333d2b36SAndroid Build Coastguard Worker Op: "remove", 841*333d2b36SAndroid Build Coastguard Worker Path: path, 842*333d2b36SAndroid Build Coastguard Worker Err: os.ErrInvalid, 843*333d2b36SAndroid Build Coastguard Worker } 844*333d2b36SAndroid Build Coastguard Worker } 845*333d2b36SAndroid Build Coastguard Worker _, isLink := parentDir.symlinks[leaf] 846*333d2b36SAndroid Build Coastguard Worker if isLink { 847*333d2b36SAndroid Build Coastguard Worker delete(parentDir.symlinks, leaf) 848*333d2b36SAndroid Build Coastguard Worker } else { 849*333d2b36SAndroid Build Coastguard Worker _, isFile := parentDir.files[leaf] 850*333d2b36SAndroid Build Coastguard Worker if !isFile { 851*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 852*333d2b36SAndroid Build Coastguard Worker Op: "remove", 853*333d2b36SAndroid Build Coastguard Worker Path: path, 854*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 855*333d2b36SAndroid Build Coastguard Worker } 856*333d2b36SAndroid Build Coastguard Worker } 857*333d2b36SAndroid Build Coastguard Worker delete(parentDir.files, leaf) 858*333d2b36SAndroid Build Coastguard Worker } 859*333d2b36SAndroid Build Coastguard Worker parentDir.modTime = m.Clock.Time() 860*333d2b36SAndroid Build Coastguard Worker return nil 861*333d2b36SAndroid Build Coastguard Worker} 862*333d2b36SAndroid Build Coastguard Worker 863*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) Symlink(oldPath string, newPath string) (err error) { 864*333d2b36SAndroid Build Coastguard Worker newPath, err = m.resolve(newPath, false) 865*333d2b36SAndroid Build Coastguard Worker if err != nil { 866*333d2b36SAndroid Build Coastguard Worker return err 867*333d2b36SAndroid Build Coastguard Worker } 868*333d2b36SAndroid Build Coastguard Worker 869*333d2b36SAndroid Build Coastguard Worker newParentPath, leaf := pathSplit(newPath) 870*333d2b36SAndroid Build Coastguard Worker newParentDir, err := m.getDir(newParentPath, false) 871*333d2b36SAndroid Build Coastguard Worker if newParentDir.readErr != nil { 872*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 873*333d2b36SAndroid Build Coastguard Worker Op: "link", 874*333d2b36SAndroid Build Coastguard Worker Path: newPath, 875*333d2b36SAndroid Build Coastguard Worker Err: newParentDir.readErr, 876*333d2b36SAndroid Build Coastguard Worker } 877*333d2b36SAndroid Build Coastguard Worker } 878*333d2b36SAndroid Build Coastguard Worker if err != nil { 879*333d2b36SAndroid Build Coastguard Worker return err 880*333d2b36SAndroid Build Coastguard Worker } 881*333d2b36SAndroid Build Coastguard Worker newParentDir.symlinks[leaf] = m.newLink(oldPath) 882*333d2b36SAndroid Build Coastguard Worker return nil 883*333d2b36SAndroid Build Coastguard Worker} 884*333d2b36SAndroid Build Coastguard Worker 885*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) RemoveAll(path string) (err error) { 886*333d2b36SAndroid Build Coastguard Worker path, err = m.resolve(path, false) 887*333d2b36SAndroid Build Coastguard Worker if err != nil { 888*333d2b36SAndroid Build Coastguard Worker return err 889*333d2b36SAndroid Build Coastguard Worker } 890*333d2b36SAndroid Build Coastguard Worker parentPath, leaf := pathSplit(path) 891*333d2b36SAndroid Build Coastguard Worker if len(leaf) == 0 { 892*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("Cannot remove %v\n", path) 893*333d2b36SAndroid Build Coastguard Worker } 894*333d2b36SAndroid Build Coastguard Worker parentDir, err := m.getDir(parentPath, false) 895*333d2b36SAndroid Build Coastguard Worker if err != nil { 896*333d2b36SAndroid Build Coastguard Worker return err 897*333d2b36SAndroid Build Coastguard Worker } 898*333d2b36SAndroid Build Coastguard Worker if parentDir == nil { 899*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 900*333d2b36SAndroid Build Coastguard Worker Op: "removeAll", 901*333d2b36SAndroid Build Coastguard Worker Path: path, 902*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 903*333d2b36SAndroid Build Coastguard Worker } 904*333d2b36SAndroid Build Coastguard Worker } 905*333d2b36SAndroid Build Coastguard Worker if parentDir.readErr != nil { 906*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 907*333d2b36SAndroid Build Coastguard Worker Op: "removeAll", 908*333d2b36SAndroid Build Coastguard Worker Path: path, 909*333d2b36SAndroid Build Coastguard Worker Err: parentDir.readErr, 910*333d2b36SAndroid Build Coastguard Worker } 911*333d2b36SAndroid Build Coastguard Worker 912*333d2b36SAndroid Build Coastguard Worker } 913*333d2b36SAndroid Build Coastguard Worker _, isFile := parentDir.files[leaf] 914*333d2b36SAndroid Build Coastguard Worker _, isLink := parentDir.symlinks[leaf] 915*333d2b36SAndroid Build Coastguard Worker if isFile || isLink { 916*333d2b36SAndroid Build Coastguard Worker return m.Remove(path) 917*333d2b36SAndroid Build Coastguard Worker } 918*333d2b36SAndroid Build Coastguard Worker _, isDir := parentDir.subdirs[leaf] 919*333d2b36SAndroid Build Coastguard Worker if !isDir { 920*333d2b36SAndroid Build Coastguard Worker if !isDir { 921*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 922*333d2b36SAndroid Build Coastguard Worker Op: "removeAll", 923*333d2b36SAndroid Build Coastguard Worker Path: path, 924*333d2b36SAndroid Build Coastguard Worker Err: os.ErrNotExist, 925*333d2b36SAndroid Build Coastguard Worker } 926*333d2b36SAndroid Build Coastguard Worker } 927*333d2b36SAndroid Build Coastguard Worker } 928*333d2b36SAndroid Build Coastguard Worker 929*333d2b36SAndroid Build Coastguard Worker delete(parentDir.subdirs, leaf) 930*333d2b36SAndroid Build Coastguard Worker parentDir.modTime = m.Clock.Time() 931*333d2b36SAndroid Build Coastguard Worker return nil 932*333d2b36SAndroid Build Coastguard Worker} 933*333d2b36SAndroid Build Coastguard Worker 934*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) SetReadable(path string, readable bool) error { 935*333d2b36SAndroid Build Coastguard Worker var readErr error 936*333d2b36SAndroid Build Coastguard Worker if !readable { 937*333d2b36SAndroid Build Coastguard Worker readErr = os.ErrPermission 938*333d2b36SAndroid Build Coastguard Worker } 939*333d2b36SAndroid Build Coastguard Worker return m.SetReadErr(path, readErr) 940*333d2b36SAndroid Build Coastguard Worker} 941*333d2b36SAndroid Build Coastguard Worker 942*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) SetReadErr(path string, readErr error) error { 943*333d2b36SAndroid Build Coastguard Worker path, err := m.resolve(path, false) 944*333d2b36SAndroid Build Coastguard Worker if err != nil { 945*333d2b36SAndroid Build Coastguard Worker return err 946*333d2b36SAndroid Build Coastguard Worker } 947*333d2b36SAndroid Build Coastguard Worker parentPath, leaf := filepath.Split(path) 948*333d2b36SAndroid Build Coastguard Worker parentDir, err := m.getDir(parentPath, false) 949*333d2b36SAndroid Build Coastguard Worker if err != nil { 950*333d2b36SAndroid Build Coastguard Worker return err 951*333d2b36SAndroid Build Coastguard Worker } 952*333d2b36SAndroid Build Coastguard Worker if parentDir.readErr != nil { 953*333d2b36SAndroid Build Coastguard Worker return &os.PathError{ 954*333d2b36SAndroid Build Coastguard Worker Op: "chmod", 955*333d2b36SAndroid Build Coastguard Worker Path: parentPath, 956*333d2b36SAndroid Build Coastguard Worker Err: parentDir.readErr, 957*333d2b36SAndroid Build Coastguard Worker } 958*333d2b36SAndroid Build Coastguard Worker } 959*333d2b36SAndroid Build Coastguard Worker 960*333d2b36SAndroid Build Coastguard Worker inode, err := m.getInode(parentDir, leaf) 961*333d2b36SAndroid Build Coastguard Worker if err != nil { 962*333d2b36SAndroid Build Coastguard Worker return err 963*333d2b36SAndroid Build Coastguard Worker } 964*333d2b36SAndroid Build Coastguard Worker inode.readErr = readErr 965*333d2b36SAndroid Build Coastguard Worker inode.permTime = m.Clock.Time() 966*333d2b36SAndroid Build Coastguard Worker return nil 967*333d2b36SAndroid Build Coastguard Worker} 968*333d2b36SAndroid Build Coastguard Worker 969*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) ClearMetrics() { 970*333d2b36SAndroid Build Coastguard Worker m.ReadDirCalls = []string{} 971*333d2b36SAndroid Build Coastguard Worker m.StatCalls = []string{} 972*333d2b36SAndroid Build Coastguard Worker} 973*333d2b36SAndroid Build Coastguard Worker 974*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) ViewId() (id string) { 975*333d2b36SAndroid Build Coastguard Worker return m.viewId 976*333d2b36SAndroid Build Coastguard Worker} 977*333d2b36SAndroid Build Coastguard Worker 978*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) SetViewId(id string) { 979*333d2b36SAndroid Build Coastguard Worker m.viewId = id 980*333d2b36SAndroid Build Coastguard Worker} 981*333d2b36SAndroid Build Coastguard Workerfunc (m *MockFs) SetDeviceNumber(deviceNumber uint64) { 982*333d2b36SAndroid Build Coastguard Worker m.deviceNumber = deviceNumber 983*333d2b36SAndroid Build Coastguard Worker} 984