github.com/searKing/golang/go@v1.2.117/io/copy_unix.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build !windows && !linux 6 // +build !windows,!linux 7 8 package io 9 10 import ( 11 "fmt" 12 "os" 13 "syscall" 14 15 "golang.org/x/sys/unix" 16 ) 17 18 func copyPath(srcPath, dstPath string, f os.FileInfo, copyMode Mode) error { 19 stat, ok := f.Sys().(*syscall.Stat_t) 20 if !ok { 21 return fmt.Errorf("unable to get raw syscall.Stat_t data for %s", srcPath) 22 } 23 24 isHardlink := false 25 26 switch mode := f.Mode(); { 27 case mode.IsRegular(): 28 // the type is 32bit on mips 29 if copyMode == Hardlink { 30 isHardlink = true 31 if err := os.Link(srcPath, dstPath); err != nil { 32 return err 33 } 34 } else { 35 if err := CopyRegular(srcPath, dstPath, f); err != nil { 36 return err 37 } 38 } 39 40 case mode.IsDir(): 41 if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) { 42 return err 43 } 44 45 case mode&os.ModeSymlink != 0: 46 link, err := os.Readlink(srcPath) 47 if err != nil { 48 return err 49 } 50 51 if err := os.Symlink(link, dstPath); err != nil { 52 return err 53 } 54 55 case mode&os.ModeNamedPipe != 0: 56 fallthrough 57 case mode&os.ModeSocket != 0: 58 if err := unix.Mkfifo(dstPath, uint32(stat.Mode)); err != nil { 59 return err 60 } 61 62 case mode&os.ModeDevice != 0: 63 if err := unix.Mknod(dstPath, uint32(stat.Mode), int(stat.Rdev)); err != nil { 64 return err 65 } 66 67 default: 68 return fmt.Errorf("unknown file type (%d / %s) for %s", f.Mode(), f.Mode().String(), srcPath) 69 } 70 71 // Everything below is copying metadata from src to dst. All this metadata 72 // already shares an inode for hardlinks. 73 if isHardlink { 74 return nil 75 } 76 77 if err := os.Lchown(dstPath, int(stat.Uid), int(stat.Gid)); err != nil { 78 return err 79 } 80 81 isSymlink := f.Mode()&os.ModeSymlink != 0 82 83 // There is no LChmod, so ignore mode for symlink. Also, this 84 // must happen after chown, as that can modify the file mode 85 if !isSymlink { 86 if err := os.Chmod(dstPath, f.Mode()); err != nil { 87 return err 88 } 89 } 90 91 return nil 92 }