Plusieurs utilitaires (notamment l'utilitaire de disque et hdiutil), permettent
sur le Macintosh de produire et de manipuler des images de disques. Ces images
peuvent se présenter dans différents formats, dont certains sont déclarés comme
obsolètes (exemple des images de disquettes).
Les images de disques peuvent être de véritables images d'un disque, donc une copie
secteur après secteur d'un disque réel (matériel). Il peut également s'agir d'un
conteneur jouant le rôle de disque virtuel et pouvant être monté et manipulé
comme un disque, mais qui contient par exemple les fichiers et les dossiers
placés dans un dossier du disque.
En ce sens, les images de disque constituent des solutions fréquemment utilisées
pour la distribution de logiciels.
Le logiciel « Utilitaire de disque » offre plusieurs options dans la création
d'une image de disque vide, qui correspondent essentiellement aux options plus
générales ci-dessous, hormis celle qui propose de créer une table de partition
unique avec MBR, qui s'identifie par la présence du code 0xAA55 à la fin du premier
secteur et le code de partition Macintosh (0xAF) dans la première rubrique de
système. Cette rubrique pointe sur un volume formaté selon le mécanisme dit de la
disquette, donc sans table de partition, avec la tête de volume logique au
secteur 2.
Une autre variante similaire est celle d'une partition de type EFI/GPT, où le
code de système est 0xEE. Le secteur 0 est suivi d'une table de partition EFI
(voir la page Wiki
pour plus de précisions.
Je n'ai jamais rencontré ces images avec compression, mais rien ne s'y oppose
en principe.
Quant à lui, le manuel de l'utilitaire hdiutil donne les différents
formats suivants :
UDRW - UDIF read/write image
UDRO - UDIF read-only image
UDCO - UDIF ADC-compressed image
UDZO - UDIF zlib-compressed image
UDBZ - UDIF bzip2-compressed image (OS X 10.4+ only)
UFBI - UDIF entire image with MD5 checksum
UDRo - UDIF read-only (obsolete format)
UDCo - UDIF compressed (obsolete format)
UDTO - DVD/CD-R master for export
UDxx - UDIF stub image
UDSP - SPARSE (grows with content)
RdWr - NDIF read/write image (deprecated)
Rdxx - NDIF read-only image (Disk Copy 6.3.3 format)
ROCo - NDIF compressed image (deprecated)
Rken - NDIF compressed (obsolete format)
DC42 - Disk Copy 4.2 image
Si l'on veut bien ignorer les 5 dernières lignes, qui sont clairement historiques,
les formats UDRW (Image UDIF en lecture/écriture) et UDTO (image-maîtresse de
CD-R/DVD-R) sont des formats non compressés, donc des images simples d'un disque réel
ou virtuel. Elles peuvent être ouvertes avec des utilitaires comme MacImage ou montées comme des disques sous Linux.
Le format UDSP est une image dans laquelle la totalité de l'espace libre du disque
n'est pas attribuée, ce qui permet de conserver une image de petite taille qui
peut grandir en fonction des besoins. Ce format est très spécifique et nous
ne l'aborderons pas ici.
Les formats compressés peuvent utiliser plusieurs modes de compression, du plus
simple où l'on ne copie pas les secteurs qui ne contiennent que des zéros, au
plus compliqué utilisant des techniques poussées de compression, le problème
étant toujours le même : la bonne compression demande du temps.
Il existe donc un compromis à trouver entre le temps de traitement pour la
compression, le temps de traitement pour la décompression et l'espace occupé sur
le disque par l'image comprimée.
Une image comprimée comprend essentiellement trois parties, qui se succèdent dans le fichier :
Les données sont de longueur variable, de même que le tableau des blocs. Par contre, le bloc binaire 'koly' est de taille fixe (512 octets) et il se situe à l'extrémité du fichier.
Le bloc binaire 'koly' est appelé ainsi parce que le premier entier du bloc
contient la signature 'koly'. Dans ce bloc, qui contient toujours beaucoup de
données parasites parce que le logiciel ne nettoie pas le tampon utilisé avant
de renseigner les variables, on distingue cependant aisément la présence de
deux entiers sur 64 bits qui codent le décalage du tableau des blocs dans le
fichier comprimé ainsi que, après le second, un autre entier sur 64 bits codant
la longueur de ce tableau.
Plus près de la fin, on voit le CRC32 de l'image comprimée ainsi que le nombre des
secteurs composant l'image.
Au tout début du bloc, les quelques premiers entiers sur 32 bits pourraient coder
le nombre des partitions et la taille des secteurs.
Le tableau des blocs se présente sous la forme d'un fichier XML. Il est souvent
appelé fichier de préférences parce qu'il suit le format XML des fichiers de
préférences (plist) sur le Macintosh. On voit aussi à son propos utiliser le terme de
branche de ressources et on observe effectivement la présence de la chaîne
'resource-fork'. D'un autre côté, appeler branche de ressources un segment de
données placé dans un conteneur XML lui même inclus dans un fichier de données
ne me semble pas vraiment justifié, mais puisque c'est ainsi...
Les données utiles constituent plusieurs séquences de données, placées entre des
balises <data> et </data>. Dans le cas d'une image de disque ou de dossier Macintosh,
nous avons généralement quatre séquences de données, également appelées partitions
dans le fichier XML :
La première de ces « partitions » contient le secteur 0 du disque. La deuxième
contient le secteur 1 et les suivants jusqu'au début du volume logique. La
troisième contient ce volume logique (les données utiles). La quatrième correspond
à la petite partition Apple_Free qui est parfois présente pour regrouper quelques
secteurs libres à la fin d'un disque ou d'une image de disque.
Ces séquences de données sont stockées sous la forme de code base64. Voir par
exemple la page Wikipedia pour
plus de renseignements.
Après décodage, on obtient un bloc d'en-tête commençant par la signature 'mish',
suivi d'une séquence de blocs qui constituent des pointeurs sur les différents
segments de données comprimées se trouvant dans l'image. La structure de ce
bloc est la suivante :
Ce bloc permet de traiter les segments de données. Les types de blocs identifiés sont les suivants :
Pour recueillir et mettre en forme les informations ci-dessus, nous nous sommes
avant tout fondés sur un examen d'images créées par l'utilitaire de disque et
l'outil hdiutil. Cela a permis assez rapidement d'identifier les modes de
compressioon Zlib et Bzlib2 et de trouver des bibliothèques qui mettent en œuvre
ces techniques, à savoir Zlib.net, bibliothèque
écrite par Jean-Loup Gailly et Mark Adler, et Bzlib.org,
bibliothèque écrite par Julian Seward. Qu'ils soient tous trois sincèrement
remerciés pour leur travail et pour les explications données dans leur code.
Plusieurs confirmations bienvenues ont été trouvées dans les deux bibliothèques
dmg2iso et dmg2img, diffusées sur le site vultur.eu.org
et écrites par Vu1tur et Jean-Pierre Demailly.
La partie la plus ardue a été le décodage du mode de compression ADC, pour lequel
il ne semble pas exister de documentation accessible publiquement. Cependant,
le travail a pu être achevé en quelques jours.
Le mode de compression ADC (Apple Data Compression) repose à la fois sur
la réduction des séquences répétitives et sur un stockage des données répétitives
dans un dictionnaire. Le mieux est de donner du pseudo-code :
Lire un octet.
Si le bit 7 est armé, c'est une séquence de données.
Prendre le reste de l'octet, ajouter 1 et copier le tampon d'origine vers le tampon de destination.Si le bit 6 est armé, c'est un code sur 3 octets.
Le premier octet code la longueur, les suivants le décalage dans le dictionnaire (qui est en fait le tampon de destination lui-même).Si aucun des deux n'est armé, c'est un code sur 2 octets.
Tous les décalages doivent être incrémentés de 1.
Ajouter 4 à la longueur après désarmement du bit 6.
Placer un pointeur de décalage dans le tampon de destination en reculant à partir du pointeur de destination. S'il y a assez de place entre les deux pour la longueur de données, utiliser memcpy pour copier les données entre le pointeur de décalage et le pointeur de destination. Sinon, utiliser memset pour recopier n fois l'octet pointé tout seul.
La longueur est codée sur les bits 2345. Elle est comptée à partir de 3 (c'est-à-dire 0000 = 3, 0001 = 4, etc.). Les bits 01 doivent être associés aux 7 bits de l'octet suivant pour donner un décalage. Faire la même chose que dans le cas précédent pour utiliser soit memcpy, soit memset.Jusqu'à ce qu'il n'y ait plus de données à décomprimer.
Notre utilitaire MacImage (en mode Partition) peut gérer ces fichiers (les décomprimer, les afficher pour copier des données vers le PC, etc.).