1 /* btrfs.c - B-tree file system. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2010,2011,2012,2013 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>
31 #include <grub/btrfs.h>
33 GRUB_MOD_LICENSE ("GPLv3+");
35 #define GRUB_BTRFS_SIGNATURE "_BHRfS_M"
37 /* From http://www.oberhumer.com/opensource/lzo/lzofaq.php
38 * LZO will expand incompressible data by a little amount. I still haven't
39 * computed the exact values, but I suggest using these formulas for
40 * a worst-case expansion calculation:
42 * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3
44 #define GRUB_BTRFS_LZO_BLOCK_SIZE 4096
45 #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
46 (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
48 typedef grub_uint8_t grub_btrfs_checksum_t
[0x20];
49 typedef grub_uint16_t grub_btrfs_uuid_t
[8];
51 struct grub_btrfs_device
53 grub_uint64_t device_id
;
55 grub_uint8_t dummy
[0x62 - 0x10];
58 struct grub_btrfs_superblock
60 grub_btrfs_checksum_t checksum
;
61 grub_btrfs_uuid_t uuid
;
62 grub_uint8_t dummy
[0x10];
63 grub_uint8_t signature
[sizeof (GRUB_BTRFS_SIGNATURE
) - 1];
64 grub_uint64_t generation
;
65 grub_uint64_t root_tree
;
66 grub_uint64_t chunk_tree
;
67 grub_uint8_t dummy2
[0x20];
68 grub_uint64_t root_dir_objectid
;
69 grub_uint8_t dummy3
[0x41];
70 struct grub_btrfs_device this_device
;
72 grub_uint8_t dummy4
[0x100];
73 grub_uint8_t bootstrap_mapping
[0x800];
78 grub_btrfs_checksum_t checksum
;
79 grub_btrfs_uuid_t uuid
;
80 grub_uint8_t dummy
[0x30];
85 struct grub_btrfs_device_desc
91 struct grub_btrfs_data
93 struct grub_btrfs_superblock sblock
;
97 struct grub_btrfs_device_desc
*devices_attached
;
98 unsigned n_devices_attached
;
99 unsigned n_devices_allocated
;
101 /* Cached extent data. */
102 grub_uint64_t extstart
;
103 grub_uint64_t extend
;
104 grub_uint64_t extino
;
105 grub_uint64_t exttree
;
107 struct grub_btrfs_extent_data
*extent
;
110 struct grub_btrfs_chunk_item
114 grub_uint64_t stripe_length
;
116 #define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07
117 #define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00
118 #define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08
119 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10
120 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20
121 #define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40
122 grub_uint8_t dummy2
[0xc];
123 grub_uint16_t nstripes
;
124 grub_uint16_t nsubstripes
;
127 struct grub_btrfs_chunk_stripe
129 grub_uint64_t device_id
;
130 grub_uint64_t offset
;
131 grub_btrfs_uuid_t device_uuid
;
134 struct grub_btrfs_leaf_node
136 struct grub_btrfs_key key
;
137 grub_uint32_t offset
;
141 struct grub_btrfs_internal_node
143 struct grub_btrfs_key key
;
148 struct grub_btrfs_dir_item
150 struct grub_btrfs_key key
;
151 grub_uint8_t dummy
[8];
154 #define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1
155 #define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2
156 #define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7
161 struct grub_btrfs_leaf_descriptor
167 grub_disk_addr_t addr
;
174 struct grub_btrfs_time
177 grub_uint32_t nanosec
;
178 } __attribute__ ((aligned (4)));
180 struct grub_btrfs_inode
182 grub_uint8_t dummy1
[0x10];
184 grub_uint8_t dummy2
[0x70];
185 struct grub_btrfs_time mtime
;
188 struct grub_btrfs_extent_data
192 grub_uint8_t compression
;
193 grub_uint8_t encryption
;
194 grub_uint16_t encoding
;
202 grub_uint64_t compressed_size
;
203 grub_uint64_t offset
;
204 grub_uint64_t filled
;
209 #define GRUB_BTRFS_EXTENT_INLINE 0
210 #define GRUB_BTRFS_EXTENT_REGULAR 1
212 #define GRUB_BTRFS_COMPRESSION_NONE 0
213 #define GRUB_BTRFS_COMPRESSION_ZLIB 1
214 #define GRUB_BTRFS_COMPRESSION_LZO 2
216 #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
218 static grub_disk_addr_t superblock_sectors
[] = { 64 * 2, 64 * 1024 * 2,
219 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
223 grub_btrfs_read_logical (struct grub_btrfs_data
*data
,
224 grub_disk_addr_t addr
, void *buf
, grub_size_t size
,
225 int recursion_depth
);
228 read_sblock (grub_disk_t disk
, struct grub_btrfs_superblock
*sb
)
231 grub_err_t err
= GRUB_ERR_NONE
;
232 for (i
= 0; i
< ARRAY_SIZE (superblock_sectors
); i
++)
234 struct grub_btrfs_superblock sblock
;
235 /* Don't try additional superblocks beyond device size. */
236 if (i
&& (grub_le_to_cpu64 (sblock
.this_device
.size
)
237 >> GRUB_DISK_SECTOR_BITS
) <= superblock_sectors
[i
])
239 err
= grub_disk_read (disk
, superblock_sectors
[i
], 0,
240 sizeof (sblock
), &sblock
);
241 if (err
== GRUB_ERR_OUT_OF_RANGE
)
244 if (grub_memcmp ((char *) sblock
.signature
, GRUB_BTRFS_SIGNATURE
,
245 sizeof (GRUB_BTRFS_SIGNATURE
) - 1) != 0)
247 if (i
== 0 || grub_le_to_cpu64 (sblock
.generation
)
248 > grub_le_to_cpu64 (sb
->generation
))
249 grub_memcpy (sb
, &sblock
, sizeof (sblock
));
252 if ((err
== GRUB_ERR_OUT_OF_RANGE
|| !err
) && i
== 0)
253 return grub_error (GRUB_ERR_BAD_FS
, "not a Btrfs filesystem");
255 if (err
== GRUB_ERR_OUT_OF_RANGE
)
256 grub_errno
= err
= GRUB_ERR_NONE
;
262 key_cmp (const struct grub_btrfs_key
*a
, const struct grub_btrfs_key
*b
)
264 if (grub_le_to_cpu64 (a
->object_id
) < grub_le_to_cpu64 (b
->object_id
))
266 if (grub_le_to_cpu64 (a
->object_id
) > grub_le_to_cpu64 (b
->object_id
))
269 if (a
->type
< b
->type
)
271 if (a
->type
> b
->type
)
274 if (grub_le_to_cpu64 (a
->offset
) < grub_le_to_cpu64 (b
->offset
))
276 if (grub_le_to_cpu64 (a
->offset
) > grub_le_to_cpu64 (b
->offset
))
282 free_iterator (struct grub_btrfs_leaf_descriptor
*desc
)
284 grub_free (desc
->data
);
288 save_ref (struct grub_btrfs_leaf_descriptor
*desc
,
289 grub_disk_addr_t addr
, unsigned i
, unsigned m
, int l
)
292 if (desc
->allocated
< desc
->depth
)
295 desc
->allocated
*= 2;
296 newdata
= grub_realloc (desc
->data
, sizeof (desc
->data
[0])
300 desc
->data
= newdata
;
302 desc
->data
[desc
->depth
- 1].addr
= addr
;
303 desc
->data
[desc
->depth
- 1].iter
= i
;
304 desc
->data
[desc
->depth
- 1].maxiter
= m
;
305 desc
->data
[desc
->depth
- 1].leaf
= l
;
306 return GRUB_ERR_NONE
;
310 next (struct grub_btrfs_data
*data
,
311 struct grub_btrfs_leaf_descriptor
*desc
,
312 grub_disk_addr_t
* outaddr
, grub_size_t
* outsize
,
313 struct grub_btrfs_key
*key_out
)
316 struct grub_btrfs_leaf_node leaf
;
318 for (; desc
->depth
> 0; desc
->depth
--)
320 desc
->data
[desc
->depth
- 1].iter
++;
321 if (desc
->data
[desc
->depth
- 1].iter
322 < desc
->data
[desc
->depth
- 1].maxiter
)
325 if (desc
->depth
== 0)
327 while (!desc
->data
[desc
->depth
- 1].leaf
)
329 struct grub_btrfs_internal_node node
;
330 struct btrfs_header head
;
332 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
334 + sizeof (struct btrfs_header
)
335 + desc
->data
[desc
->depth
- 1].addr
,
336 &node
, sizeof (node
), 0);
340 err
= grub_btrfs_read_logical (data
, grub_le_to_cpu64 (node
.addr
),
341 &head
, sizeof (head
), 0);
345 save_ref (desc
, grub_le_to_cpu64 (node
.addr
), 0,
346 grub_le_to_cpu32 (head
.nitems
), !head
.level
);
348 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
350 + sizeof (struct btrfs_header
)
351 + desc
->data
[desc
->depth
- 1].addr
, &leaf
,
355 *outsize
= grub_le_to_cpu32 (leaf
.size
);
356 *outaddr
= desc
->data
[desc
->depth
- 1].addr
+ sizeof (struct btrfs_header
)
357 + grub_le_to_cpu32 (leaf
.offset
);
363 lower_bound (struct grub_btrfs_data
*data
,
364 const struct grub_btrfs_key
*key_in
,
365 struct grub_btrfs_key
*key_out
,
367 grub_disk_addr_t
*outaddr
, grub_size_t
*outsize
,
368 struct grub_btrfs_leaf_descriptor
*desc
,
371 grub_disk_addr_t addr
= grub_le_to_cpu64 (root
);
376 desc
->allocated
= 16;
378 desc
->data
= grub_malloc (sizeof (desc
->data
[0]) * desc
->allocated
);
383 /* > 2 would work as well but be robust and allow a bit more just in case.
385 if (recursion_depth
> 10)
386 return grub_error (GRUB_ERR_BAD_FS
, "too deep btrfs virtual nesting");
388 grub_dprintf ("btrfs",
389 "retrieving %" PRIxGRUB_UINT64_T
390 " %x %" PRIxGRUB_UINT64_T
"\n",
391 key_in
->object_id
, key_in
->type
, key_in
->offset
);
396 struct btrfs_header head
;
400 /* FIXME: preread few nodes into buffer. */
401 err
= grub_btrfs_read_logical (data
, addr
, &head
, sizeof (head
),
402 recursion_depth
+ 1);
405 addr
+= sizeof (head
);
409 struct grub_btrfs_internal_node node
, node_last
;
411 grub_memset (&node_last
, 0, sizeof (node_last
));
412 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
414 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (node
),
415 &node
, sizeof (node
),
416 recursion_depth
+ 1);
420 grub_dprintf ("btrfs",
421 "internal node (depth %d) %" PRIxGRUB_UINT64_T
422 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
423 node
.key
.object_id
, node
.key
.type
,
426 if (key_cmp (&node
.key
, key_in
) == 0)
430 err
= save_ref (desc
, addr
- sizeof (head
), i
,
431 grub_le_to_cpu32 (head
.nitems
), 0);
434 addr
= grub_le_to_cpu64 (node
.addr
);
437 if (key_cmp (&node
.key
, key_in
) > 0)
446 err
= save_ref (desc
, addr
- sizeof (head
), i
- 1,
447 grub_le_to_cpu32 (head
.nitems
), 0);
450 addr
= grub_le_to_cpu64 (node_last
.addr
);
455 grub_memset (key_out
, 0, sizeof (*key_out
));
457 return save_ref (desc
, addr
- sizeof (head
), -1,
458 grub_le_to_cpu32 (head
.nitems
), 0);
459 return GRUB_ERR_NONE
;
463 struct grub_btrfs_leaf_node leaf
, leaf_last
;
465 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
467 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (leaf
),
468 &leaf
, sizeof (leaf
),
469 recursion_depth
+ 1);
473 grub_dprintf ("btrfs",
474 "leaf (depth %d) %" PRIxGRUB_UINT64_T
475 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
476 leaf
.key
.object_id
, leaf
.key
.type
, leaf
.key
.offset
);
478 if (key_cmp (&leaf
.key
, key_in
) == 0)
480 grub_memcpy (key_out
, &leaf
.key
, sizeof (*key_out
));
481 *outsize
= grub_le_to_cpu32 (leaf
.size
);
482 *outaddr
= addr
+ grub_le_to_cpu32 (leaf
.offset
);
484 return save_ref (desc
, addr
- sizeof (head
), i
,
485 grub_le_to_cpu32 (head
.nitems
), 1);
486 return GRUB_ERR_NONE
;
489 if (key_cmp (&leaf
.key
, key_in
) > 0)
498 grub_memcpy (key_out
, &leaf_last
.key
, sizeof (*key_out
));
499 *outsize
= grub_le_to_cpu32 (leaf_last
.size
);
500 *outaddr
= addr
+ grub_le_to_cpu32 (leaf_last
.offset
);
502 return save_ref (desc
, addr
- sizeof (head
), i
- 1,
503 grub_le_to_cpu32 (head
.nitems
), 1);
504 return GRUB_ERR_NONE
;
508 grub_memset (key_out
, 0, sizeof (*key_out
));
510 return save_ref (desc
, addr
- sizeof (head
), -1,
511 grub_le_to_cpu32 (head
.nitems
), 1);
512 return GRUB_ERR_NONE
;
517 /* Context for find_device. */
518 struct find_device_ctx
520 struct grub_btrfs_data
*data
;
522 grub_device_t dev_found
;
525 /* Helper for find_device. */
527 find_device_iter (const char *name
, void *data
)
529 struct find_device_ctx
*ctx
= data
;
532 struct grub_btrfs_superblock sb
;
534 dev
= grub_device_open (name
);
539 grub_device_close (dev
);
542 err
= read_sblock (dev
->disk
, &sb
);
543 if (err
== GRUB_ERR_BAD_FS
)
545 grub_device_close (dev
);
546 grub_errno
= GRUB_ERR_NONE
;
551 grub_device_close (dev
);
555 if (grub_memcmp (ctx
->data
->sblock
.uuid
, sb
.uuid
, sizeof (sb
.uuid
)) != 0
556 || sb
.this_device
.device_id
!= ctx
->id
)
558 grub_device_close (dev
);
562 ctx
->dev_found
= dev
;
567 find_device (struct grub_btrfs_data
*data
, grub_uint64_t id
, int do_rescan
)
569 struct find_device_ctx ctx
= {
576 for (i
= 0; i
< data
->n_devices_attached
; i
++)
577 if (id
== data
->devices_attached
[i
].id
)
578 return data
->devices_attached
[i
].dev
;
580 grub_device_iterate (find_device_iter
, &ctx
);
583 grub_error (GRUB_ERR_BAD_FS
,
584 N_("couldn't find a necessary member device "
585 "of multi-device filesystem"));
588 data
->n_devices_attached
++;
589 if (data
->n_devices_attached
> data
->n_devices_allocated
)
592 data
->n_devices_allocated
= 2 * data
->n_devices_attached
+ 1;
593 data
->devices_attached
594 = grub_realloc (tmp
= data
->devices_attached
,
595 data
->n_devices_allocated
596 * sizeof (data
->devices_attached
[0]));
597 if (!data
->devices_attached
)
599 grub_device_close (ctx
.dev_found
);
600 data
->devices_attached
= tmp
;
604 data
->devices_attached
[data
->n_devices_attached
- 1].id
= id
;
605 data
->devices_attached
[data
->n_devices_attached
- 1].dev
= ctx
.dev_found
;
606 return ctx
.dev_found
;
610 grub_btrfs_read_logical (struct grub_btrfs_data
*data
, grub_disk_addr_t addr
,
611 void *buf
, grub_size_t size
, int recursion_depth
)
616 struct grub_btrfs_key
*key
;
617 struct grub_btrfs_chunk_item
*chunk
;
620 struct grub_btrfs_key key_out
;
623 struct grub_btrfs_key key_in
;
625 grub_disk_addr_t chaddr
;
627 grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T
"\n",
629 for (ptr
= data
->sblock
.bootstrap_mapping
;
630 ptr
< data
->sblock
.bootstrap_mapping
631 + sizeof (data
->sblock
.bootstrap_mapping
)
632 - sizeof (struct grub_btrfs_key
);)
634 key
= (struct grub_btrfs_key
*) ptr
;
635 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
)
637 chunk
= (struct grub_btrfs_chunk_item
*) (key
+ 1);
638 grub_dprintf ("btrfs",
639 "%" PRIxGRUB_UINT64_T
" %" PRIxGRUB_UINT64_T
" \n",
640 grub_le_to_cpu64 (key
->offset
),
641 grub_le_to_cpu64 (chunk
->size
));
642 if (grub_le_to_cpu64 (key
->offset
) <= addr
643 && addr
< grub_le_to_cpu64 (key
->offset
)
644 + grub_le_to_cpu64 (chunk
->size
))
646 ptr
+= sizeof (*key
) + sizeof (*chunk
)
647 + sizeof (struct grub_btrfs_chunk_stripe
)
648 * grub_le_to_cpu16 (chunk
->nstripes
);
651 key_in
.object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
652 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_CHUNK
;
653 key_in
.offset
= grub_cpu_to_le64 (addr
);
654 err
= lower_bound (data
, &key_in
, &key_out
,
655 data
->sblock
.chunk_tree
,
656 &chaddr
, &chsize
, NULL
, recursion_depth
);
660 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
661 || !(grub_le_to_cpu64 (key
->offset
) <= addr
))
662 return grub_error (GRUB_ERR_BAD_FS
,
663 "couldn't find the chunk descriptor");
665 chunk
= grub_malloc (chsize
);
670 err
= grub_btrfs_read_logical (data
, chaddr
, chunk
, chsize
,
680 grub_uint64_t stripen
;
681 grub_uint64_t stripe_offset
;
682 grub_uint64_t off
= addr
- grub_le_to_cpu64 (key
->offset
);
683 grub_uint64_t chunk_stripe_length
;
684 grub_uint16_t nstripes
;
685 unsigned redundancy
= 1;
688 if (grub_le_to_cpu64 (chunk
->size
) <= off
)
690 grub_dprintf ("btrfs", "no chunk\n");
691 return grub_error (GRUB_ERR_BAD_FS
,
692 "couldn't find the chunk descriptor");
695 nstripes
= grub_le_to_cpu16 (chunk
->nstripes
) ? : 1;
696 chunk_stripe_length
= grub_le_to_cpu64 (chunk
->stripe_length
) ? : 512;
697 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
698 "+0x%" PRIxGRUB_UINT64_T
699 " (%d stripes (%d substripes) of %"
700 PRIxGRUB_UINT64_T
")\n",
701 grub_le_to_cpu64 (key
->offset
),
702 grub_le_to_cpu64 (chunk
->size
),
704 grub_le_to_cpu16 (chunk
->nsubstripes
),
705 chunk_stripe_length
);
707 switch (grub_le_to_cpu64 (chunk
->type
)
708 & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE
)
710 case GRUB_BTRFS_CHUNK_TYPE_SINGLE
:
712 grub_uint64_t stripe_length
;
713 grub_dprintf ("btrfs", "single\n");
714 stripe_length
= grub_divmod64 (grub_le_to_cpu64 (chunk
->size
),
717 if (stripe_length
== 0)
719 stripen
= grub_divmod64 (off
, stripe_length
, &stripe_offset
);
720 csize
= (stripen
+ 1) * stripe_length
- off
;
723 case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED
:
724 case GRUB_BTRFS_CHUNK_TYPE_RAID1
:
726 grub_dprintf ("btrfs", "RAID1\n");
729 csize
= grub_le_to_cpu64 (chunk
->size
) - off
;
733 case GRUB_BTRFS_CHUNK_TYPE_RAID0
:
735 grub_uint64_t middle
, high
;
737 grub_dprintf ("btrfs", "RAID0\n");
738 middle
= grub_divmod64 (off
,
742 high
= grub_divmod64 (middle
, nstripes
,
745 low
+ chunk_stripe_length
* high
;
746 csize
= chunk_stripe_length
- low
;
749 case GRUB_BTRFS_CHUNK_TYPE_RAID10
:
751 grub_uint64_t middle
, high
;
753 grub_uint16_t nsubstripes
;
754 nsubstripes
= grub_le_to_cpu16 (chunk
->nsubstripes
) ? : 1;
755 middle
= grub_divmod64 (off
,
759 high
= grub_divmod64 (middle
,
760 nstripes
/ nsubstripes
? : 1,
762 stripen
*= nsubstripes
;
763 redundancy
= nsubstripes
;
764 stripe_offset
= low
+ chunk_stripe_length
766 csize
= chunk_stripe_length
- low
;
770 grub_dprintf ("btrfs", "unsupported RAID\n");
771 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
772 "unsupported RAID flags %" PRIxGRUB_UINT64_T
,
773 grub_le_to_cpu64 (chunk
->type
));
776 return grub_error (GRUB_ERR_BUG
,
777 "couldn't find the chunk descriptor");
778 if (csize
> (grub_uint64_t
) size
)
781 for (j
= 0; j
< 2; j
++)
783 for (i
= 0; i
< redundancy
; i
++)
785 struct grub_btrfs_chunk_stripe
*stripe
;
786 grub_disk_addr_t paddr
;
788 stripe
= (struct grub_btrfs_chunk_stripe
*) (chunk
+ 1);
789 /* Right now the redundancy handling is easy.
790 With RAID5-like it will be more difficult. */
791 stripe
+= stripen
+ i
;
793 paddr
= grub_le_to_cpu64 (stripe
->offset
) + stripe_offset
;
795 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
796 "+0x%" PRIxGRUB_UINT64_T
797 " (%d stripes (%d substripes) of %"
798 PRIxGRUB_UINT64_T
") stripe %" PRIxGRUB_UINT64_T
799 " maps to 0x%" PRIxGRUB_UINT64_T
"\n",
800 grub_le_to_cpu64 (key
->offset
),
801 grub_le_to_cpu64 (chunk
->size
),
802 grub_le_to_cpu16 (chunk
->nstripes
),
803 grub_le_to_cpu16 (chunk
->nsubstripes
),
804 grub_le_to_cpu64 (chunk
->stripe_length
),
805 stripen
, stripe
->offset
);
806 grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T
807 " for laddr 0x%" PRIxGRUB_UINT64_T
"\n", paddr
,
810 dev
= find_device (data
, stripe
->device_id
, j
);
814 grub_errno
= GRUB_ERR_NONE
;
818 err
= grub_disk_read (dev
->disk
, paddr
>> GRUB_DISK_SECTOR_BITS
,
819 paddr
& (GRUB_DISK_SECTOR_SIZE
- 1),
823 grub_errno
= GRUB_ERR_NONE
;
829 return grub_errno
= err
;
832 buf
= (grub_uint8_t
*) buf
+ csize
;
837 return GRUB_ERR_NONE
;
840 static struct grub_btrfs_data
*
841 grub_btrfs_mount (grub_device_t dev
)
843 struct grub_btrfs_data
*data
;
848 grub_error (GRUB_ERR_BAD_FS
, "not BtrFS");
852 data
= grub_zalloc (sizeof (*data
));
856 err
= read_sblock (dev
->disk
, &data
->sblock
);
863 data
->n_devices_allocated
= 16;
864 data
->devices_attached
= grub_malloc (sizeof (data
->devices_attached
[0])
865 * data
->n_devices_allocated
);
866 if (!data
->devices_attached
)
871 data
->n_devices_attached
= 1;
872 data
->devices_attached
[0].dev
= dev
;
873 data
->devices_attached
[0].id
= data
->sblock
.this_device
.device_id
;
879 grub_btrfs_unmount (struct grub_btrfs_data
*data
)
882 /* The device 0 is closed one layer upper. */
883 for (i
= 1; i
< data
->n_devices_attached
; i
++)
884 grub_device_close (data
->devices_attached
[i
].dev
);
885 grub_free (data
->devices_attached
);
886 grub_free (data
->extent
);
891 grub_btrfs_read_inode (struct grub_btrfs_data
*data
,
892 struct grub_btrfs_inode
*inode
, grub_uint64_t num
,
895 struct grub_btrfs_key key_in
, key_out
;
896 grub_disk_addr_t elemaddr
;
897 grub_size_t elemsize
;
900 key_in
.object_id
= num
;
901 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
;
904 err
= lower_bound (data
, &key_in
, &key_out
, tree
, &elemaddr
, &elemsize
, NULL
,
908 if (num
!= key_out
.object_id
909 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
)
910 return grub_error (GRUB_ERR_BAD_FS
, "inode not found");
912 return grub_btrfs_read_logical (data
, elemaddr
, inode
, sizeof (*inode
), 0);
916 grub_btrfs_lzo_decompress(char *ibuf
, grub_size_t isize
, grub_off_t off
,
917 char *obuf
, grub_size_t osize
)
919 grub_uint32_t total_size
, cblock_size
;
923 total_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
924 ibuf
+= sizeof (total_size
);
926 if (isize
< total_size
)
929 /* Jump forward to first block with requested data. */
930 while (off
>= GRUB_BTRFS_LZO_BLOCK_SIZE
)
932 /* Don't let following uint32_t cross the page boundary. */
933 if (((ibuf
- ibuf0
) & 0xffc) == 0xffc)
934 ibuf
= ((ibuf
- ibuf0
+ 3) & ~3) + ibuf0
;
936 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
937 ibuf
+= sizeof (cblock_size
);
939 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
942 off
-= GRUB_BTRFS_LZO_BLOCK_SIZE
;
948 lzo_uint usize
= GRUB_BTRFS_LZO_BLOCK_SIZE
;
950 /* Don't let following uint32_t cross the page boundary. */
951 if (((ibuf
- ibuf0
) & 0xffc) == 0xffc)
952 ibuf
= ((ibuf
- ibuf0
+ 3) & ~3) + ibuf0
;
954 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
955 ibuf
+= sizeof (cblock_size
);
957 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
960 /* Block partially filled with requested data. */
961 if (off
> 0 || osize
< GRUB_BTRFS_LZO_BLOCK_SIZE
)
963 grub_size_t to_copy
= GRUB_BTRFS_LZO_BLOCK_SIZE
- off
;
969 buf
= grub_malloc (GRUB_BTRFS_LZO_BLOCK_SIZE
);
973 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, buf
, &usize
,
982 grub_memcpy(obuf
, buf
+ off
, to_copy
);
994 /* Decompress whole block directly to output buffer. */
995 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, (lzo_bytep
)obuf
,
996 &usize
, NULL
) != LZO_E_OK
)
1002 ibuf
+= cblock_size
;
1009 grub_btrfs_extent_read (struct grub_btrfs_data
*data
,
1010 grub_uint64_t ino
, grub_uint64_t tree
,
1011 grub_off_t pos0
, char *buf
, grub_size_t len
)
1013 grub_off_t pos
= pos0
;
1019 if (!data
->extent
|| data
->extstart
> pos
|| data
->extino
!= ino
1020 || data
->exttree
!= tree
|| data
->extend
<= pos
)
1022 struct grub_btrfs_key key_in
, key_out
;
1023 grub_disk_addr_t elemaddr
;
1024 grub_size_t elemsize
;
1026 grub_free (data
->extent
);
1027 key_in
.object_id
= ino
;
1028 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
;
1029 key_in
.offset
= grub_cpu_to_le64 (pos
);
1030 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
1031 &elemaddr
, &elemsize
, NULL
, 0);
1034 if (key_out
.object_id
!= ino
1035 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
)
1037 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1040 if ((grub_ssize_t
) elemsize
< ((char *) &data
->extent
->inl
1041 - (char *) data
->extent
))
1043 grub_error (GRUB_ERR_BAD_FS
, "extent descriptor is too short");
1046 data
->extstart
= grub_le_to_cpu64 (key_out
.offset
);
1047 data
->extsize
= elemsize
;
1048 data
->extent
= grub_malloc (elemsize
);
1050 data
->exttree
= tree
;
1054 err
= grub_btrfs_read_logical (data
, elemaddr
, data
->extent
,
1059 data
->extend
= data
->extstart
+ grub_le_to_cpu64 (data
->extent
->size
);
1060 if (data
->extent
->type
== GRUB_BTRFS_EXTENT_REGULAR
1061 && (char *) data
->extent
+ elemsize
1062 >= (char *) &data
->extent
->filled
+ sizeof (data
->extent
->filled
))
1064 data
->extstart
+ grub_le_to_cpu64 (data
->extent
->filled
);
1066 grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T
"+0x%"
1067 PRIxGRUB_UINT64_T
"\n",
1068 grub_le_to_cpu64 (key_out
.offset
),
1069 grub_le_to_cpu64 (data
->extent
->size
));
1070 if (data
->extend
<= pos
)
1072 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1076 csize
= data
->extend
- pos
;
1077 extoff
= pos
- data
->extstart
;
1081 if (data
->extent
->encryption
)
1083 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1084 "encryption not supported");
1088 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
1089 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_ZLIB
1090 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_LZO
)
1092 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1093 "compression type 0x%x not supported",
1094 data
->extent
->compression
);
1098 if (data
->extent
->encoding
)
1100 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "encoding not supported");
1104 switch (data
->extent
->type
)
1106 case GRUB_BTRFS_EXTENT_INLINE
:
1107 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1109 if (grub_zlib_decompress (data
->extent
->inl
, data
->extsize
-
1110 ((grub_uint8_t
*) data
->extent
->inl
1111 - (grub_uint8_t
*) data
->extent
),
1113 != (grub_ssize_t
) csize
)
1116 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
,
1117 "premature end of compressed");
1121 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1123 if (grub_btrfs_lzo_decompress(data
->extent
->inl
, data
->extsize
-
1124 ((grub_uint8_t
*) data
->extent
->inl
1125 - (grub_uint8_t
*) data
->extent
),
1127 != (grub_ssize_t
) csize
)
1131 grub_memcpy (buf
, data
->extent
->inl
+ extoff
, csize
);
1133 case GRUB_BTRFS_EXTENT_REGULAR
:
1134 if (!data
->extent
->laddr
)
1136 grub_memset (buf
, 0, csize
);
1140 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
)
1143 grub_uint64_t zsize
;
1146 zsize
= grub_le_to_cpu64 (data
->extent
->compressed_size
);
1147 tmp
= grub_malloc (zsize
);
1150 err
= grub_btrfs_read_logical (data
,
1151 grub_le_to_cpu64 (data
->extent
->laddr
),
1159 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1160 ret
= grub_zlib_decompress (tmp
, zsize
, extoff
1161 + grub_le_to_cpu64 (data
->extent
->offset
),
1163 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1164 ret
= grub_btrfs_lzo_decompress (tmp
, zsize
, extoff
1165 + grub_le_to_cpu64 (data
->extent
->offset
),
1172 if (ret
!= (grub_ssize_t
) csize
)
1175 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
,
1176 "premature end of compressed");
1182 err
= grub_btrfs_read_logical (data
,
1183 grub_le_to_cpu64 (data
->extent
->laddr
)
1184 + grub_le_to_cpu64 (data
->extent
->offset
)
1185 + extoff
, buf
, csize
, 0);
1190 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1191 "unsupported extent type 0x%x", data
->extent
->type
);
1202 get_root (struct grub_btrfs_data
*data
, struct grub_btrfs_key
*key
,
1203 grub_uint64_t
*tree
, grub_uint8_t
*type
)
1206 grub_disk_addr_t elemaddr
;
1207 grub_size_t elemsize
;
1208 struct grub_btrfs_key key_out
, key_in
;
1209 struct grub_btrfs_root_item ri
;
1211 key_in
.object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_ROOT_VOL_OBJECTID
);
1213 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
;
1214 err
= lower_bound (data
, &key_in
, &key_out
,
1215 data
->sblock
.root_tree
,
1216 &elemaddr
, &elemsize
, NULL
, 0);
1219 if (key_in
.object_id
!= key_out
.object_id
1220 || key_in
.type
!= key_out
.type
1221 || key_in
.offset
!= key_out
.offset
)
1222 return grub_error (GRUB_ERR_BAD_FS
, "no root");
1223 err
= grub_btrfs_read_logical (data
, elemaddr
, &ri
,
1227 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1229 key
->object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
1231 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1232 return GRUB_ERR_NONE
;
1236 find_path (struct grub_btrfs_data
*data
,
1237 const char *path
, struct grub_btrfs_key
*key
,
1238 grub_uint64_t
*tree
, grub_uint8_t
*type
)
1240 const char *slash
= path
;
1242 grub_disk_addr_t elemaddr
;
1243 grub_size_t elemsize
;
1244 grub_size_t allocated
= 0;
1245 struct grub_btrfs_dir_item
*direl
= NULL
;
1246 struct grub_btrfs_key key_out
;
1248 grub_size_t ctokenlen
;
1249 char *path_alloc
= NULL
;
1250 char *origpath
= NULL
;
1251 unsigned symlinks_max
= 32;
1253 err
= get_root (data
, key
, tree
, type
);
1257 origpath
= grub_strdup (path
);
1263 while (path
[0] == '/')
1267 slash
= grub_strchr (path
, '/');
1269 slash
= path
+ grub_strlen (path
);
1271 ctokenlen
= slash
- path
;
1273 if (*type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1275 grub_free (path_alloc
);
1276 grub_free (origpath
);
1277 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
1280 if (ctokenlen
== 1 && ctoken
[0] == '.')
1285 if (ctokenlen
== 2 && ctoken
[0] == '.' && ctoken
[1] == '.')
1287 key
->type
= GRUB_BTRFS_ITEM_TYPE_INODE_REF
;
1290 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1295 grub_free (path_alloc
);
1296 grub_free (origpath
);
1300 if (key_out
.type
!= key
->type
1301 || key
->object_id
!= key_out
.object_id
)
1304 grub_free (path_alloc
);
1305 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1306 grub_free (origpath
);
1310 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1311 key
->object_id
= key_out
.offset
;
1318 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1319 key
->offset
= grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken
, ctokenlen
));
1321 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1326 grub_free (path_alloc
);
1327 grub_free (origpath
);
1330 if (key_cmp (key
, &key_out
) != 0)
1333 grub_free (path_alloc
);
1334 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1335 grub_free (origpath
);
1339 struct grub_btrfs_dir_item
*cdirel
;
1340 if (elemsize
> allocated
)
1342 allocated
= 2 * elemsize
;
1344 direl
= grub_malloc (allocated
+ 1);
1347 grub_free (path_alloc
);
1348 grub_free (origpath
);
1353 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
, 0);
1357 grub_free (path_alloc
);
1358 grub_free (origpath
);
1362 for (cdirel
= direl
;
1363 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1364 < (grub_ssize_t
) elemsize
;
1365 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1366 + grub_le_to_cpu16 (cdirel
->n
)
1367 + grub_le_to_cpu16 (cdirel
->m
)))
1369 if (ctokenlen
== grub_le_to_cpu16 (cdirel
->n
)
1370 && grub_memcmp (cdirel
->name
, ctoken
, ctokenlen
) == 0)
1373 if ((grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1374 >= (grub_ssize_t
) elemsize
)
1377 grub_free (path_alloc
);
1378 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1379 grub_free (origpath
);
1384 if (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK
)
1386 struct grub_btrfs_inode inode
;
1388 if (--symlinks_max
== 0)
1391 grub_free (path_alloc
);
1392 grub_free (origpath
);
1393 return grub_error (GRUB_ERR_SYMLINK_LOOP
,
1394 N_("too deep nesting of symlinks"));
1397 err
= grub_btrfs_read_inode (data
, &inode
,
1398 cdirel
->key
.object_id
, *tree
);
1402 grub_free (path_alloc
);
1403 grub_free (origpath
);
1406 tmp
= grub_malloc (grub_le_to_cpu64 (inode
.size
)
1407 + grub_strlen (path
) + 1);
1411 grub_free (path_alloc
);
1412 grub_free (origpath
);
1416 if (grub_btrfs_extent_read (data
, cdirel
->key
.object_id
,
1418 grub_le_to_cpu64 (inode
.size
))
1419 != (grub_ssize_t
) grub_le_to_cpu64 (inode
.size
))
1422 grub_free (path_alloc
);
1423 grub_free (origpath
);
1427 grub_memcpy (tmp
+ grub_le_to_cpu64 (inode
.size
), path
,
1428 grub_strlen (path
) + 1);
1429 grub_free (path_alloc
);
1430 path
= path_alloc
= tmp
;
1433 err
= get_root (data
, key
, tree
, type
);
1439 *type
= cdirel
->type
;
1441 switch (cdirel
->key
.type
)
1443 case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
:
1445 struct grub_btrfs_root_item ri
;
1446 err
= lower_bound (data
, &cdirel
->key
, &key_out
,
1447 data
->sblock
.root_tree
,
1448 &elemaddr
, &elemsize
, NULL
, 0);
1452 grub_free (path_alloc
);
1453 grub_free (origpath
);
1456 if (cdirel
->key
.object_id
!= key_out
.object_id
1457 || cdirel
->key
.type
!= key_out
.type
)
1460 grub_free (path_alloc
);
1461 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1462 grub_free (origpath
);
1465 err
= grub_btrfs_read_logical (data
, elemaddr
, &ri
,
1470 grub_free (path_alloc
);
1471 grub_free (origpath
);
1474 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1476 key
->object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
1480 case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
:
1481 if (*slash
&& *type
== GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1484 grub_free (path_alloc
);
1485 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1486 grub_free (origpath
);
1490 if (*type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1491 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1494 grub_free (path_alloc
);
1495 grub_free (origpath
);
1497 return grub_error (GRUB_ERR_BAD_FS
, "unrecognised object type 0x%x",
1503 grub_free (origpath
);
1504 grub_free (path_alloc
);
1505 return GRUB_ERR_NONE
;
1509 grub_btrfs_dir (grub_device_t device
, const char *path
,
1510 grub_fs_dir_hook_t hook
, void *hook_data
)
1512 struct grub_btrfs_data
*data
= grub_btrfs_mount (device
);
1513 struct grub_btrfs_key key_in
, key_out
;
1515 grub_disk_addr_t elemaddr
;
1516 grub_size_t elemsize
;
1517 grub_size_t allocated
= 0;
1518 struct grub_btrfs_dir_item
*direl
= NULL
;
1519 struct grub_btrfs_leaf_descriptor desc
;
1527 err
= find_path (data
, path
, &key_in
, &tree
, &type
);
1530 grub_btrfs_unmount (data
);
1533 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1535 grub_btrfs_unmount (data
);
1536 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
1539 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
1540 &elemaddr
, &elemsize
, &desc
, 0);
1543 grub_btrfs_unmount (data
);
1546 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1547 || key_out
.object_id
!= key_in
.object_id
)
1549 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1555 struct grub_btrfs_dir_item
*cdirel
;
1556 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1557 || key_out
.object_id
!= key_in
.object_id
)
1562 if (elemsize
> allocated
)
1564 allocated
= 2 * elemsize
;
1566 direl
= grub_malloc (allocated
+ 1);
1574 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
, 0);
1581 for (cdirel
= direl
;
1582 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1583 < (grub_ssize_t
) elemsize
;
1584 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1585 + grub_le_to_cpu16 (cdirel
->n
)
1586 + grub_le_to_cpu16 (cdirel
->m
)))
1589 struct grub_btrfs_inode inode
;
1590 struct grub_dirhook_info info
;
1591 err
= grub_btrfs_read_inode (data
, &inode
, cdirel
->key
.object_id
,
1593 grub_memset (&info
, 0, sizeof (info
));
1595 grub_errno
= GRUB_ERR_NONE
;
1598 info
.mtime
= grub_le_to_cpu64 (inode
.mtime
.sec
);
1601 c
= cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)];
1602 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = 0;
1603 info
.dir
= (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
);
1604 if (hook (cdirel
->name
, &info
, hook_data
))
1606 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = c
;
1608 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1615 free_iterator (&desc
);
1616 grub_btrfs_unmount (data
);
1622 grub_btrfs_open (struct grub_file
*file
, const char *name
)
1624 struct grub_btrfs_data
*data
= grub_btrfs_mount (file
->device
);
1626 struct grub_btrfs_inode inode
;
1628 struct grub_btrfs_key key_in
;
1633 err
= find_path (data
, name
, &key_in
, &data
->tree
, &type
);
1636 grub_btrfs_unmount (data
);
1639 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1641 grub_btrfs_unmount (data
);
1642 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a regular file"));
1645 data
->inode
= key_in
.object_id
;
1646 err
= grub_btrfs_read_inode (data
, &inode
, data
->inode
, data
->tree
);
1649 grub_btrfs_unmount (data
);
1654 file
->size
= grub_le_to_cpu64 (inode
.size
);
1660 grub_btrfs_close (grub_file_t file
)
1662 grub_btrfs_unmount (file
->data
);
1664 return GRUB_ERR_NONE
;
1668 grub_btrfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
1670 struct grub_btrfs_data
*data
= file
->data
;
1672 return grub_btrfs_extent_read (data
, data
->inode
,
1673 data
->tree
, file
->offset
, buf
, len
);
1677 grub_btrfs_uuid (grub_device_t device
, char **uuid
)
1679 struct grub_btrfs_data
*data
;
1683 data
= grub_btrfs_mount (device
);
1687 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1688 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
1689 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
1690 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
1691 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
1692 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
1693 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
1694 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
1695 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
1697 grub_btrfs_unmount (data
);
1703 grub_btrfs_label (grub_device_t device
, char **label
)
1705 struct grub_btrfs_data
*data
;
1709 data
= grub_btrfs_mount (device
);
1713 *label
= grub_strndup (data
->sblock
.label
, sizeof (data
->sblock
.label
));
1715 grub_btrfs_unmount (data
);
1722 grub_btrfs_embed (grub_device_t device
__attribute__ ((unused
)),
1723 unsigned int *nsectors
,
1724 unsigned int max_nsectors
,
1725 grub_embed_type_t embed_type
,
1726 grub_disk_addr_t
**sectors
)
1730 if (embed_type
!= GRUB_EMBED_PCBIOS
)
1731 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1732 "BtrFS currently supports only PC-BIOS embedding");
1734 if (64 * 2 - 1 < *nsectors
)
1735 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
1736 N_("your core.img is unusually large. "
1737 "It won't fit in the embedding area"));
1739 *nsectors
= 64 * 2 - 1;
1740 if (*nsectors
> max_nsectors
)
1741 *nsectors
= max_nsectors
;
1742 *sectors
= grub_malloc (*nsectors
* sizeof (**sectors
));
1745 for (i
= 0; i
< *nsectors
; i
++)
1746 (*sectors
)[i
] = i
+ 1;
1748 return GRUB_ERR_NONE
;
1752 static struct grub_fs grub_btrfs_fs
= {
1754 .dir
= grub_btrfs_dir
,
1755 .open
= grub_btrfs_open
,
1756 .read
= grub_btrfs_read
,
1757 .close
= grub_btrfs_close
,
1758 .uuid
= grub_btrfs_uuid
,
1759 .label
= grub_btrfs_label
,
1761 .embed
= grub_btrfs_embed
,
1762 .reserved_first_sector
= 1,
1763 .blocklist_install
= 0,
1767 GRUB_MOD_INIT (btrfs
)
1769 grub_fs_register (&grub_btrfs_fs
);
1772 GRUB_MOD_FINI (btrfs
)
1774 grub_fs_unregister (&grub_btrfs_fs
);