You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

copyOnWriteFs.go 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. package afero
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "syscall"
  7. "time"
  8. )
  9. var _ Lstater = (*CopyOnWriteFs)(nil)
  10. // The CopyOnWriteFs is a union filesystem: a read only base file system with
  11. // a possibly writeable layer on top. Changes to the file system will only
  12. // be made in the overlay: Changing an existing file in the base layer which
  13. // is not present in the overlay will copy the file to the overlay ("changing"
  14. // includes also calls to e.g. Chtimes() and Chmod()).
  15. //
  16. // Reading directories is currently only supported via Open(), not OpenFile().
  17. type CopyOnWriteFs struct {
  18. base Fs
  19. layer Fs
  20. }
  21. func NewCopyOnWriteFs(base Fs, layer Fs) Fs {
  22. return &CopyOnWriteFs{base: base, layer: layer}
  23. }
  24. // Returns true if the file is not in the overlay
  25. func (u *CopyOnWriteFs) isBaseFile(name string) (bool, error) {
  26. if _, err := u.layer.Stat(name); err == nil {
  27. return false, nil
  28. }
  29. _, err := u.base.Stat(name)
  30. if err != nil {
  31. if oerr, ok := err.(*os.PathError); ok {
  32. if oerr.Err == os.ErrNotExist || oerr.Err == syscall.ENOENT || oerr.Err == syscall.ENOTDIR {
  33. return false, nil
  34. }
  35. }
  36. if err == syscall.ENOENT {
  37. return false, nil
  38. }
  39. }
  40. return true, err
  41. }
  42. func (u *CopyOnWriteFs) copyToLayer(name string) error {
  43. return copyToLayer(u.base, u.layer, name)
  44. }
  45. func (u *CopyOnWriteFs) Chtimes(name string, atime, mtime time.Time) error {
  46. b, err := u.isBaseFile(name)
  47. if err != nil {
  48. return err
  49. }
  50. if b {
  51. if err := u.copyToLayer(name); err != nil {
  52. return err
  53. }
  54. }
  55. return u.layer.Chtimes(name, atime, mtime)
  56. }
  57. func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error {
  58. b, err := u.isBaseFile(name)
  59. if err != nil {
  60. return err
  61. }
  62. if b {
  63. if err := u.copyToLayer(name); err != nil {
  64. return err
  65. }
  66. }
  67. return u.layer.Chmod(name, mode)
  68. }
  69. func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) {
  70. fi, err := u.layer.Stat(name)
  71. if err != nil {
  72. isNotExist := u.isNotExist(err)
  73. if isNotExist {
  74. return u.base.Stat(name)
  75. }
  76. return nil, err
  77. }
  78. return fi, nil
  79. }
  80. func (u *CopyOnWriteFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
  81. llayer, ok1 := u.layer.(Lstater)
  82. lbase, ok2 := u.base.(Lstater)
  83. if ok1 {
  84. fi, b, err := llayer.LstatIfPossible(name)
  85. if err == nil {
  86. return fi, b, nil
  87. }
  88. if !u.isNotExist(err) {
  89. return nil, b, err
  90. }
  91. }
  92. if ok2 {
  93. fi, b, err := lbase.LstatIfPossible(name)
  94. if err == nil {
  95. return fi, b, nil
  96. }
  97. if !u.isNotExist(err) {
  98. return nil, b, err
  99. }
  100. }
  101. fi, err := u.Stat(name)
  102. return fi, false, err
  103. }
  104. func (u *CopyOnWriteFs) isNotExist(err error) bool {
  105. if e, ok := err.(*os.PathError); ok {
  106. err = e.Err
  107. }
  108. if err == os.ErrNotExist || err == syscall.ENOENT || err == syscall.ENOTDIR {
  109. return true
  110. }
  111. return false
  112. }
  113. // Renaming files present only in the base layer is not permitted
  114. func (u *CopyOnWriteFs) Rename(oldname, newname string) error {
  115. b, err := u.isBaseFile(oldname)
  116. if err != nil {
  117. return err
  118. }
  119. if b {
  120. return syscall.EPERM
  121. }
  122. return u.layer.Rename(oldname, newname)
  123. }
  124. // Removing files present only in the base layer is not permitted. If
  125. // a file is present in the base layer and the overlay, only the overlay
  126. // will be removed.
  127. func (u *CopyOnWriteFs) Remove(name string) error {
  128. err := u.layer.Remove(name)
  129. switch err {
  130. case syscall.ENOENT:
  131. _, err = u.base.Stat(name)
  132. if err == nil {
  133. return syscall.EPERM
  134. }
  135. return syscall.ENOENT
  136. default:
  137. return err
  138. }
  139. }
  140. func (u *CopyOnWriteFs) RemoveAll(name string) error {
  141. err := u.layer.RemoveAll(name)
  142. switch err {
  143. case syscall.ENOENT:
  144. _, err = u.base.Stat(name)
  145. if err == nil {
  146. return syscall.EPERM
  147. }
  148. return syscall.ENOENT
  149. default:
  150. return err
  151. }
  152. }
  153. func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
  154. b, err := u.isBaseFile(name)
  155. if err != nil {
  156. return nil, err
  157. }
  158. if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
  159. if b {
  160. if err = u.copyToLayer(name); err != nil {
  161. return nil, err
  162. }
  163. return u.layer.OpenFile(name, flag, perm)
  164. }
  165. dir := filepath.Dir(name)
  166. isaDir, err := IsDir(u.base, dir)
  167. if err != nil && !os.IsNotExist(err) {
  168. return nil, err
  169. }
  170. if isaDir {
  171. if err = u.layer.MkdirAll(dir, 0777); err != nil {
  172. return nil, err
  173. }
  174. return u.layer.OpenFile(name, flag, perm)
  175. }
  176. isaDir, err = IsDir(u.layer, dir)
  177. if err != nil {
  178. return nil, err
  179. }
  180. if isaDir {
  181. return u.layer.OpenFile(name, flag, perm)
  182. }
  183. return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOTDIR} // ...or os.ErrNotExist?
  184. }
  185. if b {
  186. return u.base.OpenFile(name, flag, perm)
  187. }
  188. return u.layer.OpenFile(name, flag, perm)
  189. }
  190. // This function handles the 9 different possibilities caused
  191. // by the union which are the intersection of the following...
  192. // layer: doesn't exist, exists as a file, and exists as a directory
  193. // base: doesn't exist, exists as a file, and exists as a directory
  194. func (u *CopyOnWriteFs) Open(name string) (File, error) {
  195. // Since the overlay overrides the base we check that first
  196. b, err := u.isBaseFile(name)
  197. if err != nil {
  198. return nil, err
  199. }
  200. // If overlay doesn't exist, return the base (base state irrelevant)
  201. if b {
  202. return u.base.Open(name)
  203. }
  204. // If overlay is a file, return it (base state irrelevant)
  205. dir, err := IsDir(u.layer, name)
  206. if err != nil {
  207. return nil, err
  208. }
  209. if !dir {
  210. return u.layer.Open(name)
  211. }
  212. // Overlay is a directory, base state now matters.
  213. // Base state has 3 states to check but 2 outcomes:
  214. // A. It's a file or non-readable in the base (return just the overlay)
  215. // B. It's an accessible directory in the base (return a UnionFile)
  216. // If base is file or nonreadable, return overlay
  217. dir, err = IsDir(u.base, name)
  218. if !dir || err != nil {
  219. return u.layer.Open(name)
  220. }
  221. // Both base & layer are directories
  222. // Return union file (if opens are without error)
  223. bfile, bErr := u.base.Open(name)
  224. lfile, lErr := u.layer.Open(name)
  225. // If either have errors at this point something is very wrong. Return nil and the errors
  226. if bErr != nil || lErr != nil {
  227. return nil, fmt.Errorf("BaseErr: %v\nOverlayErr: %v", bErr, lErr)
  228. }
  229. return &UnionFile{Base: bfile, Layer: lfile}, nil
  230. }
  231. func (u *CopyOnWriteFs) Mkdir(name string, perm os.FileMode) error {
  232. dir, err := IsDir(u.base, name)
  233. if err != nil {
  234. return u.layer.MkdirAll(name, perm)
  235. }
  236. if dir {
  237. return ErrFileExists
  238. }
  239. return u.layer.MkdirAll(name, perm)
  240. }
  241. func (u *CopyOnWriteFs) Name() string {
  242. return "CopyOnWriteFs"
  243. }
  244. func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
  245. dir, err := IsDir(u.base, name)
  246. if err != nil {
  247. return u.layer.MkdirAll(name, perm)
  248. }
  249. if dir {
  250. // This is in line with how os.MkdirAll behaves.
  251. return nil
  252. }
  253. return u.layer.MkdirAll(name, perm)
  254. }
  255. func (u *CopyOnWriteFs) Create(name string) (File, error) {
  256. return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
  257. }