J'ai récemment voulu faire ça avec tar
. Une enquête m'a indiqué que c'était plus qu'un peu absurde que je ne pouvais pas. J'ai trouvé cette split --filter="cat >file; tar -r ..."
chose bizarre , mais bon, c'était terriblement lent. Et plus je lisais sur tar
le plus insensé, il semblait.
Vous voyez, tar
c'est juste une liste concaténée d'enregistrements. Les fichiers constituants ne sont en aucun cas modifiés - ils sont entiers dans l'archive. Mais ils sont bloqués sur des limites de bloc de 512 octets , et avant chaque fichier, il y a un en- tête . C'est ça. Le format d'en-tête est également très, très simple.
J'ai donc écrit le mien tar
. Je l' appelle ... 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"
}
C'est vraiment la viande et les pommes de terre. Il écrit les en-têtes et calcule le chksum - qui, relativement parlant, est la seule partie difficile. Il fait le ustar
format d'en-tête ... peut-être . Au moins, il émule ce que GNU tar
semble penser être le ustar
format d'en-tête au point qu'il ne se plaint pas. Et il y a plus, c'est juste que je ne l'ai pas encore vraiment coagulé . Ici, je vais vous montrer:
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
Voilà tar
. Tout est rembourré avec des valeurs \0
nulles, donc je me transforme em
en \n
lignes électroniques pour plus de lisibilité. Et 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 .
PRODUCTION
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:.
Je dis un peu là-haut parce que ce n'est pas shitar
le but - le fait tar
déjà magnifiquement. Je voulais juste montrer comment cela fonctionne - ce qui signifie que je dois toucher le chksum
. Si ce n'était pas pour ça, je serais juste en train de dd
perdre la tête d'un tar
dossier et j'en aurais fini. Cela peut même parfois fonctionner, mais cela devient compliqué lorsqu'il y a plusieurs membres dans l'archive. Pourtant, le chksum est vraiment facile.
Tout d'abord, faites-en 7 espaces - (ce qui est une chose gnu bizarre, je pense, comme le spécifie 8, mais peu importe - un hack est un hack) . Additionnez ensuite les valeurs octales de chaque octet dans l'en-tête. Voilà votre chksum. Vous avez donc besoin des métadonnées du fichier avant de faire l'en-tête, ou vous n'avez pas de chksum. Et c'est ustar
surtout une archive.
D'accord. Maintenant, ce qu'il est censé faire:
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
Cela crée trois images disque de 500 millions de pixels, les formate et les monte chacune, et écrit un fichier sur chacune.
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
Remarque - apparemment, les périphériques bloqués seront toujours bloqués correctement. Assez pratique.
C'est tar
le contenu des fichiers de périphérique de disque en flux et dirige la sortie vers 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
Maintenant, le moment de vérité ...
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
Hourra! Extraction...
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
Comparaison...
cmp disk1 disk11 && echo yay || echo shite
yay
Et la monture ...
sudo mount disk13 mnt
cat mnt/*
disk3 file3
Et donc, dans ce cas, shitar
fonctionne bien, je suppose. Je préfère ne pas entrer dans toutes les choses que cela ne fera pas bien. Mais, je dirai - ne faites pas au moins de nouvelles lignes dans les noms de fichiers.
Vous pouvez également le faire - et peut-être devriez-vous, compte tenu des alternatives que j'ai proposées - avec cela squashfs
. Non seulement vous obtenez l'archive unique construite à partir du flux - mais elle est mount
capable et intégrée au noyau vfs
:
Du pseudo-fichier.exemple :
# 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
Vous pouvez également utiliser btrfs (send|receive)
pour diffuser un sous- stdin
volume dans le compresseur capable de votre choix. Ce sous-volume n'a pas besoin d'exister avant que vous décidiez de l'utiliser comme conteneur de compression, bien sûr.
Pourtant, à propos de squashfs
...
Je ne crois pas que je fais cette justice. Voici un exemple très simple:
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
Ce n'est que l' -p
argument en ligne pour mksquash
. Vous pouvez créer un fichier -pf
contenant autant de fichiers que vous le souhaitez. Le format est simple - vous définissez le nom / chemin d'un fichier cible dans le système de fichiers de la nouvelle archive, vous lui donnez un mode et un propriétaire, puis vous lui dites à partir de quel processus exécuter et lire stdout. Vous pouvez en créer autant que vous le souhaitez - et vous pouvez utiliser LZMA, GZIP, LZ4, XZ ... hmm il y a plus ... de formats de compression que vous le souhaitez. Et le résultat final est une archive dans laquelle vous cd
.
Plus d'informations sur le format cependant:
Bien sûr, il ne s'agit pas seulement d' une archive - c'est une image compressée et montable du système de fichiers Linux. Son format est celui du noyau Linux - c'est un système de fichiers pris en charge par le noyau vanilla. De cette façon, il est aussi commun que le noyau Linux vanilla. Donc, si vous me disiez que vous utilisiez un système Linux vanilla sur lequel le tar
programme n'était pas installé, je serais douteux - mais je vous croirais probablement. Mais si vous me disiez que vous utilisiez un système Linux vanilla sur lequel le squashfs
système de fichiers n'était pas pris en charge, je ne vous croirais pas.