Intéressé par des cours d'informatique en ligne ?
Visitez mon nouveau site https://www.yesik.it !

Il y a peu de temps, j'ai eu besoin de récupérer sous Linux des données enregistrées dans une image disque MacOS X (fichier .dmg).

Pour la petite histoire, il s'agissait de l'archive de JavaFX qui comme vous le savez peut-être n'est disponible dans sa version 1.1 que pour Windows et Mac OS X. Mais les informations données ici devraient pouvoir s'appliquer à n'importe quelle image disque ".dmg".

Ce qui ne marche pas

Comme il se doit, j'ai tout d'abord commencé par une rapide recherche sur internet. Où j'ai trouvé à l'adresse http://www.weiqigao.com/blog/2008/12/04/using_javafx_1_0_on_linux.html la procédure suivante. Celle-ci consiste à décompresser l'archive, puis à monter l'image disque décompressée.

sh$ bunzip2 javafx_sdk-1_1_1-macosx-universal.dmg
bunzip2: Can't guess original name for javafx_sdk-1_1_1-macosx-universal.dmg -- using javafx_sdk-1_1_1-macosx-universal.dmg.out

bunzip2: javafx_sdk-1_1_1-macosx-universal.dmg: trailing garbage after EOF ignored
sh$ mkdir mount-point
sh$ sudo mount -o loop -t hfsplus javafx_sdk-1_1_1-macosx-universal.dmg.out mount-point
Password:
mount: wrong fs type, bad option, bad superblock on /dev/loop1,
       missing codepage or helper program, or other error
       In some cases useful info is found in syslog - try
       dmesg | tail  or so

Oups! D'après son Blog, Gao a réussi à monter son image ainsi sur Ubuntu. Mais visiblement sur ma distribution Debian Etch, ça ne marche pas. Dommage...

Investigations

La question à se poser maintenant, est "est-ce que le fichier décompressé contient bien une image disque d'un système de fichier HFS+"?

HFS+

HFS+ est le système de fichiers utilisé par Mac OS X. Les anciens Mac (pré-OS X) utilisaient le système de fichier HFS.

Plusieurs solutions pour répondre à cette question. Pour ma part, j'aime bien utiliser hexdump. C'est un peu "rustique" mais ça permet d'avoir une première idée du contenu d'un fichier "mystère":

sh$ hexdump -C javafx_sdk-1_1_1-macosx-universal.dmg.out | more
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 fe  |................|
000001c0  ff ff ee fe ff ff 01 00  00 00 ff ff 03 00 00 00  |................|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  45 46 49 20 50 41 52 54  00 00 01 00 5c 00 00 00  |EFI PART....\...|
00000210  17 1b d9 7e 00 00 00 00  01 00 00 00 00 00 00 00  |...~............|
00000220  ff ff 03 00 00 00 00 00  22 00 00 00 00 00 00 00  |........".......|
00000230  de ff 03 00 00 00 00 00  61 45 5a dc 09 f7 47 48  |........aEZ...GH|
00000240  aa 88 bb bf 04 20 fe cd  02 00 00 00 00 00 00 00  |..... ..........|
00000250  80 00 00 00 80 00 00 00  c3 ef fc 93 00 00 00 00  |................|
00000260  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  00 53 46 48 00 00 aa 11  aa 11 00 30 65 43 ec ac  |.SFH.......0eC..|
00000410  8d 5c 6f b3 57 8e 78 45  a7 f6 56 eb ad e2 b6 5e  |.\o.W.xE..V....^|
00000420  28 00 00 00 00 00 00 00  d7 ff 03 00 00 00 00 00  |(...............|
00000430  00 00 00 00 00 00 00 00  64 00 69 00 73 00 6b 00  |........d.i.s.k.|
00000440  20 00 69 00 6d 00 61 00  67 00 65 00 00 00 00 00  | .i.m.a.g.e.....|
00000450  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00004800  48 2b 00 04 00 00 01 00  31 30 2e 30 00 00 00 00  |H+......10.0....|

Ha, ha! A l'offset 4800(hex) je vois les deux caractères H+. Et alors? Et bien, il s'agit de la signature dans l'en-tête d'un système de fichier HFS+. Si un tel système de fichier est dans l'archive, son en-tête est situé à l'offset 4800(hex).

Bon, ben il n'y a plus qu'à monter l'image en "sautant" les 4800 premiers octets. Oui?

sh$ sudo losetup  -o 18432 -s -f javafx_sdk-1_1_1-macosx-universal.dmg.out
/dev/loop0
sh$ sudo mount -o loop -t hfsplus /dev/loop0 mount-point
mount: wrong fs type, bad option, bad superblock on /dev/loop1,
       missing codepage or helper program, or other error
       In some cases useful info is found in syslog - try
       dmesg | tail  or so

Ah ben non... Pourtant j'utilise losetup pour créer un pseudo-device correspondant au fichier. Et je précise bien de "sauter" 18432(dec) octets. Ce qui correspond bien à l'offset 4800(hex).

L'explication de ce problème se trouve en lisant (mieux) la documentation du format HFS+ (TN1150: HFS+ Volume Format). Plus particulièrement la section sur l'en-tête HFS+:

Each HFS Plus volume contains a volume header 1024 bytes from the start of the volume.

Et oui: l'en-tête HFS+ n'est pas au début du volume, mais 1024 octects plus loin. Bref, j'ai "sauté" 1024 octets de trop:

sh$ sudo losetup -d /dev/loop0 # On annule les bêtises faites précédemment
sh$ sudo  sudo losetup  -o 17408 /dev/loop0 javafx_sdk-1_1_1-macosx-universal.dmg.out # 18432-1024
sh$ sudo mount -o loop -t hfsplus /dev/loop0 mount-point
sh$ ls mount-point
background.png  JavaFX 1.1 SDK.mpkg

Et voilà! L'image disque du fichier .dmg est montée sur ma machine Linux. Super! Enfin, sauf que les fichiers qui m'intéressent sont dans un paquet MacOS X (le dossier .mpkg que l'on voit dans le résultat de la commande ls). Bon ben ça n'est pas tout de suite que je vais jouer avec JavaFX...

Extraire sous Linux les données d'un méta-package Mac OS X

Si comme moi vous n'avez pas de chance, et que les données que vous souhaitez récupérer sur votre machine Linux sont encapsulées dans un méta-package (dossier .mpkg), vous pouvez peut-être vous en tirer avec la procédure suivante.

Tout d'abord, il faut explorer le contenu du dossier .mpkg à la recherche d'une archive contenant effectivement les données qui vous intéressent. C'est une archive GZip. Un find devrait faire l'affaire:

sh$ ls mount-point
background.png  JavaFX 1.1 SDK.mpkg
sh$ find 'mount-point/JavaFX 1.1 SDK.mpkg' -name '*.gz'
mount-point/JavaFX 1.1 SDK.mpkg/Contents/Packages/javafxsdk.pkg/Contents/Archive.pax.gz

Un seul '.gz' dans le package. Là je n'ai pas le choix. Les données qui m'intéressent sont forcément là-dedans. Hop: copie, décompression.

sh$ mkdir extract
sh$ cp 'mount-point/JavaFX 1.1 SDK.mpkg/Contents/Packages/javafxsdk.pkg/Contents/Archive.pax.gz' extract
sh$ cd extract
sh$ gunzip Archive.pax.gz
sh$ ls
Archive.pax

Reste à savoir ce qu'est ce fichier ".pax". La commande file vient à notre rescousse:

sh$ file Archive.pax
Archive.pax: ASCII cpio archive (pre-SVR4 or odc)

D'accord: c'est une archive cpio. Maintenant, c'est facile:

sh$ cpio -id < Archive.pax
90696 blocks
sh$ ls
Archive.pax     lib          samples                      timestamp
bin             LICENSE.txt  servicetag
COPYRIGHT.html  profiles     src.zip
docs            README.html  THIRDPARTYLICENSEREADME.txt
sh$ find . -name javafxc
./bin/javafxc

Enfin: j'ai récupéré le SDK JavaFX. Ca a été un peu laborieux, mais finalement c'est fait. Je vais enfin pouvoir essayer JavaFX. Mais ceci est une autre histoire...