【问题标题】:How to remap uid/gid in tar archive?如何在 tar 存档中重新映射 uid/gid?
【发布时间】:2017-01-02 09:03:13
【问题描述】:

我有包含文件的文件夹:

 UID     GID 
10000   10000   ./file1.txt
10000   10000   ./file2.txt
10400   10400   ./file3.txt
10402   10402   ./file4.txt
10052   10052   ./file5.txt

我想用下一个 UID/GID 创建 tar.bz2 存档:

UID     GID 
0   0    ./file1.txt
0   0    ./file2.txt
400 400  ./file3.txt
402 402  ./file4.txt
52  52   ./file5.txt

我想从所有 uid 和 gid 中减去 10000 并将结果保存为 tar.bz2。

我该怎么做?

【问题讨论】:

  • 我纠正了我(以前未经测试的)答案中的一些错误。它现在经过测试和验证可以正常工作。

标签: linux shell terminal console tar


【解决方案1】:

大概你知道你需要root 权限来改变UID/GID。以下脚本将起作用。可以通过使用命令行参数来指定输入目录和输出 .tar.bz2 文件名来改进它。

#!/bin/bash

for file in `find . -type f -print`
do
    UID=`ls -lnd "$file" | awk '{print $3}'`
    GID=`ls -lnd "$file" | awk '{print $4}'`
    NEWUID=`expr $UID - 10000`
    NEWGID=`expr $GID - 10000`
    if [ "$NEWUID" -ge 0  -a "$NEWGID" -ge 0 ]; then
        echo chown ${NEWUID}:${NEWGID} "$file"
        chown ${NEWUID}:${NEWGID} "$file"
    fi
done
tar cvjSf /tmp/remap.tar.bz2 .

【讨论】:

  • 文件名中带有空格的文件会怎样? (我同意这是愚蠢的!)。至少 dbl 引用 "$file" 的引用。此外,摆脱你 30 年的 csh 并使用 bash 享受“现代”(1988 年后)cmd 替换 UID=$(ls -lnd "$file" | awk '{print $3}') ;-) 祝大家好运。
  • @shellter 但我喜欢我厌倦的旧习惯!!老实说,老式的反引号命令替换与 /bin/sh 经验的关系比其他任何东西都多。我会解决引用问题,谢谢指出。
  • 请不要指示人们在不需要时使用超级用户权限。 OP 的问题无需成为 root 即可解决,因为 OP 最终只想要一个具有调整权限的 tarball。要创建它,不必先更改文件的所有权。
【解决方案2】:

以下 Python 脚本读取标准输入上的 tarball,并从其所有成员的 uid 和 gid 中减去 10000:

#!/usr/bin/env python3
import tarfile
import sys

with tarfile.open(fileobj=sys.stdin.buffer, mode="r|*") as in_tar, \
    tarfile.open(fileobj=sys.stdout.buffer, mode="w|", format=tarfile.PAX_FORMAT) as out_tar:
    for member in in_tar:
        member.uid = member.uid-10000
        member.gid = member.gid-10000
        if member.isfile():
            with in_tar.extractfile(member) as file:
                out_tar.addfile(member, file)
        else:
            out_tar.addfile(member)

编辑:这篇文章的早期版本省略了format=tarfile.PAX_FORMATtarfile.open() 的参数。这意味着输出 tarball 将不包含可能包含在 Python 3.7 及更早版本的输入 tarball 的 PAX 标头中的扩展属性。从 Python 3.8 开始,PAX_FORMAT 是默认值。

本文的其余部分留作历史用途。

这个 Python 脚本的问题是,tarball 模块不支持扩展属性(xattr、SCHILY),因此它不适合转换根文件系统的 tarball,这是想要转换 uid/gid 的主要原因数字。这是一个有效的 go 脚本:

package main    

import (
        "archive/tar"
        "io"
        "log"
        "os"
)

func main() {
        tr := tar.NewReader(os.Stdin)
        tw := tar.NewWriter(os.Stdout)

        for {
                hdr, err := tr.Next()
                if err == io.EOF {
                        break
                } else if err != nil {
                        log.Fatal(err)
                }

                hdr.Uid -= 10000
                hdr.Gid -= 10000
                if err := tw.WriteHeader(hdr); err != nil {
                        log.Fatal(err)
                }

                if hdr.Typeflag == tar.TypeReg {
                        if _, err := io.Copy(tw, tr); err != nil {
                                log.Fatal(err)
                        }
                }
        }

        if err := tw.Close(); err != nil {
                log.Fatal(err)
        }
}

使用go run script.go 运行它或使用go build script.go 编译它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 1970-01-01
    • 2017-08-12
    • 2019-11-12
    • 1970-01-01
    相关资源
    最近更新 更多