safepath.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. package safepath
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "github.com/containerd/log"
  7. )
  8. type SafePath struct {
  9. path string
  10. cleanup func(ctx context.Context) error
  11. mutex sync.Mutex
  12. // Immutable fields
  13. sourceBase, sourceSubpath string
  14. }
  15. // Close releases the resources used by the path.
  16. func (s *SafePath) Close(ctx context.Context) error {
  17. s.mutex.Lock()
  18. defer s.mutex.Unlock()
  19. if s.path == "" {
  20. base, sub := s.SourcePath()
  21. log.G(ctx).WithFields(log.Fields{
  22. "path": s.Path(),
  23. "sourceBase": base,
  24. "sourceSubpath": sub,
  25. }).Warn("an attempt to close an already closed SafePath")
  26. return nil
  27. }
  28. s.path = ""
  29. if s.cleanup != nil {
  30. return s.cleanup(ctx)
  31. }
  32. return nil
  33. }
  34. // IsValid return true when path can still be used and wasn't cleaned up by Close.
  35. func (s *SafePath) IsValid() bool {
  36. s.mutex.Lock()
  37. defer s.mutex.Unlock()
  38. return s.path != ""
  39. }
  40. // Path returns a safe, temporary path that can be used to access the original path.
  41. func (s *SafePath) Path() string {
  42. s.mutex.Lock()
  43. defer s.mutex.Unlock()
  44. if s.path == "" {
  45. panic(fmt.Sprintf("use-after-close attempted for safepath with source [%s, %s]", s.sourceBase, s.sourceSubpath))
  46. }
  47. return s.path
  48. }
  49. // SourcePath returns the source path the safepath points to.
  50. func (s *SafePath) SourcePath() (string, string) {
  51. // No mutex lock because these are immutable.
  52. return s.sourceBase, s.sourceSubpath
  53. }