filesystem.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. "errors"
  9. "io"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. "time"
  14. )
  15. // The Filesystem interface abstracts access to the file system.
  16. type Filesystem interface {
  17. Chmod(name string, mode FileMode) error
  18. Chtimes(name string, atime time.Time, mtime time.Time) error
  19. Create(name string) (File, error)
  20. CreateSymlink(name, target string) error
  21. DirNames(name string) ([]string, error)
  22. Lstat(name string) (FileInfo, error)
  23. Mkdir(name string, perm FileMode) error
  24. MkdirAll(name string, perm FileMode) error
  25. Open(name string) (File, error)
  26. OpenFile(name string, flags int, mode FileMode) (File, error)
  27. ReadSymlink(name string) (string, error)
  28. Remove(name string) error
  29. RemoveAll(name string) error
  30. Rename(oldname, newname string) error
  31. Stat(name string) (FileInfo, error)
  32. SymlinksSupported() bool
  33. Walk(root string, walkFn WalkFunc) error
  34. Hide(name string) error
  35. Unhide(name string) error
  36. Glob(pattern string) ([]string, error)
  37. Roots() ([]string, error)
  38. Usage(name string) (Usage, error)
  39. Type() FilesystemType
  40. URI() string
  41. }
  42. // The File interface abstracts access to a regular file, being a somewhat
  43. // smaller interface than os.File
  44. type File interface {
  45. io.Closer
  46. io.Reader
  47. io.ReaderAt
  48. io.Seeker
  49. io.Writer
  50. io.WriterAt
  51. Name() string
  52. Truncate(size int64) error
  53. Stat() (FileInfo, error)
  54. Sync() error
  55. }
  56. // The FileInfo interface is almost the same as os.FileInfo, but with the
  57. // Sys method removed (as we don't want to expose whatever is underlying)
  58. // and with a couple of convenience methods added.
  59. type FileInfo interface {
  60. // Standard things present in os.FileInfo
  61. Name() string
  62. Mode() FileMode
  63. Size() int64
  64. ModTime() time.Time
  65. IsDir() bool
  66. // Extensions
  67. IsRegular() bool
  68. IsSymlink() bool
  69. }
  70. // FileMode is similar to os.FileMode
  71. type FileMode uint32
  72. // Usage represents filesystem space usage
  73. type Usage struct {
  74. Free int64
  75. Total int64
  76. }
  77. // Equivalents from os package.
  78. const ModePerm = FileMode(os.ModePerm)
  79. const ModeSetgid = FileMode(os.ModeSetgid)
  80. const ModeSetuid = FileMode(os.ModeSetuid)
  81. const ModeSticky = FileMode(os.ModeSticky)
  82. const PathSeparator = os.PathSeparator
  83. const OptAppend = os.O_APPEND
  84. const OptCreate = os.O_CREATE
  85. const OptExclusive = os.O_EXCL
  86. const OptReadOnly = os.O_RDONLY
  87. const OptReadWrite = os.O_RDWR
  88. const OptSync = os.O_SYNC
  89. const OptTruncate = os.O_TRUNC
  90. const OptWriteOnly = os.O_WRONLY
  91. // SkipDir is used as a return value from WalkFuncs to indicate that
  92. // the directory named in the call is to be skipped. It is not returned
  93. // as an error by any function.
  94. var SkipDir = filepath.SkipDir
  95. // IsExist is the equivalent of os.IsExist
  96. var IsExist = os.IsExist
  97. // IsNotExist is the equivalent of os.IsNotExist
  98. var IsNotExist = os.IsNotExist
  99. // IsPermission is the equivalent of os.IsPermission
  100. var IsPermission = os.IsPermission
  101. // IsPathSeparator is the equivalent of os.IsPathSeparator
  102. var IsPathSeparator = os.IsPathSeparator
  103. func NewFilesystem(fsType FilesystemType, uri string) Filesystem {
  104. var fs Filesystem
  105. switch fsType {
  106. case FilesystemTypeBasic:
  107. fs = NewWalkFilesystem(newBasicFilesystem(uri))
  108. default:
  109. l.Debugln("Unknown filesystem", fsType, uri)
  110. fs = &errorFilesystem{
  111. fsType: fsType,
  112. uri: uri,
  113. err: errors.New("filesystem with type " + fsType.String() + " does not exist."),
  114. }
  115. }
  116. if l.ShouldDebug("filesystem") {
  117. fs = &logFilesystem{fs}
  118. }
  119. return fs
  120. }
  121. // IsInternal returns true if the file, as a path relative to the folder
  122. // root, represents an internal file that should always be ignored. The file
  123. // path must be clean (i.e., in canonical shortest form).
  124. func IsInternal(file string) bool {
  125. internals := []string{".stfolder", ".stignore", ".stversions"}
  126. pathSep := string(PathSeparator)
  127. for _, internal := range internals {
  128. if file == internal {
  129. return true
  130. }
  131. if strings.HasPrefix(file, internal+pathSep) {
  132. return true
  133. }
  134. }
  135. return false
  136. }