Browse Source

Filesystem: Perform syscalls directly instead of executing userland
tools. Added sanity checks. Improved unit tests.

Andrea Luzzardi 12 years ago
parent
commit
e035f3e92b
2 changed files with 82 additions and 8 deletions
  1. 29 7
      filesystem.go
  2. 53 1
      filesystem_test.go

+ 29 - 7
filesystem.go

@@ -1,9 +1,10 @@
 package docker
 
 import (
+	"errors"
 	"fmt"
 	"os"
-	"os/exec"
+	"syscall"
 )
 
 type Filesystem struct {
@@ -23,6 +24,9 @@ func (fs *Filesystem) createMountPoints() error {
 }
 
 func (fs *Filesystem) Mount() error {
+	if fs.IsMounted() {
+		return errors.New("Mount: Filesystem already mounted")
+	}
 	if err := fs.createMountPoints(); err != nil {
 		return err
 	}
@@ -32,15 +36,33 @@ func (fs *Filesystem) Mount() error {
 		roBranches += fmt.Sprintf("%v=ro:", layer)
 	}
 	branches := fmt.Sprintf("br:%v:%v", rwBranch, roBranches)
-	cmd := exec.Command("mount", "-t", "aufs", "-o", branches, "none", fs.RootFS)
-	if err := cmd.Run(); err != nil {
-		return err
-	}
-	return nil
+	return syscall.Mount("none", fs.RootFS, "aufs", 0, branches)
 }
 
 func (fs *Filesystem) Umount() error {
-	return exec.Command("umount", fs.RootFS).Run()
+	if !fs.IsMounted() {
+		return errors.New("Umount: Filesystem not mounted")
+	}
+	return syscall.Unmount(fs.RootFS, 0)
+}
+
+func (fs *Filesystem) IsMounted() bool {
+	f, err := os.Open(fs.RootFS)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return false
+		}
+		panic(err)
+	}
+	list, err := f.Readdirnames(1)
+	f.Close()
+	if err != nil {
+		return false
+	}
+	if len(list) > 0 {
+		return true
+	}
+	return false
 }
 
 func newFilesystem(rootfs string, rwpath string, layers []string) *Filesystem {

+ 53 - 1
filesystem_test.go

@@ -1,7 +1,10 @@
 package docker
 
 import (
+	"bytes"
 	"io/ioutil"
+	"os"
+	"path"
 	"testing"
 )
 
@@ -15,7 +18,7 @@ func TestFilesystem(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	filesystem := newFilesystem(rootfs, rwpath, []string{"/var/lib/docker/images/ubuntu", "/var/lib/docker/images/test"})
+	filesystem := newFilesystem(rootfs, rwpath, []string{"/var/lib/docker/images/ubuntu"})
 
 	if err := filesystem.Umount(); err == nil {
 		t.Errorf("Umount succeeded even though the filesystem was not mounted")
@@ -25,6 +28,10 @@ func TestFilesystem(t *testing.T) {
 		t.Fatal(err)
 	}
 
+	if err := filesystem.Mount(); err == nil {
+		t.Errorf("Double mount succeeded")
+	}
+
 	if err := filesystem.Umount(); err != nil {
 		t.Fatal(err)
 	}
@@ -33,3 +40,48 @@ func TestFilesystem(t *testing.T) {
 		t.Errorf("Umount succeeded even though the filesystem was already umounted")
 	}
 }
+
+func TestFilesystemMultiLayer(t *testing.T) {
+	// Create a fake layer
+	fakeLayer, err := ioutil.TempDir("", "docker-layer")
+	if err != nil {
+		t.Fatal(err)
+	}
+	data := []byte("hello world")
+	if err := ioutil.WriteFile(path.Join(fakeLayer, "test_file"), data, 0700); err != nil {
+		t.Fatal(err)
+	}
+
+	// Create the layered filesystem and add our fake layer on top
+	rootfs, err := ioutil.TempDir("", "docker-test-root")
+	if err != nil {
+		t.Fatal(err)
+	}
+	rwpath, err := ioutil.TempDir("", "docker-test-rw")
+	if err != nil {
+		t.Fatal(err)
+	}
+	filesystem := newFilesystem(rootfs, rwpath, []string{"/var/lib/docker/images/ubuntu", fakeLayer})
+
+	// Mount it
+	if err := filesystem.Mount(); err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if err := filesystem.Umount(); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	// Check to see whether we can access our fake layer
+	if _, err := os.Stat(path.Join(rootfs, "test_file")); err != nil {
+		t.Fatal(err)
+	}
+	fsdata, err := ioutil.ReadFile(path.Join(rootfs, "test_file"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Equal(data, fsdata) {
+		t.Error(string(fsdata))
+	}
+}