mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			162 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package fileutils
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"syscall"
 | |
| )
 | |
| 
 | |
| // CopyFile copies the file at source to dest
 | |
| func CopyFile(source string, dest string) error {
 | |
| 	si, err := os.Lstat(source)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	st, ok := si.Sys().(*syscall.Stat_t)
 | |
| 	if !ok {
 | |
| 		return fmt.Errorf("could not convert to syscall.Stat_t")
 | |
| 	}
 | |
| 
 | |
| 	uid := int(st.Uid)
 | |
| 	gid := int(st.Gid)
 | |
| 
 | |
| 	// Handle symlinks
 | |
| 	if si.Mode()&os.ModeSymlink != 0 {
 | |
| 		target, err := os.Readlink(source)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if err := os.Symlink(target, dest); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Handle device files
 | |
| 	if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
 | |
| 		devMajor := int64(major(uint64(st.Rdev)))
 | |
| 		devMinor := int64(minor(uint64(st.Rdev)))
 | |
| 		mode := uint32(si.Mode() & 07777)
 | |
| 		if st.Mode&syscall.S_IFMT == syscall.S_IFBLK {
 | |
| 			mode |= syscall.S_IFBLK
 | |
| 		}
 | |
| 		if st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
 | |
| 			mode |= syscall.S_IFCHR
 | |
| 		}
 | |
| 		if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Handle regular files
 | |
| 	if si.Mode().IsRegular() {
 | |
| 		sf, err := os.Open(source)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		defer sf.Close()
 | |
| 
 | |
| 		df, err := os.Create(dest)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		defer df.Close()
 | |
| 
 | |
| 		_, err = io.Copy(df, sf)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Chown the file
 | |
| 	if err := os.Lchown(dest, uid, gid); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Chmod the file
 | |
| 	if !(si.Mode()&os.ModeSymlink == os.ModeSymlink) {
 | |
| 		if err := os.Chmod(dest, si.Mode()); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // CopyDirectory copies the files under the source directory
 | |
| // to dest directory. The dest directory is created if it
 | |
| // does not exist.
 | |
| func CopyDirectory(source string, dest string) error {
 | |
| 	fi, err := os.Stat(source)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	// Get owner.
 | |
| 	st, ok := fi.Sys().(*syscall.Stat_t)
 | |
| 	if !ok {
 | |
| 		return fmt.Errorf("could not convert to syscall.Stat_t")
 | |
| 	}
 | |
| 
 | |
| 	// We have to pick an owner here anyway.
 | |
| 	if err := MkdirAllNewAs(dest, fi.Mode(), int(st.Uid), int(st.Gid)); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		// Get the relative path
 | |
| 		relPath, err := filepath.Rel(source, path)
 | |
| 		if err != nil {
 | |
| 			return nil
 | |
| 		}
 | |
| 
 | |
| 		if info.IsDir() {
 | |
| 			// Skip the source directory.
 | |
| 			if path != source {
 | |
| 				// Get the owner.
 | |
| 				st, ok := info.Sys().(*syscall.Stat_t)
 | |
| 				if !ok {
 | |
| 					return fmt.Errorf("could not convert to syscall.Stat_t")
 | |
| 				}
 | |
| 
 | |
| 				uid := int(st.Uid)
 | |
| 				gid := int(st.Gid)
 | |
| 
 | |
| 				if err := os.Mkdir(filepath.Join(dest, relPath), info.Mode()); err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 
 | |
| 				if err := os.Lchown(filepath.Join(dest, relPath), uid, gid); err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 			}
 | |
| 			return nil
 | |
| 		}
 | |
| 
 | |
| 		// Copy the file.
 | |
| 		if err := CopyFile(path, filepath.Join(dest, relPath)); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		return nil
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func major(device uint64) uint64 {
 | |
| 	return (device >> 8) & 0xfff
 | |
| }
 | |
| 
 | |
| func minor(device uint64) uint64 {
 | |
| 	return (device & 0xff) | ((device >> 12) & 0xfff00)
 | |
| }
 | |
| 
 | |
| func mkdev(major int64, minor int64) uint32 {
 | |
| 	return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
 | |
| }
 |