github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libfs/mount_interrupter.go (about) 1 // Copyright 2017 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package libfs 6 7 import ( 8 "errors" 9 "sync" 10 11 "github.com/keybase/client/go/logger" 12 ) 13 14 // Mounter is the interface for filesystems to be mounted by MountInterrupter. 15 type Mounter interface { 16 // Mount a filesystem. 17 Mount() error 18 // Unmount a mounted filesystem. 19 Unmount() error 20 } 21 22 // MountInterrupter is for managing mounts with cancelation. 23 type MountInterrupter struct { 24 // can be locked from external code too. 25 sync.Mutex 26 once sync.Once 27 done chan struct{} 28 fun func() error 29 log logger.Logger 30 } 31 32 // NewMountInterrupter creates a new MountInterrupter. 33 func NewMountInterrupter(log logger.Logger) *MountInterrupter { 34 return &MountInterrupter{done: make(chan struct{}), log: log} 35 } 36 37 // MountAndSetUnmount calls Mount and sets the unmount function 38 // to be called once if mount succeeds. 39 // If Done has already been called MountAndSetUnmount returns 40 // an error. 41 func (mi *MountInterrupter) MountAndSetUnmount(mounter Mounter) error { 42 mi.log.Debug("Starting to mount the filesystem") 43 mi.Lock() 44 defer mi.Unlock() 45 select { 46 case <-mi.done: 47 return errors.New("MountInterrupter already done") 48 default: 49 } 50 err := mounter.Mount() 51 if err != nil { 52 mi.log.Errorf("Mounting the filesystem failed: %v", err) 53 return err 54 } 55 mi.fun = mounter.Unmount 56 mi.log.Info("Mounting the filesystem was a success") 57 return nil 58 } 59 60 // Done signals Wait and runs the unmounter if set by MountAndSetUnmount. 61 // It can be called multiple times with no harm. Each call triggers a call to 62 // the unmounter. 63 func (mi *MountInterrupter) Done() error { 64 mi.Lock() 65 defer mi.Unlock() 66 if mi.fun != nil { 67 err := mi.fun() 68 if err != nil { 69 mi.log.Errorf("Mount interrupter callback failed: %v", err) 70 return err 71 } 72 } 73 mi.once.Do(func() { 74 close(mi.done) 75 }) 76 return nil 77 } 78 79 // Wait waits till Done is called. 80 func (mi *MountInterrupter) Wait() { 81 <-mi.done 82 }