/* hfsplus.c - HFS+ Filesystem. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 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 http://developer.apple.com/technotes/tn/tn1150.html */
GRUB_MOD_LICENSE ("GPLv3+");
/* A HFS+ extent. */
struct grub_hfsplus_extent
{
/* The first block of a file on disk. */
/* The amount of blocks described by this extent. */
} __attribute__ ((packed));
/* The descriptor of a fork. */
struct grub_hfsplus_forkdata
{
} __attribute__ ((packed));
/* The HFS+ Volume Header. */
struct grub_hfsplus_volheader
{
} __attribute__ ((packed));
/* The type of node. */
{
};
struct grub_hfsplus_btnode
{
} __attribute__ ((packed));
/* The header of a HFS+ B+ Tree. */
struct grub_hfsplus_btheader
{
} __attribute__ ((packed));
/* The on disk layout of a catalog key. */
struct grub_hfsplus_catkey
{
} __attribute__ ((packed));
/* The on disk layout of an extent overflow file key. */
struct grub_hfsplus_extkey
{
} __attribute__ ((packed));
struct grub_hfsplus_key
{
union
{
};
} __attribute__ ((packed));
struct grub_hfsplus_catfile
{
} __attribute__ ((packed));
/* Filetype information as used in inodes. */
/* Some pre-defined file IDs. */
{
};
/* Internal representation of a catalog key. */
struct grub_hfsplus_catkey_internal
{
};
/* Internal representation of an extent overflow key. */
struct grub_hfsplus_extkey_internal
{
};
struct grub_hfsplus_key_internal
{
union
{
};
};
struct grub_fshelp_node
{
};
struct grub_hfsplus_btree
{
/* Catalog file node. */
};
/* Information about a "mounted" HFS+ filesystem. */
struct grub_hfsplus_data
{
unsigned int log2blksize;
/* This is the offset into the physical disk for an embedded HFS+
filesystem (one inside a plain HFS wrapper). */
int case_sensitive;
};
/* Return the offset of the record with the index INDEX, in the node
NODE which is part of the B+ tree BTREE. */
static inline grub_off_t
{
void *recptr;
}
/* Return a pointer to the record with the index INDEX, in the node
NODE which is part of the B+ tree BTREE. */
static inline struct grub_hfsplus_key *
{
}
/* Find the extent that points to FILEBLOCK. If it is not in one of
the 8 extents described by EXTENT, return -1. In that case set
FILEBLOCK to the next block. */
static grub_disk_addr_t
{
int i;
/* First lookup the file in the given extents. */
for (i = 0; i < 8; i++)
{
}
return 0xffffffffffffffffULL;
}
static grub_err_t
struct grub_hfsplus_key_internal *key,
struct grub_hfsplus_key_internal *keyb),
struct grub_hfsplus_btnode **matchnode,
struct grub_hfsplus_key_internal *keyb);
/* Search for the block FILEBLOCK inside the file NODE. Return the
blocknumber of this block on disk. */
static grub_disk_addr_t
{
while (1)
{
/* Try to find this block in the current set of extents. */
/* The previous iteration of this loop allocated memory. The
code above used this memory, it can be freed now. */
nnode = 0;
if (blk != 0xffffffffffffffffULL)
return (blk
- GRUB_DISK_SECTOR_BITS)));
/* For the extent overflow file, extra extents can't be found in
the extent overflow file. If this happens, you found a
bug... */
{
"extra extents found in an extend overflow file");
break;
}
/* Set up the key to look for in the extent overflow file. */
{
"no block found for the file id 0x%x and the block offset 0x%x",
break;
}
/* The extent overflow file has 8 extents right after the key. */
key = (struct grub_hfsplus_extkey *)
/* The block wasn't found. Perhaps the next iteration will find
it. The last block we found is stored in BLKSLEFT now. */
}
/* Too bad, you lose. */
return -1;
}
/* 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
{
}
static struct grub_hfsplus_data *
{
union {
} volheader;
if (!data)
return 0;
/* Read the bootblock. */
&volheader);
if (grub_errno)
goto fail;
data->embedded_offset = 0;
{
/* See if there's an embedded HFS+ filesystem. */
{
goto fail;
}
/* Calculate the offset needed to translate HFS+ sector numbers. */
* (ablk_size >> GRUB_DISK_SECTOR_BITS));
if (grub_errno)
goto fail;
}
/* Make sure this is an HFS+ filesystem. XXX: Do we really support
HFX? */
{
goto fail;
}
&data->log2blksize))
goto fail;
/* Make a new node for the catalog tree. */
/* Make a new node for the extent overflow file. */
/* Read the essential information about the trees. */
sizeof (struct grub_hfsplus_btnode),
goto fail;
sizeof (struct grub_hfsplus_btnode),
goto fail;
goto fail;
return data;
fail:
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
return 0;
}
/* Compare the on disk catalog key KEYA with the catalog key we are
looking for (KEYB). */
static int
struct grub_hfsplus_key_internal *keyb)
{
int diff;
/* Safe unsigned comparison */
return 1;
return -1;
if (diff == 0)
return diff;
}
/* Compare the on disk catalog key KEYA with the catalog key we are
looking for (KEYB). */
static int
struct grub_hfsplus_key_internal *keyb)
{
/* Safe unsigned comparison */
return 1;
return -1;
return 0;
}
/* Compare the on disk extent overflow key KEYA with the extent
overflow key we are looking for (KEYB). */
static int
struct grub_hfsplus_key_internal *keyb)
{
/* Safe unsigned comparison */
return 1;
return -1;
return 1;
return -1;
return 0;
}
static char *
{
char *symlink;
if (!symlink)
return 0;
{
return 0;
}
return symlink;
}
static int
struct grub_hfsplus_btnode *first_node,
{
for (;;)
{
/* Iterate over all records in this node. */
{
return 1;
}
if (! first_node->next)
break;
return 1;
/* Don't skip any record in the next iteration. */
first_rec = 0;
}
return 0;
}
/* Lookup the node described by KEY in the B+ Tree BTREE. Compare
keys using the function COMPARE_KEYS. When a match is found,
return the node in MATCHNODE and a pointer to the data in this node
in KEYOFFSET. MATCHNODE should be freed by the caller. */
static grub_err_t
struct grub_hfsplus_key_internal *key,
struct grub_hfsplus_key_internal *keyb),
struct grub_hfsplus_btnode **matchnode,
{
char *node;
if (! node)
return grub_errno;
while (1)
{
int match = 0;
/* Read a node. */
{
}
/* Find the record in this tree. */
{
/* The action that has to be taken depend on the type of
record. */
{
/* An exact match was found! */
return 0;
}
{
void *pointer;
/* The place where the key could have been found didn't
contain the key. This means that the previous match
is the one that should be followed. */
break;
/* Mark the last key which is lower or equal to the key
that we are looking for. The last match that is
found will be used to locate the child which can
contain the record. */
+ 2);
match = 1;
}
}
/* No match is found, no record with this key exists in the
tree. */
if (! match)
{
*matchnode = 0;
return 1;
}
}
}
static int
int NESTED_FUNC_ATTR
enum grub_fshelp_filetype filetype,
{
int ret = 0;
auto int list_nodes (void *record);
{
char *filename;
int i;
fileinfo =
(struct grub_hfsplus_catfile *) ((char *) record
% 2));
/* Stop iterating when the last directory entry is found. */
return 1;
/* Determine the type of the node that is found. */
{
if (mode == GRUB_HFSPLUS_FILEMODE_REG)
else if (mode == GRUB_HFSPLUS_FILEMODE_SYMLINK)
else
}
if (type == GRUB_FSHELP_UNKNOWN)
return 0;
* GRUB_MAX_UTF8_PER_UTF16 + 1);
if (! filename)
return 0;
/* Make sure the byte order of the UTF16 string is correct. */
{
/* If the name is obviously invalid, skip this node. */
return 0;
}
/* Restore the byte order to what it was previously. */
{
}
/* hfs+ is case insensitive. */
/* A valid node is found; setup the node and call the
callback function. */
return ret;
}
/* Create a key that points to the first entry in the directory. */
/* First lookup the first entry. */
return 0;
/* Iterate over all entries in this directory. */
return ret;
}
/* Open a file named NAME and initialize FILE. */
static grub_err_t
{
if (!data)
goto fail;
if (grub_errno)
goto fail;
return 0;
fail:
return grub_errno;
}
static grub_err_t
{
return GRUB_ERR_NONE;
}
/* Read LEN bytes data from FILE into BUF. */
static grub_ssize_t
{
}
static grub_err_t
const struct grub_dirhook_info *info))
{
enum grub_fshelp_filetype filetype,
enum grub_fshelp_filetype filetype,
{
}
if (!data)
goto fail;
/* Find the directory that should be opened. */
if (grub_errno)
goto fail;
/* Iterate over all entries in this directory. */
fail:
return grub_errno;
}
static grub_err_t
{
int i, label_len;
*label = 0;
if (!data)
return grub_errno;
/* Create a key that points to the label. */
/* First lookup the first entry. */
{
return 0;
}
catkey = (struct grub_hfsplus_catkey *)
for (i = 0; i < label_len; i++)
{
/* If the name is obviously invalid, skip this node. */
return 0;
}
if (! *label)
return grub_errno;
label_len) = '\0';
return GRUB_ERR_NONE;
}
/* Get mtime. */
static grub_err_t
{
if (!data)
*tm = 0;
else
return grub_errno;
}
static grub_err_t
{
if (data)
{
(unsigned long long)
}
else
return grub_errno;
}
{
.name = "hfsplus",
.dir = grub_hfsplus_dir,
#ifdef GRUB_UTIL
.reserved_first_sector = 1,
#endif
.next = 0
};
{
}
{
}