filesystem.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package fs
  7. import (
  8. "context"
  9. "errors"
  10. "io"
  11. "os"
  12. "path/filepath"
  13. "strings"
  14. "time"
  15. )
  16. // The Filesystem interface abstracts access to the file system.
  17. type Filesystem interface {
  18. Chmod(name string, mode FileMode) error
  19. Chtimes(name string, atime time.Time, mtime time.Time) error
  20. Create(name string) (File, error)
  21. CreateSymlink(name, target string) error
  22. DirNames(name string) ([]string, error)
  23. Lstat(name string) (FileInfo, error)
  24. Mkdir(name string, perm FileMode) error
  25. MkdirAll(name string, perm FileMode) error
  26. Open(name string) (File, error)
  27. OpenFile(name string, flags int, mode FileMode) (File, error)
  28. ReadSymlink(name string) (string, error)
  29. Remove(name string) error
  30. RemoveAll(name string) error
  31. Rename(oldname, newname string) error
  32. Stat(name string) (FileInfo, error)
  33. SymlinksSupported() bool
  34. Walk(name string, walkFn WalkFunc) error
  35. Watch(path string, ignore Matcher, ctx context.Context, ignorePerms bool) (<-chan Event, error)
  36. Hide(name string) error
  37. Unhide(name string) error
  38. Glob(pattern string) ([]string, error)
  39. Roots() ([]string, error)
  40. Usage(name string) (Usage, error)
  41. Type() FilesystemType
  42. URI() string
  43. }
  44. // The File interface abstracts access to a regular file, being a somewhat
  45. // smaller interface than os.File
  46. type File interface {
  47. io.Closer
  48. io.Reader
  49. io.ReaderAt
  50. io.Seeker
  51. io.Writer
  52. io.WriterAt
  53. Name() string
  54. Truncate(size int64) error
  55. Stat() (FileInfo, error)
  56. Sync() error
  57. }
  58. // The FileInfo interface is almost the same as os.FileInfo, but with the
  59. // Sys method removed (as we don't want to expose whatever is underlying)
  60. // and with a couple of convenience methods added.
  61. type FileInfo interface {
  62. // Standard things present in os.FileInfo
  63. Name() string
  64. Mode() FileMode
  65. Size() int64
  66. ModTime() time.Time
  67. IsDir() bool
  68. // Extensions
  69. IsRegular() bool
  70. IsSymlink() bool
  71. }
  72. // FileMode is similar to os.FileMode
  73. type FileMode uint32
  74. // Usage represents filesystem space usage
  75. type Usage struct {
  76. Free int64
  77. Total int64
  78. }
  79. type Matcher interface {
  80. ShouldIgnore(name string) bool
  81. }
  82. type MatchResult interface {
  83. IsIgnored() bool
  84. }
  85. type Event struct {
  86. Name string
  87. Type EventType
  88. }
  89. type EventType int
  90. const (
  91. NonRemove EventType = 1 + iota
  92. Remove
  93. Mixed // Should probably not be necessary to be used in filesystem interface implementation
  94. )
  95. func (evType EventType) String() string {
  96. switch {
  97. case evType == NonRemove:
  98. return "non-remove"
  99. case evType == Remove:
  100. return "remove"
  101. case evType == Mixed:
  102. return "mixed"
  103. default:
  104. panic("bug: Unknown event type")
  105. }
  106. }
  107. var ErrWatchNotSupported = errors.New("watching is not supported")
  108. // Equivalents from os package.
  109. const ModePerm = FileMode(os.ModePerm)
  110. const ModeSetgid = FileMode(os.ModeSetgid)
  111. const ModeSetuid = FileMode(os.ModeSetuid)
  112. const ModeSticky = FileMode(os.ModeSticky)
  113. const PathSeparator = os.PathSeparator
  114. const OptAppend = os.O_APPEND
  115. const OptCreate = os.O_CREATE
  116. const OptExclusive = os.O_EXCL
  117. const OptReadOnly = os.O_RDONLY
  118. const OptReadWrite = os.O_RDWR
  119. const OptSync = os.O_SYNC
  120. const OptTruncate = os.O_TRUNC
  121. const OptWriteOnly = os.O_WRONLY
  122. // SkipDir is used as a return value from WalkFuncs to indicate that
  123. // the directory named in the call is to be skipped. It is not returned
  124. // as an error by any function.
  125. var SkipDir = filepath.SkipDir
  126. // IsExist is the equivalent of os.IsExist
  127. var IsExist = os.IsExist
  128. // IsNotExist is the equivalent of os.IsNotExist
  129. var IsNotExist = os.IsNotExist
  130. // IsPermission is the equivalent of os.IsPermission
  131. var IsPermission = os.IsPermission
  132. // IsPathSeparator is the equivalent of os.IsPathSeparator
  133. var IsPathSeparator = os.IsPathSeparator
  134. func NewFilesystem(fsType FilesystemType, uri string) Filesystem {
  135. var fs Filesystem
  136. switch fsType {
  137. case FilesystemTypeBasic:
  138. fs = NewWalkFilesystem(newBasicFilesystem(uri))
  139. default:
  140. l.Debugln("Unknown filesystem", fsType, uri)
  141. fs = &errorFilesystem{
  142. fsType: fsType,
  143. uri: uri,
  144. err: errors.New("filesystem with type " + fsType.String() + " does not exist."),
  145. }
  146. }
  147. if l.ShouldDebug("filesystem") {
  148. fs = &logFilesystem{fs}
  149. }
  150. return fs
  151. }
  152. // IsInternal returns true if the file, as a path relative to the folder
  153. // root, represents an internal file that should always be ignored. The file
  154. // path must be clean (i.e., in canonical shortest form).
  155. func IsInternal(file string) bool {
  156. internals := []string{".stfolder", ".stignore", ".stversions"}
  157. pathSep := string(PathSeparator)
  158. for _, internal := range internals {
  159. if file == internal {
  160. return true
  161. }
  162. if strings.HasPrefix(file, internal+pathSep) {
  163. return true
  164. }
  165. }
  166. return false
  167. }