Images de disques Macintosh

Résumé : Une page consacrée à une description des différents formats des images de disques Macintosh.
 

Introduction

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.

Formats des images

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

Formats non compressés

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.

Formats compressés

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.

Maquette générale

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.

Bloc binaire 'koly'

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.

Tableau des blocs

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 :

Sources d'informations

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.

Mode de compression ADC

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).
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.
Si aucun des deux n'est armé, c'est un code sur 2 octets.
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.

Quels outils pour gérer ces fichiers sur un PC ?

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.).

 
Pierre Duhem (ex-Logiciels & Services Duhem)
3, rue Pierre Haret - F-75009 Paris (France) - Tél. (+33) [0]149 700 455
web : http://www.macdisk.com