如何在 tar 存档中重新映射 uid/gid?
How to remap uid/gid in tar archive?
我有包含文件的文件夹:
UID GID
10000 10000 ./file1.txt
10000 10000 ./file2.txt
10400 10400 ./file3.txt
10402 10402 ./file4.txt
10052 10052 ./file5.txt
我想创建 tar.bz2 存档,下一个 UID/GID:
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.
我该怎么做?
想必您知道您需要 root
权限才能更改 UID/GID。以下脚本将起作用。可以通过使用命令行参数来指定输入目录和输出 .tar.bz2 文件名.
来改进它
#!/bin/bash
for file in `find . -type f -print`
do
UID=`ls -lnd "$file" | awk '{print }'`
GID=`ls -lnd "$file" | awk '{print }'`
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 .
以下 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)
编辑:这个post的早期版本省略了tarfile.open()
的format=tarfile.PAX_FORMAT
参数。这意味着输出 tarball 将不包含 Python 3.7 及更早版本的输入 tarball 的 PAX headers 中可能包含的扩展属性。从 Python 3.8 开始,PAX_FORMAT
是默认值。
此 post 的其余部分留作历史用途。
这个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
.
编译
我有包含文件的文件夹:
UID GID
10000 10000 ./file1.txt
10000 10000 ./file2.txt
10400 10400 ./file3.txt
10402 10402 ./file4.txt
10052 10052 ./file5.txt
我想创建 tar.bz2 存档,下一个 UID/GID:
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.
我该怎么做?
想必您知道您需要 root
权限才能更改 UID/GID。以下脚本将起作用。可以通过使用命令行参数来指定输入目录和输出 .tar.bz2 文件名.
#!/bin/bash
for file in `find . -type f -print`
do
UID=`ls -lnd "$file" | awk '{print }'`
GID=`ls -lnd "$file" | awk '{print }'`
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 .
以下 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)
编辑:这个post的早期版本省略了tarfile.open()
的format=tarfile.PAX_FORMAT
参数。这意味着输出 tarball 将不包含 Python 3.7 及更早版本的输入 tarball 的 PAX headers 中可能包含的扩展属性。从 Python 3.8 开始,PAX_FORMAT
是默认值。
此 post 的其余部分留作历史用途。
这个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
.