Exemplo n.º 1
0
/* Search for the block FILEBLOCK inside the file NODE.  Return the
   blocknumber of this block on disk.  */
static grub_disk_addr_t
grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
{
  struct grub_hfsplus_btnode *nnode = 0;
  grub_disk_addr_t blksleft = fileblock;
  struct grub_hfsplus_extent *extents = &node->extents[0];

  while (1)
    {
      struct grub_hfsplus_extkey *key;
      struct grub_hfsplus_key_internal extoverflow;
      grub_disk_addr_t blk;
      grub_off_t ptr;

      /* Try to find this block in the current set of extents.  */
      blk = grub_hfsplus_find_block (extents, &blksleft);

      /* The previous iteration of this loop allocated memory.  The
	 code above used this memory, it can be freed now.  */
      grub_free (nnode);
      nnode = 0;

      if (blk != 0xffffffffffffffffULL)
	return blk;

      /* For the extent overflow file, extra extents can't be found in
	 the extent overflow file.  If this happens, you found a
	 bug...  */
      if (node->fileid == GRUB_HFSPLUS_FILEID_OVERFLOW)
	{
	  grub_error (GRUB_ERR_READ_ERROR,
		      "extra extents found in an extend overflow file");
	  break;
	}

      /* Set up the key to look for in the extent overflow file.  */
      extoverflow.extkey.fileid = node->fileid;
      extoverflow.extkey.type = 0;
      extoverflow.extkey.start = fileblock - blksleft;

      if (grub_hfsplus_btree_search (&node->data->extoverflow_tree,
				     &extoverflow,
				     grub_hfsplus_cmp_extkey, &nnode, &ptr))
	{
	  grub_error (GRUB_ERR_READ_ERROR,
		      "no block found for the file id 0x%x and the block offset 0x%x",
		      node->fileid, fileblock);
	  break;
	}

      /* The extent overflow file has 8 extents right after the key.  */
      key = (struct grub_hfsplus_extkey *)
	grub_hfsplus_btree_recptr (&node->data->extoverflow_tree, nnode, ptr);
      extents = (struct grub_hfsplus_extent *) (key + 1);

      /* The block wasn't found.  Perhaps the next iteration will find
	 it.  The last block we found is stored in BLKSLEFT now.  */
    }

  grub_free (nnode);

  /* Too bad, you lose.  */
  return -1;
}
Exemplo n.º 2
0
static grub_err_t 
hfsplus_open_compressed_real (struct grub_hfsplus_file *node)
{
  grub_err_t err;
  struct grub_hfsplus_btnode *attr_node;
  grub_off_t attr_off;
  struct grub_hfsplus_key_internal key;
  struct grub_hfsplus_attr_header *attr_head;
  struct grub_hfsplus_compress_attr *cmp_head;
#define c grub_cpu_to_be16_compile_time
  const grub_uint16_t compress_attr_name[] =
    {
      c('c'), c('o'), c('m'), c('.'), c('a'), c('p'), c('p'), c('l'), c('e'),
      c('.'), c('d'), c('e'), c('c'), c('m'), c('p'), c('f'), c('s') };
#undef c
  if (node->size)
    return 0;

  key.attrkey.cnid = node->fileid;
  key.attrkey.namelen = sizeof (compress_attr_name) / sizeof (compress_attr_name[0]);
  key.attrkey.name = compress_attr_name;

  err = grub_hfsplus_btree_search (&node->data->attr_tree, &key,
				   grub_hfsplus_cmp_attrkey,
				   &attr_node, &attr_off);
  if (err || !attr_node)
    {
      grub_errno = 0;
      return 0;
    }

  attr_head = (struct grub_hfsplus_attr_header *)
    ((char *) grub_hfsplus_btree_recptr (&node->data->attr_tree,
					 attr_node, attr_off)
     + sizeof (struct grub_hfsplus_attrkey) + sizeof (compress_attr_name));
  if (attr_head->type != 0x10
      || !(attr_head->size & grub_cpu_to_be64_compile_time(~0xfULL)))
    {
      grub_free (attr_node);
      return 0;
    }
  cmp_head = (struct grub_hfsplus_compress_attr *) (attr_head + 1);
  if (cmp_head->magic != grub_cpu_to_be32_compile_time (0x66706d63))
    {
      grub_free (attr_node);
      return 0;
    }
  node->size = grub_le_to_cpu32 (cmp_head->uncompressed_inline_size);

  if (cmp_head->type == grub_cpu_to_le32_compile_time (HFSPLUS_COMPRESSION_RESOURCE))
    {
      grub_uint32_t index_size;
      node->compressed = 2;

      if (grub_hfsplus_read_file (node, 0, 0,
				  0x104, sizeof (index_size),
				  (char *) &index_size)
	  != 4)
	{
	  node->compressed = 0;
	  grub_free (attr_node);
	  grub_errno = 0;
	  return 0;
	}
      node->compress_index_size = grub_le_to_cpu32 (index_size);
      node->compress_index = grub_malloc (node->compress_index_size
					  * sizeof (node->compress_index[0]));
      if (!node->compress_index)
	{
	  node->compressed = 0;
	  grub_free (attr_node);
	  return grub_errno;
	}
      if (grub_hfsplus_read_file (node, 0, 0,
				  0x104 + sizeof (index_size),
				  node->compress_index_size
				  * sizeof (node->compress_index[0]),
				  (char *) node->compress_index)
	  != (grub_ssize_t) (node->compress_index_size
			     * sizeof (node->compress_index[0])))
	{
	  node->compressed = 0;
	  grub_free (attr_node);
	  grub_free (node->compress_index);
	  grub_errno = 0;
	  return 0;
	}

      node->cbuf_block = -1;

      node->cbuf = grub_malloc (HFSPLUS_COMPRESS_BLOCK_SIZE);
      grub_free (attr_node);
      if (!node->cbuf)
	{
	  node->compressed = 0;
	  grub_free (node->compress_index);
	  return grub_errno;
	}
      return 0;
    }
  if (cmp_head->type != HFSPLUS_COMPRESSION_INLINE)
    {
      grub_free (attr_node);
      return 0;
    }

  node->cbuf = grub_malloc (node->size);
  if (!node->cbuf)
    return grub_errno;

  if (grub_zlib_decompress ((char *) (cmp_head + 1),
			    grub_cpu_to_be64 (attr_head->size)
			    - sizeof (*cmp_head), 0,
			    node->cbuf, node->size) < 0)
    return grub_errno;
  node->compressed = 1;
  return 0;
}