Fix volumes on the host by following symlinks in a scope

This commit is contained in:
Michael Crosby 2013-12-11 16:31:02 -08:00
parent bd292759f0
commit f396c42cad
6 changed files with 148 additions and 15 deletions

View File

@ -774,14 +774,14 @@ func (container *Container) getBindMap() (map[string]BindMap, error) {
}
binds[path.Clean(dst)] = bindMap
}
return binds, nil
return binds, nil
}
func (container *Container) createVolumes() error {
binds, err := container.getBindMap()
if err != nil {
return err
}
binds, err := container.getBindMap()
if err != nil {
return err
}
volumesDriver := container.runtime.volumes.driver
// Create the requested volumes if they don't exist
for volPath := range container.Config.Volumes {
@ -824,26 +824,25 @@ func (container *Container) createVolumes() error {
}
container.Volumes[volPath] = srcPath
container.VolumesRW[volPath] = srcRW
// Create the mountpoint
rootVolPath := path.Join(container.RootfsPath(), volPath)
if volIsDir {
if err := os.MkdirAll(rootVolPath, 0755); err != nil {
return err
}
volPath = path.Join(container.RootfsPath(), volPath)
rootVolPath, err := utils.FollowSymlink(volPath, container.RootfsPath())
if err != nil {
panic(err)
}
volPath = path.Join(container.RootfsPath(), volPath)
if _, err := os.Stat(volPath); err != nil {
if _, err := os.Stat(rootVolPath); err != nil {
if os.IsNotExist(err) {
if volIsDir {
if err := os.MkdirAll(volPath, 0755); err != nil {
if err := os.MkdirAll(rootVolPath, 0755); err != nil {
return err
}
} else {
if err := os.MkdirAll(path.Dir(volPath), 0755); err != nil {
if err := os.MkdirAll(path.Dir(rootVolPath), 0755); err != nil {
return err
}
if f, err := os.OpenFile(volPath, os.O_CREATE, 0755); err != nil {
if f, err := os.OpenFile(rootVolPath, os.O_CREATE, 0755); err != nil {
return err
} else {
f.Close()

View File

@ -3,6 +3,7 @@ package utils
import (
"os"
"path/filepath"
"strings"
"syscall"
)
@ -33,3 +34,49 @@ func TreeSize(dir string) (size int64, err error) {
})
return
}
// FollowSymlink will follow an existing link and scope it to the root
// path provided.
func FollowSymlinkInScope(link, root string) (string, error) {
prev := "."
root, err := filepath.Abs(root)
if err != nil {
return "", err
}
root = filepath.Clean(root)
link, err := filepath.Abs(link)
if err != nil {
return "", err
}
link = filepath.Clean(link)
for _, p := range strings.Split(link, "/") {
prev = filepath.Join(prev, p)
prev = filepath.Clean(prev)
stat, err := os.Lstat(prev)
if err != nil {
if os.IsNotExist(err) {
continue
}
return "", err
}
if stat.Mode()&os.ModeSymlink == os.ModeSymlink {
dest, err := os.Readlink(prev)
if err != nil {
return "", err
}
switch dest[0] {
case '/':
prev = filepath.Join(root, dest)
case '.':
if prev = filepath.Clean(filepath.Join(filepath.Dir(prev), dest)); len(prev) < len(root) {
prev = filepath.Join(root, filepath.Base(dest))
}
}
}
}
return prev, nil
}

84
utils/fs_test.go Normal file
View File

@ -0,0 +1,84 @@
package utils
import (
"os"
"path/filepath"
"testing"
)
func abs(p string) string {
o, err := filepath.Abs(p)
if err != nil {
panic(err)
}
return o
}
func TestFollowSymLinkNormal(t *testing.T) {
link := "testdata/fs/a/d/c/data"
rewrite, err := FollowSymlink(link, "test")
if err != nil {
t.Fatal(err)
}
if expected := abs("test/b/c/data"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
}
func TestFollowSymLinkRandomString(t *testing.T) {
rewrite, err := FollowSymlink("toto", "test")
if err != nil {
t.Fatal(err)
}
if rewrite != "toto" {
t.Fatalf("Expected toto got %s", rewrite)
}
}
func TestFollowSymLinkLastLink(t *testing.T) {
link := "testdata/fs/a/d"
rewrite, err := FollowSymlink(link, "test")
if err != nil {
t.Fatal(err)
}
if expected := abs("test/b"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
}
func TestFollowSymLinkRelativeLink(t *testing.T) {
link := "testdata/fs/a/e/c/data"
rewrite, err := FollowSymlink(link, "test")
if err != nil {
t.Fatal(err)
}
if expected := abs("testdata/fs/a/e/c/data"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
}
func TestFollowSymLinkRelativeLinkScope(t *testing.T) {
link := "testdata/fs/a/f"
pwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
root := filepath.Join(pwd, "testdata")
rewrite, err := FollowSymlink(link, root)
if err != nil {
t.Fatal(err)
}
if expected := abs("testdata/test"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
}

1
utils/testdata/fs/a/d vendored Symbolic link
View File

@ -0,0 +1 @@
/b

1
utils/testdata/fs/a/e vendored Symbolic link
View File

@ -0,0 +1 @@
../b

1
utils/testdata/fs/a/f vendored Symbolic link
View File

@ -0,0 +1 @@
../../../../test