Di recente ho voluto farlo con tar
. Qualche indagine mi ha indicato che era più che un po 'assurdo che non potevo. Mi è venuta in mente questa split --filter="cat >file; tar -r ..."
cosa strana , ma, beh, è stato terribilmente lento. E più leggo tar
più assurdità sembrava.
Vedete, tar
è solo un elenco concatenato di record. I file costituenti non vengono modificati in alcun modo: sono interi all'interno dell'archivio. Ma sono bloccati su limiti di blocco da 512 byte e prima di ogni file c'è un'intestazione . Questo è tutto. Anche il formato dell'intestazione è davvero molto semplice.
Quindi, ho scritto il mio tar
. Io lo chiamo ... 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"
}
Quella è la carne e le patate, davvero. Scrive le intestazioni e calcola il chksum - che, relativamente parlando, è l'unica parte difficile. Fa il ustar
formato dell'intestazione ... forse . Almeno, emula ciò che GNU tar
sembra pensare sia il ustar
formato dell'intestazione al punto da non lamentarsi. E c'è di più, è solo che non l'ho ancora davvero coagulato . Qui, ti mostrerò:
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
Questo è tar
. Tutto è riempito di \0
null quindi mi trasformo em
in \n
ewline per leggibilità. E 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 .
PRODUZIONE
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:.
Dico un po ' lassù perché quello non è lo shitar
scopo - lo tar
fa già magnificamente. Volevo solo mostrare come funziona, il che significa che devo toccare il chksum
. Se non fosse stato per questo, mi limiterei a dd
scrivere un tar
file e finirlo. A volte potrebbe anche funzionare, ma diventa disordinato quando ci sono più membri nell'archivio. Tuttavia, il chksum è davvero facile.
Per prima cosa, rendilo 7 spazi - (che è una cosa strana di gnu, penso, come dice la specifica 8, ma comunque - un hack è un hack) . Quindi sommare i valori ottali di ogni byte nell'intestazione. Questo è il tuo chksum. Quindi hai bisogno dei metadati del file prima di fare l'intestazione, o non hai un chksum. E questo è un ustar
archivio, per lo più.
Ok. Ora, cosa si intende fare:
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
Ciò crea tre immagini del disco da 500 M, formatta e monta ciascuna e scrive un file su ciascuna.
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
Nota : apparentemente i dispositivi di blocco si bloccheranno sempre correttamente. Abbastanza utile.
Questo tar
è il contenuto dei file del dispositivo disco in-stream e indirizza l'output a 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
Ora, il momento della verità ...
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
Evviva! Estrazione...
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
Confronto...
cmp disk1 disk11 && echo yay || echo shite
yay
E il monte ...
sudo mount disk13 mnt
cat mnt/*
disk3 file3
E quindi, in questo caso, shitar
funziona bene, immagino. Preferirei non approfondire tutte le cose che non andranno bene. Ma, dirò: non fare almeno nuove righe nei nomi dei file.
Puoi anche fare - e forse dovresti, considerando le alternative che ho offerto - questo con squashfs
. Non solo ottieni il singolo archivio creato dallo stream, ma è in mount
grado e integrato nei kernel vfs
:
Da 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
Potresti anche usare btrfs (send|receive)
per eseguire lo streaming di un volume secondario in qualunque stdin
compressore adatto a te. Questo sottovolume non deve necessariamente esistere prima di decidere di usarlo come contenitore di compressione, ovviamente.
Tuttavia, circa squashfs
...
Non credo di fare questa giustizia. Ecco un esempio molto semplice:
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
Questo è solo l' -p
argomento in linea per mksquash
. Puoi creare un file -pf
contenente il numero di quelli che desideri. Il formato è semplice: definisci il nome / percorso di un file di destinazione nel filesystem del nuovo archivio, gli dai una modalità e un proprietario e poi gli dici da quale processo eseguire e leggere lo stdout. Puoi crearne quanti ne vuoi - e puoi usare LZMA, GZIP, LZ4, XZ ... hmm ci sono più ... formati di compressione che vuoi. E il risultato finale è un archivio in cui tu cd
.
Altre informazioni sul formato:
Questo, ovviamente, non è solo un archivio: è un'immagine di file system Linux compresso e montabile. Il suo formato è quello del kernel Linux - è un filesystem supportato dal kernel vanilla. In questo modo è comune come il kernel Linux vaniglia. Quindi se mi dicessi che stavi eseguendo un sistema Linux vanilla su cui tar
non era installato il programma sarei dubbioso - ma probabilmente ti crederei. Ma se mi dicessi che stavi eseguendo un sistema Linux vanilla su cui il squashfs
filesystem non era supportato non ti avrei creduto.