以下是使用 Golang 实现 Linux 下文件复制,包括 ACL 权限及文件扩展属性的示例代码:

package main

import (
    "fmt"
    "io"
    "os"
    "path/filepath"
    "syscall"
)

func copyFile(src, dst string) error {
    srcStat, err := os.Stat(src)
    if err != nil {
        return err
    }

    dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, srcStat.Mode())
    if err != nil {
        return err
    }
    defer dstFile.Close()

    srcFile, err := os.Open(src)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    _, err = io.Copy(dstFile, srcFile)
    if err != nil {
        return err
    }

    err = os.Chmod(dst, srcStat.Mode())
    if err != nil {
        return err
    }

    err = copyAcl(src, dst)
    if err != nil {
        return err
    }

    err = copyXattr(src, dst)
    if err != nil {
        return err
    }

    return nil
}

func copyAcl(src, dst string) error {
    acl, err := getAcl(src)
    if err != nil {
        return err
    }

    if acl != nil {
        err = setAcl(dst, acl)
        if err != nil {
            return err
        }
    }

    return nil
}

func getAcl(path string) (*syscall.ACL, error) {
    fileInfo, err := os.Stat(path)
    if err != nil {
        return nil, err
    }

    acl, err := syscall.Getfacl(path)
    if err != nil {
        return nil, err
    }

    userMap, err := getUserMap()
    if err != nil {
        return nil, err
    }

    for i := range acl {
        if acl[i].Tag == 'user' {
            uid, ok := userMap[acl[i].Qualifier]
            if ok {
                acl[i].Qualifier = fmt.Sprintf('%d', uid)
            }
        }
    }

    return acl, nil
}

func setAcl(path string, acl *syscall.ACL) error {
    userMap, err := getUserMap()
    if err != nil {
        return err
    }

    for i := range acl {
        if acl[i].Tag == 'user' {
            uid, ok := userMap[acl[i].Qualifier]
            if ok {
                acl[i].Qualifier = fmt.Sprintf('%d', uid)
            }
        }
    }

    return syscall.Setfacl(path, acl)
}

func getUserMap() (map[string]int, error) {
    userMap := make(map[string]int)

    passwdFile, err := os.Open('/etc/passwd')
    if err != nil {
        return nil, err
    }
    defer passwdFile.Close()

    scanner := bufio.NewScanner(passwdFile)
    for scanner.Scan() {
        fields := strings.Split(scanner.Text(), ':')
        if len(fields) >= 3 {
            uid, err := strconv.Atoi(fields[2])
            if err == nil {
                userMap[fields[0]] = uid
            }
        }
    }

    return userMap, nil
}

func copyXattr(src, dst string) error {
    xattrs, err := getXattrs(src)
    if err != nil {
        return err
    }

    for name, value := range xattrs {
        err := setXattr(dst, name, value)
        if err != nil {
            return err
        }
    }

    return nil
}

func getXattrs(path string) (map[string][]byte, error) {
    xattrs := make(map[string][]byte)

    xattrList := make([]byte, 1024)
    for {
        n, err := syscall.Listxattr(path, xattrList)
        if err != nil {
            return nil, err
        }

        if n == len(xattrList) {
            xattrList = make([]byte, n*2)
        } else {
            break
        }
    }

    for _, name := range bytes.Split(xattrList[:], []byte{0}) {
        if len(name) > 0 {
            value := make([]byte, 1024)
            for {
                n, err := syscall.Getxattr(path, string(name), value)
                if err != nil {
                    return nil, err
                }

                if n == len(value) {
                    value = make([]byte, n*2)
                } else {
                    xattrs[string(name)] = value[:n]
                    break
                }
            }
        }
    }

    return xattrs, nil
}

func setXattr(path, name string, value []byte) error {
    return syscall.Setxattr(path, name, value, 0)
}

func main() {
    src := '/path/to/source/file'
    dst := '/path/to/destination/file'

    err := copyFile(src, dst)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println('File copied successfully.')
}

注意事项:

  1. 以上代码仅在 Linux 环境下使用,并且需要 root 权限才能访问 ACL 和 xattr。
  2. 由于 ACL 和 xattr 可能包含敏感信息,因此需要谨慎使用。在实际使用中,应该先检查源文件是否包含这些属性,然后再复制到目标文件中。
Golang 实现 Linux 文件复制,含 ACL 权限和扩展属性

原文地址: https://www.cveoy.top/t/topic/mtZu 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录