Ostatnio chciałem to zrobić tar
. Niektóre dochodzenie wskazało mi, że nie było to trochę nonsensowne. Wymyśliłem tę dziwną split --filter="cat >file; tar -r ..."
rzecz, ale, cóż, było to strasznie wolne. Im więcej czytałem o tar
tym, tym bardziej wydawało się to bezsensowne.
Widzisz, tar
to tylko połączona lista rekordów. Pliki składowe nie są w żaden sposób zmieniane - są całe w archiwum. Są one jednak zablokowane na 512-bajtowych granicach bloku , a przed każdym plikiem znajduje się nagłówek . Otóż to. Format nagłówka jest również bardzo prosty.
Więc napisałem własny tar
. Ja to nazywam ... 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"
}
To naprawdę mięso i ziemniaki. Zapisuje nagłówki i oblicza chksum - co, relatywnie rzecz biorąc, jest jedyną trudną częścią. Robi ustar
format nagłówka ... może . Przynajmniej emuluje to, co GNU tar
wydaje się uważać za ustar
format nagłówka do tego stopnia, że nie narzeka. I jest coś więcej, po prostu jeszcze tego nie skoagulowałem . Tutaj pokażę ci:
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
To tar
. Wszystko jest wypełnione \0
zerami, więc zmieniam się em
w \n
ewline dla czytelności. I 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 .
WYNIK
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:.
Mówię trochę na górze, bo to nie shitar
jest cel - tar
robi to już pięknie. Chciałem tylko pokazać, jak to działa - co oznacza, że muszę dotknąć chksum
. Gdyby nie to, po prostu dd
oderwałbym się od tar
pliku i skończyłbym z nim. Może to czasem działać, ale robi się bałagan, gdy w archiwum jest wielu członków. Mimo to, chksum jest naprawdę łatwe.
Najpierw zrób 7 spacji - (myślę, że to dziwna rzecz gnu, jak mówi specyfikacja 8, ale cokolwiek - hack to hack) . Następnie dodaj wartości ósemkowe każdego bajtu w nagłówku. To twoje chksum. Więc potrzebujesz metadanych pliku przed wykonaniem nagłówka, inaczej nie masz programu chksum. A to ustar
głównie archiwum.
Dobrze. Co to znaczy:
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
To sprawia, że trzy obrazy dysków 500M, formatują i montuje każdy, i zapisuje plik do każdego.
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
Uwaga - najwyraźniej urządzenia blokujące zawsze będą blokować poprawnie. Bardzo przydatny.
To tar
jest zawartość plików urządzeń dyskowych typu In-Stream i potokuje dane wyjściowe 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
Chwila prawdy ...
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
Brawo! Ekstrakcja...
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
Porównanie...
cmp disk1 disk11 && echo yay || echo shite
yay
A wierzchowiec ...
sudo mount disk13 mnt
cat mnt/*
disk3 file3
I tak w tym przypadku shitar
działa dobrze. Wolałbym nie zajmować się wszystkimi rzeczami, które nie przyniosą dobrego rezultatu. Ale powiem - nie rób co najmniej nowego wiersza w nazwach plików.
Możesz także zrobić - a może powinieneś, biorąc pod uwagę oferowane przeze mnie alternatywy - z tym squashfs
. Nie tylko dostajesz jedno archiwum zbudowane ze strumienia - ale jest w mount
stanie i wbudowane w jądro vfs
:
Z pseudopliku. Przykład :
# 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
Możesz także użyć btrfs (send|receive)
do przesłania strumienia objętości do dowolnego stdin
kompresora, który ci się podoba. Ta podobjętość nie musi oczywiście istnieć, zanim zdecydujesz się użyć jej jako kontenera kompresyjnego.
Mimo to około squashfs
...
Nie wierzę, że robię tę sprawiedliwość. Oto bardzo prosty przykład:
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
To tylko wewnętrzny -p
argument za mksquash
. Możesz pobrać plik -pf
zawierający tyle plików, ile chcesz. Format jest prosty - definiujesz nazwę / ścieżkę pliku docelowego w systemie plików nowego archiwum, nadajesz mu tryb i właściciela, a następnie mówisz, z którego procesu wykonać i odczytać standardowe wyjście. Możesz utworzyć tyle, ile chcesz - i możesz używać LZMA, GZIP, LZ4, XZ ... hmm jest więcej ... formatów kompresji, jak chcesz. A efektem końcowym jest archiwum, w którym ty cd
.
Więcej o tym formacie:
Oczywiście nie jest to tylko archiwum - jest to skompresowany, możliwy do zamontowania obraz systemu plików Linux. Jego format to jądro Linuksa - jest to system plików obsługiwany przez jądro wanilii. W ten sposób jest tak powszechny jak waniliowe jądro Linuksa. Więc jeśli powiedziałbyś mi, że używasz waniliowego systemu Linux, na którym tar
program nie został zainstalowany, byłbym wątpliwy - ale prawdopodobnie uwierzyłbym ci. Ale jeśli powiedziałbyś mi, że używasz waniliowego systemu Linux, na którym squashfs
system plików nie był obsługiwany, nie uwierzyłbym ci.