그래서 최근에이 작업을 수행하고 싶었습니다 tar
. 일부 조사에 따르면 내가 할 수 없었던 것은 조금 무의미한 것 이상이었습니다. 나는이 이상한 split --filter="cat >file; tar -r ..."
것을 생각해 냈지만, 정말 느 렸습니다. 그리고 나는 tar
더 무의미한 것에 대해 더 많이 읽었습니다 .
보시다시피, tar
연결된 레코드 목록 일뿐입니다. 구성 요소 파일은 어떤 식 으로든 변경되지 않으며 전체가 아카이브 내에 있습니다. 그러나 그들은되어 차단 된 512 바이트에 떨어져 블록 경계, 모든 파일을 이전하는 것은이 헤더 . 그게 다야. 헤더 형식도 매우 간단합니다.
그래서 나는 내 자신의 글을 썼습니다 tar
. 나는 그것을 부른다 shitar
. …
z() (IFS=0; printf '%.s\\0' $(printf "%.$(($1-${#2}))d"))
chk() (IFS=${IFS#??}; set -f; set -- $(
printf "$(fmt)" "$n" "$@" '' "$un" "$gn"
); IFS=; a="$*"; printf %06o "$(($(
while printf %d+ "'${a:?}"; do a=${a#?}; done 2>/dev/null
)0))")
fmt() { printf '%s\\'"${1:-n}" %s "${1:+$(z 99 "$n")}%07d" \
%07o %07o %011o %011o "%-${1:-7}s" ' 0' "${1:+$(z 99)}ustar " %s \
"${1:+$(z 31 "$un")}%s"
}
바로 고기와 감자입니다. 헤더를 작성하고 chksum을 계산합니다. chksum은 비교적 어려운 부분입니다. 그것은하지 ustar
... 헤더 형식을 어쩌면 . 적어도 GNU tar
가 생각 ustar
하지 않는 것처럼 보이는 헤더 형식을 에뮬레이트합니다 . 그리고 그것에 더 많은 것이 있습니다, 그것은 제가 아직 그것을 아직 응고 하지 않은 것입니다. 여기서 보여 드리겠습니다.
for f in 1 2; do echo hey > file$f; done
{ tar -cf - file[123]; echo .; } | tr \\0 \\n | grep -b .
0:file1 #filename - first 100 bytes
100:0000644 #octal mode - next 8
108:0001750 #octal uid,
116:0001750 #gid - next 16
124:00000000004 #octal filesize - next 12
136:12401536267 #octal epoch mod time - next 12
148:012235 #chksum - more on this
155: 0 #file type - gnu is weird here - so is shitar
257:ustar #magic string - header type
265:mikeserv #owner
297:mikeserv #group - link name... others shitar doesnt do
512:hey #512-bytes - start of file
1024:file2 #512 more - start of header 2
1124:0000644
1132:0001750
1140:0001750
1148:00000000004
1160:12401536267
1172:012236
1179: 0
1281:ustar
1289:mikeserv
1321:mikeserv
1536:hey
10240:. #default blocking factor 20 * 512
그렇습니다 tar
. 모든 것이 \0
null em
로 \n
채워져 있으므로 가독성을 위해 ewlines 로 바꿉니다. 그리고 shitar
:
#the rest, kind of, calls z(), fmt(), chk() + gets $mdata and blocks w/ dd
for n in file[123]
do d=$n; un=$USER; gn=$(id --group --name)
set -- $(stat --printf "%a\n%u\n%g\n%s\n%Y" "$n")
printf "$(fmt 0)" "$n" "$@" "$(chk "$@")" "$un" "$gn"
printf "$(z $((512-298)) "$gn")"; cat "$d"
printf "$(x=$(($4%512));z $(($4>512?($x>0?$x:512):512-$4)))"
done |
{ dd iflag=fullblock conv=sync bs=10240 2>/dev/null; echo .; } |
tr \\0 \\n | grep -b .
산출
0:file1 #it's the same. I shortened it.
100:0000644 #but the whole first file is here
108:0001750
116:0001750
124:00000000004
136:12401536267
148:012235 #including its checksum
155: 0
257:ustar
265:mikeserv
297:mikeserv
512:hey
1024:file2
...
1172:012236 #and file2s checksum
...
1536:hey
10240:.
나는 그것이 목적 이 아니기 때문에 일종의 위로 말합니다 . 벌써 아름답게합니다. 방금 작동 방식을 보여주고 싶었습니다 . 그게 아니라면 파일 의 머리 부분에서 벗어나서 끝낼 것입니다. 때로는 작동 할 수도 있지만 아카이브에 여러 구성원이 있으면 지저분 해집니다. 여전히 chksum은 정말 쉽습니다.shitar
tar
chksum
dd
tar
먼저 7 개의 공백을 만드십시오 (스펙이 8이라고 말한 것처럼 이상한 gnu 일 것입니다.하지만 해킹은 해킹입니다) . 그런 다음 헤더의 모든 바이트의 8 진 값을 더하십시오. 그게 당신의 chksum입니다. 따라서 헤더를 수행하기 전에 파일 메타 데이터가 필요하거나 chksum이 없습니다. 그리고 그것은 ustar
대부분 아카이브입니다.
확인. 이제해야 할 일 :
cd /tmp; mkdir -p mnt
for d in 1 2 3
do fallocate -l $((1024*1024*500)) disk$d
lp=$(sudo losetup -f --show disk$d)
sync
sudo mkfs.vfat -n disk$d "$lp"
sudo mount "$lp" mnt
echo disk$d file$d | sudo tee mnt/file$d
sudo umount mnt
sudo losetup -d "$lp"
done
이렇게하면 3 개의 500M 디스크 이미지를 만들고 각각을 포맷하고 마운트하며 파일을 각각에 씁니다.
for n in disk[123]
do d=$(sudo losetup -f --show "$n")
un=$USER; gn=$(id --group --name)
set -- $(stat --printf "%a\n%u\n%g\n$(lsblk -bno SIZE "$d")\n%Y" "$n")
printf "$(fmt 0)" "$n" "$@" "$(chk "$@")" "$un" "$gn"
printf "$(z $((512-298)) "$gn")"
sudo cat "$d"
sudo losetup -d "$d"
done |
dd iflag=fullblock conv=sync bs=10240 2>/dev/null |
xz >disks.tar.xz
참고 -분명히 장치를 차단하면 항상 올바르게 차단됩니다. 꽤 편리합니다.
이는 tar
디스크 장치 파일의 내용을 인스 트림으로 출력하여 파이프에 출력합니다 xz
.
ls -l disk*
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk1
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk2
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk3
-rw-r--r-- 1 mikeserv mikeserv 229796 Sep 3 01:05 disks.tar.xz
이제 진실의 순간은 ...
xz -d <./disks.tar.xz| tar -tvf -
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk1
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk2
-rw-r--r-- mikeserv/mikeserv 524288000 2014-09-03 01:01 disk3
만세! 추출...
xz -d <./disks.tar.xz| tar -xf - --xform='s/[123]/1&/'
ls -l disk*
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk1
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk11
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk12
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk13
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk2
-rw-r--r-- 1 mikeserv mikeserv 524288000 Sep 3 01:01 disk3
-rw-r--r-- 1 mikeserv mikeserv 229796 Sep 3 01:05 disks.tar.xz
비교...
cmp disk1 disk11 && echo yay || echo shite
yay
그리고 산은 ...
sudo mount disk13 mnt
cat mnt/*
disk3 file3
그래서이 경우에는 shitar
괜찮습니다. 차라리 그것이 잘 되지 않는 모든 것들에 들어 가지 않을 것입니다. 그러나 나는 말할 것입니다-최소한 파일 이름에 줄 바꿈을하지 마십시오.
내가 제공 한 대안을 고려하여 할 수도 있고해야 할 수도 있습니다 squashfs
. 스트림에서 빌드 된 단일 아카이브를 얻을 수있을 뿐만 아니라mount
커널에 내장되어 있습니다 vfs
.
에서 의사 file.example :
# Copy 10K from the device /dev/sda1 into the file input. Ordinarily
# Mksquashfs given a device, fifo, or named socket will place that special file
# within the Squashfs filesystem, this allows input from these special
# files to be captured and placed in the Squashfs filesystem.
input f 444 root root dd if=/dev/sda1 bs=1024 count=10
# Creating a block or character device examples
# Create a character device "chr_dev" with major:minor 100:1 and
# a block device "blk_dev" with major:minor 200:200, both with root
# uid/gid and a mode of rw-rw-rw.
chr_dev c 666 root root 100 1
blk_dev b 666 0 0 200 200
btrfs (send|receive)
원하는 stdin
용량의 압축기 로 하위 볼륨을 스트리밍하는 데 사용할 수도 있습니다 . 물론이 하위 볼륨은 압축 컨테이너로 사용하기 전에 존재하지 않아도됩니다.
아직도, 약 squashfs
...
나는 내가이 정의를하고 있다고 믿지 않는다. 다음은 매우 간단한 예입니다.
cd /tmp; mkdir ./emptydir
mksquashfs ./emptydir /tmp/tmp.sfs -p \
'file f 644 mikeserv mikeserv echo "this is the contents of file"'
Parallel mksquashfs: Using 6 processors
Creating 4.0 filesystem on /tmp/tmp.sfs, block size 131072.
[==================================================================================|] 1/1 100%
Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072
compressed data, compressed metadata, compressed fragments,...
###...
###AND SO ON
###...
echo '/tmp/tmp.sfs /tmp/imgmnt squashfs loop,defaults,user 0 0'|
sudo tee -a /etc/fstab >/dev/null
mount ./tmp.sfs
cd ./imgmnt
ls
total 1
-rw-r--r-- 1 mikeserv mikeserv 29 Aug 20 11:34 file
cat file
this is the contents of file
cd ..
umount ./imgmnt
의 인라인 -p
인수입니다 mksquash
. 원하는 -pf
만큼 포함 하여 파일을 소싱 할 수 있습니다 . 형식은 간단합니다. 새 아카이브의 파일 시스템에 대상 파일의 이름 / 경로를 정의하고 모드와 소유자를 지정한 다음 stdout을 실행하고 읽을 프로세스를 알려줍니다. 원하는만큼 만들 수 있으며 LZMA, GZIP, LZ4, XZ를 사용할 수 있습니다. 음, 원하는대로 더 많은 압축 형식이 있습니다. 그리고 최종 결과는 당신에게 아카이브 cd
입니다.
형식에 대한 자세한 내용 :
이것은 물론 아카이브 일뿐 아니라 압축 가능한 마운트 가능한 Linux 파일 시스템 이미지입니다. 형식은 Linux 커널이며, 바닐라 커널 지원 파일 시스템입니다. 이런 식으로 바닐라 리눅스 커널만큼 흔합니다. 따라서 tar
프로그램이 설치되지 않은 바닐라 리눅스 시스템을 실행하고 있다고 말하면 모호 할 것입니다.하지만 아마 당신을 믿을 것입니다. 그러나 squashfs
파일 시스템이 지원되지 않는 바닐라 리눅스 시스템을 실행하고 있다고 말하면 나는 당신을 믿지 않을 것입니다.