volume_unix.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // +build linux freebsd darwin
  2. package volume
  3. import (
  4. "fmt"
  5. "path/filepath"
  6. "strings"
  7. derr "github.com/docker/docker/errors"
  8. )
  9. // read-write modes
  10. var rwModes = map[string]bool{
  11. "rw": true,
  12. "rw,Z": true,
  13. "rw,z": true,
  14. "z,rw": true,
  15. "Z,rw": true,
  16. "Z": true,
  17. "z": true,
  18. }
  19. // read-only modes
  20. var roModes = map[string]bool{
  21. "ro": true,
  22. "ro,Z": true,
  23. "ro,z": true,
  24. "z,ro": true,
  25. "Z,ro": true,
  26. }
  27. // BackwardsCompatible decides whether this mount point can be
  28. // used in old versions of Docker or not.
  29. // Only bind mounts and local volumes can be used in old versions of Docker.
  30. func (m *MountPoint) BackwardsCompatible() bool {
  31. return len(m.Source) > 0 || m.Driver == DefaultDriverName
  32. }
  33. // HasResource checks whether the given absolute path for a container is in
  34. // this mount point. If the relative path starts with `../` then the resource
  35. // is outside of this mount point, but we can't simply check for this prefix
  36. // because it misses `..` which is also outside of the mount, so check both.
  37. func (m *MountPoint) HasResource(absolutePath string) bool {
  38. relPath, err := filepath.Rel(m.Destination, absolutePath)
  39. return err == nil && relPath != ".." && !strings.HasPrefix(relPath, fmt.Sprintf("..%c", filepath.Separator))
  40. }
  41. // ParseMountSpec validates the configuration of mount information is valid.
  42. func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
  43. spec = filepath.ToSlash(spec)
  44. mp := &MountPoint{
  45. RW: true,
  46. }
  47. if strings.Count(spec, ":") > 2 {
  48. return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
  49. }
  50. arr := strings.SplitN(spec, ":", 3)
  51. if arr[0] == "" {
  52. return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
  53. }
  54. switch len(arr) {
  55. case 1:
  56. // Just a destination path in the container
  57. mp.Destination = filepath.Clean(arr[0])
  58. case 2:
  59. if isValid := ValidMountMode(arr[1]); isValid {
  60. // Destination + Mode is not a valid volume - volumes
  61. // cannot include a mode. eg /foo:rw
  62. return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
  63. }
  64. // Host Source Path or Name + Destination
  65. mp.Source = arr[0]
  66. mp.Destination = arr[1]
  67. case 3:
  68. // HostSourcePath+DestinationPath+Mode
  69. mp.Source = arr[0]
  70. mp.Destination = arr[1]
  71. mp.Mode = arr[2] // Mode field is used by SELinux to decide whether to apply label
  72. if !ValidMountMode(mp.Mode) {
  73. return nil, derr.ErrorCodeVolumeInvalidMode.WithArgs(mp.Mode)
  74. }
  75. mp.RW = ReadWrite(mp.Mode)
  76. default:
  77. return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
  78. }
  79. //validate the volumes destination path
  80. mp.Destination = filepath.Clean(mp.Destination)
  81. if !filepath.IsAbs(mp.Destination) {
  82. return nil, derr.ErrorCodeVolumeAbs.WithArgs(mp.Destination)
  83. }
  84. // Destination cannot be "/"
  85. if mp.Destination == "/" {
  86. return nil, derr.ErrorCodeVolumeSlash.WithArgs(spec)
  87. }
  88. name, source := ParseVolumeSource(mp.Source)
  89. if len(source) == 0 {
  90. mp.Source = "" // Clear it out as we previously assumed it was not a name
  91. mp.Driver = volumeDriver
  92. if len(mp.Driver) == 0 {
  93. mp.Driver = DefaultDriverName
  94. }
  95. } else {
  96. mp.Source = filepath.Clean(source)
  97. }
  98. mp.Name = name
  99. return mp, nil
  100. }
  101. // ParseVolumeSource parses the origin sources that's mounted into the container.
  102. // It returns a name and a source. It looks to see if the spec passed in
  103. // is an absolute file. If it is, it assumes the spec is a source. If not,
  104. // it assumes the spec is a name.
  105. func ParseVolumeSource(spec string) (string, string) {
  106. if !filepath.IsAbs(spec) {
  107. return spec, ""
  108. }
  109. return "", spec
  110. }
  111. // IsVolumeNameValid checks a volume name in a platform specific manner.
  112. func IsVolumeNameValid(name string) (bool, error) {
  113. return true, nil
  114. }