Преглед изворни кода

Ensure that ownership and perms are copied to volume

This only works if the file or dir is already created in
the image before setting it to be a volume.  There is no way around this
because we don't have the data avaliable to set the volume at the
beginning of the dockerfile
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
Michael Crosby пре 11 година
родитељ
комит
f41ced96af
1 измењених фајлова са 54 додато и 48 уклоњено
  1. 54 48
      daemon/volumes.go

+ 54 - 48
daemon/volumes.go

@@ -97,13 +97,16 @@ func applyVolumesFrom(container *Container) error {
 				if _, exists := container.Volumes[volPath]; exists {
 					continue
 				}
+
 				stat, err := os.Stat(c.getResourcePath(volPath))
 				if err != nil {
 					return err
 				}
+
 				if err := createIfNotExists(container.getResourcePath(volPath), stat.IsDir()); err != nil {
 					return err
 				}
+
 				container.Volumes[volPath] = id
 				if isRW, exists := c.VolumesRW[volPath]; exists {
 					container.VolumesRW[volPath] = isRW && mountRW
@@ -180,38 +183,39 @@ func createVolumes(container *Container) error {
 	return nil
 }
 
-func createIfNotExists(path string, isDir bool) error {
-	if _, err := os.Stat(path); err != nil {
-		if os.IsNotExist(err) {
-			if isDir {
-				if err := os.MkdirAll(path, 0755); err != nil {
-					return err
-				}
-			} else {
-				if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
-					return err
-				}
-				f, err := os.OpenFile(path, os.O_CREATE, 0755)
-				if err != nil {
-					return err
-				}
-				defer f.Close()
+func createIfNotExists(destination string, isDir bool) error {
+	if _, err := os.Stat(destination); err != nil && os.IsNotExist(err) {
+		if isDir {
+			if err := os.MkdirAll(destination, 0755); err != nil {
+				return err
+			}
+		} else {
+			if err := os.MkdirAll(filepath.Dir(destination), 0755); err != nil {
+				return err
+			}
+
+			f, err := os.OpenFile(destination, os.O_CREATE, 0755)
+			if err != nil {
+				return err
 			}
+			f.Close()
 		}
 	}
+
 	return nil
 }
 
 func initializeVolume(container *Container, volPath string, binds map[string]BindMap) error {
 	volumesDriver := container.daemon.volumes.Driver()
 	volPath = filepath.Clean(volPath)
+
 	// Skip existing volumes
 	if _, exists := container.Volumes[volPath]; exists {
 		return nil
 	}
 
 	var (
-		srcPath     string
+		destination string
 		isBindMount bool
 		volIsDir    = true
 
@@ -221,19 +225,21 @@ func initializeVolume(container *Container, volPath string, binds map[string]Bin
 	// If an external bind is defined for this volume, use that as a source
 	if bindMap, exists := binds[volPath]; exists {
 		isBindMount = true
-		srcPath = bindMap.SrcPath
-		if !filepath.IsAbs(srcPath) {
-			return fmt.Errorf("%s must be an absolute path", srcPath)
+		destination = bindMap.SrcPath
+
+		if !filepath.IsAbs(destination) {
+			return fmt.Errorf("%s must be an absolute path", destination)
 		}
+
 		if strings.ToLower(bindMap.Mode) == "rw" {
 			srcRW = true
 		}
+
 		if stat, err := os.Stat(bindMap.SrcPath); err != nil {
 			return err
 		} else {
 			volIsDir = stat.IsDir()
 		}
-		// Otherwise create an directory in $ROOT/volumes/ and use that
 	} else {
 		// Do not pass a container as the parameter for the volume creation.
 		// The graph driver using the container's information ( Image ) to
@@ -242,26 +248,28 @@ func initializeVolume(container *Container, volPath string, binds map[string]Bin
 		if err != nil {
 			return err
 		}
-		srcPath, err = volumesDriver.Get(c.ID, "")
+
+		destination, err = volumesDriver.Get(c.ID, "")
 		if err != nil {
 			return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
 		}
-		srcRW = true // RW by default
+
+		srcRW = true
 	}
 
-	if p, err := filepath.EvalSymlinks(srcPath); err != nil {
+	if p, err := filepath.EvalSymlinks(destination); err != nil {
 		return err
 	} else {
-		srcPath = p
+		destination = p
 	}
 
 	// Create the mountpoint
-	rootVolPath, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, volPath), container.basefs)
+	source, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, volPath), container.basefs)
 	if err != nil {
 		return err
 	}
 
-	newVolPath, err := filepath.Rel(container.basefs, rootVolPath)
+	newVolPath, err := filepath.Rel(container.basefs, source)
 	if err != nil {
 		return err
 	}
@@ -272,59 +280,57 @@ func initializeVolume(container *Container, volPath string, binds map[string]Bin
 		delete(container.VolumesRW, volPath)
 	}
 
-	container.Volumes[newVolPath] = srcPath
+	container.Volumes[newVolPath] = destination
 	container.VolumesRW[newVolPath] = srcRW
 
-	if err := createIfNotExists(rootVolPath, volIsDir); err != nil {
+	if err := createIfNotExists(source, volIsDir); err != nil {
 		return err
 	}
 
 	// Do not copy or change permissions if we are mounting from the host
 	if srcRW && !isBindMount {
-		if err := copyExistingContents(rootVolPath, srcPath); err != nil {
+		if err := copyExistingContents(source, destination); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
-func copyExistingContents(rootVolPath, srcPath string) error {
-	volList, err := ioutil.ReadDir(rootVolPath)
+func copyExistingContents(source, destination string) error {
+	volList, err := ioutil.ReadDir(source)
 	if err != nil {
 		return err
 	}
 
 	if len(volList) > 0 {
-		srcList, err := ioutil.ReadDir(srcPath)
+		srcList, err := ioutil.ReadDir(destination)
 		if err != nil {
 			return err
 		}
 
 		if len(srcList) == 0 {
 			// If the source volume is empty copy files from the root into the volume
-			if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
+			if err := archive.CopyWithTar(source, destination); err != nil {
 				return err
 			}
 		}
 	}
 
-	var (
-		stat    syscall.Stat_t
-		srcStat syscall.Stat_t
-	)
+	return copyOwnership(source, destination)
+}
+
+// copyOwnership copies the permissions and uid:gid of the source file
+// into the destination file
+func copyOwnership(source, destination string) error {
+	var stat syscall.Stat_t
 
-	if err := syscall.Stat(rootVolPath, &stat); err != nil {
+	if err := syscall.Stat(source, &stat); err != nil {
 		return err
 	}
-	if err := syscall.Stat(srcPath, &srcStat); err != nil {
+
+	if err := os.Chown(destination, int(stat.Uid), int(stat.Gid)); err != nil {
 		return err
 	}
-	// Change the source volume's ownership if it differs from the root
-	// files that were just copied
-	if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
-		if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
-			return err
-		}
-	}
-	return nil
+
+	return os.Chmod(destination, os.FileMode(stat.Mode))
 }