mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 17:40:15 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1118 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1118 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* bfs.c - The Bee File System.  */
 | |
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *  Copyright (C) 2010,2011  Free Software Foundation, Inc.
 | |
|  *
 | |
|  *  GRUB is free software: you can redistribute it and/or modify
 | |
|  *  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/>.
 | |
|  */
 | |
| /*
 | |
|   Based on the book "Practical File System Design by Dominic Giampaolo
 | |
|   with corrections and completitions based on Haiku code.
 | |
| */
 | |
| 
 | |
| #include <grub/err.h>
 | |
| #include <grub/file.h>
 | |
| #include <grub/mm.h>
 | |
| #include <grub/misc.h>
 | |
| #include <grub/disk.h>
 | |
| #include <grub/dl.h>
 | |
| #include <grub/types.h>
 | |
| #include <grub/i18n.h>
 | |
| #include <grub/fshelp.h>
 | |
| 
 | |
| GRUB_MOD_LICENSE ("GPLv3+");
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
| #define BTREE_ALIGN 4
 | |
| #define SUPERBLOCK  2
 | |
| #else
 | |
| #define BTREE_ALIGN 8
 | |
| #define SUPERBLOCK  1
 | |
| #endif
 | |
| 
 | |
| #define grub_bfs_to_cpu16 grub_le_to_cpu16
 | |
| #define grub_bfs_to_cpu32 grub_le_to_cpu32
 | |
| #define grub_bfs_to_cpu64 grub_le_to_cpu64
 | |
| #define grub_cpu_to_bfs32_compile_time grub_cpu_to_le32_compile_time
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
| #define grub_bfs_to_cpu_treehead grub_bfs_to_cpu32
 | |
| #else
 | |
| #define grub_bfs_to_cpu_treehead grub_bfs_to_cpu16
 | |
| #endif
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
| #define SUPER_BLOCK_MAGIC1 0x41465331
 | |
| #else
 | |
| #define SUPER_BLOCK_MAGIC1 0x42465331
 | |
| #endif
 | |
| #define SUPER_BLOCK_MAGIC2 0xdd121031
 | |
| #define SUPER_BLOCK_MAGIC3 0x15b6830e
 | |
| #define POINTER_INVALID 0xffffffffffffffffULL
 | |
| 
 | |
| #define ATTR_TYPE      0160000
 | |
| #define ATTR_REG       0100000
 | |
| #define ATTR_DIR       0040000
 | |
| #define ATTR_LNK       0120000
 | |
| 
 | |
| #define DOUBLE_INDIRECT_SHIFT 2
 | |
| 
 | |
| #define LOG_EXTENT_SIZE 3
 | |
| struct grub_bfs_extent
 | |
| {
 | |
|   grub_uint32_t ag;
 | |
|   grub_uint16_t start;
 | |
|   grub_uint16_t len;
 | |
| } GRUB_PACKED;
 | |
| 
 | |
| struct grub_bfs_superblock
 | |
| {
 | |
|   char label[32];
 | |
|   grub_uint32_t magic1;
 | |
|   grub_uint32_t unused1;
 | |
|   grub_uint32_t bsize;
 | |
|   grub_uint32_t log2_bsize;
 | |
|   grub_uint8_t unused[20];
 | |
|   grub_uint32_t magic2;
 | |
|   grub_uint32_t unused2;
 | |
|   grub_uint32_t log2_ag_size;
 | |
|   grub_uint8_t unused3[32];
 | |
|   grub_uint32_t magic3;
 | |
|   struct grub_bfs_extent root_dir;
 | |
| } GRUB_PACKED;
 | |
| 
 | |
| struct grub_bfs_inode
 | |
| {
 | |
|   grub_uint8_t unused[20];
 | |
|   grub_uint32_t mode;
 | |
|   grub_uint32_t flags;
 | |
| #ifdef MODE_AFS
 | |
|   grub_uint8_t unused2[12];
 | |
| #else
 | |
|   grub_uint8_t unused2[8];
 | |
| #endif
 | |
|   grub_uint64_t mtime;
 | |
|   grub_uint8_t unused3[8];
 | |
|   struct grub_bfs_extent attr;
 | |
|   grub_uint8_t unused4[12];
 | |
| 
 | |
|   union
 | |
|   {
 | |
|     struct
 | |
|     {
 | |
|       struct grub_bfs_extent direct[12];
 | |
|       grub_uint64_t max_direct_range;
 | |
|       struct grub_bfs_extent indirect;
 | |
|       grub_uint64_t max_indirect_range;
 | |
|       struct grub_bfs_extent double_indirect;
 | |
|       grub_uint64_t max_double_indirect_range;
 | |
|       grub_uint64_t size;
 | |
|       grub_uint32_t pad[4];
 | |
|     } GRUB_PACKED;
 | |
|     char inplace_link[144];
 | |
|   } GRUB_PACKED;
 | |
|   grub_uint8_t small_data[0];
 | |
| } GRUB_PACKED;
 | |
| 
 | |
| enum
 | |
| {
 | |
|   LONG_SYMLINK = 0x40
 | |
| };
 | |
| 
 | |
| struct grub_bfs_small_data_element_header
 | |
| {
 | |
|   grub_uint32_t type;
 | |
|   grub_uint16_t name_len;
 | |
|   grub_uint16_t value_len;
 | |
| } GRUB_PACKED;
 | |
| 
 | |
| struct grub_bfs_btree_header
 | |
| {
 | |
|   grub_uint32_t magic;
 | |
| #ifdef MODE_AFS
 | |
|   grub_uint64_t root;
 | |
|   grub_uint32_t level;
 | |
|   grub_uint32_t node_size;
 | |
|   grub_uint32_t unused;
 | |
| #else
 | |
|   grub_uint32_t node_size;
 | |
|   grub_uint32_t level;
 | |
|   grub_uint32_t unused;
 | |
|   grub_uint64_t root;
 | |
| #endif
 | |
|   grub_uint32_t unused2[2];
 | |
| } GRUB_PACKED;
 | |
| 
 | |
| struct grub_bfs_btree_node
 | |
| {
 | |
|   grub_uint64_t unused;
 | |
|   grub_uint64_t right;
 | |
|   grub_uint64_t overflow;
 | |
| #ifdef MODE_AFS
 | |
|   grub_uint32_t count_keys;
 | |
|   grub_uint32_t total_key_len;
 | |
| #else
 | |
|   grub_uint16_t count_keys;
 | |
|   grub_uint16_t total_key_len;
 | |
| #endif
 | |
| } GRUB_PACKED;
 | |
| 
 | |
| struct grub_bfs_data
 | |
| {
 | |
|   struct grub_bfs_superblock sb;
 | |
|   struct grub_bfs_inode ino;
 | |
| };
 | |
| 
 | |
| /* Context for grub_bfs_dir.  */
 | |
| struct grub_bfs_dir_ctx
 | |
| {
 | |
|   grub_device_t device;
 | |
|   grub_fs_dir_hook_t hook;
 | |
|   void *hook_data;
 | |
|   struct grub_bfs_superblock sb;
 | |
| };
 | |
| 
 | |
| static grub_err_t
 | |
| read_extent (grub_disk_t disk,
 | |
| 	     const struct grub_bfs_superblock *sb,
 | |
| 	     const struct grub_bfs_extent *in,
 | |
| 	     grub_off_t off, grub_off_t byteoff, void *buf, grub_size_t len)
 | |
| {
 | |
| #ifdef MODE_AFS
 | |
|   return grub_disk_read (disk, ((grub_bfs_to_cpu32 (in->ag)
 | |
| 				 << (grub_bfs_to_cpu32 (sb->log2_ag_size)
 | |
| 				     - GRUB_DISK_SECTOR_BITS))
 | |
| 				+ ((grub_bfs_to_cpu16 (in->start) + off)
 | |
| 				   << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 				       - GRUB_DISK_SECTOR_BITS))),
 | |
| 			 byteoff, len, buf);
 | |
| #else
 | |
|   return grub_disk_read (disk, (((grub_bfs_to_cpu32 (in->ag)
 | |
| 				  << grub_bfs_to_cpu32 (sb->log2_ag_size))
 | |
| 				 + grub_bfs_to_cpu16 (in->start) + off)
 | |
| 				<< (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 				    - GRUB_DISK_SECTOR_BITS)),
 | |
| 			 byteoff, len, buf);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
| #define RANGE_SHIFT grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| #else
 | |
| #define RANGE_SHIFT 0
 | |
| #endif
 | |
| 
 | |
| static grub_err_t
 | |
| read_bfs_file (grub_disk_t disk,
 | |
| 	       const struct grub_bfs_superblock *sb,
 | |
| 	       const struct grub_bfs_inode *ino,
 | |
| 	       grub_off_t off, void *buf, grub_size_t len,
 | |
| 	       grub_disk_read_hook_t read_hook, void *read_hook_data)
 | |
| {
 | |
|   if (len == 0)
 | |
|     return GRUB_ERR_NONE;
 | |
| 
 | |
|   if (off + len > grub_bfs_to_cpu64 (ino->size))
 | |
|     return grub_error (GRUB_ERR_OUT_OF_RANGE,
 | |
| 		       N_("attempt to read past the end of file"));
 | |
| 
 | |
|   if (off < (grub_bfs_to_cpu64 (ino->max_direct_range) << RANGE_SHIFT))
 | |
|     {
 | |
|       unsigned i;
 | |
|       grub_uint64_t pos = 0;
 | |
|       for (i = 0; i < ARRAY_SIZE (ino->direct); i++)
 | |
| 	{
 | |
| 	  grub_uint64_t newpos;
 | |
| 	  newpos = pos + (((grub_uint64_t) grub_bfs_to_cpu16 (ino->direct[i].len))
 | |
| 			  << grub_bfs_to_cpu32 (sb->log2_bsize));
 | |
| 	  if (newpos > off)
 | |
| 	    {
 | |
| 	      grub_size_t read_size;
 | |
| 	      grub_err_t err;
 | |
| 	      read_size = newpos - off;
 | |
| 	      if (read_size > len)
 | |
| 		read_size = len;
 | |
| 	      disk->read_hook = read_hook;
 | |
| 	      disk->read_hook_data = read_hook_data;
 | |
| 	      err = read_extent (disk, sb, &ino->direct[i], 0, off - pos,
 | |
| 				 buf, read_size);
 | |
| 	      disk->read_hook = 0;
 | |
| 	      if (err)
 | |
| 		return err;
 | |
| 	      off += read_size;
 | |
| 	      len -= read_size;
 | |
| 	      buf = (char *) buf + read_size;
 | |
| 	      if (len == 0)
 | |
| 		return GRUB_ERR_NONE;
 | |
| 	    }
 | |
| 	  pos = newpos;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (off < (grub_bfs_to_cpu64 (ino->max_direct_range) << RANGE_SHIFT))
 | |
|     return grub_error (GRUB_ERR_BAD_FS, "incorrect direct blocks");
 | |
| 
 | |
|   if (off < (grub_bfs_to_cpu64 (ino->max_indirect_range) << RANGE_SHIFT))
 | |
|     {
 | |
|       unsigned i;
 | |
|       struct grub_bfs_extent *entries;
 | |
|       grub_size_t nentries;
 | |
|       grub_err_t err;
 | |
|       grub_uint64_t pos = (grub_bfs_to_cpu64 (ino->max_direct_range)
 | |
| 			   << RANGE_SHIFT);
 | |
|       nentries = (((grub_size_t) grub_bfs_to_cpu16 (ino->indirect.len))
 | |
| 		  << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE));
 | |
|       entries = grub_malloc (nentries << LOG_EXTENT_SIZE);
 | |
|       if (!entries)
 | |
| 	return grub_errno;
 | |
|       err = read_extent (disk, sb, &ino->indirect, 0, 0,
 | |
| 			 entries, nentries << LOG_EXTENT_SIZE);
 | |
|       for (i = 0; i < nentries; i++)
 | |
| 	{
 | |
| 	  grub_uint64_t newpos;
 | |
| 	  newpos = pos + (((grub_uint64_t) grub_bfs_to_cpu16 (entries[i].len))
 | |
| 			  << grub_bfs_to_cpu32 (sb->log2_bsize));
 | |
| 	  if (newpos > off)
 | |
| 	    {
 | |
| 	      grub_size_t read_size;
 | |
| 	      read_size = newpos - off;
 | |
| 	      if (read_size > len)
 | |
| 		read_size = len;
 | |
| 	      disk->read_hook = read_hook;
 | |
| 	      disk->read_hook_data = read_hook_data;
 | |
| 	      err = read_extent (disk, sb, &entries[i], 0, off - pos,
 | |
| 				 buf, read_size);
 | |
| 	      disk->read_hook = 0;
 | |
| 	      if (err)
 | |
| 		{
 | |
| 		  grub_free (entries);
 | |
| 		  return err;
 | |
| 		}
 | |
| 	      off += read_size;
 | |
| 	      len -= read_size;
 | |
| 	      buf = (char *) buf + read_size;
 | |
| 	      if (len == 0)
 | |
| 		{
 | |
| 		  grub_free (entries);
 | |
| 		  return GRUB_ERR_NONE;
 | |
| 		}
 | |
| 	    }
 | |
| 	  pos = newpos;
 | |
| 	}
 | |
|       grub_free (entries);
 | |
|     }
 | |
| 
 | |
|   if (off < (grub_bfs_to_cpu64 (ino->max_indirect_range) << RANGE_SHIFT))
 | |
|     return grub_error (GRUB_ERR_BAD_FS, "incorrect indirect blocks");
 | |
| 
 | |
|   {
 | |
|     struct grub_bfs_extent *l1_entries, *l2_entries;
 | |
|     grub_size_t nl1_entries, nl2_entries;
 | |
|     grub_off_t last_l1n = ~0ULL;
 | |
|     grub_err_t err;
 | |
|     nl1_entries = (((grub_uint64_t) grub_bfs_to_cpu16 (ino->double_indirect.len))
 | |
| 		   << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE));
 | |
|     l1_entries = grub_malloc (nl1_entries << LOG_EXTENT_SIZE);
 | |
|     if (!l1_entries)
 | |
|       return grub_errno;
 | |
|     nl2_entries = 0;
 | |
|     l2_entries = grub_malloc (1 << (DOUBLE_INDIRECT_SHIFT
 | |
| 				    + grub_bfs_to_cpu32 (sb->log2_bsize)));
 | |
|     if (!l2_entries)
 | |
|       {
 | |
| 	grub_free (l1_entries);
 | |
| 	return grub_errno;
 | |
|       }
 | |
|     err = read_extent (disk, sb, &ino->double_indirect, 0, 0,
 | |
| 		       l1_entries, nl1_entries << LOG_EXTENT_SIZE);
 | |
|     if (err)
 | |
|       {
 | |
| 	grub_free (l1_entries);
 | |
| 	grub_free (l2_entries);
 | |
| 	return err;
 | |
|       }
 | |
| 
 | |
|     while (len > 0)
 | |
|       {
 | |
| 	grub_off_t boff, l2n, l1n;
 | |
| 	grub_size_t read_size;
 | |
| 	grub_off_t double_indirect_offset;
 | |
| 	double_indirect_offset = off
 | |
| 	  - grub_bfs_to_cpu64 (ino->max_indirect_range);
 | |
| 	boff = (double_indirect_offset
 | |
| 		& ((1 << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 			  + DOUBLE_INDIRECT_SHIFT)) - 1));
 | |
| 	l2n = ((double_indirect_offset >> (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 					   + DOUBLE_INDIRECT_SHIFT))
 | |
| 	       & ((1 << (grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE
 | |
| 			 + DOUBLE_INDIRECT_SHIFT)) - 1));
 | |
| 	l1n =
 | |
| 	  (double_indirect_offset >>
 | |
| 	   (2 * grub_bfs_to_cpu32 (sb->log2_bsize) - LOG_EXTENT_SIZE +
 | |
| 	    2 * DOUBLE_INDIRECT_SHIFT));
 | |
| 	if (l1n > nl1_entries)
 | |
| 	  {
 | |
| 	    grub_free (l1_entries);
 | |
| 	    grub_free (l2_entries);
 | |
| 	    return grub_error (GRUB_ERR_BAD_FS,
 | |
| 			       "incorrect double-indirect block");
 | |
| 	  }
 | |
| 	if (l1n != last_l1n)
 | |
| 	  {
 | |
| 	    nl2_entries = (((grub_uint64_t) grub_bfs_to_cpu16 (l1_entries[l1n].len))
 | |
| 			   << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 			       - LOG_EXTENT_SIZE));
 | |
| 	    if (nl2_entries > (1U << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 				      - LOG_EXTENT_SIZE
 | |
| 				      + DOUBLE_INDIRECT_SHIFT)))
 | |
| 	      nl2_entries = (1 << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 				   - LOG_EXTENT_SIZE
 | |
| 				   + DOUBLE_INDIRECT_SHIFT));
 | |
| 	    err = read_extent (disk, sb, &l1_entries[l1n], 0, 0,
 | |
| 			       l2_entries, nl2_entries << LOG_EXTENT_SIZE);
 | |
| 	    if (err)
 | |
| 	      {
 | |
| 		grub_free (l1_entries);
 | |
| 		grub_free (l2_entries);
 | |
| 		return err;
 | |
| 	      }
 | |
| 	    last_l1n = l1n;
 | |
| 	  }
 | |
| 	if (l2n > nl2_entries)
 | |
| 	  {
 | |
| 	    grub_free (l1_entries);
 | |
| 	    grub_free (l2_entries);
 | |
| 	    return grub_error (GRUB_ERR_BAD_FS,
 | |
| 			       "incorrect double-indirect block");
 | |
| 	  }
 | |
| 
 | |
| 	read_size = (1 << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 			   + DOUBLE_INDIRECT_SHIFT)) - boff;
 | |
| 	if (read_size > len)
 | |
| 	  read_size = len;
 | |
| 	disk->read_hook = read_hook;
 | |
| 	disk->read_hook_data = read_hook_data;
 | |
| 	err = read_extent (disk, sb, &l2_entries[l2n], 0, boff,
 | |
| 			   buf, read_size);
 | |
| 	disk->read_hook = 0;
 | |
| 	if (err)
 | |
| 	  {
 | |
| 	    grub_free (l1_entries);
 | |
| 	    grub_free (l2_entries);
 | |
| 	    return err;
 | |
| 	  }
 | |
| 	off += read_size;
 | |
| 	len -= read_size;
 | |
| 	buf = (char *) buf + read_size;
 | |
|       }
 | |
|     return GRUB_ERR_NONE;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| read_b_node (grub_disk_t disk,
 | |
| 	     const struct grub_bfs_superblock *sb,
 | |
| 	     const struct grub_bfs_inode *ino,
 | |
| 	     grub_uint64_t node_off,
 | |
| 	     struct grub_bfs_btree_node **node,
 | |
| 	     char **key_data, grub_uint16_t **keylen_idx,
 | |
| 	     grub_unaligned_uint64_t **key_values)
 | |
| {
 | |
|   void *ret;
 | |
|   struct grub_bfs_btree_node node_head;
 | |
|   grub_size_t total_size;
 | |
|   grub_err_t err;
 | |
| 
 | |
|   *node = NULL;
 | |
|   *key_data = NULL;
 | |
|   *keylen_idx = NULL;
 | |
|   *key_values = NULL;
 | |
| 
 | |
|   err = read_bfs_file (disk, sb, ino, node_off, &node_head, sizeof (node_head),
 | |
| 		       0, 0);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   total_size = ALIGN_UP (sizeof (node_head) +
 | |
| 			 grub_bfs_to_cpu_treehead
 | |
| 			 (node_head.total_key_len),
 | |
| 			 BTREE_ALIGN) +
 | |
|     grub_bfs_to_cpu_treehead (node_head.count_keys) *
 | |
|     sizeof (grub_uint16_t)
 | |
|     + grub_bfs_to_cpu_treehead (node_head.count_keys) *
 | |
|     sizeof (grub_uint64_t);
 | |
| 
 | |
|   ret = grub_malloc (total_size);
 | |
|   if (!ret)
 | |
|     return grub_errno;
 | |
| 
 | |
|   err = read_bfs_file (disk, sb, ino, node_off, ret, total_size, 0, 0);
 | |
|   if (err)
 | |
|     {
 | |
|       grub_free (ret);
 | |
|       return err;
 | |
|     }
 | |
| 
 | |
|   *node = ret;
 | |
|   *key_data = (char *) ret + sizeof (node_head);
 | |
|   *keylen_idx = (grub_uint16_t *) ret
 | |
|     + ALIGN_UP (sizeof (node_head) +
 | |
| 		grub_bfs_to_cpu_treehead (node_head.total_key_len),
 | |
| 		BTREE_ALIGN) / 2;
 | |
|   *key_values = (grub_unaligned_uint64_t *)
 | |
|     (*keylen_idx +
 | |
|      grub_bfs_to_cpu_treehead (node_head.count_keys));
 | |
| 
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static int
 | |
| iterate_in_b_tree (grub_disk_t disk,
 | |
| 		   const struct grub_bfs_superblock *sb,
 | |
| 		   const struct grub_bfs_inode *ino,
 | |
| 		   int (*hook) (const char *name, grub_uint64_t value,
 | |
| 				struct grub_bfs_dir_ctx *ctx),
 | |
| 		   struct grub_bfs_dir_ctx *ctx)
 | |
| {
 | |
|   struct grub_bfs_btree_header head;
 | |
|   grub_err_t err;
 | |
|   int level;
 | |
|   grub_uint64_t node_off;
 | |
| 
 | |
|   err = read_bfs_file (disk, sb, ino, 0, &head, sizeof (head), 0, 0);
 | |
|   if (err)
 | |
|     return 0;
 | |
|   node_off = grub_bfs_to_cpu64 (head.root);
 | |
| 
 | |
|   level = grub_bfs_to_cpu32 (head.level) - 1;
 | |
|   while (level--)
 | |
|     {
 | |
|       struct grub_bfs_btree_node node;
 | |
|       grub_uint64_t key_value;
 | |
|       err = read_bfs_file (disk, sb, ino, node_off, &node, sizeof (node),
 | |
| 			   0, 0);
 | |
|       if (err)
 | |
| 	return 0;
 | |
|       err = read_bfs_file (disk, sb, ino, node_off
 | |
| 			   + ALIGN_UP (sizeof (node) +
 | |
| 				       grub_bfs_to_cpu_treehead (node.
 | |
| 								 total_key_len),
 | |
| 				       BTREE_ALIGN) +
 | |
| 			   grub_bfs_to_cpu_treehead (node.count_keys) *
 | |
| 			   sizeof (grub_uint16_t), &key_value,
 | |
| 			   sizeof (grub_uint64_t), 0, 0);
 | |
|       if (err)
 | |
| 	return 0;
 | |
| 
 | |
|       node_off = grub_bfs_to_cpu64 (key_value);
 | |
|     }
 | |
| 
 | |
|   while (1)
 | |
|     {
 | |
|       struct grub_bfs_btree_node *node;
 | |
|       char *key_data;
 | |
|       grub_uint16_t *keylen_idx;
 | |
|       grub_unaligned_uint64_t *key_values;
 | |
|       unsigned i;
 | |
|       grub_uint16_t start = 0, end = 0;
 | |
| 
 | |
|       err = read_b_node (disk, sb, ino,
 | |
| 			 node_off,
 | |
| 			 &node,
 | |
| 			 &key_data, 
 | |
| 			 &keylen_idx,
 | |
| 			 &key_values);
 | |
| 
 | |
|       if (err)
 | |
| 	return 0;
 | |
|       
 | |
|       for (i = 0; i < grub_bfs_to_cpu_treehead (node->count_keys); i++)
 | |
| 	{
 | |
| 	  char c;
 | |
| 	  start = end;
 | |
| 	  end = grub_bfs_to_cpu16 (keylen_idx[i]);
 | |
| 	  if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
 | |
| 	    end = grub_bfs_to_cpu_treehead (node->total_key_len);
 | |
| 	  c = key_data[end];
 | |
| 	  key_data[end] = 0;
 | |
| 	  if (hook (key_data + start, grub_bfs_to_cpu64 (key_values[i].val),
 | |
| 		    ctx))
 | |
| 	    {
 | |
| 	      grub_free (node);
 | |
| 	      return 1;
 | |
| 	    }
 | |
| 	    key_data[end] = c;
 | |
| 	  }
 | |
| 	node_off = grub_bfs_to_cpu64 (node->right);
 | |
| 	grub_free (node);
 | |
| 	if (node_off == POINTER_INVALID)
 | |
| 	  return 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int
 | |
| bfs_strcmp (const char *a, const char *b, grub_size_t alen)
 | |
| {
 | |
|   char ac, bc;
 | |
|   while (*b && alen)
 | |
|     {
 | |
|       if (*a != *b)
 | |
| 	break;
 | |
| 
 | |
|       a++;
 | |
|       b++;
 | |
|       alen--;
 | |
|     }
 | |
| 
 | |
|   ac = alen ? *a : 0;
 | |
|   bc = *b;
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
|   return (int) (grub_int8_t) ac - (int) (grub_int8_t) bc;
 | |
| #else
 | |
|   return (int) (grub_uint8_t) ac - (int) (grub_uint8_t) bc;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| find_in_b_tree (grub_disk_t disk,
 | |
| 		const struct grub_bfs_superblock *sb,
 | |
| 		const struct grub_bfs_inode *ino, const char *name,
 | |
| 		grub_uint64_t * res)
 | |
| {
 | |
|   struct grub_bfs_btree_header head;
 | |
|   grub_err_t err;
 | |
|   int level;
 | |
|   grub_uint64_t node_off;
 | |
| 
 | |
|   err = read_bfs_file (disk, sb, ino, 0, &head, sizeof (head), 0, 0);
 | |
|   if (err)
 | |
|     return err;
 | |
|   node_off = grub_bfs_to_cpu64 (head.root);
 | |
| 
 | |
|   level = grub_bfs_to_cpu32 (head.level) - 1;
 | |
|   while (1)
 | |
|     {
 | |
|       struct grub_bfs_btree_node *node;
 | |
|       char *key_data;
 | |
|       grub_uint16_t *keylen_idx;
 | |
|       grub_unaligned_uint64_t *key_values;
 | |
|       int lg, j;
 | |
|       unsigned i;
 | |
| 
 | |
|       err = read_b_node (disk, sb, ino, node_off, &node, &key_data, &keylen_idx, &key_values);
 | |
|       if (err)
 | |
| 	return err;
 | |
| 
 | |
|       if (node->count_keys == 0)
 | |
| 	{
 | |
| 	  grub_free (node);
 | |
| 	  return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
 | |
| 			     name);
 | |
| 	}
 | |
| 
 | |
|       for (lg = 0; grub_bfs_to_cpu_treehead (node->count_keys) >> lg; lg++);
 | |
| 
 | |
|       i = 0;
 | |
| 
 | |
|       for (j = lg - 1; j >= 0; j--)
 | |
| 	{
 | |
| 	  int cmp;
 | |
| 	  grub_uint16_t start = 0, end = 0;
 | |
| 	  if ((i | (1 << j)) >= grub_bfs_to_cpu_treehead (node->count_keys))
 | |
| 	    continue;
 | |
| 	  start = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j)) - 1]);
 | |
| 	  end = grub_bfs_to_cpu16 (keylen_idx[(i | (1 << j))]);
 | |
| 	  if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
 | |
| 	    end = grub_bfs_to_cpu_treehead (node->total_key_len);
 | |
| 	  cmp = bfs_strcmp (key_data + start, name, end - start);
 | |
| 	  if (cmp == 0 && level == 0)
 | |
| 	    {
 | |
| 	      *res = grub_bfs_to_cpu64 (key_values[i | (1 << j)].val);
 | |
| 	      grub_free (node);
 | |
| 	      return GRUB_ERR_NONE;
 | |
| 	    }
 | |
| #ifdef MODE_AFS
 | |
| 	  if (cmp <= 0)
 | |
| #else
 | |
| 	  if (cmp < 0)
 | |
| #endif
 | |
| 	    i |= (1 << j);
 | |
| 	}
 | |
|       if (i == 0)
 | |
| 	{
 | |
| 	  grub_uint16_t end = 0;
 | |
| 	  int cmp;
 | |
| 	  end = grub_bfs_to_cpu16 (keylen_idx[0]);
 | |
| 	  if (grub_bfs_to_cpu_treehead (node->total_key_len) <= end)
 | |
| 	    end = grub_bfs_to_cpu_treehead (node->total_key_len);
 | |
| 	  cmp = bfs_strcmp (key_data, name, end);
 | |
| 	  if (cmp == 0 && level == 0)
 | |
| 	    {
 | |
| 	      *res = grub_bfs_to_cpu64 (key_values[0].val);
 | |
| 	      grub_free (node);
 | |
| 	      return GRUB_ERR_NONE;
 | |
| 	    }
 | |
| #ifdef MODE_AFS
 | |
| 	  if (cmp > 0 && level != 0)
 | |
| #else
 | |
| 	    if (cmp >= 0 && level != 0)
 | |
| #endif
 | |
| 	      {
 | |
| 		node_off = grub_bfs_to_cpu64 (key_values[0].val);
 | |
| 		level--;
 | |
| 		grub_free (node);
 | |
| 		continue;
 | |
| 	      }
 | |
| 	    else if (level != 0
 | |
| 		     && grub_bfs_to_cpu_treehead (node->count_keys) >= 2)
 | |
| 	      {
 | |
| 		node_off = grub_bfs_to_cpu64 (key_values[1].val);
 | |
| 		level--;
 | |
| 		grub_free (node);
 | |
| 		continue;
 | |
| 	      }	      
 | |
| 	  }
 | |
| 	else if (level != 0
 | |
| 		 && i + 1 < grub_bfs_to_cpu_treehead (node->count_keys))
 | |
| 	  {
 | |
| 	    node_off = grub_bfs_to_cpu64 (key_values[i + 1].val);
 | |
| 	    level--;
 | |
| 	    grub_free (node);
 | |
| 	    continue;
 | |
| 	  }
 | |
| 	if (node->overflow != POINTER_INVALID)
 | |
| 	  {
 | |
| 	    node_off = grub_bfs_to_cpu64 (node->overflow);
 | |
| 	    /* This level-- isn't specified but is needed.  */
 | |
| 	    level--;
 | |
| 	    grub_free (node);
 | |
| 	    continue;
 | |
| 	  }
 | |
| 	grub_free (node);
 | |
| 	return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"),
 | |
| 			   name);
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct grub_fshelp_node
 | |
| {
 | |
|   grub_disk_t disk;
 | |
|   const struct grub_bfs_superblock *sb;
 | |
|   struct grub_bfs_inode ino;
 | |
| };
 | |
| 
 | |
| static grub_err_t
 | |
| lookup_file (grub_fshelp_node_t dir,
 | |
| 	     const char *name,
 | |
| 	     grub_fshelp_node_t *foundnode,
 | |
| 	     enum grub_fshelp_filetype *foundtype)
 | |
| {
 | |
|   grub_err_t err;
 | |
|   struct grub_bfs_inode *new_ino;
 | |
|   grub_uint64_t res = 0;
 | |
| 
 | |
|   err = find_in_b_tree (dir->disk, dir->sb, &dir->ino, name, &res);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   *foundnode = grub_malloc (sizeof (struct grub_fshelp_node));
 | |
|   if (!*foundnode)
 | |
|     return grub_errno;
 | |
| 
 | |
|   (*foundnode)->disk = dir->disk;
 | |
|   (*foundnode)->sb = dir->sb;
 | |
|   new_ino = &(*foundnode)->ino;
 | |
| 
 | |
|   if (grub_disk_read (dir->disk, res
 | |
| 		      << (grub_bfs_to_cpu32 (dir->sb->log2_bsize)
 | |
| 			  - GRUB_DISK_SECTOR_BITS), 0,
 | |
| 		      sizeof (*new_ino), (char *) new_ino))
 | |
|     {
 | |
|       grub_free (*foundnode);
 | |
|       return grub_errno;
 | |
|     }
 | |
|   switch (grub_bfs_to_cpu32 (new_ino->mode) & ATTR_TYPE)
 | |
|     {
 | |
|     default:
 | |
|     case ATTR_REG:
 | |
|       *foundtype = GRUB_FSHELP_REG;
 | |
|       break;
 | |
|     case ATTR_DIR:
 | |
|       *foundtype = GRUB_FSHELP_DIR;
 | |
|       break;
 | |
|     case ATTR_LNK:
 | |
|       *foundtype = GRUB_FSHELP_SYMLINK;
 | |
|       break;
 | |
|     }
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static char *
 | |
| read_symlink (grub_fshelp_node_t node)
 | |
| {
 | |
|   char *alloc = NULL;
 | |
|   grub_err_t err;
 | |
| 
 | |
| #ifndef MODE_AFS
 | |
|   if (!(grub_bfs_to_cpu32 (node->ino.flags) & LONG_SYMLINK))
 | |
|     {
 | |
|       alloc = grub_malloc (sizeof (node->ino.inplace_link) + 1);
 | |
|       if (!alloc)
 | |
| 	{
 | |
| 	  return NULL;
 | |
| 	}
 | |
|       grub_memcpy (alloc, node->ino.inplace_link,
 | |
| 		   sizeof (node->ino.inplace_link));
 | |
|       alloc[sizeof (node->ino.inplace_link)] = 0;
 | |
|     }
 | |
|   else
 | |
| #endif
 | |
|     {
 | |
|       grub_size_t symsize = grub_bfs_to_cpu64 (node->ino.size);
 | |
|       alloc = grub_malloc (symsize + 1);
 | |
|       if (!alloc)
 | |
| 	return NULL;
 | |
|       err = read_bfs_file (node->disk, node->sb, &node->ino, 0, alloc, symsize, 0, 0);
 | |
|       if (err)
 | |
| 	{
 | |
| 	  grub_free (alloc);
 | |
| 	  return NULL;
 | |
| 	}
 | |
|       alloc[symsize] = 0;
 | |
|     }
 | |
| 
 | |
|   return alloc;
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| find_file (const char *path, grub_disk_t disk,
 | |
| 	   const struct grub_bfs_superblock *sb, struct grub_bfs_inode *ino,
 | |
| 	   enum grub_fshelp_filetype exptype)
 | |
| {
 | |
|   grub_err_t err;
 | |
|   struct grub_fshelp_node root = {
 | |
|     .disk = disk,
 | |
|     .sb = sb,
 | |
|   };
 | |
|   struct grub_fshelp_node *found;
 | |
| 
 | |
|   err = read_extent (disk, sb, &sb->root_dir, 0, 0, &root.ino,
 | |
| 		     sizeof (root.ino));
 | |
|   if (err)
 | |
|     return err;
 | |
|   err = grub_fshelp_find_file_lookup (path, &root, &found, lookup_file, read_symlink, exptype);
 | |
|   if (!err)
 | |
|     grub_memcpy (ino, &found->ino, sizeof (*ino));
 | |
| 
 | |
|   if (&root != found)
 | |
|     grub_free (found);
 | |
|   return err;
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| mount (grub_disk_t disk, struct grub_bfs_superblock *sb)
 | |
| {
 | |
|   grub_err_t err;
 | |
|   err = grub_disk_read (disk, SUPERBLOCK, 0, sizeof (*sb), sb);
 | |
|   if (err == GRUB_ERR_OUT_OF_RANGE)
 | |
|     return grub_error (GRUB_ERR_BAD_FS, 
 | |
| #ifdef MODE_AFS
 | |
| 		       "not an AFS filesystem"
 | |
| #else
 | |
| 		       "not a BFS filesystem"
 | |
| #endif
 | |
| 		       );
 | |
|   if (err)
 | |
|     return err;
 | |
|   if (sb->magic1 != grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC1)
 | |
|       || sb->magic2 != grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC2)
 | |
|       || sb->magic3 != grub_cpu_to_bfs32_compile_time (SUPER_BLOCK_MAGIC3)
 | |
|       || sb->bsize == 0
 | |
|       || (grub_bfs_to_cpu32 (sb->bsize)
 | |
| 	  != (1U << grub_bfs_to_cpu32 (sb->log2_bsize)))
 | |
|       || grub_bfs_to_cpu32 (sb->log2_bsize) < GRUB_DISK_SECTOR_BITS)
 | |
|     return grub_error (GRUB_ERR_BAD_FS, 
 | |
| #ifdef MODE_AFS
 | |
| 		       "not an AFS filesystem"
 | |
| #else
 | |
| 		       "not a BFS filesystem"
 | |
| #endif
 | |
| 		       );
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| /* Helper for grub_bfs_dir.  */
 | |
| static int
 | |
| grub_bfs_dir_iter (const char *name, grub_uint64_t value,
 | |
| 		   struct grub_bfs_dir_ctx *ctx)
 | |
| {
 | |
|   grub_err_t err2;
 | |
|   struct grub_bfs_inode ino;
 | |
|   struct grub_dirhook_info info;
 | |
| 
 | |
|   err2 = grub_disk_read (ctx->device->disk, value
 | |
| 			 << (grub_bfs_to_cpu32 (ctx->sb.log2_bsize)
 | |
| 			     - GRUB_DISK_SECTOR_BITS), 0,
 | |
| 			 sizeof (ino), (char *) &ino);
 | |
|   if (err2)
 | |
|     {
 | |
|       grub_print_error ();
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   info.mtimeset = 1;
 | |
| #ifdef MODE_AFS
 | |
|   info.mtime =
 | |
|     grub_divmod64 (grub_bfs_to_cpu64 (ino.mtime), 1000000, 0);
 | |
| #else
 | |
|   info.mtime = grub_bfs_to_cpu64 (ino.mtime) >> 16;
 | |
| #endif
 | |
|   info.dir = ((grub_bfs_to_cpu32 (ino.mode) & ATTR_TYPE) == ATTR_DIR);
 | |
|   return ctx->hook (name, &info, ctx->hook_data);
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| grub_bfs_dir (grub_device_t device, const char *path,
 | |
| 	      grub_fs_dir_hook_t hook, void *hook_data)
 | |
| {
 | |
|   struct grub_bfs_dir_ctx ctx = {
 | |
|     .device = device,
 | |
|     .hook = hook,
 | |
|     .hook_data = hook_data
 | |
|   };
 | |
|   grub_err_t err;
 | |
| 
 | |
|   err = mount (device->disk, &ctx.sb);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   {
 | |
|     struct grub_bfs_inode ino;
 | |
|     err = find_file (path, device->disk, &ctx.sb, &ino, GRUB_FSHELP_DIR);
 | |
|     if (err)
 | |
|       return err;
 | |
|     iterate_in_b_tree (device->disk, &ctx.sb, &ino, grub_bfs_dir_iter,
 | |
| 		       &ctx);
 | |
|   }
 | |
| 
 | |
|   return grub_errno;
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| grub_bfs_open (struct grub_file *file, const char *name)
 | |
| {
 | |
|   struct grub_bfs_superblock sb;
 | |
|   grub_err_t err;
 | |
| 
 | |
|   err = mount (file->device->disk, &sb);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   {
 | |
|     struct grub_bfs_inode ino;
 | |
|     struct grub_bfs_data *data;
 | |
|     err = find_file (name, file->device->disk, &sb, &ino, GRUB_FSHELP_REG);
 | |
|     if (err)
 | |
|       return err;
 | |
| 
 | |
|     data = grub_zalloc (sizeof (struct grub_bfs_data));
 | |
|     if (!data)
 | |
|       return grub_errno;
 | |
|     data->sb = sb;
 | |
|     grub_memcpy (&data->ino, &ino, sizeof (data->ino));
 | |
|     file->data = data;
 | |
|     file->size = grub_bfs_to_cpu64 (ino.size);
 | |
|   }
 | |
| 
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| grub_bfs_close (grub_file_t file)
 | |
| {
 | |
|   grub_free (file->data);
 | |
| 
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static grub_ssize_t
 | |
| grub_bfs_read (grub_file_t file, char *buf, grub_size_t len)
 | |
| {
 | |
|   grub_err_t err;
 | |
|   struct grub_bfs_data *data = file->data;
 | |
| 
 | |
|   err = read_bfs_file (file->device->disk, &data->sb,
 | |
| 		       &data->ino, file->offset, buf, len,
 | |
| 		       file->read_hook, file->read_hook_data);
 | |
|   if (err)
 | |
|     return -1;
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| grub_bfs_label (grub_device_t device, char **label)
 | |
| {
 | |
|   struct grub_bfs_superblock sb;
 | |
|   grub_err_t err;
 | |
| 
 | |
|   *label = 0;
 | |
| 
 | |
|   err = mount (device->disk, &sb);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   *label = grub_strndup (sb.label, sizeof (sb.label));
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| #ifndef MODE_AFS
 | |
| static grub_ssize_t
 | |
| read_bfs_attr (grub_disk_t disk,
 | |
| 	       const struct grub_bfs_superblock *sb,
 | |
| 	       struct grub_bfs_inode *ino,
 | |
| 	       const char *name, void *buf, grub_size_t len)
 | |
| {
 | |
|   grub_uint8_t *ptr = (grub_uint8_t *) ino->small_data;
 | |
|   grub_uint8_t *end = ((grub_uint8_t *) ino + grub_bfs_to_cpu32 (sb->bsize));
 | |
| 
 | |
|   while (ptr + sizeof (struct grub_bfs_small_data_element_header) < end)
 | |
|     {
 | |
|       struct grub_bfs_small_data_element_header *el;
 | |
|       char *el_name;
 | |
|       grub_uint8_t *data;
 | |
|       el = (struct grub_bfs_small_data_element_header *) ptr;
 | |
|       if (el->name_len == 0)
 | |
| 	break;
 | |
|       el_name = (char *) (el + 1);
 | |
|       data = (grub_uint8_t *) el_name + grub_bfs_to_cpu16 (el->name_len) + 3;
 | |
|       ptr = data + grub_bfs_to_cpu16 (el->value_len) + 1;
 | |
|       if (grub_memcmp (name, el_name, grub_bfs_to_cpu16 (el->name_len)) == 0
 | |
| 	  && name[el->name_len] == 0)
 | |
| 	{
 | |
| 	  grub_size_t copy;
 | |
| 	  copy = len;
 | |
| 	  if (grub_bfs_to_cpu16 (el->value_len) > copy)
 | |
| 	    copy = grub_bfs_to_cpu16 (el->value_len);
 | |
| 	  grub_memcpy (buf, data, copy);
 | |
| 	  return copy;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   if (ino->attr.len != 0)
 | |
|     {
 | |
|       grub_size_t read;
 | |
|       grub_err_t err;
 | |
|       grub_uint64_t res;
 | |
| 
 | |
|       err = read_extent (disk, sb, &ino->attr, 0, 0, ino,
 | |
| 			 grub_bfs_to_cpu32 (sb->bsize));
 | |
|       if (err)
 | |
| 	return -1;
 | |
| 
 | |
|       err = find_in_b_tree (disk, sb, ino, name, &res);
 | |
|       if (err)
 | |
| 	return -1;
 | |
|       grub_disk_read (disk, res
 | |
| 		      << (grub_bfs_to_cpu32 (sb->log2_bsize)
 | |
| 			  - GRUB_DISK_SECTOR_BITS), 0,
 | |
| 		      grub_bfs_to_cpu32 (sb->bsize), (char *) ino);
 | |
|       read = grub_bfs_to_cpu64 (ino->size);
 | |
|       if (read > len)
 | |
| 	read = len;
 | |
| 
 | |
|       err = read_bfs_file (disk, sb, ino, 0, buf, read, 0, 0);
 | |
|       if (err)
 | |
| 	return -1;
 | |
|       return read;
 | |
|     }
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| static grub_err_t
 | |
| grub_bfs_uuid (grub_device_t device, char **uuid)
 | |
| {
 | |
|   struct grub_bfs_superblock sb;
 | |
|   grub_err_t err;
 | |
|   struct grub_bfs_inode *ino;
 | |
|   grub_uint64_t vid;
 | |
| 
 | |
|   *uuid = 0;
 | |
| 
 | |
|   err = mount (device->disk, &sb);
 | |
|   if (err)
 | |
|     return err;
 | |
| 
 | |
|   ino = grub_malloc (grub_bfs_to_cpu32 (sb.bsize));
 | |
|   if (!ino)
 | |
|     return grub_errno;
 | |
| 
 | |
|   err = read_extent (device->disk, &sb, &sb.root_dir, 0, 0,
 | |
| 		     ino, grub_bfs_to_cpu32 (sb.bsize));
 | |
|   if (err)
 | |
|     {
 | |
|       grub_free (ino);
 | |
|       return err;
 | |
|     }
 | |
|   if (read_bfs_attr (device->disk, &sb, ino, "be:volume_id",
 | |
| 		     &vid, sizeof (vid)) == sizeof (vid))
 | |
|     *uuid =
 | |
|       grub_xasprintf ("%016" PRIxGRUB_UINT64_T, grub_bfs_to_cpu64 (vid));
 | |
| 
 | |
|   grub_free (ino);
 | |
| 
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static struct grub_fs grub_bfs_fs = {
 | |
| #ifdef MODE_AFS
 | |
|   .name = "afs",
 | |
| #else
 | |
|   .name = "bfs",
 | |
| #endif
 | |
|   .dir = grub_bfs_dir,
 | |
|   .open = grub_bfs_open,
 | |
|   .read = grub_bfs_read,
 | |
|   .close = grub_bfs_close,
 | |
|   .label = grub_bfs_label,
 | |
| #ifndef MODE_AFS
 | |
|   .uuid = grub_bfs_uuid,
 | |
| #endif
 | |
| #ifdef GRUB_UTIL
 | |
|   .reserved_first_sector = 1,
 | |
|   .blocklist_install = 1,
 | |
| #endif
 | |
| };
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
| GRUB_MOD_INIT (afs)
 | |
| #else
 | |
| GRUB_MOD_INIT (bfs)
 | |
| #endif
 | |
| {
 | |
|   COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE ==
 | |
| 		       sizeof (struct grub_bfs_extent));
 | |
|   grub_fs_register (&grub_bfs_fs);
 | |
| }
 | |
| 
 | |
| #ifdef MODE_AFS
 | |
| GRUB_MOD_FINI (afs)
 | |
| #else
 | |
| GRUB_MOD_FINI (bfs)
 | |
| #endif
 | |
| {
 | |
|   grub_fs_unregister (&grub_bfs_fs);
 | |
| }
 | 
