Also wollte ich das kürzlich mit machen tar
. Einige Nachforschungen ergaben, dass es mehr als unsinnig war, dass ich es nicht konnte. Ich habe mir dieses seltsame split --filter="cat >file; tar -r ..."
Ding ausgedacht , aber es war furchtbar langsam. Und je mehr ich darüber las, tar
desto unsinniger schien es.
Sie sehen, tar
ist nur eine verkettete Liste von Datensätzen. Die konstituierenden Dateien werden in keiner Weise geändert - sie befinden sich vollständig im Archiv. Sie sind jedoch an 512-Byte- Blockgrenzen blockiert , und vor jeder Datei steht ein Header . Das ist es. Das Header-Format ist wirklich sehr einfach.
Also schrieb ich meine eigenen tar
. Ich nenne es ... 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"
}
Das ist wirklich das Fleisch und die Kartoffeln. Es schreibt die Überschriften und berechnet die Chksum - was relativ gesehen der einzige schwierige Teil ist. Es macht das ustar
Header-Format ... vielleicht . Zumindest emuliert es das, was GNU tar
für das ustar
Header-Format hält, bis zu dem Punkt, dass es sich nicht beschwert. Und es steckt noch mehr dahinter, ich habe es nur noch nicht wirklich geronnen . Hier zeige ich Ihnen:
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
Das ist tar
. Alles ist mit \0
Nullen aufgefüllt, daher verwandle ich mich em
zur \n
besseren Lesbarkeit in eWlines. Und 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 .
AUSGABE
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:.
Ich sage irgendwie da oben, weil das nicht shitar
das Ziel ist - tar
macht das schon wunderbar. Ich wollte nur zeigen, wie es funktioniert - was bedeutet, ich muss auf die berühren chksum
. Wenn es das nicht gäbe, würde ich einem einfach dd
den Kopf abschneidentar
Akte loswerden und damit fertig sein. Das mag manchmal sogar funktionieren, aber es wird chaotisch, wenn sich mehrere Mitglieder im Archiv befinden. Trotzdem ist die Chksum wirklich einfach.
Machen Sie zuerst 7 Leerzeichen (was eine seltsame Gnu-Sache ist, denke ich, wie in der Spezifikation 8 steht, aber was auch immer - ein Hack ist ein Hack) . Addieren Sie dann die Oktalwerte jedes Bytes im Header. Das ist dein Chksum. Sie benötigen also die Dateimetadaten, bevor Sie den Header erstellen, oder Sie haben keine Prüfsumme. Und das ist einustar
meistens Archiv.
In Ordnung. Nun, was soll es tun:
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
Das macht drei 500-MB-Disk-Images, formatiert und hängt jede und schreibt eine Datei in jede.
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
Hinweis - Anscheinend werden blockierte Geräte nur immer korrekt blockiert. Ziemlich praktisch.
Das ist tar
der Inhalt der Datenträger-Gerätedateien im Stream und leitet die Ausgabe an 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
Nun, der Moment der Wahrheit ...
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
Hurra! Extraktion...
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
Vergleich...
cmp disk1 disk11 && echo yay || echo shite
yay
Und der Berg ...
sudo mount disk13 mnt
cat mnt/*
disk3 file3
Und so, in diesem Fall, shitar
funktioniert es, denke ich. Ich möchte lieber nicht auf all die Dinge eingehen, die es nicht gut machen wird. Aber ich werde sagen - mach zumindest keine Zeilenumbrüche in den Dateinamen.
Sie können dies auch tun - und sollten es vielleicht tun, wenn Sie die Alternativen in Betracht ziehen, die ich Ihnen angeboten habe squashfs
. Nicht nur erhalten Sie das einzelne Archiv aus dem Stream gebaut - aber es ist mount
möglich und builtin den Kernelvfs
:
Aus pseudo-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
Sie können auch verwenden btrfs (send|receive)
, um ein Sub-Volume in einen beliebigen stdin
-fähigen Kompressor zu streamen . Dieses Subvolume muss nicht existieren, bevor Sie es als Kompressionscontainer verwenden möchten.
Trotzdem über squashfs
...
Ich glaube nicht, dass ich dies gerecht mache. Hier ist ein sehr einfaches Beispiel:
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
Das ist nur das Inline- -p
Argument für mksquash
. Sie können eine Datei mit beliebig -pf
vielen Quellen erstellen . Das Format ist einfach: Sie definieren den Namen / Pfad einer Zieldatei im Dateisystem des neuen Archivs, geben ihm einen Modus und einen Eigentümer und legen fest, von welchem Prozess stdout ausgeführt und gelesen werden soll. Sie können so viele erstellen, wie Sie möchten - und Sie können LZMA, GZIP, LZ4, XZ ... verwenden. Hmm, es gibt mehr ... Komprimierungsformate, als Sie möchten. Und das Endergebnis ist ein Archiv, in das Siecd
.
Mehr zum Format:
Dies ist natürlich nicht nur ein Archiv, sondern ein komprimiertes, einbindbares Linux-Dateisystem-Image. Das Format ist das des Linux-Kernels - es ist ein von Vanille-Kernel unterstütztes Dateisystem. Auf diese Weise ist es genauso verbreitet wie der Vanilla Linux-Kernel. Wenn Sie mir also sagen würden, dass Sie ein Vanilla-Linux-System verwenden, auf dem das tar
Programm nicht installiert ist, wäre ich zweifelhaft - aber ich würde Ihnen wahrscheinlich glauben. Aber wenn Sie mir sagen würden, dass Sie ein Vanilla Linux-System verwenden, auf dem das squashfs
Dateisystem nicht unterstützt wird, würde ich Ihnen nicht glauben.