19428323dSchristos //
29428323dSchristos // hfs_misc.c - hfs routines
39428323dSchristos //
49428323dSchristos // Written by Eryk Vershen
59428323dSchristos //
69428323dSchristos
79428323dSchristos /*
89428323dSchristos * Copyright 2000 by Eryk Vershen
99428323dSchristos */
109428323dSchristos
119428323dSchristos // for *printf()
129428323dSchristos #include <stdio.h>
139428323dSchristos
149428323dSchristos // for malloc(), calloc() & free()
159428323dSchristos #ifndef __linux__
169428323dSchristos #include <stdlib.h>
179428323dSchristos #else
189428323dSchristos #include <malloc.h>
199428323dSchristos #endif
209428323dSchristos
219428323dSchristos // for strncpy() & strcmp()
229428323dSchristos #include <string.h>
239428323dSchristos // for O_RDONLY & O_RDWR
249428323dSchristos #include <fcntl.h>
259428323dSchristos // for errno
269428323dSchristos #include <errno.h>
279428323dSchristos
28*48a628aeSchristos #include <inttypes.h>
29*48a628aeSchristos
309428323dSchristos #include "hfs_misc.h"
319428323dSchristos #include "partition_map.h"
329428323dSchristos #include "convert.h"
339428323dSchristos #include "errors.h"
349428323dSchristos
359428323dSchristos
369428323dSchristos //
379428323dSchristos // Defines
389428323dSchristos //
399428323dSchristos #define MDB_OFFSET 2
409428323dSchristos #define HFS_SIG 0x4244 /* i.e 'BD' */
419428323dSchristos #define HFS_PLUS_SIG 0x482B /* i.e 'H+' */
429428323dSchristos
43*48a628aeSchristos #define get_align_long(x) (*(uint32_t*)(x))
449428323dSchristos
459428323dSchristos
469428323dSchristos //
479428323dSchristos // Types
489428323dSchristos //
499428323dSchristos typedef long long u64;
509428323dSchristos
519428323dSchristos typedef struct ExtDescriptor { // extent descriptor
52*48a628aeSchristos uint16_t xdrStABN; // first allocation block
53*48a628aeSchristos uint16_t xdrNumABlks; // number of allocation blocks
549428323dSchristos } ext_descriptor;
559428323dSchristos
569428323dSchristos typedef struct ExtDataRec {
579428323dSchristos ext_descriptor ed[3]; // extent data record
589428323dSchristos } ext_data_rec;
599428323dSchristos
609428323dSchristos /*
61*48a628aeSchristos * The crazy "uint16_t x[2]" stuff here is to get around the fact
629428323dSchristos * that I can't convince the Mac compiler to align on 32 bit
639428323dSchristos * quantities on 16 bit boundaries...
649428323dSchristos */
659428323dSchristos struct mdb_record { // master directory block
66*48a628aeSchristos uint16_t drSigWord; // volume signature
67*48a628aeSchristos uint16_t drCrDate[2]; // date and time of volume creation
68*48a628aeSchristos uint16_t drLsMod[2]; // date and time of last modification
69*48a628aeSchristos uint16_t drAtrb; // volume attributes
70*48a628aeSchristos uint16_t drNmFls; // number of files in root directory
71*48a628aeSchristos uint16_t drVBMSt; // first block of volume bitmap
72*48a628aeSchristos uint16_t drAllocPtr; // start of next allocation search
73*48a628aeSchristos uint16_t drNmAlBlks; // number of allocation blocks in volume
74*48a628aeSchristos uint32_t drAlBlkSiz; // size (in bytes) of allocation blocks
75*48a628aeSchristos uint32_t drClpSiz; // default clump size
76*48a628aeSchristos uint16_t drAlBlSt; // first allocation block in volume
77*48a628aeSchristos uint16_t drNxtCNID[2]; // next unused catalog node ID
78*48a628aeSchristos uint16_t drFreeBks; // number of unused allocation blocks
799428323dSchristos char drVN[28]; // volume name
80*48a628aeSchristos uint16_t drVolBkUp[2]; // date and time of last backup
81*48a628aeSchristos uint16_t drVSeqNum; // volume backup sequence number
82*48a628aeSchristos uint16_t drWrCnt[2]; // volume write count
83*48a628aeSchristos uint16_t drXTClpSiz[2]; // clump size for extents overflow file
84*48a628aeSchristos uint16_t drCTClpSiz[2]; // clump size for catalog file
85*48a628aeSchristos uint16_t drNmRtDirs; // number of directories in root directory
86*48a628aeSchristos uint32_t drFilCnt; // number of files in volume
87*48a628aeSchristos uint32_t drDirCnt; // number of directories in volume
88*48a628aeSchristos uint32_t drFndrInfo[8]; // information used by the Finder
899428323dSchristos #ifdef notdef
90*48a628aeSchristos uint16_t drVCSize; // size (in blocks) of volume cache
91*48a628aeSchristos uint16_t drVBMCSize; // size (in blocks) of volume bitmap cache
92*48a628aeSchristos uint16_t drCtlCSize; // size (in blocks) of common volume cache
939428323dSchristos #else
94*48a628aeSchristos uint16_t drEmbedSigWord; // type of embedded volume
959428323dSchristos ext_descriptor drEmbedExtent; // embedded volume extent
969428323dSchristos #endif
97*48a628aeSchristos uint16_t drXTFlSize[2]; // size of extents overflow file
989428323dSchristos ext_data_rec drXTExtRec; // extent record for extents overflow file
99*48a628aeSchristos uint16_t drCTFlSize[2]; // size of catalog file
1009428323dSchristos ext_data_rec drCTExtRec; // extent record for catalog file
1019428323dSchristos };
1029428323dSchristos
1039428323dSchristos
104*48a628aeSchristos typedef uint32_t HFSCatalogNodeID;
1059428323dSchristos
1069428323dSchristos typedef struct HFSPlusExtentDescriptor {
107*48a628aeSchristos uint32_t startBlock;
108*48a628aeSchristos uint32_t blockCount;
1099428323dSchristos } HFSPlusExtentDescriptor;
1109428323dSchristos
1119428323dSchristos typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8];
1129428323dSchristos
1139428323dSchristos typedef struct HFSPlusForkData {
1149428323dSchristos u64 logicalSize;
115*48a628aeSchristos uint32_t clumpSize;
116*48a628aeSchristos uint32_t totalBlocks;
1179428323dSchristos HFSPlusExtentRecord extents;
1189428323dSchristos } HFSPlusForkData;
1199428323dSchristos
1209428323dSchristos struct HFSPlusVolumeHeader {
121*48a628aeSchristos uint16_t signature;
122*48a628aeSchristos uint16_t version;
123*48a628aeSchristos uint32_t attributes;
124*48a628aeSchristos uint32_t lastMountedVersion;
125*48a628aeSchristos uint32_t reserved;
126*48a628aeSchristos uint32_t createDate;
127*48a628aeSchristos uint32_t modifyDate;
128*48a628aeSchristos uint32_t backupDate;
129*48a628aeSchristos uint32_t checkedDate;
130*48a628aeSchristos uint32_t fileCount;
131*48a628aeSchristos uint32_t folderCount;
132*48a628aeSchristos uint32_t blockSize;
133*48a628aeSchristos uint32_t totalBlocks;
134*48a628aeSchristos uint32_t freeBlocks;
135*48a628aeSchristos uint32_t nextAllocation;
136*48a628aeSchristos uint32_t rsrcClumpSize;
137*48a628aeSchristos uint32_t dataClumpSize;
1389428323dSchristos HFSCatalogNodeID nextCatalogID;
139*48a628aeSchristos uint32_t writeCount;
1409428323dSchristos u64 encodingsBitmap;
141*48a628aeSchristos uint8_t finderInfo[ 32];
1429428323dSchristos HFSPlusForkData allocationFile;
1439428323dSchristos HFSPlusForkData extentsFile;
1449428323dSchristos HFSPlusForkData catalogFile;
1459428323dSchristos HFSPlusForkData attributesFile;
1469428323dSchristos HFSPlusForkData startupFile;
1479428323dSchristos } HFSPlusVolumeHeader;
1489428323dSchristos
1499428323dSchristos
1509428323dSchristos //
1519428323dSchristos // Global Constants
1529428323dSchristos //
1539428323dSchristos
1549428323dSchristos
1559428323dSchristos //
1569428323dSchristos // Global Variables
1579428323dSchristos //
1589428323dSchristos
1599428323dSchristos
1609428323dSchristos //
1619428323dSchristos // Forward declarations
1629428323dSchristos //
163*48a628aeSchristos uint32_t embeded_offset(struct mdb_record *mdb, uint32_t sector);
164*48a628aeSchristos int read_partition_block(partition_map *entry, uint32_t num, char *buf);
1659428323dSchristos
1669428323dSchristos
1679428323dSchristos //
1689428323dSchristos // Routines
1699428323dSchristos //
170*48a628aeSchristos uint32_t
embeded_offset(struct mdb_record * mdb,uint32_t sector)171*48a628aeSchristos embeded_offset(struct mdb_record *mdb, uint32_t sector)
1729428323dSchristos {
173*48a628aeSchristos uint32_t e_offset;
1749428323dSchristos
1759428323dSchristos e_offset = mdb->drAlBlSt + mdb->drEmbedExtent.xdrStABN * (mdb->drAlBlkSiz / 512);
1769428323dSchristos
1779428323dSchristos return e_offset + sector;
1789428323dSchristos }
1799428323dSchristos
1809428323dSchristos
1819428323dSchristos char *
get_HFS_name(partition_map * entry,int * kind)1829428323dSchristos get_HFS_name(partition_map *entry, int *kind)
1839428323dSchristos {
1849428323dSchristos DPME *data;
1859428323dSchristos struct mdb_record *mdb;
1869428323dSchristos //struct HFSPlusVolumeHeader *mdb2;
1879428323dSchristos char *name = NULL;
1889428323dSchristos int len;
1899428323dSchristos
1909428323dSchristos *kind = kHFS_not;
1919428323dSchristos
1929428323dSchristos mdb = (struct mdb_record *) malloc(PBLOCK_SIZE);
1939428323dSchristos if (mdb == NULL) {
1949428323dSchristos error(errno, "can't allocate memory for MDB");
1959428323dSchristos return NULL;
1969428323dSchristos }
1979428323dSchristos
1989428323dSchristos data = entry->data;
1999428323dSchristos if (strcmp(data->dpme_type, kHFSType) == 0) {
2009428323dSchristos if (read_partition_block(entry, 2, (char *)mdb) == 0) {
201*48a628aeSchristos error(-1, "Can't read block %d from partition %d", 2, entry->disk_address);
2029428323dSchristos goto not_hfs;
2039428323dSchristos }
2049428323dSchristos if (mdb->drSigWord == HFS_PLUS_SIG) {
2059428323dSchristos // pure HFS Plus
206*48a628aeSchristos // printf("%lu HFS Plus\n", entry->disk_address);
2079428323dSchristos *kind = kHFS_plus;
2089428323dSchristos } else if (mdb->drSigWord != HFS_SIG) {
2099428323dSchristos // not HFS !!!
210*48a628aeSchristos // printf("%"PRIu32" not HFS\n", entry->disk_address);
2119428323dSchristos *kind = kHFS_not;
2129428323dSchristos } else if (mdb->drEmbedSigWord != HFS_PLUS_SIG) {
2139428323dSchristos // HFS
214*48a628aeSchristos // printf("%lu HFS\n", entry->disk_address);
2159428323dSchristos *kind = kHFS_std;
2169428323dSchristos len = mdb->drVN[0];
2179428323dSchristos name = (char *) malloc(len+1);
2189428323dSchristos strncpy(name, &mdb->drVN[1], len);
2199428323dSchristos name[len] = 0;
2209428323dSchristos } else {
2219428323dSchristos // embedded HFS plus
222*48a628aeSchristos // printf("%lu embedded HFS Plus\n", entry->disk_address);
2239428323dSchristos *kind = kHFS_embed;
2249428323dSchristos len = mdb->drVN[0];
2259428323dSchristos name = (char *) malloc(len+1);
2269428323dSchristos strncpy(name, &mdb->drVN[1], len);
2279428323dSchristos name[len] = 0;
2289428323dSchristos }
2299428323dSchristos }
2309428323dSchristos not_hfs:
2319428323dSchristos free(mdb);
2329428323dSchristos return name;
2339428323dSchristos }
2349428323dSchristos
2359428323dSchristos // really need a function to read block n from partition m
2369428323dSchristos
2379428323dSchristos int
read_partition_block(partition_map * entry,uint32_t num,char * buf)238*48a628aeSchristos read_partition_block(partition_map *entry, uint32_t num, char *buf)
2399428323dSchristos {
2409428323dSchristos DPME *data;
2419428323dSchristos partition_map_header * map;
242*48a628aeSchristos uint32_t base;
2439428323dSchristos u64 offset;
2449428323dSchristos
2459428323dSchristos map = entry->the_map;
2469428323dSchristos data = entry->data;
2479428323dSchristos base = data->dpme_pblock_start;
2489428323dSchristos
2499428323dSchristos if (num >= data->dpme_pblocks) {
2509428323dSchristos return 0;
2519428323dSchristos }
2529428323dSchristos offset = ((long long) base) * map->logical_block + num * 512;
2539428323dSchristos
2549428323dSchristos return read_media(map->m, offset, 512, (void *)buf);
2559428323dSchristos }
256