tractor.dev/toolkit-go@v0.0.0-20241010005851-214d91207d07/engine/fs/unionfs/file.go (about) 1 package unionfs 2 3 import ( 4 "fmt" 5 "io" 6 "io/fs" 7 "os" 8 ) 9 10 // The UnionFile implements the afero.File interface and will be returned 11 // when reading a directory present at least in the overlay or opening a file 12 // for writing. 13 // 14 // The calls to 15 // Readdir() and Readdirnames() merge the file os.FileInfo / names from the 16 // base and the overlay - for files present in both layers, only those 17 // from the overlay will be used. 18 // 19 // When opening files for writing (Create() / OpenFile() with the right flags) 20 // the operations will be done in both layers, starting with the overlay. A 21 // successful read in the overlay will move the cursor position in the base layer 22 // by the number of bytes read. 23 type File struct { 24 Base fs.File 25 Layer fs.File 26 Merger DirsMerger 27 off int 28 files []fs.DirEntry 29 } 30 31 func (f *File) Close() error { 32 // first close base, so we have a newer timestamp in the overlay. If we'd close 33 // the overlay first, we'd get a cacheStale the next time we access this file 34 // -> cache would be useless ;-) 35 if f.Base != nil { 36 f.Base.Close() 37 } 38 if f.Layer != nil { 39 return f.Layer.Close() 40 } 41 return fs.ErrInvalid 42 } 43 44 func (f *File) Read(s []byte) (int, error) { 45 if f.Layer != nil { 46 n, err := f.Layer.Read(s) 47 if (err == nil || err == io.EOF) && f.Base != nil { 48 // advance the file position also in the base file, the next 49 // call may be a write at this position (or a seek with SEEK_CUR) 50 fseek, ok := f.Base.(io.Seeker) 51 if !ok { 52 return n, fmt.Errorf("unable to seek file") 53 } 54 if _, seekErr := fseek.Seek(int64(n), os.SEEK_CUR); seekErr != nil { 55 // only overwrite err in case the seek fails: we need to 56 // report an eventual io.EOF to the caller 57 err = seekErr 58 } 59 } 60 return n, err 61 } 62 if f.Base != nil { 63 return f.Base.Read(s) 64 } 65 return 0, fs.ErrInvalid 66 } 67 68 func (f *File) ReadAt(s []byte, o int64) (int, error) { 69 if f.Layer != nil { 70 freadat, ok := f.Layer.(io.ReaderAt) 71 if !ok { 72 return 0, fmt.Errorf("unable to readat file") 73 } 74 n, err := freadat.ReadAt(s, o) 75 if (err == nil || err == io.EOF) && f.Base != nil { 76 fseek, ok := f.Base.(io.Seeker) 77 if !ok { 78 return n, fmt.Errorf("unable to seek file") 79 } 80 _, err = fseek.Seek(o+int64(n), os.SEEK_SET) 81 } 82 return n, err 83 } 84 if f.Base != nil { 85 freadat, ok := f.Layer.(io.ReaderAt) 86 if !ok { 87 return 0, fmt.Errorf("unable to readat file") 88 } 89 return freadat.ReadAt(s, o) 90 } 91 return 0, fs.ErrInvalid 92 } 93 94 func (f *File) Seek(o int64, w int) (pos int64, err error) { 95 if f.Layer != nil { 96 fseek, ok := f.Layer.(io.Seeker) 97 if !ok { 98 return 0, fmt.Errorf("unable to seek file") 99 } 100 pos, err = fseek.Seek(o, w) 101 if (err == nil || err == io.EOF) && f.Base != nil { 102 fseek, ok := f.Base.(io.Seeker) 103 if !ok { 104 return 0, fmt.Errorf("unable to seek file") 105 } 106 _, err = fseek.Seek(o, w) 107 } 108 return pos, err 109 } 110 if f.Base != nil { 111 fseek, ok := f.Base.(io.Seeker) 112 if !ok { 113 return 0, fmt.Errorf("unable to seek file") 114 } 115 return fseek.Seek(o, w) 116 } 117 return 0, fs.ErrInvalid 118 } 119 120 func (f *File) Write(s []byte) (n int, err error) { 121 if f.Layer != nil { 122 fw, ok := f.Layer.(io.Writer) 123 if !ok { 124 return 0, fs.ErrPermission 125 } 126 n, err = fw.Write(s) 127 if err == nil && f.Base != nil { // hmm, do we have fixed size files where a write may hit the EOF mark? 128 fw, ok := f.Base.(io.Writer) 129 if !ok { 130 return 0, fs.ErrPermission 131 } 132 _, err = fw.Write(s) 133 } 134 return n, err 135 } 136 if f.Base != nil { 137 fw, ok := f.Base.(io.Writer) 138 if !ok { 139 return 0, fs.ErrPermission 140 } 141 return fw.Write(s) 142 } 143 return 0, fs.ErrInvalid 144 } 145 146 func (f *File) WriteAt(s []byte, o int64) (n int, err error) { 147 if f.Layer != nil { 148 fwriteat, ok := f.Layer.(io.WriterAt) 149 if !ok { 150 return 0, fmt.Errorf("unable to writeat file") 151 } 152 n, err = fwriteat.WriteAt(s, o) 153 if err == nil && f.Base != nil { 154 fwriteat, ok := f.Base.(io.WriterAt) 155 if !ok { 156 return 0, fmt.Errorf("unable to writeat file") 157 } 158 _, err = fwriteat.WriteAt(s, o) 159 } 160 return n, err 161 } 162 if f.Base != nil { 163 fwriteat, ok := f.Base.(io.WriterAt) 164 if !ok { 165 return 0, fmt.Errorf("unable to writeat file") 166 } 167 return fwriteat.WriteAt(s, o) 168 } 169 return 0, fs.ErrInvalid 170 } 171 172 // DirsMerger is how UnionFile weaves two directories together. 173 // It takes the FileInfo slices from the layer and the base and returns a 174 // single view. 175 type DirsMerger func(lofi, bofi []fs.DirEntry) ([]fs.DirEntry, error) 176 177 var defaultUnionMergeDirsFn = func(lofi, bofi []fs.DirEntry) ([]fs.DirEntry, error) { 178 var files = make(map[string]fs.DirEntry) 179 180 for _, fi := range lofi { 181 files[fi.Name()] = fi 182 } 183 184 for _, fi := range bofi { 185 if _, exists := files[fi.Name()]; !exists { 186 files[fi.Name()] = fi 187 } 188 } 189 190 rfi := make([]fs.DirEntry, len(files)) 191 192 i := 0 193 for _, fi := range files { 194 rfi[i] = fi 195 i++ 196 } 197 198 return rfi, nil 199 200 } 201 202 // Readdir will weave the two directories together and 203 // return a single view of the overlayed directories. 204 // At the end of the directory view, the error is io.EOF if c > 0. 205 func (f *File) ReadDir(c int) (ofi []fs.DirEntry, err error) { 206 var merge DirsMerger = f.Merger 207 if merge == nil { 208 merge = defaultUnionMergeDirsFn 209 } 210 211 if f.off == 0 { 212 var lfi []fs.DirEntry 213 if f.Layer != nil { 214 df, ok := f.Layer.(fs.ReadDirFile) 215 if !ok { 216 return nil, fmt.Errorf("unable to readdir file") 217 } 218 lfi, err = df.ReadDir(-1) 219 if err != nil { 220 return nil, err 221 } 222 } 223 224 var bfi []fs.DirEntry 225 if f.Base != nil { 226 df, ok := f.Base.(fs.ReadDirFile) 227 if !ok { 228 return nil, fmt.Errorf("unable to readdir file") 229 } 230 bfi, err = df.ReadDir(-1) 231 if err != nil { 232 return nil, err 233 } 234 235 } 236 merged, err := merge(lfi, bfi) 237 if err != nil { 238 return nil, err 239 } 240 f.files = append(f.files, merged...) 241 } 242 files := f.files[f.off:] 243 244 if c <= 0 { 245 return files, nil 246 } 247 248 if len(files) == 0 { 249 return nil, io.EOF 250 } 251 252 if c > len(files) { 253 c = len(files) 254 } 255 256 defer func() { f.off += c }() 257 return files[:c], nil 258 } 259 260 func (f *File) Stat() (fs.FileInfo, error) { 261 if f.Layer != nil { 262 return f.Layer.Stat() 263 } 264 if f.Base != nil { 265 return f.Base.Stat() 266 } 267 return nil, fs.ErrInvalid 268 } 269 270 func (f *File) Sync() (err error) { 271 if f.Layer != nil { 272 fsync, ok := f.Layer.(interface{ Sync() error }) 273 if !ok { 274 return fmt.Errorf("unable to sync file") 275 } 276 err = fsync.Sync() 277 if err == nil && f.Base != nil { 278 fsync, ok := f.Base.(interface{ Sync() error }) 279 if !ok { 280 return fmt.Errorf("unable to sync file") 281 } 282 err = fsync.Sync() 283 } 284 return err 285 } 286 if f.Base != nil { 287 fsync, ok := f.Base.(interface{ Sync() error }) 288 if !ok { 289 return fmt.Errorf("unable to sync file") 290 } 291 return fsync.Sync() 292 } 293 return fs.ErrInvalid 294 } 295 296 func (f *File) Truncate(s int64) (err error) { 297 if f.Layer != nil { 298 ft, ok := f.Layer.(interface{ Truncate(int64) error }) 299 if !ok { 300 return fmt.Errorf("unable to truncate file") 301 } 302 err = ft.Truncate(s) 303 if err == nil && f.Base != nil { 304 ft, ok := f.Base.(interface{ Truncate(int64) error }) 305 if !ok { 306 return fmt.Errorf("unable to truncate file") 307 } 308 err = ft.Truncate(s) 309 } 310 return err 311 } 312 if f.Base != nil { 313 ft, ok := f.Base.(interface{ Truncate(int64) error }) 314 if !ok { 315 return fmt.Errorf("unable to truncate file") 316 } 317 return ft.Truncate(s) 318 } 319 return fs.ErrInvalid 320 } 321 322 // func copyToLayer(base fs.FS, layer fs.FS, name string) error { 323 // bfh, err := base.Open(name) 324 // if err != nil { 325 // return err 326 // } 327 // defer bfh.Close() 328 329 // // First make sure the directory exists 330 // exists, err := vfs.Exists(layer, filepath.Dir(name)) 331 // if err != nil { 332 // return err 333 // } 334 // if !exists { 335 // err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME? 336 // if err != nil { 337 // return err 338 // } 339 // } 340 341 // // Create the file on the overlay 342 // lfh, err := layer.Create(name) 343 // if err != nil { 344 // return err 345 // } 346 // n, err := io.Copy(lfh, bfh) 347 // if err != nil { 348 // // If anything fails, clean up the file 349 // layer.Remove(name) 350 // lfh.Close() 351 // return err 352 // } 353 354 // bfi, err := bfh.Stat() 355 // if err != nil || bfi.Size() != n { 356 // layer.Remove(name) 357 // lfh.Close() 358 // return syscall.EIO 359 // } 360 361 // err = lfh.Close() 362 // if err != nil { 363 // layer.Remove(name) 364 // lfh.Close() 365 // return err 366 // } 367 // return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime()) 368 // }