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  }