Jelajahi Sumber

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 tahun lalu
induk
melakukan
f41ced96af
1 mengubah file dengan 54 tambahan dan 48 penghapusan
  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 {
 				if _, exists := container.Volumes[volPath]; exists {
 					continue
 					continue
 				}
 				}
+
 				stat, err := os.Stat(c.getResourcePath(volPath))
 				stat, err := os.Stat(c.getResourcePath(volPath))
 				if err != nil {
 				if err != nil {
 					return err
 					return err
 				}
 				}
+
 				if err := createIfNotExists(container.getResourcePath(volPath), stat.IsDir()); err != nil {
 				if err := createIfNotExists(container.getResourcePath(volPath), stat.IsDir()); err != nil {
 					return err
 					return err
 				}
 				}
+
 				container.Volumes[volPath] = id
 				container.Volumes[volPath] = id
 				if isRW, exists := c.VolumesRW[volPath]; exists {
 				if isRW, exists := c.VolumesRW[volPath]; exists {
 					container.VolumesRW[volPath] = isRW && mountRW
 					container.VolumesRW[volPath] = isRW && mountRW
@@ -180,38 +183,39 @@ func createVolumes(container *Container) error {
 	return nil
 	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
 	return nil
 }
 }
 
 
 func initializeVolume(container *Container, volPath string, binds map[string]BindMap) error {
 func initializeVolume(container *Container, volPath string, binds map[string]BindMap) error {
 	volumesDriver := container.daemon.volumes.Driver()
 	volumesDriver := container.daemon.volumes.Driver()
 	volPath = filepath.Clean(volPath)
 	volPath = filepath.Clean(volPath)
+
 	// Skip existing volumes
 	// Skip existing volumes
 	if _, exists := container.Volumes[volPath]; exists {
 	if _, exists := container.Volumes[volPath]; exists {
 		return nil
 		return nil
 	}
 	}
 
 
 	var (
 	var (
-		srcPath     string
+		destination string
 		isBindMount bool
 		isBindMount bool
 		volIsDir    = true
 		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 an external bind is defined for this volume, use that as a source
 	if bindMap, exists := binds[volPath]; exists {
 	if bindMap, exists := binds[volPath]; exists {
 		isBindMount = true
 		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" {
 		if strings.ToLower(bindMap.Mode) == "rw" {
 			srcRW = true
 			srcRW = true
 		}
 		}
+
 		if stat, err := os.Stat(bindMap.SrcPath); err != nil {
 		if stat, err := os.Stat(bindMap.SrcPath); err != nil {
 			return err
 			return err
 		} else {
 		} else {
 			volIsDir = stat.IsDir()
 			volIsDir = stat.IsDir()
 		}
 		}
-		// Otherwise create an directory in $ROOT/volumes/ and use that
 	} else {
 	} else {
 		// Do not pass a container as the parameter for the volume creation.
 		// Do not pass a container as the parameter for the volume creation.
 		// The graph driver using the container's information ( Image ) to
 		// 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 {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		srcPath, err = volumesDriver.Get(c.ID, "")
+
+		destination, err = volumesDriver.Get(c.ID, "")
 		if err != nil {
 		if err != nil {
 			return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
 			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
 		return err
 	} else {
 	} else {
-		srcPath = p
+		destination = p
 	}
 	}
 
 
 	// Create the mountpoint
 	// 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 {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	newVolPath, err := filepath.Rel(container.basefs, rootVolPath)
+	newVolPath, err := filepath.Rel(container.basefs, source)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -272,59 +280,57 @@ func initializeVolume(container *Container, volPath string, binds map[string]Bin
 		delete(container.VolumesRW, volPath)
 		delete(container.VolumesRW, volPath)
 	}
 	}
 
 
-	container.Volumes[newVolPath] = srcPath
+	container.Volumes[newVolPath] = destination
 	container.VolumesRW[newVolPath] = srcRW
 	container.VolumesRW[newVolPath] = srcRW
 
 
-	if err := createIfNotExists(rootVolPath, volIsDir); err != nil {
+	if err := createIfNotExists(source, volIsDir); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Do not copy or change permissions if we are mounting from the host
 	// Do not copy or change permissions if we are mounting from the host
 	if srcRW && !isBindMount {
 	if srcRW && !isBindMount {
-		if err := copyExistingContents(rootVolPath, srcPath); err != nil {
+		if err := copyExistingContents(source, destination); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
 	return nil
 	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 {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	if len(volList) > 0 {
 	if len(volList) > 0 {
-		srcList, err := ioutil.ReadDir(srcPath)
+		srcList, err := ioutil.ReadDir(destination)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
 
 
 		if len(srcList) == 0 {
 		if len(srcList) == 0 {
 			// If the source volume is empty copy files from the root into the volume
 			// 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
 				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
 		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
 		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))
 }
 }