/* hfs.c - HFS. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/* HFS is documented at
GRUB_MOD_LICENSE ("GPLv3+");
/* The two supported filesystems a record can have. */
enum
{
};
/* Catalog node ID (CNID). */
enum grub_hfs_cnid_type
{
};
/* A node descriptor. This is the header of every node. */
struct grub_hfs_node
{
} __attribute__ ((packed));
/* The head of the B*-Tree. */
struct grub_hfs_treeheader
{
/* The number of the first node. */
} __attribute__ ((packed));
/* The state of a mounted HFS filesystem. */
struct grub_hfs_data
{
int fileid;
int size;
int ext_root;
int ext_size;
int cat_root;
int cat_size;
int blksz;
int log2_blksz;
int rootdir;
};
/* The key as used on disk in a catalog tree. This is used to lookup
struct grub_hfs_catalog_key
{
/* Filename length. */
/* Filename. */
} __attribute__ ((packed));
/* The key as used on disk in a extent overflow tree. Using this key
the extents can be looked up using a fileid and logical start block
as index. */
struct grub_hfs_extent_key
{
/* The kind of fork. This is used to store meta information like
icons, attributes, etc. We will only use the datafork, which is
0. */
} __attribute__ ((packed));
/* A directory record. This is used to find out the directory ID. */
struct grub_hfs_dirrec
{
/* For a directory, type == 1. */
} __attribute__ ((packed));
/* Information about a file. */
struct grub_hfs_filerec
{
/* For a file, type == 2. */
/* The first 3 extents of the file. The other extents can be found
in the extent overflow file. */
} __attribute__ ((packed));
/* A record descriptor, both key and data, used to pass to call back
functions. */
struct grub_hfs_record
{
void *key;
int keylen;
void *data;
int datalen;
};
static int grub_hfs_find_node (struct grub_hfs_data *, char *,
grub_uint32_t, int, char *, int);
/* Find block BLOCK of the file FILE in the mounted UFS filesystem
DATA. The first 3 extents are described by DAT. If cache is set,
using caching to improve non-random reads. */
static unsigned int
{
int pos = 0;
int tree = 0;
static int cache_file = 0;
static int cache_pos = 0;
{
}
for (;;)
{
int i;
/* Try all 3 extents. */
for (i = 0; i < 3; i++)
{
/* Check if the block is stored in this extent. */
{
/* If the cache is enabled, store the current position
in the tree. */
{
cache_file = file;
}
}
/* Try the next extent. */
}
/* Lookup the block in the extent overflow file. */
tree = 1;
if (grub_errno)
return 0;
}
}
/* Read LEN bytes from the file described by DATA starting with byte
POS. Return the amount of read bytes in READ. */
static grub_ssize_t
{
grub_off_t i;
{
int skipfirst = 0;
if (grub_errno)
return -1;
/* Last block. */
if (i == blockcnt - 1)
{
/* The last portion is exactly EXT2_BLOCK_SIZE (data). */
if (! blockend)
}
/* First block. */
{
}
/* If the block number is 0 this block is not stored on disk but
is zero filled instead. */
if (blknr)
{
if (grub_errno)
return -1;
}
}
return len;
}
/* Mount the filesystem on the disk DISK. */
static struct grub_hfs_data *
{
int first_block;
struct
{
} treehead;
if (!data)
return 0;
/* Read the superblock. */
goto fail;
/* Check if this is a HFS filesystem. */
{
goto fail;
}
/* Check if this is an embedded HFS+ filesystem. */
{
goto fail;
}
/* Lookup the root node of the extent overflow tree. */
goto fail;
/* Lookup the root node of the catalog tree. */
goto fail;
/* Lookup the root directory node in the catalog tree using the
volume name. */
{
goto fail;
}
if (grub_errno)
goto fail;
return data;
fail:
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
return 0;
}
/* Compare the K1 and K2 catalog file keys using HFS character ordering. */
static int
struct grub_hfs_catalog_key *k2)
{
/* Taken from hfsutils 3.2.6 and converted to a readable form */
[0x00] = 0,
[0x01] = 1,
[0x02] = 2,
[0x03] = 3,
[0x04] = 4,
[0x05] = 5,
[0x06] = 6,
[0x07] = 7,
[0x08] = 8,
[0x09] = 9,
[0x0A] = 10,
[0x0B] = 11,
[0x0C] = 12,
[0x0D] = 13,
[0x0E] = 14,
[0x0F] = 15,
[0x10] = 16,
[0x11] = 17,
[0x12] = 18,
[0x13] = 19,
[0x14] = 20,
[0x15] = 21,
[0x16] = 22,
[0x17] = 23,
[0x18] = 24,
[0x19] = 25,
[0x1A] = 26,
[0x1B] = 27,
[0x1C] = 28,
[0x1D] = 29,
[0x1E] = 30,
[0x1F] = 31,
[' '] = 32, [0xCA] = 32,
['!'] = 33,
['"'] = 34,
[0xD2] = 35,
[0xD3] = 36,
[0xC7] = 37,
[0xC8] = 38,
['#'] = 39,
['$'] = 40,
['%'] = 41,
['&'] = 42,
['\''] = 43,
[0xD4] = 44,
[0xD5] = 45,
['('] = 46,
[')'] = 47,
['*'] = 48,
['+'] = 49,
[','] = 50,
['-'] = 51,
['.'] = 52,
['/'] = 53,
['0'] = 54,
['1'] = 55,
['2'] = 56,
['3'] = 57,
['4'] = 58,
['5'] = 59,
['6'] = 60,
['7'] = 61,
['8'] = 62,
['9'] = 63,
[':'] = 64,
[';'] = 65,
['<'] = 66,
['='] = 67,
['>'] = 68,
['?'] = 69,
['@'] = 70,
['A'] = 71, ['a'] = 71,
[0x88] = 72, [0xCB] = 72,
[0x80] = 73, [0x8A] = 73,
[0x8B] = 74, [0xCC] = 74,
[0x81] = 75, [0x8C] = 75,
[0xAE] = 76, [0xBE] = 76,
['`'] = 77,
[0x87] = 78,
[0x89] = 79,
[0xBB] = 80,
['B'] = 81, ['b'] = 81,
['C'] = 82, ['c'] = 82,
[0x82] = 83, [0x8D] = 83,
['D'] = 84, ['d'] = 84,
['E'] = 85, ['e'] = 85,
[0x83] = 86, [0x8E] = 86,
[0x8F] = 87,
[0x90] = 88,
[0x91] = 89,
['F'] = 90, ['f'] = 90,
['G'] = 91, ['g'] = 91,
['H'] = 92, ['h'] = 92,
['I'] = 93, ['i'] = 93,
[0x92] = 94,
[0x93] = 95,
[0x94] = 96,
[0x95] = 97,
['J'] = 98, ['j'] = 98,
['K'] = 99, ['k'] = 99,
['L'] = 100, ['l'] = 100,
['M'] = 101, ['m'] = 101,
['N'] = 102, ['n'] = 102,
[0x84] = 103, [0x96] = 103,
['O'] = 104, ['o'] = 104,
[0x85] = 105, [0x9A] = 105,
[0x9B] = 106, [0xCD] = 106,
[0xAF] = 107, [0xBF] = 107,
[0xCE] = 108, [0xCF] = 108,
[0x97] = 109,
[0x98] = 110,
[0x99] = 111,
[0xBC] = 112,
['P'] = 113, ['p'] = 113,
['Q'] = 114, ['q'] = 114,
['R'] = 115, ['r'] = 115,
['S'] = 116, ['s'] = 116,
[0xA7] = 117,
['T'] = 118, ['t'] = 118,
['U'] = 119, ['u'] = 119,
[0x86] = 120, [0x9F] = 120,
[0x9C] = 121,
[0x9D] = 122,
[0x9E] = 123,
['V'] = 124, ['v'] = 124,
['W'] = 125, ['w'] = 125,
['X'] = 126, ['x'] = 126,
['Y'] = 127, ['y'] = 127,
[0xD8] = 128,
['Z'] = 129, ['z'] = 129,
['['] = 130,
['\\'] = 131,
[']'] = 132,
['^'] = 133,
['_'] = 134,
['{'] = 135,
['|'] = 136,
['}'] = 137,
['~'] = 138,
[0x7F] = 139,
[0xA0] = 140,
[0xA1] = 141,
[0xA2] = 142,
[0xA3] = 143,
[0xA4] = 144,
[0xA5] = 145,
[0xA6] = 146,
[0xA8] = 147,
[0xA9] = 148,
[0xAA] = 149,
[0xAB] = 150,
[0xAC] = 151,
[0xAD] = 152,
[0xB0] = 153,
[0xB1] = 154,
[0xB2] = 155,
[0xB3] = 156,
[0xB4] = 157,
[0xB5] = 158,
[0xB6] = 159,
[0xB7] = 160,
[0xB8] = 161,
[0xB9] = 162,
[0xBA] = 163,
[0xBD] = 164,
[0xC0] = 165,
[0xC1] = 166,
[0xC2] = 167,
[0xC3] = 168,
[0xC4] = 169,
[0xC5] = 170,
[0xC6] = 171,
[0xC9] = 172,
[0xD0] = 173,
[0xD1] = 174,
[0xD6] = 175,
[0xD7] = 176,
[0xD9] = 177,
[0xDA] = 178,
[0xDB] = 179,
[0xDC] = 180,
[0xDD] = 181,
[0xDE] = 182,
[0xDF] = 183,
[0xE0] = 184,
[0xE1] = 185,
[0xE2] = 186,
[0xE3] = 187,
[0xE4] = 188,
[0xE5] = 189,
[0xE6] = 190,
[0xE7] = 191,
[0xE8] = 192,
[0xE9] = 193,
[0xEA] = 194,
[0xEB] = 195,
[0xEC] = 196,
[0xED] = 197,
[0xEE] = 198,
[0xEF] = 199,
[0xF0] = 200,
[0xF1] = 201,
[0xF2] = 202,
[0xF3] = 203,
[0xF4] = 204,
[0xF5] = 205,
[0xF6] = 206,
[0xF7] = 207,
[0xF8] = 208,
[0xF9] = 209,
[0xFA] = 210,
[0xFB] = 211,
[0xFC] = 212,
[0xFD] = 213,
[0xFE] = 214,
[0xFF] = 215,
};
int i;
int cmp;
if (cmp != 0)
return cmp;
for (i = 0; i < minlen; i++)
{
if (cmp != 0)
return cmp;
}
/* Shorter strings precede long ones. */
}
/* Compare the K1 and K2 extent overflow file keys. */
static int
struct grub_hfs_extent_key *k2)
{
if (cmp == 0)
if (cmp == 0)
return cmp;
}
/* Iterate the records in the node with index IDX in the mounted HFS
filesystem DATA. This node holds data of the type TYPE (0 =
catalog node, 1 = extent overflow node). If this is set, continue
iterating to the next node. For every records, call NODE_HOOK. */
static grub_err_t
struct grub_hfs_record *))
{
union
{
} node;
do
{
int i;
int blk;
/* Read the node into memory. */
if (grub_errno)
return grub_errno;
return grub_errno;
/* Iterate over all records in this node. */
{
struct pointer
{
{
};
return 0;
}
return 0;
}
/* Lookup a record in the mounted filesystem DATA using the key KEY.
The index of the node on top of the tree is IDX. The tree is of
the type TYPE (0 = catalog node, 1 = extent overflow node). Return
the data in DATAR with a maximum length of DATALEN. */
static int
{
int isleaf = 0;
int done = 0;
{
if (type == 0)
else
/* If the key is smaller or equal to the current node, mark the
entry. In case of a non-leaf mode it will be used to lookup
the rest of the tree. */
if (cmp <= 0)
else /* The key can not be found in the tree. */
return 1;
/* Check if this node is a leaf node. */
{
isleaf = 1;
/* Found it!!!! */
if (cmp == 0)
{
done = 1;
return 1;
}
}
return 0;
}
do
{
found = -1;
return 0;
if (found == -1)
return 0;
} while (! isleaf);
return done;
}
/* Iterate over the directory with the id DIR. The tree is searched
starting with the node ROOT_IDX. For every entry in this directory
call HOOK. */
static grub_err_t
{
int isleaf = 0;
int next = 0;
/* The lowest key possible with DIR as root directory. */
struct grub_hfs_record *);
{
{
isleaf = 1;
/* An entry was found. */
}
return 0;
}
struct grub_hfs_record *rec)
{
/* Stop when the entries do not match anymore. */
return 1;
}
do
{
found = -1;
return grub_errno;
if (found == -1)
return 0;
} while (! isleaf);
/* If there was a matching record in this leaf node, continue the
iteration until the last record was found. */
return grub_errno;
}
{
/* 80 */ "\xc3\x84",
/* 81 */ "\xc3\x85",
/* 82 */ "\xc3\x87",
/* 83 */ "\xc3\x89",
/* 84 */ "\xc3\x91",
/* 85 */ "\xc3\x96",
/* 86 */ "\xc3\x9c",
/* 87 */ "\xc3\xa1",
/* 88 */ "\xc3\xa0",
/* 89 */ "\xc3\xa2",
/* 8A */ "\xc3\xa4",
/* 8B */ "\xc3\xa3",
/* 8C */ "\xc3\xa5",
/* 8D */ "\xc3\xa7",
/* 8E */ "\xc3\xa9",
/* 8F */ "\xc3\xa8",
/* 90 */ "\xc3\xaa",
/* 91 */ "\xc3\xab",
/* 92 */ "\xc3\xad",
/* 93 */ "\xc3\xac",
/* 94 */ "\xc3\xae",
/* 95 */ "\xc3\xaf",
/* 96 */ "\xc3\xb1",
/* 97 */ "\xc3\xb3",
/* 98 */ "\xc3\xb2",
/* 99 */ "\xc3\xb4",
/* 9A */ "\xc3\xb6",
/* 9B */ "\xc3\xb5",
/* 9C */ "\xc3\xba",
/* 9D */ "\xc3\xb9",
/* 9E */ "\xc3\xbb",
/* 9F */ "\xc3\xbc",
/* A0 */ "\xe2\x80\xa0",
/* A1 */ "\xc2\xb0",
/* A2 */ "\xc2\xa2",
/* A3 */ "\xc2\xa3",
/* A4 */ "\xc2\xa7",
/* A5 */ "\xe2\x80\xa2",
/* A6 */ "\xc2\xb6",
/* A7 */ "\xc3\x9f",
/* A8 */ "\xc2\xae",
/* A9 */ "\xc2\xa9",
/* AA */ "\xe2\x84\xa2",
/* AB */ "\xc2\xb4",
/* AC */ "\xc2\xa8",
/* AD */ "\xe2\x89\xa0",
/* AE */ "\xc3\x86",
/* AF */ "\xc3\x98",
/* B0 */ "\xe2\x88\x9e",
/* B1 */ "\xc2\xb1",
/* B2 */ "\xe2\x89\xa4",
/* B3 */ "\xe2\x89\xa5",
/* B4 */ "\xc2\xa5",
/* B5 */ "\xc2\xb5",
/* B6 */ "\xe2\x88\x82",
/* B7 */ "\xe2\x88\x91",
/* B8 */ "\xe2\x88\x8f",
/* B9 */ "\xcf\x80",
/* BA */ "\xe2\x88\xab",
/* BB */ "\xc2\xaa",
/* BC */ "\xc2\xba",
/* BD */ "\xce\xa9",
/* BE */ "\xc3\xa6",
/* BF */ "\xc3\xb8",
/* C0 */ "\xc2\xbf",
/* C1 */ "\xc2\xa1",
/* C2 */ "\xc2\xac",
/* C3 */ "\xe2\x88\x9a",
/* C4 */ "\xc6\x92",
/* C5 */ "\xe2\x89\x88",
/* C6 */ "\xe2\x88\x86",
/* C7 */ "\xc2\xab",
/* C8 */ "\xc2\xbb",
/* C9 */ "\xe2\x80\xa6",
/* CA */ "\xc2\xa0",
/* CB */ "\xc3\x80",
/* CC */ "\xc3\x83",
/* CD */ "\xc3\x95",
/* CE */ "\xc5\x92",
/* CF */ "\xc5\x93",
/* D0 */ "\xe2\x80\x93",
/* D1 */ "\xe2\x80\x94",
/* D2 */ "\xe2\x80\x9c",
/* D3 */ "\xe2\x80\x9d",
/* D4 */ "\xe2\x80\x98",
/* D5 */ "\xe2\x80\x99",
/* D6 */ "\xc3\xb7",
/* D7 */ "\xe2\x97\x8a",
/* D8 */ "\xc3\xbf",
/* D9 */ "\xc5\xb8",
/* DA */ "\xe2\x81\x84",
/* DB */ "\xe2\x82\xac",
/* DC */ "\xe2\x80\xb9",
/* DD */ "\xe2\x80\xba",
/* DE */ "\xef\xac\x81",
/* DF */ "\xef\xac\x82",
/* E0 */ "\xe2\x80\xa1",
/* E1 */ "\xc2\xb7",
/* E2 */ "\xe2\x80\x9a",
/* E3 */ "\xe2\x80\x9e",
/* E4 */ "\xe2\x80\xb0",
/* E5 */ "\xc3\x82",
/* E6 */ "\xc3\x8a",
/* E7 */ "\xc3\x81",
/* E8 */ "\xc3\x8b",
/* E9 */ "\xc3\x88",
/* EA */ "\xc3\x8d",
/* EB */ "\xc3\x8e",
/* EC */ "\xc3\x8f",
/* ED */ "\xc3\x8c",
/* EE */ "\xc3\x93",
/* EF */ "\xc3\x94",
/* F0 */ "\xef\xa3\xbf",
/* F1 */ "\xc3\x92",
/* F2 */ "\xc3\x9a",
/* F3 */ "\xc3\x9b",
/* F4 */ "\xc3\x99",
/* F5 */ "\xc4\xb1",
/* F6 */ "\xcb\x86",
/* F7 */ "\xcb\x9c",
/* F8 */ "\xc2\xaf",
/* F9 */ "\xcb\x98",
/* FA */ "\xcb\x99",
/* FB */ "\xcb\x9a",
/* FC */ "\xc2\xb8",
/* FD */ "\xcb\x9d",
/* FE */ "\xcb\x9b",
/* FF */ "\xcb\x87",
};
static void
{
{
/* Translate '/' to ':' as per HFS spec. */
if (*iptr == '/')
{
*optr++ = ':';
continue;
}
if (!(*iptr & 0x80))
{
continue;
}
}
*optr = 0;
}
static grub_ssize_t
{
{
int i, clen;
/* Translate ':' to '/' as per HFS spec. */
if (*iptr == ':')
{
*optr++ = '/';
iptr++;
continue;
}
if (!(*iptr & 0x80))
{
continue;
}
clen = 2;
clen++;
for (i = 0; i < 0x80; i++)
break;
if (i == 0x80)
break;
*optr++ = i | 0x80;
}
/* Too long or not encodable. */
if (*iptr)
return -1;
}
/* Find a file or directory with the pathname PATH in the filesystem
DATA. Return the file record in RETDATA when it is non-zero.
Return the directory number in RETINODE when it is non-zero. */
static grub_err_t
{
char *next;
char *origpath;
union {
} fdrec;
if (path[0] != '/')
{
return 0;
}
if (!origpath)
return grub_errno;
while (*path == '/')
path++;
{
{
goto fail;
}
/* Isolate a part of the path. */
if (next)
{
while (*next == '/')
*(next++) = '\0';
}
if (slen < 0)
{
goto fail;
}
/* Lookup this node. */
{
goto fail;
}
if (grub_errno)
goto fail;
}
if (retdata)
if (retinode)
fail:
return grub_errno;
}
static grub_err_t
const struct grub_dirhook_info *info))
{
int inode;
{
{
}
{
}
return 0;
}
if (!data)
goto fail;
/* First the directory ID for the directory. */
goto fail;
{
goto fail;
}
fail:
return grub_errno;
}
/* Open a file named NAME and initialize FILE. */
static grub_err_t
{
{
return grub_errno;
}
{
return grub_errno;
}
return 0;
}
static grub_ssize_t
{
}
static grub_err_t
{
return 0;
}
static grub_err_t
{
if (data)
{
if (*label)
len + 1);
}
else
*label = 0;
return grub_errno;
}
static grub_err_t
{
if (data)
else
*tm = 0;
return grub_errno;
}
static grub_err_t
{
{
(unsigned long long)
}
else
return grub_errno;
}
{
.name = "hfs",
.dir = grub_hfs_dir,
.open = grub_hfs_open,
.read = grub_hfs_read,
.close = grub_hfs_close,
.label = grub_hfs_label,
.uuid = grub_hfs_uuid,
.mtime = grub_hfs_mtime,
.next = 0
};
{
}
{
}