1 /* btrfs.c - B-tree file system. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 #include <grub/file.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
26 #include <grub/types.h>
27 #include <grub/lib/crc.h>
28 #include <grub/deflate.h>
30 #include <grub/i18n.h>
32 GRUB_MOD_LICENSE ("GPLv3+");
34 #define GRUB_BTRFS_SIGNATURE "_BHRfS_M"
36 /* From http://www.oberhumer.com/opensource/lzo/lzofaq.php
37 * LZO will expand incompressible data by a little amount. I still haven't
38 * computed the exact values, but I suggest using these formulas for
39 * a worst-case expansion calculation:
41 * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3
43 #define GRUB_BTRFS_LZO_BLOCK_SIZE 4096
44 #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
45 (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
47 typedef grub_uint8_t grub_btrfs_checksum_t
[0x20];
48 typedef grub_uint16_t grub_btrfs_uuid_t
[8];
50 struct grub_btrfs_device
52 grub_uint64_t device_id
;
54 grub_uint8_t dummy
[0x62 - 0x10];
55 } __attribute__ ((packed
));
57 struct grub_btrfs_superblock
59 grub_btrfs_checksum_t checksum
;
60 grub_btrfs_uuid_t uuid
;
61 grub_uint8_t dummy
[0x10];
62 grub_uint8_t signature
[sizeof (GRUB_BTRFS_SIGNATURE
) - 1];
63 grub_uint64_t generation
;
64 grub_uint64_t root_tree
;
65 grub_uint64_t chunk_tree
;
66 grub_uint8_t dummy2
[0x20];
67 grub_uint64_t root_dir_objectid
;
68 grub_uint8_t dummy3
[0x41];
69 struct grub_btrfs_device this_device
;
71 grub_uint8_t dummy4
[0x100];
72 grub_uint8_t bootstrap_mapping
[0x800];
73 } __attribute__ ((packed
));
77 grub_btrfs_checksum_t checksum
;
78 grub_btrfs_uuid_t uuid
;
79 grub_uint8_t dummy
[0x30];
82 } __attribute__ ((packed
));
84 struct grub_btrfs_device_desc
90 struct grub_btrfs_data
92 struct grub_btrfs_superblock sblock
;
96 struct grub_btrfs_device_desc
*devices_attached
;
97 unsigned n_devices_attached
;
98 unsigned n_devices_allocated
;
100 /* Cached extent data. */
101 grub_uint64_t extstart
;
102 grub_uint64_t extend
;
103 grub_uint64_t extino
;
104 grub_uint64_t exttree
;
106 struct grub_btrfs_extent_data
*extent
;
111 GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
= 0x01,
112 GRUB_BTRFS_ITEM_TYPE_INODE_REF
= 0x0c,
113 GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
= 0x54,
114 GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
= 0x6c,
115 GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
= 0x84,
116 GRUB_BTRFS_ITEM_TYPE_DEVICE
= 0xd8,
117 GRUB_BTRFS_ITEM_TYPE_CHUNK
= 0xe4
120 struct grub_btrfs_key
122 grub_uint64_t object_id
;
124 grub_uint64_t offset
;
125 } __attribute__ ((packed
));
127 struct grub_btrfs_chunk_item
131 grub_uint64_t stripe_length
;
133 #define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07
134 #define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00
135 #define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08
136 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10
137 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20
138 #define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40
139 grub_uint8_t dummy2
[0xc];
140 grub_uint16_t nstripes
;
141 grub_uint16_t nsubstripes
;
142 } __attribute__ ((packed
));
144 struct grub_btrfs_chunk_stripe
146 grub_uint64_t device_id
;
147 grub_uint64_t offset
;
148 grub_btrfs_uuid_t device_uuid
;
149 } __attribute__ ((packed
));
151 struct grub_btrfs_leaf_node
153 struct grub_btrfs_key key
;
154 grub_uint32_t offset
;
156 } __attribute__ ((packed
));
158 struct grub_btrfs_internal_node
160 struct grub_btrfs_key key
;
163 } __attribute__ ((packed
));
165 struct grub_btrfs_dir_item
167 struct grub_btrfs_key key
;
168 grub_uint8_t dummy
[8];
171 #define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1
172 #define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2
173 #define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7
176 } __attribute__ ((packed
));
178 struct grub_btrfs_leaf_descriptor
184 grub_disk_addr_t addr
;
191 struct grub_btrfs_root_item
193 grub_uint8_t dummy
[0xb0];
198 struct grub_btrfs_time
201 grub_uint32_t nanosec
;
202 } __attribute__ ((aligned (4)));
204 struct grub_btrfs_inode
206 grub_uint8_t dummy1
[0x10];
208 grub_uint8_t dummy2
[0x70];
209 struct grub_btrfs_time mtime
;
210 } __attribute__ ((packed
));
212 struct grub_btrfs_extent_data
216 grub_uint8_t compression
;
217 grub_uint8_t encryption
;
218 grub_uint16_t encoding
;
226 grub_uint64_t compressed_size
;
227 grub_uint64_t offset
;
228 grub_uint64_t filled
;
231 } __attribute__ ((packed
));
233 #define GRUB_BTRFS_EXTENT_INLINE 0
234 #define GRUB_BTRFS_EXTENT_REGULAR 1
236 #define GRUB_BTRFS_COMPRESSION_NONE 0
237 #define GRUB_BTRFS_COMPRESSION_ZLIB 1
238 #define GRUB_BTRFS_COMPRESSION_LZO 2
240 #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
242 static grub_disk_addr_t superblock_sectors
[] = { 64 * 2, 64 * 1024 * 2,
243 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
247 grub_btrfs_read_logical (struct grub_btrfs_data
*data
,
248 grub_disk_addr_t addr
, void *buf
, grub_size_t size
,
249 int recursion_depth
);
252 read_sblock (grub_disk_t disk
, struct grub_btrfs_superblock
*sb
)
255 grub_err_t err
= GRUB_ERR_NONE
;
256 for (i
= 0; i
< ARRAY_SIZE (superblock_sectors
); i
++)
258 struct grub_btrfs_superblock sblock
;
259 /* Don't try additional superblocks beyond device size. */
260 if (i
&& (grub_le_to_cpu64 (sblock
.this_device
.size
)
261 >> GRUB_DISK_SECTOR_BITS
) <= superblock_sectors
[i
])
263 err
= grub_disk_read (disk
, superblock_sectors
[i
], 0,
264 sizeof (sblock
), &sblock
);
265 if (err
== GRUB_ERR_OUT_OF_RANGE
)
268 if (grub_memcmp ((char *) sblock
.signature
, GRUB_BTRFS_SIGNATURE
,
269 sizeof (GRUB_BTRFS_SIGNATURE
) - 1) != 0)
271 if (i
== 0 || grub_le_to_cpu64 (sblock
.generation
)
272 > grub_le_to_cpu64 (sb
->generation
))
273 grub_memcpy (sb
, &sblock
, sizeof (sblock
));
276 if ((err
== GRUB_ERR_OUT_OF_RANGE
|| !err
) && i
== 0)
277 return grub_error (GRUB_ERR_BAD_FS
, "not a Btrfs filesystem");
279 if (err
== GRUB_ERR_OUT_OF_RANGE
)
280 grub_errno
= err
= GRUB_ERR_NONE
;
286 key_cmp (const struct grub_btrfs_key
*a
, const struct grub_btrfs_key
*b
)
288 if (grub_le_to_cpu64 (a
->object_id
) < grub_le_to_cpu64 (b
->object_id
))
290 if (grub_le_to_cpu64 (a
->object_id
) > grub_le_to_cpu64 (b
->object_id
))
293 if (a
->type
< b
->type
)
295 if (a
->type
> b
->type
)
298 if (grub_le_to_cpu64 (a
->offset
) < grub_le_to_cpu64 (b
->offset
))
300 if (grub_le_to_cpu64 (a
->offset
) > grub_le_to_cpu64 (b
->offset
))
306 free_iterator (struct grub_btrfs_leaf_descriptor
*desc
)
308 grub_free (desc
->data
);
312 save_ref (struct grub_btrfs_leaf_descriptor
*desc
,
313 grub_disk_addr_t addr
, unsigned i
, unsigned m
, int l
)
316 if (desc
->allocated
< desc
->depth
)
319 desc
->allocated
*= 2;
320 newdata
= grub_realloc (desc
->data
, sizeof (desc
->data
[0])
324 desc
->data
= newdata
;
326 desc
->data
[desc
->depth
- 1].addr
= addr
;
327 desc
->data
[desc
->depth
- 1].iter
= i
;
328 desc
->data
[desc
->depth
- 1].maxiter
= m
;
329 desc
->data
[desc
->depth
- 1].leaf
= l
;
330 return GRUB_ERR_NONE
;
334 next (struct grub_btrfs_data
*data
,
335 struct grub_btrfs_leaf_descriptor
*desc
,
336 grub_disk_addr_t
* outaddr
, grub_size_t
* outsize
,
337 struct grub_btrfs_key
*key_out
)
340 struct grub_btrfs_leaf_node leaf
;
342 for (; desc
->depth
> 0; desc
->depth
--)
344 desc
->data
[desc
->depth
- 1].iter
++;
345 if (desc
->data
[desc
->depth
- 1].iter
346 < desc
->data
[desc
->depth
- 1].maxiter
)
349 if (desc
->depth
== 0)
351 while (!desc
->data
[desc
->depth
- 1].leaf
)
353 struct grub_btrfs_internal_node node
;
354 struct btrfs_header head
;
356 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
358 + sizeof (struct btrfs_header
)
359 + desc
->data
[desc
->depth
- 1].addr
,
360 &node
, sizeof (node
), 0);
364 err
= grub_btrfs_read_logical (data
, grub_le_to_cpu64 (node
.addr
),
365 &head
, sizeof (head
), 0);
369 save_ref (desc
, grub_le_to_cpu64 (node
.addr
), 0,
370 grub_le_to_cpu32 (head
.nitems
), !head
.level
);
372 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
374 + sizeof (struct btrfs_header
)
375 + desc
->data
[desc
->depth
- 1].addr
, &leaf
,
379 *outsize
= grub_le_to_cpu32 (leaf
.size
);
380 *outaddr
= desc
->data
[desc
->depth
- 1].addr
+ sizeof (struct btrfs_header
)
381 + grub_le_to_cpu32 (leaf
.offset
);
387 lower_bound (struct grub_btrfs_data
*data
,
388 const struct grub_btrfs_key
*key_in
,
389 struct grub_btrfs_key
*key_out
,
391 grub_disk_addr_t
*outaddr
, grub_size_t
*outsize
,
392 struct grub_btrfs_leaf_descriptor
*desc
,
395 grub_disk_addr_t addr
= grub_le_to_cpu64 (root
);
400 desc
->allocated
= 16;
402 desc
->data
= grub_malloc (sizeof (desc
->data
[0]) * desc
->allocated
);
407 /* > 2 would work as well but be robust and allow a bit more just in case.
409 if (recursion_depth
> 10)
410 return grub_error (GRUB_ERR_BAD_FS
, "too deep btrfs virtual nesting");
412 grub_dprintf ("btrfs",
413 "retrieving %" PRIxGRUB_UINT64_T
414 " %x %" PRIxGRUB_UINT64_T
"\n",
415 key_in
->object_id
, key_in
->type
, key_in
->offset
);
420 struct btrfs_header head
;
424 /* FIXME: preread few nodes into buffer. */
425 err
= grub_btrfs_read_logical (data
, addr
, &head
, sizeof (head
),
426 recursion_depth
+ 1);
429 addr
+= sizeof (head
);
433 struct grub_btrfs_internal_node node
, node_last
;
435 grub_memset (&node_last
, 0, sizeof (node_last
));
436 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
438 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (node
),
439 &node
, sizeof (node
),
440 recursion_depth
+ 1);
444 grub_dprintf ("btrfs",
445 "internal node (depth %d) %" PRIxGRUB_UINT64_T
446 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
447 node
.key
.object_id
, node
.key
.type
,
450 if (key_cmp (&node
.key
, key_in
) == 0)
454 err
= save_ref (desc
, addr
- sizeof (head
), i
,
455 grub_le_to_cpu32 (head
.nitems
), 0);
458 addr
= grub_le_to_cpu64 (node
.addr
);
461 if (key_cmp (&node
.key
, key_in
) > 0)
470 err
= save_ref (desc
, addr
- sizeof (head
), i
- 1,
471 grub_le_to_cpu32 (head
.nitems
), 0);
474 addr
= grub_le_to_cpu64 (node_last
.addr
);
479 grub_memset (key_out
, 0, sizeof (*key_out
));
481 return save_ref (desc
, addr
- sizeof (head
), -1,
482 grub_le_to_cpu32 (head
.nitems
), 0);
483 return GRUB_ERR_NONE
;
487 struct grub_btrfs_leaf_node leaf
, leaf_last
;
489 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
491 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (leaf
),
492 &leaf
, sizeof (leaf
),
493 recursion_depth
+ 1);
497 grub_dprintf ("btrfs",
498 "leaf (depth %d) %" PRIxGRUB_UINT64_T
499 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
500 leaf
.key
.object_id
, leaf
.key
.type
, leaf
.key
.offset
);
502 if (key_cmp (&leaf
.key
, key_in
) == 0)
504 grub_memcpy (key_out
, &leaf
.key
, sizeof (*key_out
));
505 *outsize
= grub_le_to_cpu32 (leaf
.size
);
506 *outaddr
= addr
+ grub_le_to_cpu32 (leaf
.offset
);
508 return save_ref (desc
, addr
- sizeof (head
), i
,
509 grub_le_to_cpu32 (head
.nitems
), 1);
510 return GRUB_ERR_NONE
;
513 if (key_cmp (&leaf
.key
, key_in
) > 0)
522 grub_memcpy (key_out
, &leaf_last
.key
, sizeof (*key_out
));
523 *outsize
= grub_le_to_cpu32 (leaf_last
.size
);
524 *outaddr
= addr
+ grub_le_to_cpu32 (leaf_last
.offset
);
526 return save_ref (desc
, addr
- sizeof (head
), i
- 1,
527 grub_le_to_cpu32 (head
.nitems
), 1);
528 return GRUB_ERR_NONE
;
532 grub_memset (key_out
, 0, sizeof (*key_out
));
534 return save_ref (desc
, addr
- sizeof (head
), -1,
535 grub_le_to_cpu32 (head
.nitems
), 1);
536 return GRUB_ERR_NONE
;
542 find_device (struct grub_btrfs_data
*data
, grub_uint64_t id
, int do_rescan
)
544 grub_device_t dev_found
= NULL
;
545 auto int hook (const char *name
);
546 int hook (const char *name
)
550 struct grub_btrfs_superblock sb
;
551 dev
= grub_device_open (name
);
556 grub_device_close (dev
);
559 err
= read_sblock (dev
->disk
, &sb
);
560 if (err
== GRUB_ERR_BAD_FS
)
562 grub_device_close (dev
);
563 grub_errno
= GRUB_ERR_NONE
;
568 grub_device_close (dev
);
572 if (grub_memcmp (data
->sblock
.uuid
, sb
.uuid
, sizeof (sb
.uuid
)) != 0
573 || sb
.this_device
.device_id
!= id
)
575 grub_device_close (dev
);
585 for (i
= 0; i
< data
->n_devices_attached
; i
++)
586 if (id
== data
->devices_attached
[i
].id
)
587 return data
->devices_attached
[i
].dev
;
589 grub_device_iterate (hook
);
592 grub_error (GRUB_ERR_BAD_FS
,
593 N_("couldn't find a necessary member device "
594 "of multi-device filesystem"));
597 data
->n_devices_attached
++;
598 if (data
->n_devices_attached
> data
->n_devices_allocated
)
601 data
->n_devices_allocated
= 2 * data
->n_devices_attached
+ 1;
602 data
->devices_attached
603 = grub_realloc (tmp
= data
->devices_attached
,
604 data
->n_devices_allocated
605 * sizeof (data
->devices_attached
[0]));
606 if (!data
->devices_attached
)
608 grub_device_close (dev_found
);
609 data
->devices_attached
= tmp
;
613 data
->devices_attached
[data
->n_devices_attached
- 1].id
= id
;
614 data
->devices_attached
[data
->n_devices_attached
- 1].dev
= dev_found
;
619 grub_btrfs_read_logical (struct grub_btrfs_data
*data
, grub_disk_addr_t addr
,
620 void *buf
, grub_size_t size
, int recursion_depth
)
625 struct grub_btrfs_key
*key
;
626 struct grub_btrfs_chunk_item
*chunk
;
629 struct grub_btrfs_key key_out
;
632 struct grub_btrfs_key key_in
;
634 grub_disk_addr_t chaddr
;
636 grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T
"\n",
638 for (ptr
= data
->sblock
.bootstrap_mapping
;
639 ptr
< data
->sblock
.bootstrap_mapping
640 + sizeof (data
->sblock
.bootstrap_mapping
)
641 - sizeof (struct grub_btrfs_key
);)
643 key
= (struct grub_btrfs_key
*) ptr
;
644 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
)
646 chunk
= (struct grub_btrfs_chunk_item
*) (key
+ 1);
647 grub_dprintf ("btrfs",
648 "%" PRIxGRUB_UINT64_T
" %" PRIxGRUB_UINT64_T
" \n",
649 grub_le_to_cpu64 (key
->offset
),
650 grub_le_to_cpu64 (chunk
->size
));
651 if (grub_le_to_cpu64 (key
->offset
) <= addr
652 && addr
< grub_le_to_cpu64 (key
->offset
)
653 + grub_le_to_cpu64 (chunk
->size
))
655 ptr
+= sizeof (*key
) + sizeof (*chunk
)
656 + sizeof (struct grub_btrfs_chunk_stripe
)
657 * grub_le_to_cpu16 (chunk
->nstripes
);
660 key_in
.object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
661 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_CHUNK
;
662 key_in
.offset
= grub_cpu_to_le64 (addr
);
663 err
= lower_bound (data
, &key_in
, &key_out
,
664 data
->sblock
.chunk_tree
,
665 &chaddr
, &chsize
, NULL
, recursion_depth
);
669 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
670 || !(grub_le_to_cpu64 (key
->offset
) <= addr
))
671 return grub_error (GRUB_ERR_BAD_FS
,
672 "couldn't find the chunk descriptor");
674 chunk
= grub_malloc (chsize
);
679 err
= grub_btrfs_read_logical (data
, chaddr
, chunk
, chsize
,
689 grub_uint64_t stripen
;
690 grub_uint64_t stripe_offset
;
691 grub_uint64_t off
= addr
- grub_le_to_cpu64 (key
->offset
);
692 unsigned redundancy
= 1;
695 if (grub_le_to_cpu64 (chunk
->size
) <= off
)
697 grub_dprintf ("btrfs", "no chunk\n");
698 return grub_error (GRUB_ERR_BAD_FS
,
699 "couldn't find the chunk descriptor");
702 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
703 "+0x%" PRIxGRUB_UINT64_T
704 " (%d stripes (%d substripes) of %"
705 PRIxGRUB_UINT64_T
")\n",
706 grub_le_to_cpu64 (key
->offset
),
707 grub_le_to_cpu64 (chunk
->size
),
708 grub_le_to_cpu16 (chunk
->nstripes
),
709 grub_le_to_cpu16 (chunk
->nsubstripes
),
710 grub_le_to_cpu64 (chunk
->stripe_length
));
712 switch (grub_le_to_cpu64 (chunk
->type
)
713 & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE
)
715 case GRUB_BTRFS_CHUNK_TYPE_SINGLE
:
717 grub_uint64_t stripe_length
;
718 grub_dprintf ("btrfs", "single\n");
719 stripe_length
= grub_divmod64 (grub_le_to_cpu64 (chunk
->size
),
720 grub_le_to_cpu16 (chunk
->nstripes
),
722 stripen
= grub_divmod64 (off
, stripe_length
, &stripe_offset
);
723 csize
= (stripen
+ 1) * stripe_length
- off
;
726 case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED
:
727 case GRUB_BTRFS_CHUNK_TYPE_RAID1
:
729 grub_dprintf ("btrfs", "RAID1\n");
732 csize
= grub_le_to_cpu64 (chunk
->size
) - off
;
736 case GRUB_BTRFS_CHUNK_TYPE_RAID0
:
738 grub_uint64_t middle
, high
;
740 grub_dprintf ("btrfs", "RAID0\n");
741 middle
= grub_divmod64 (off
,
742 grub_le_to_cpu64 (chunk
->stripe_length
),
745 high
= grub_divmod64 (middle
, grub_le_to_cpu16 (chunk
->nstripes
),
748 low
+ grub_le_to_cpu64 (chunk
->stripe_length
) * high
;
749 csize
= grub_le_to_cpu64 (chunk
->stripe_length
) - low
;
752 case GRUB_BTRFS_CHUNK_TYPE_RAID10
:
754 grub_uint64_t middle
, high
;
756 middle
= grub_divmod64 (off
,
757 grub_le_to_cpu64 (chunk
->stripe_length
),
760 high
= grub_divmod64 (middle
,
761 grub_le_to_cpu16 (chunk
->nstripes
)
762 / grub_le_to_cpu16 (chunk
->nsubstripes
),
764 stripen
*= grub_le_to_cpu16 (chunk
->nsubstripes
);
765 redundancy
= grub_le_to_cpu16 (chunk
->nsubstripes
);
766 stripe_offset
= low
+ grub_le_to_cpu64 (chunk
->stripe_length
)
768 csize
= grub_le_to_cpu64 (chunk
->stripe_length
) - low
;
772 grub_dprintf ("btrfs", "unsupported RAID\n");
773 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
774 "unsupported RAID flags %" PRIxGRUB_UINT64_T
,
775 grub_le_to_cpu64 (chunk
->type
));
778 return grub_error (GRUB_ERR_BUG
,
779 "couldn't find the chunk descriptor");
780 if (csize
> (grub_uint64_t
) size
)
783 for (j
= 0; j
< 2; j
++)
785 for (i
= 0; i
< redundancy
; i
++)
787 struct grub_btrfs_chunk_stripe
*stripe
;
788 grub_disk_addr_t paddr
;
790 stripe
= (struct grub_btrfs_chunk_stripe
*) (chunk
+ 1);
791 /* Right now the redundancy handling is easy.
792 With RAID5-like it will be more difficult. */
793 stripe
+= stripen
+ i
;
795 paddr
= grub_le_to_cpu64 (stripe
->offset
) + stripe_offset
;
797 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
798 "+0x%" PRIxGRUB_UINT64_T
799 " (%d stripes (%d substripes) of %"
800 PRIxGRUB_UINT64_T
") stripe %" PRIxGRUB_UINT64_T
801 " maps to 0x%" PRIxGRUB_UINT64_T
"\n",
802 grub_le_to_cpu64 (key
->offset
),
803 grub_le_to_cpu64 (chunk
->size
),
804 grub_le_to_cpu16 (chunk
->nstripes
),
805 grub_le_to_cpu16 (chunk
->nsubstripes
),
806 grub_le_to_cpu64 (chunk
->stripe_length
),
807 stripen
, stripe
->offset
);
808 grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T
809 " for laddr 0x%" PRIxGRUB_UINT64_T
"\n", paddr
,
812 dev
= find_device (data
, stripe
->device_id
, j
);
816 grub_errno
= GRUB_ERR_NONE
;
820 err
= grub_disk_read (dev
->disk
, paddr
>> GRUB_DISK_SECTOR_BITS
,
821 paddr
& (GRUB_DISK_SECTOR_SIZE
- 1),
825 grub_errno
= GRUB_ERR_NONE
;
831 return grub_errno
= err
;
834 buf
= (grub_uint8_t
*) buf
+ csize
;
839 return GRUB_ERR_NONE
;
842 static struct grub_btrfs_data
*
843 grub_btrfs_mount (grub_device_t dev
)
845 struct grub_btrfs_data
*data
;
850 grub_error (GRUB_ERR_BAD_FS
, "not BtrFS");
854 data
= grub_zalloc (sizeof (*data
));
858 err
= read_sblock (dev
->disk
, &data
->sblock
);
865 data
->n_devices_allocated
= 16;
866 data
->devices_attached
= grub_malloc (sizeof (data
->devices_attached
[0])
867 * data
->n_devices_allocated
);
868 if (!data
->devices_attached
)
873 data
->n_devices_attached
= 1;
874 data
->devices_attached
[0].dev
= dev
;
875 data
->devices_attached
[0].id
= data
->sblock
.this_device
.device_id
;
881 grub_btrfs_unmount (struct grub_btrfs_data
*data
)
884 /* The device 0 is closed one layer upper. */
885 for (i
= 1; i
< data
->n_devices_attached
; i
++)
886 grub_device_close (data
->devices_attached
[i
].dev
);
887 grub_free (data
->devices_attached
);
888 grub_free (data
->extent
);
893 grub_btrfs_read_inode (struct grub_btrfs_data
*data
,
894 struct grub_btrfs_inode
*inode
, grub_uint64_t num
,
897 struct grub_btrfs_key key_in
, key_out
;
898 grub_disk_addr_t elemaddr
;
899 grub_size_t elemsize
;
902 key_in
.object_id
= num
;
903 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
;
906 err
= lower_bound (data
, &key_in
, &key_out
, tree
, &elemaddr
, &elemsize
, NULL
,
910 if (num
!= key_out
.object_id
911 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
)
912 return grub_error (GRUB_ERR_BAD_FS
, "inode not found");
914 return grub_btrfs_read_logical (data
, elemaddr
, inode
, sizeof (*inode
), 0);
918 grub_btrfs_lzo_decompress(char *ibuf
, grub_size_t isize
, grub_off_t off
,
919 char *obuf
, grub_size_t osize
)
921 grub_uint32_t total_size
, cblock_size
;
923 unsigned char buf
[GRUB_BTRFS_LZO_BLOCK_SIZE
];
926 total_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
927 ibuf
+= sizeof (total_size
);
929 if (isize
< total_size
)
932 /* Jump forward to first block with requested data. */
933 while (off
>= GRUB_BTRFS_LZO_BLOCK_SIZE
)
935 /* Don't let following uint32_t cross the page boundary. */
936 if (((ibuf
- ibuf0
) & 0xffc) == 0xffc)
937 ibuf
= ((ibuf
- ibuf0
+ 3) & ~3) + ibuf0
;
939 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
940 ibuf
+= sizeof (cblock_size
);
942 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
945 off
-= GRUB_BTRFS_LZO_BLOCK_SIZE
;
951 lzo_uint usize
= GRUB_BTRFS_LZO_BLOCK_SIZE
;
953 /* Don't let following uint32_t cross the page boundary. */
954 if (((ibuf
- ibuf0
) & 0xffc) == 0xffc)
955 ibuf
= ((ibuf
- ibuf0
+ 3) & ~3) + ibuf0
;
957 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
958 ibuf
+= sizeof (cblock_size
);
960 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
963 /* Block partially filled with requested data. */
964 if (off
> 0 || osize
< GRUB_BTRFS_LZO_BLOCK_SIZE
)
966 grub_size_t to_copy
= GRUB_BTRFS_LZO_BLOCK_SIZE
- off
;
971 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, buf
, &usize
,
977 grub_memcpy(obuf
, buf
+ off
, to_copy
);
987 /* Decompress whole block directly to output buffer. */
988 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, (lzo_bytep
)obuf
,
989 &usize
, NULL
) != LZO_E_OK
)
1002 grub_btrfs_extent_read (struct grub_btrfs_data
*data
,
1003 grub_uint64_t ino
, grub_uint64_t tree
,
1004 grub_off_t pos0
, char *buf
, grub_size_t len
)
1006 grub_off_t pos
= pos0
;
1012 if (!data
->extent
|| data
->extstart
> pos
|| data
->extino
!= ino
1013 || data
->exttree
!= tree
|| data
->extend
<= pos
)
1015 struct grub_btrfs_key key_in
, key_out
;
1016 grub_disk_addr_t elemaddr
;
1017 grub_size_t elemsize
;
1019 grub_free (data
->extent
);
1020 key_in
.object_id
= ino
;
1021 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
;
1022 key_in
.offset
= grub_cpu_to_le64 (pos
);
1023 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
1024 &elemaddr
, &elemsize
, NULL
, 0);
1027 if (key_out
.object_id
!= ino
1028 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
)
1030 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1033 if ((grub_ssize_t
) elemsize
< ((char *) &data
->extent
->inl
1034 - (char *) data
->extent
))
1036 grub_error (GRUB_ERR_BAD_FS
, "extent descriptor is too short");
1039 data
->extstart
= grub_le_to_cpu64 (key_out
.offset
);
1040 data
->extsize
= elemsize
;
1041 data
->extent
= grub_malloc (elemsize
);
1043 data
->exttree
= tree
;
1047 err
= grub_btrfs_read_logical (data
, elemaddr
, data
->extent
,
1052 data
->extend
= data
->extstart
+ grub_le_to_cpu64 (data
->extent
->size
);
1053 if (data
->extent
->type
== GRUB_BTRFS_EXTENT_REGULAR
1054 && (char *) &data
->extent
+ elemsize
1055 >= (char *) &data
->extent
->filled
+ sizeof (data
->extent
->filled
))
1057 data
->extstart
+ grub_le_to_cpu64 (data
->extent
->filled
);
1059 grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T
"+0x%"
1060 PRIxGRUB_UINT64_T
"\n",
1061 grub_le_to_cpu64 (key_out
.offset
),
1062 grub_le_to_cpu64 (data
->extent
->size
));
1063 if (data
->extend
<= pos
)
1065 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1069 csize
= data
->extend
- pos
;
1070 extoff
= pos
- data
->extstart
;
1074 if (data
->extent
->encryption
)
1076 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1077 "encryption not supported");
1081 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
1082 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_ZLIB
1083 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_LZO
)
1085 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1086 "compression type 0x%x not supported",
1087 data
->extent
->compression
);
1091 if (data
->extent
->encoding
)
1093 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "encoding not supported");
1097 switch (data
->extent
->type
)
1099 case GRUB_BTRFS_EXTENT_INLINE
:
1100 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1102 if (grub_zlib_decompress (data
->extent
->inl
, data
->extsize
-
1103 ((grub_uint8_t
*) data
->extent
->inl
1104 - (grub_uint8_t
*) data
->extent
),
1106 != (grub_ssize_t
) csize
)
1109 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1111 if (grub_btrfs_lzo_decompress(data
->extent
->inl
, data
->extsize
-
1112 ((grub_uint8_t
*) data
->extent
->inl
1113 - (grub_uint8_t
*) data
->extent
),
1115 != (grub_ssize_t
) csize
)
1119 grub_memcpy (buf
, data
->extent
->inl
+ extoff
, csize
);
1121 case GRUB_BTRFS_EXTENT_REGULAR
:
1122 if (!data
->extent
->laddr
)
1124 grub_memset (buf
, 0, csize
);
1128 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
)
1131 grub_uint64_t zsize
;
1134 zsize
= grub_le_to_cpu64 (data
->extent
->compressed_size
);
1135 tmp
= grub_malloc (zsize
);
1138 err
= grub_btrfs_read_logical (data
,
1139 grub_le_to_cpu64 (data
->extent
->laddr
),
1147 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1148 ret
= grub_zlib_decompress (tmp
, zsize
, extoff
1149 + grub_le_to_cpu64 (data
->extent
->offset
),
1151 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1152 ret
= grub_btrfs_lzo_decompress (tmp
, zsize
, extoff
1153 + grub_le_to_cpu64 (data
->extent
->offset
),
1160 if (ret
!= (grub_ssize_t
) csize
)
1165 err
= grub_btrfs_read_logical (data
,
1166 grub_le_to_cpu64 (data
->extent
->laddr
)
1167 + grub_le_to_cpu64 (data
->extent
->offset
)
1168 + extoff
, buf
, csize
, 0);
1173 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1174 "unsupported extent type 0x%x", data
->extent
->type
);
1185 find_path (struct grub_btrfs_data
*data
,
1186 const char *path
, struct grub_btrfs_key
*key
,
1187 grub_uint64_t
*tree
, grub_uint8_t
*type
)
1189 const char *slash
= path
;
1191 grub_disk_addr_t elemaddr
;
1192 grub_size_t elemsize
;
1193 grub_size_t allocated
= 0;
1194 struct grub_btrfs_dir_item
*direl
= NULL
;
1195 struct grub_btrfs_key key_out
;
1198 grub_size_t ctokenlen
;
1199 char *path_alloc
= NULL
;
1200 char *origpath
= NULL
;
1201 unsigned symlinks_max
= 32;
1203 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1204 *tree
= data
->sblock
.root_tree
;
1205 key
->object_id
= data
->sblock
.root_dir_objectid
;
1206 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1209 origpath
= grub_strdup (path
);
1217 while (path
[0] == '/')
1221 slash
= grub_strchr (path
, '/');
1223 slash
= path
+ grub_strlen (path
);
1225 ctokenlen
= slash
- path
;
1230 ctokenlen
= sizeof ("default") - 1;
1233 if (*type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1235 grub_free (path_alloc
);
1236 grub_free (origpath
);
1237 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
1240 if (ctokenlen
== 1 && ctoken
[0] == '.')
1247 if (ctokenlen
== 2 && ctoken
[0] == '.' && ctoken
[1] == '.')
1249 key
->type
= GRUB_BTRFS_ITEM_TYPE_INODE_REF
;
1252 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1257 grub_free (path_alloc
);
1258 grub_free (origpath
);
1262 if (key_out
.type
!= key
->type
1263 || key
->object_id
!= key_out
.object_id
)
1266 grub_free (path_alloc
);
1267 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1268 grub_free (origpath
);
1272 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1273 key
->object_id
= key_out
.offset
;
1282 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1283 key
->offset
= grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken
, ctokenlen
));
1285 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1290 grub_free (path_alloc
);
1291 grub_free (origpath
);
1294 if (key_cmp (key
, &key_out
) != 0)
1297 grub_free (path_alloc
);
1298 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1299 grub_free (origpath
);
1303 struct grub_btrfs_dir_item
*cdirel
;
1304 if (elemsize
> allocated
)
1306 allocated
= 2 * elemsize
;
1308 direl
= grub_malloc (allocated
+ 1);
1311 grub_free (path_alloc
);
1312 grub_free (origpath
);
1317 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
, 0);
1321 grub_free (path_alloc
);
1322 grub_free (origpath
);
1326 for (cdirel
= direl
;
1327 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1328 < (grub_ssize_t
) elemsize
;
1329 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1330 + grub_le_to_cpu16 (cdirel
->n
)
1331 + grub_le_to_cpu16 (cdirel
->m
)))
1333 if (ctokenlen
== grub_le_to_cpu16 (cdirel
->n
)
1334 && grub_memcmp (cdirel
->name
, ctoken
, ctokenlen
) == 0)
1337 if ((grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1338 >= (grub_ssize_t
) elemsize
)
1341 grub_free (path_alloc
);
1342 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1343 grub_free (origpath
);
1350 if (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK
)
1352 struct grub_btrfs_inode inode
;
1354 if (--symlinks_max
== 0)
1357 grub_free (path_alloc
);
1358 grub_free (origpath
);
1359 return grub_error (GRUB_ERR_SYMLINK_LOOP
,
1360 N_("too deep nesting of symlinks"));
1363 err
= grub_btrfs_read_inode (data
, &inode
,
1364 cdirel
->key
.object_id
, *tree
);
1368 grub_free (path_alloc
);
1369 grub_free (origpath
);
1372 tmp
= grub_malloc (grub_le_to_cpu64 (inode
.size
)
1373 + grub_strlen (path
) + 1);
1377 grub_free (path_alloc
);
1378 grub_free (origpath
);
1382 if (grub_btrfs_extent_read (data
, cdirel
->key
.object_id
,
1384 grub_le_to_cpu64 (inode
.size
))
1385 != (grub_ssize_t
) grub_le_to_cpu64 (inode
.size
))
1388 grub_free (path_alloc
);
1389 grub_free (origpath
);
1393 grub_memcpy (tmp
+ grub_le_to_cpu64 (inode
.size
), path
,
1394 grub_strlen (path
) + 1);
1395 grub_free (path_alloc
);
1396 path
= path_alloc
= tmp
;
1399 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1400 *tree
= data
->sblock
.root_tree
;
1401 key
->object_id
= data
->sblock
.root_dir_objectid
;
1402 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1408 *type
= cdirel
->type
;
1410 switch (cdirel
->key
.type
)
1412 case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
:
1414 struct grub_btrfs_root_item ri
;
1415 err
= lower_bound (data
, &cdirel
->key
, &key_out
,
1416 data
->sblock
.root_tree
,
1417 &elemaddr
, &elemsize
, NULL
, 0);
1421 grub_free (path_alloc
);
1422 grub_free (origpath
);
1425 if (cdirel
->key
.object_id
!= key_out
.object_id
1426 || cdirel
->key
.type
!= key_out
.type
)
1429 grub_free (path_alloc
);
1430 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1431 grub_free (origpath
);
1434 err
= grub_btrfs_read_logical (data
, elemaddr
, &ri
,
1439 grub_free (path_alloc
);
1440 grub_free (origpath
);
1443 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1445 key
->object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
1449 case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
:
1450 if (*slash
&& *type
== GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1453 grub_free (path_alloc
);
1454 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1455 grub_free (origpath
);
1459 if (*type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1460 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1463 grub_free (path_alloc
);
1464 grub_free (origpath
);
1466 return grub_error (GRUB_ERR_BAD_FS
, "unrecognised object type 0x%x",
1472 grub_free (origpath
);
1473 grub_free (path_alloc
);
1474 return GRUB_ERR_NONE
;
1478 grub_btrfs_dir (grub_device_t device
, const char *path
,
1479 int (*hook
) (const char *filename
,
1480 const struct grub_dirhook_info
*info
))
1482 struct grub_btrfs_data
*data
= grub_btrfs_mount (device
);
1483 struct grub_btrfs_key key_in
, key_out
;
1485 grub_disk_addr_t elemaddr
;
1486 grub_size_t elemsize
;
1487 grub_size_t allocated
= 0;
1488 struct grub_btrfs_dir_item
*direl
= NULL
;
1489 struct grub_btrfs_leaf_descriptor desc
;
1497 err
= find_path (data
, path
, &key_in
, &tree
, &type
);
1500 grub_btrfs_unmount (data
);
1503 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1505 grub_btrfs_unmount (data
);
1506 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
1509 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
1510 &elemaddr
, &elemsize
, &desc
, 0);
1513 grub_btrfs_unmount (data
);
1516 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1517 || key_out
.object_id
!= key_in
.object_id
)
1519 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1525 struct grub_btrfs_dir_item
*cdirel
;
1526 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1527 || key_out
.object_id
!= key_in
.object_id
)
1532 if (elemsize
> allocated
)
1534 allocated
= 2 * elemsize
;
1536 direl
= grub_malloc (allocated
+ 1);
1544 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
, 0);
1551 for (cdirel
= direl
;
1552 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1553 < (grub_ssize_t
) elemsize
;
1554 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1555 + grub_le_to_cpu16 (cdirel
->n
)
1556 + grub_le_to_cpu16 (cdirel
->m
)))
1559 struct grub_btrfs_inode inode
;
1560 struct grub_dirhook_info info
;
1561 err
= grub_btrfs_read_inode (data
, &inode
, cdirel
->key
.object_id
,
1563 grub_memset (&info
, 0, sizeof (info
));
1565 grub_errno
= GRUB_ERR_NONE
;
1568 info
.mtime
= grub_le_to_cpu64 (inode
.mtime
.sec
);
1571 c
= cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)];
1572 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = 0;
1573 info
.dir
= (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
);
1574 if (hook (cdirel
->name
, &info
))
1576 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = c
;
1578 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1585 free_iterator (&desc
);
1586 grub_btrfs_unmount (data
);
1592 grub_btrfs_open (struct grub_file
*file
, const char *name
)
1594 struct grub_btrfs_data
*data
= grub_btrfs_mount (file
->device
);
1596 struct grub_btrfs_inode inode
;
1598 struct grub_btrfs_key key_in
;
1603 err
= find_path (data
, name
, &key_in
, &data
->tree
, &type
);
1606 grub_btrfs_unmount (data
);
1609 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1611 grub_btrfs_unmount (data
);
1612 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a regular file"));
1615 data
->inode
= key_in
.object_id
;
1616 err
= grub_btrfs_read_inode (data
, &inode
, data
->inode
, data
->tree
);
1619 grub_btrfs_unmount (data
);
1624 file
->size
= grub_le_to_cpu64 (inode
.size
);
1630 grub_btrfs_close (grub_file_t file
)
1632 grub_btrfs_unmount (file
->data
);
1634 return GRUB_ERR_NONE
;
1638 grub_btrfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
1640 struct grub_btrfs_data
*data
= file
->data
;
1642 return grub_btrfs_extent_read (data
, data
->inode
,
1643 data
->tree
, file
->offset
, buf
, len
);
1647 grub_btrfs_uuid (grub_device_t device
, char **uuid
)
1649 struct grub_btrfs_data
*data
;
1653 data
= grub_btrfs_mount (device
);
1657 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1658 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
1659 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
1660 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
1661 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
1662 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
1663 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
1664 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
1665 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
1667 grub_btrfs_unmount (data
);
1673 grub_btrfs_label (grub_device_t device
, char **label
)
1675 struct grub_btrfs_data
*data
;
1679 data
= grub_btrfs_mount (device
);
1683 *label
= grub_strndup (data
->sblock
.label
, sizeof (data
->sblock
.label
));
1685 grub_btrfs_unmount (data
);
1692 grub_btrfs_embed (grub_device_t device
__attribute__ ((unused
)),
1693 unsigned int *nsectors
,
1694 unsigned int max_nsectors
,
1695 grub_embed_type_t embed_type
,
1696 grub_disk_addr_t
**sectors
)
1700 if (embed_type
!= GRUB_EMBED_PCBIOS
)
1701 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1702 "BtrFS currently supports only PC-BIOS embedding");
1704 if (64 * 2 - 1 < *nsectors
)
1705 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
1706 N_("your core.img is unusually large. "
1707 "It won't fit in the embedding area"));
1709 *nsectors
= 64 * 2 - 1;
1710 if (*nsectors
> max_nsectors
)
1711 *nsectors
= max_nsectors
;
1712 *sectors
= grub_malloc (*nsectors
* sizeof (**sectors
));
1715 for (i
= 0; i
< *nsectors
; i
++)
1716 (*sectors
)[i
] = i
+ 1;
1718 return GRUB_ERR_NONE
;
1722 static struct grub_fs grub_btrfs_fs
= {
1724 .dir
= grub_btrfs_dir
,
1725 .open
= grub_btrfs_open
,
1726 .read
= grub_btrfs_read
,
1727 .close
= grub_btrfs_close
,
1728 .uuid
= grub_btrfs_uuid
,
1729 .label
= grub_btrfs_label
,
1731 .embed
= grub_btrfs_embed
,
1732 .reserved_first_sector
= 1,
1733 .blocklist_install
= 0,
1737 GRUB_MOD_INIT (btrfs
)
1739 grub_fs_register (&grub_btrfs_fs
);
1742 GRUB_MOD_FINI (btrfs
)
1744 grub_fs_unregister (&grub_btrfs_fs
);