doujiku1028 2017-03-23 18:25
浏览 11
已采纳

有没有办法用Go复制tar -h选项?

In Unix the tar utility has a -h option that archives the target of the link. I'm wondering if there's a way to do this with Go. Right now when I try to copy the contents of the link to the tar with the header name set to the symlink file I get a tar: Damaged tar archive error. The code below is what I'm currently using. The goal of the function is to recursively tar everything in the current directory.

I thought maybe all I'd have to do is set the size of the symlink to the size of the target file but still getting an error.

func createTarFile() {
    tarfile, _ := os.Create(buildCtxTar)
    defer tarfile.Close()

    tarball := tar.NewWriter(tarfile)
    defer tarball.Close()

    //get the working directory
    rootDir, _ := os.Getwd()

    //add all the files in the current directory to the tarball
    walkFn := func(path string, info os.FileInfo, err error) error {
        //don't add the tar file to itself, don't add the working directory either
        if info.Name() == buildCtxTar || info.Name() == filepath.Base(rootDir) {
            return nil
        }

        //no absolute paths in the tar file, the "+1" strips the leading file separator
        relativePath := path[len(rootDir)+1:]

        isSymlink := info.Mode()&os.ModeSymlink == os.ModeSymlink
        var size int64 = -1
        //evaluate symbolic links
        if isSymlink {
            path, size, err = handleSymlink(path)
            if err != nil {
                return err
            }
        }

        header, err := tar.FileInfoHeader(info, path)
        if err != nil {
            return err
        }

        //if the OS is windows we need to convert the '\' to '/'
        relativePath = filepath.ToSlash(relativePath)

        //rename the name of the file to its path for a structured tarball
        header.Name = relativePath
        if isSymlink {
            header.Size = size
        }
        if err := tarball.WriteHeader(header); err != nil {
            return err
        }

        //don't attempt copy data from special files (like directories)
        if !isSymlink && !info.Mode().IsRegular() {
            return nil
        }
        f, err := os.Open(path)
        if err != nil {
            return err
        }
        defer f.Close()

        // copy the file data to the tarball
        if _, err := io.Copy(tarball, f); err != nil {
            return err
        }
        return nil
    }

    //walks through all files and subdirectories of the current directory
    err := filepath.Walk(rootDir, walkFn)
}

//get the filepath for the symbolic link
func handleSymlink(path string) (string, int64, error) {
    //read the link
    link, err := os.Readlink(path)
    if err != nil {
        return "", -1, err
    }
    //if the filepath isn't an absolute path we need to
    //reconstruct it so that it is
    if !filepath.IsAbs(link) {
        link = filepath.Join(filepath.Dir(path), link)
        if err != nil {
            return "", -1, err
        }
    }
    fi, err := os.Stat(link)
    if err != nil {
        return "", -1, err
    }
    size := fi.Size()
    return link, size, nil
}
  • 写回答

1条回答 默认 最新

  • dt3674 2017-03-23 21:18
    关注

    You are creating the tar.Header from the symlink FileInfo, which is still going to have the Typeflag and Mode of a symlink.

    Create a new header from the target file, and "move" it into the archive by changing the Name field to that of the symlink.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 前端echarts坐标轴问题
  • ¥15 CMFCPropertyPage
  • ¥15 ad5933的I2C
  • ¥15 请问RTX4060的笔记本电脑可以训练yolov5模型吗?
  • ¥15 数学建模求思路及代码
  • ¥50 silvaco GaN HEMT有栅极场板的击穿电压仿真问题
  • ¥15 谁会P4语言啊,我想请教一下
  • ¥15 这个怎么改成直流激励源给加热电阻提供5a电流呀
  • ¥50 求解vmware的网络模式问题 别拿AI回答
  • ¥24 EFS加密后,在同一台电脑解密出错,证书界面找不到对应指纹的证书,未备份证书,求在原电脑解密的方法,可行即采纳