- uint8_t *buffer;
- struct btrfs_superblock *sb;
-
- /* Don't try additional superblocks beyond device size. */
- if (total_blocks <= superblock_pos[i])
- break;
-
- err = fsw_block_get(vol, superblock_pos[i], 0, (void **)&buffer);
- if (err == FSW_UNSUPPORTED) {
- fsw_block_release(vol, superblock_pos[i], buffer);
- break;
- }
-
- sb = (struct btrfs_superblock *)buffer;
- if (!fsw_memeq (sb->signature, GRUB_BTRFS_SIGNATURE,
- sizeof (GRUB_BTRFS_SIGNATURE) - 1))
- {
- fsw_block_release(vol, superblock_pos[i], buffer);
- break;
- }
- if (i == 0 || fsw_u64_le_swap (sb->generation) > fsw_u64_le_swap (sb_out->generation))
- {
- fsw_memcpy (sb_out, sb, sizeof (*sb));
- total_blocks = fsw_u64_le_swap (sb->this_device.size) >> 12;
- }
- fsw_block_release(vol, superblock_pos[i], buffer);
+ uint8_t *buffer;
+ struct btrfs_superblock *sb;
+
+ /* Don't try additional superblocks beyond device size. */
+ if (total_blocks <= superblock_pos[i])
+ break;
+
+ err = fsw_block_get(vol, superblock_pos[i], 0, (void **)&buffer);
+ if (err == FSW_UNSUPPORTED) {
+ fsw_block_release(vol, superblock_pos[i], buffer);
+ break;
+ }
+
+ sb = (struct btrfs_superblock *)buffer;
+ if (!fsw_memeq (sb->signature, GRUB_BTRFS_SIGNATURE,
+ sizeof (GRUB_BTRFS_SIGNATURE) - 1))
+ {
+ fsw_block_release(vol, superblock_pos[i], buffer);
+ break;
+ }
+ if (i == 0 || fsw_u64_le_swap (sb->generation) > fsw_u64_le_swap (sb_out->generation))
+ {
+ fsw_memcpy (sb_out, sb, sizeof (*sb));
+ total_blocks = fsw_u64_le_swap (sb->this_device.size) >> 12;
+ }
+ fsw_block_release(vol, superblock_pos[i], buffer);
- depth++;
- /* FIXME: preread few nodes into buffer. */
- err = fsw_btrfs_read_logical (vol, addr, &head, sizeof (head),
- rdepth + 1, depth2cache(rdepth));
- if (err)
- return err;
- addr += sizeof (head);
- if (head.level)
- {
- unsigned i;
- struct btrfs_internal_node node, node_last;
- int have_last = 0;
- fsw_memzero (&node_last, sizeof (node_last));
- for (i = 0; i < fsw_u32_le_swap (head.nitems); i++)
- {
- err = fsw_btrfs_read_logical (vol, addr + i * sizeof (node),
- &node, sizeof (node), rdepth + 1, depth2cache(rdepth));
- if (err)
- return err;
-
- DPRINT (L"btrfs: internal node (depth %d) %lx %x %lx\n", depth,
- node.key.object_id, node.key.type,
- node.key.offset);
-
- if (key_cmp (&node.key, key_in) == 0)
- {
- err = FSW_SUCCESS;
- if (desc)
- err = save_ref (desc, addr - sizeof (head), i,
- fsw_u32_le_swap (head.nitems), 0);
- if (err)
- return err;
- addr = fsw_u64_le_swap (node.addr);
- goto reiter;
- }
- if (key_cmp (&node.key, key_in) > 0)
- break;
- node_last = node;
- have_last = 1;
- }
- if (have_last)
- {
- err = FSW_SUCCESS;
- if (desc)
- err = save_ref (desc, addr - sizeof (head), i - 1,
- fsw_u32_le_swap (head.nitems), 0);
- if (err)
- return err;
- addr = fsw_u64_le_swap (node_last.addr);
- goto reiter;
- }
- *outsize = 0;
- *outaddr = 0;
- fsw_memzero (key_out, sizeof (*key_out));
- if (desc)
- return save_ref (desc, addr - sizeof (head), -1,
- fsw_u32_le_swap (head.nitems), 0);
- return FSW_SUCCESS;
- }
- {
- unsigned i;
- struct btrfs_leaf_node leaf, leaf_last;
- int have_last = 0;
- for (i = 0; i < fsw_u32_le_swap (head.nitems); i++)
- {
- err = fsw_btrfs_read_logical (vol, addr + i * sizeof (leaf),
- &leaf, sizeof (leaf), rdepth + 1, depth2cache(rdepth));
- if (err)
- return err;
-
- DPRINT (L"btrfs: leaf (depth %d) %lx %x %lx\n", depth,
- leaf.key.object_id, leaf.key.type, leaf.key.offset);
-
- if (key_cmp (&leaf.key, key_in) == 0)
- {
- fsw_memcpy (key_out, &leaf.key, sizeof (*key_out));
- *outsize = fsw_u32_le_swap (leaf.size);
- *outaddr = addr + fsw_u32_le_swap (leaf.offset);
- if (desc)
- return save_ref (desc, addr - sizeof (head), i,
- fsw_u32_le_swap (head.nitems), 1);
- return FSW_SUCCESS;
- }
-
- if (key_cmp (&leaf.key, key_in) > 0)
- break;
-
- have_last = 1;
- leaf_last = leaf;
- }
-
- if (have_last)
- {
- fsw_memcpy (key_out, &leaf_last.key, sizeof (*key_out));
- *outsize = fsw_u32_le_swap (leaf_last.size);
- *outaddr = addr + fsw_u32_le_swap (leaf_last.offset);
- if (desc)
- return save_ref (desc, addr - sizeof (head), i - 1,
- fsw_u32_le_swap (head.nitems), 1);
- return FSW_SUCCESS;
- }
- *outsize = 0;
- *outaddr = 0;
- fsw_memzero (key_out, sizeof (*key_out));
- if (desc)
- return save_ref (desc, addr - sizeof (head), -1,
- fsw_u32_le_swap (head.nitems), 1);
- return FSW_SUCCESS;
- }
+ depth++;
+ /* FIXME: preread few nodes into buffer. */
+ err = fsw_btrfs_read_logical (vol, addr, &head, sizeof (head),
+ rdepth + 1, depth2cache(rdepth));
+ if (err)
+ return err;
+ addr += sizeof (head);
+ if (head.level)
+ {
+ unsigned i;
+ struct btrfs_internal_node node, node_last;
+ int have_last = 0;
+ fsw_memzero (&node_last, sizeof (node_last));
+ for (i = 0; i < fsw_u32_le_swap (head.nitems); i++)
+ {
+ err = fsw_btrfs_read_logical (vol, addr + i * sizeof (node),
+ &node, sizeof (node), rdepth + 1, depth2cache(rdepth));
+ if (err)
+ return err;
+
+ DPRINT (L"btrfs: internal node (depth %d) %lx %x %lx\n", depth,
+ node.key.object_id, node.key.type,
+ node.key.offset);
+
+ if (key_cmp (&node.key, key_in) == 0)
+ {
+ err = FSW_SUCCESS;
+ if (desc)
+ err = save_ref (desc, addr - sizeof (head), i,
+ fsw_u32_le_swap (head.nitems), 0);
+ if (err)
+ return err;
+ addr = fsw_u64_le_swap (node.addr);
+ goto reiter;
+ }
+ if (key_cmp (&node.key, key_in) > 0)
+ break;
+ node_last = node;
+ have_last = 1;
+ }
+ if (have_last)
+ {
+ err = FSW_SUCCESS;
+ if (desc)
+ err = save_ref (desc, addr - sizeof (head), i - 1,
+ fsw_u32_le_swap (head.nitems), 0);
+ if (err)
+ return err;
+ addr = fsw_u64_le_swap (node_last.addr);
+ goto reiter;
+ }
+ *outsize = 0;
+ *outaddr = 0;
+ fsw_memzero (key_out, sizeof (*key_out));
+ if (desc)
+ return save_ref (desc, addr - sizeof (head), -1,
+ fsw_u32_le_swap (head.nitems), 0);
+ return FSW_SUCCESS;
+ }
+ {
+ unsigned i;
+ struct btrfs_leaf_node leaf, leaf_last;
+ int have_last = 0;
+ for (i = 0; i < fsw_u32_le_swap (head.nitems); i++)
+ {
+ err = fsw_btrfs_read_logical (vol, addr + i * sizeof (leaf),
+ &leaf, sizeof (leaf), rdepth + 1, depth2cache(rdepth));
+ if (err)
+ return err;
+
+ DPRINT (L"btrfs: leaf (depth %d) %lx %x %lx\n", depth,
+ leaf.key.object_id, leaf.key.type, leaf.key.offset);
+
+ if (key_cmp (&leaf.key, key_in) == 0)
+ {
+ fsw_memcpy (key_out, &leaf.key, sizeof (*key_out));
+ *outsize = fsw_u32_le_swap (leaf.size);
+ *outaddr = addr + fsw_u32_le_swap (leaf.offset);
+ if (desc)
+ return save_ref (desc, addr - sizeof (head), i,
+ fsw_u32_le_swap (head.nitems), 1);
+ return FSW_SUCCESS;
+ }
+
+ if (key_cmp (&leaf.key, key_in) > 0)
+ break;
+
+ have_last = 1;
+ leaf_last = leaf;
+ }
+
+ if (have_last)
+ {
+ fsw_memcpy (key_out, &leaf_last.key, sizeof (*key_out));
+ *outsize = fsw_u32_le_swap (leaf_last.size);
+ *outaddr = addr + fsw_u32_le_swap (leaf_last.offset);
+ if (desc)
+ return save_ref (desc, addr - sizeof (head), i - 1,
+ fsw_u32_le_swap (head.nitems), 1);
+ return FSW_SUCCESS;
+ }
+ *outsize = 0;
+ *outaddr = 0;
+ fsw_memzero (key_out, sizeof (*key_out));
+ if (desc)
+ return save_ref (desc, addr - sizeof (head), -1,
+ fsw_u32_le_swap (head.nitems), 1);
+ return FSW_SUCCESS;
+ }
- uint8_t *ptr;
- struct btrfs_key *key;
- struct btrfs_chunk_item *chunk;
- uint64_t csize;
- fsw_status_t err = 0;
- struct btrfs_key key_out;
- int challoc = 0;
- struct btrfs_key key_in;
- fsw_size_t chsize;
- uint64_t chaddr;
-
- for (ptr = vol->bootstrap_mapping; ptr < vol->bootstrap_mapping + sizeof (vol->bootstrap_mapping) - sizeof (struct btrfs_key);)
- {
- key = (struct btrfs_key *) ptr;
- if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK)
- break;
- chunk = (struct btrfs_chunk_item *) (key + 1);
- if (fsw_u64_le_swap (key->offset) <= addr
- && addr < fsw_u64_le_swap (key->offset)
- + fsw_u64_le_swap (chunk->size))
- {
- goto chunk_found;
- }
- ptr += sizeof (*key) + sizeof (*chunk)
- + sizeof (struct btrfs_chunk_stripe)
- * fsw_u16_le_swap (chunk->nstripes);
- }
-
- key_in.object_id = fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK);
- key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK;
- key_in.offset = fsw_u64_le_swap (addr);
- err = lower_bound (vol, &key_in, &key_out, vol->chunk_tree, &chaddr, &chsize, NULL, rdepth);
- if (err)
- return err;
- key = &key_out;
- if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK
- || !(fsw_u64_le_swap (key->offset) <= addr))
- {
- return FSW_VOLUME_CORRUPTED;
- }
- // "couldn't find the chunk descriptor");
-
- chunk = AllocatePool (chsize);
- if (!chunk) {
- return FSW_OUT_OF_MEMORY;
- }
-
- challoc = 1;
- err = fsw_btrfs_read_logical (vol, chaddr, chunk, chsize, rdepth, cache_level < 5 ? cache_level+1 : 5);
- if (err)
- {
- if(chunk)
- FreePool (chunk);
- return err;
- }
+ uint8_t *ptr;
+ struct btrfs_key *key;
+ struct btrfs_chunk_item *chunk;
+ uint64_t csize;
+ fsw_status_t err = 0;
+ struct btrfs_key key_out;
+ int challoc = 0;
+ struct btrfs_key key_in;
+ fsw_size_t chsize;
+ uint64_t chaddr;
+
+ for (ptr = vol->bootstrap_mapping; ptr < vol->bootstrap_mapping + sizeof (vol->bootstrap_mapping) - sizeof (struct btrfs_key);)
+ {
+ key = (struct btrfs_key *) ptr;
+ if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK)
+ break;
+ chunk = (struct btrfs_chunk_item *) (key + 1);
+ if (fsw_u64_le_swap (key->offset) <= addr
+ && addr < fsw_u64_le_swap (key->offset)
+ + fsw_u64_le_swap (chunk->size))
+ {
+ goto chunk_found;
+ }
+ ptr += sizeof (*key) + sizeof (*chunk)
+ + sizeof (struct btrfs_chunk_stripe)
+ * fsw_u16_le_swap (chunk->nstripes);
+ }
+
+ key_in.object_id = fsw_u64_le_swap (GRUB_BTRFS_OBJECT_ID_CHUNK);
+ key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK;
+ key_in.offset = fsw_u64_le_swap (addr);
+ err = lower_bound (vol, &key_in, &key_out, vol->chunk_tree, &chaddr, &chsize, NULL, rdepth);
+ if (err)
+ return err;
+ key = &key_out;
+ if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK
+ || !(fsw_u64_le_swap (key->offset) <= addr))
+ {
+ return FSW_VOLUME_CORRUPTED;
+ }
+ // "couldn't find the chunk descriptor");
+
+ chunk = AllocatePool (chsize);
+ if (!chunk) {
+ return FSW_OUT_OF_MEMORY;
+ }
+
+ challoc = 1;
+ err = fsw_btrfs_read_logical (vol, chaddr, chunk, chsize, rdepth, cache_level < 5 ? cache_level+1 : 5);
+ if (err)
+ {
+ if(chunk)
+ FreePool (chunk);
+ return err;
+ }
- UINTREM stripen;
- UINTREM stripe_offset;
- uint64_t off = addr - fsw_u64_le_swap (key->offset);
- unsigned redundancy = 1;
- unsigned i, j;
-
- if (fsw_u64_le_swap (chunk->size) <= off)
- {
- return FSW_VOLUME_CORRUPTED;
- //"couldn't find the chunk descriptor");
- }
-
- DPRINT(L"btrfs chunk 0x%lx+0xlx %d stripes (%d substripes) of %lx\n",
- fsw_u64_le_swap (key->offset),
- fsw_u64_le_swap (chunk->size),
- fsw_u16_le_swap (chunk->nstripes),
- fsw_u16_le_swap (chunk->nsubstripes),
- fsw_u64_le_swap (chunk->stripe_length));
-
- /* gnu-efi has no DivU64x64Remainder, limited to DivU64x32 */
- switch (fsw_u64_le_swap (chunk->type)
- & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE)
- {
- case GRUB_BTRFS_CHUNK_TYPE_SINGLE:
- {
- uint64_t stripe_length;
-
- stripe_length = DivU64x32 (fsw_u64_le_swap (chunk->size),
- fsw_u16_le_swap (chunk->nstripes), NULL);
-
- if(stripe_length > 1UL<<30)
- return FSW_VOLUME_CORRUPTED;
-
- stripen = DivU64x32 (off, (uint32_t)stripe_length, &stripe_offset);
- csize = (stripen + 1) * stripe_length - off;
- DPRINT(L"read_logical %d chunk_found single csize=%d\n", __LINE__, csize);
- break;
- }
- case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED:
- case GRUB_BTRFS_CHUNK_TYPE_RAID1:
- {
- stripen = 0;
- stripe_offset = off;
- csize = fsw_u64_le_swap (chunk->size) - off;
- redundancy = 2;
- DPRINT(L"read_logical %d chunk_found dup/raid1 off=%lx csize=%d\n", __LINE__, stripe_offset, csize);
- break;
- }
- case GRUB_BTRFS_CHUNK_TYPE_RAID0:
- {
- uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length);
- uint64_t middle, high;
- UINTREM low;
-
- if(stripe_length > 1UL<<30)
- return FSW_VOLUME_CORRUPTED;
-
- middle = DivU64x32 (off, (uint32_t)stripe_length, &low);
-
- high = DivU64x32 (middle, fsw_u16_le_swap (chunk->nstripes), &stripen);
- stripe_offset =
- low + fsw_u64_le_swap (chunk->stripe_length) * high;
- csize = fsw_u64_le_swap (chunk->stripe_length) - low;
- DPRINT(L"read_logical %d chunk_found raid0 csize=%d\n", __LINE__, csize);
- break;
- }
- case GRUB_BTRFS_CHUNK_TYPE_RAID10:
- {
- uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length);
- uint64_t middle, high;
- UINTREM low;
-
- if(stripe_length > 1UL<<30)
- return FSW_VOLUME_CORRUPTED;
-
- middle = DivU64x32 (off, stripe_length, &low);
-
- high = DivU64x32 (middle,
- fsw_u16_le_swap (chunk->nstripes)
- / fsw_u16_le_swap (chunk->nsubstripes),
- &stripen);
- stripen *= fsw_u16_le_swap (chunk->nsubstripes);
- redundancy = fsw_u16_le_swap (chunk->nsubstripes);
- stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length)
- * high;
- csize = fsw_u64_le_swap (chunk->stripe_length) - low;
- DPRINT(L"read_logical %d chunk_found raid01 csize=%d\n", __LINE__, csize);
- break;
- }
- default:
- DPRINT (L"btrfs: unsupported RAID\n");
- return FSW_UNSUPPORTED;
- }
- if (csize == 0)
- //"couldn't find the chunk descriptor");
- return FSW_VOLUME_CORRUPTED;
-
- if (csize > (uint64_t) size)
- csize = size;
-
- for (j = 0; j < 2; j++)
- {
- for (i = 0; i < redundancy; i++)
- {
- struct btrfs_chunk_stripe *stripe;
- uint64_t paddr;
- struct fsw_volume *dev;
-
- stripe = (struct btrfs_chunk_stripe *) (chunk + 1);
- /* Right now the redundancy handling is easy.
- With RAID5-like it will be more difficult. */
- stripe += stripen + i;
-
- paddr = fsw_u64_le_swap (stripe->offset) + stripe_offset;
-
- DPRINT (L"btrfs: chunk 0x%lx+0x%lx (%d stripes (%d substripes) of %lx) stripe %lx maps to 0x%lx\n",
- fsw_u64_le_swap (key->offset),
- fsw_u64_le_swap (chunk->size),
- fsw_u16_le_swap (chunk->nstripes),
- fsw_u16_le_swap (chunk->nsubstripes),
- fsw_u64_le_swap (chunk->stripe_length),
- stripen, stripe->offset);
- DPRINT (L"btrfs: reading paddr 0x%lx for laddr 0x%lx\n", paddr, addr);
-
- dev = find_device (vol, stripe->device_id, j);
- if (!dev)
- {
- err = FSW_VOLUME_CORRUPTED;
- continue;
- }
-
- uint32_t off = paddr & (vol->sectorsize - 1);
- paddr >>= vol->sectorshift;
- uint64_t n = 0;
- while(n < csize) {
- char *buffer;
- err = fsw_block_get(dev, paddr, cache_level, (void **)&buffer);
- if(err)
- break;
- int s = vol->sectorsize - off;
- if(s > csize - n)
- s = csize - n;
- fsw_memcpy(buf+n, buffer+off, s);
- fsw_block_release(dev, paddr, (void *)buffer);
-
- n += s;
- off = 0;
- paddr++;
- }
- DPRINT (L"read logical: err %d csize %d got %d\n",
- err, csize, n);
- if(n>=csize)
- break;
- }
- if (i != redundancy)
- break;
- }
- if (err)
- return err;
- }
- size -= csize;
- buf = (uint8_t *) buf + csize;
- addr += csize;
- if (challoc && chunk)
- FreePool (chunk);
+ UINTREM stripen;
+ UINTREM stripe_offset;
+ uint64_t off = addr - fsw_u64_le_swap (key->offset);
+ unsigned redundancy = 1;
+ unsigned i, j;
+
+ if (fsw_u64_le_swap (chunk->size) <= off)
+ {
+ return FSW_VOLUME_CORRUPTED;
+ //"couldn't find the chunk descriptor");
+ }
+
+ DPRINT(L"btrfs chunk 0x%lx+0xlx %d stripes (%d substripes) of %lx\n",
+ fsw_u64_le_swap (key->offset),
+ fsw_u64_le_swap (chunk->size),
+ fsw_u16_le_swap (chunk->nstripes),
+ fsw_u16_le_swap (chunk->nsubstripes),
+ fsw_u64_le_swap (chunk->stripe_length));
+
+ /* gnu-efi has no DivU64x64Remainder, limited to DivU64x32 */
+ switch (fsw_u64_le_swap (chunk->type)
+ & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE)
+ {
+ case GRUB_BTRFS_CHUNK_TYPE_SINGLE:
+ {
+ uint64_t stripe_length;
+
+ stripe_length = DivU64x32 (fsw_u64_le_swap (chunk->size),
+ fsw_u16_le_swap (chunk->nstripes), NULL);
+
+ if(stripe_length > 1UL<<30)
+ return FSW_VOLUME_CORRUPTED;
+
+ stripen = DivU64x32 (off, (uint32_t)stripe_length, &stripe_offset);
+ csize = (stripen + 1) * stripe_length - off;
+ DPRINT(L"read_logical %d chunk_found single csize=%d\n", __LINE__, csize);
+ break;
+ }
+ case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED:
+ case GRUB_BTRFS_CHUNK_TYPE_RAID1:
+ {
+ stripen = 0;
+ stripe_offset = off;
+ csize = fsw_u64_le_swap (chunk->size) - off;
+ redundancy = 2;
+ DPRINT(L"read_logical %d chunk_found dup/raid1 off=%lx csize=%d\n", __LINE__, stripe_offset, csize);
+ break;
+ }
+ case GRUB_BTRFS_CHUNK_TYPE_RAID0:
+ {
+ uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length);
+ uint64_t middle, high;
+ UINTREM low;
+
+ if(stripe_length > 1UL<<30)
+ return FSW_VOLUME_CORRUPTED;
+
+ middle = DivU64x32 (off, (uint32_t)stripe_length, &low);
+
+ high = DivU64x32 (middle, fsw_u16_le_swap (chunk->nstripes), &stripen);
+ stripe_offset =
+ low + fsw_u64_le_swap (chunk->stripe_length) * high;
+ csize = fsw_u64_le_swap (chunk->stripe_length) - low;
+ DPRINT(L"read_logical %d chunk_found raid0 csize=%d\n", __LINE__, csize);
+ break;
+ }
+ case GRUB_BTRFS_CHUNK_TYPE_RAID10:
+ {
+ uint64_t stripe_length = fsw_u64_le_swap (chunk->stripe_length);
+ uint64_t middle, high;
+ UINTREM low;
+
+ if(stripe_length > 1UL<<30)
+ return FSW_VOLUME_CORRUPTED;
+
+ middle = DivU64x32 (off, stripe_length, &low);
+
+ high = DivU64x32 (middle,
+ fsw_u16_le_swap (chunk->nstripes)
+ / fsw_u16_le_swap (chunk->nsubstripes),
+ &stripen);
+ stripen *= fsw_u16_le_swap (chunk->nsubstripes);
+ redundancy = fsw_u16_le_swap (chunk->nsubstripes);
+ stripe_offset = low + fsw_u64_le_swap (chunk->stripe_length)
+ * high;
+ csize = fsw_u64_le_swap (chunk->stripe_length) - low;
+ DPRINT(L"read_logical %d chunk_found raid01 csize=%d\n", __LINE__, csize);
+ break;
+ }
+ default:
+ DPRINT (L"btrfs: unsupported RAID\n");
+ return FSW_UNSUPPORTED;
+ }
+ if (csize == 0)
+ //"couldn't find the chunk descriptor");
+ return FSW_VOLUME_CORRUPTED;
+
+ if (csize > (uint64_t) size)
+ csize = size;
+
+ for (j = 0; j < 2; j++)
+ {
+ for (i = 0; i < redundancy; i++)
+ {
+ struct btrfs_chunk_stripe *stripe;
+ uint64_t paddr;
+ struct fsw_volume *dev;
+
+ stripe = (struct btrfs_chunk_stripe *) (chunk + 1);
+ /* Right now the redundancy handling is easy.
+ With RAID5-like it will be more difficult. */
+ stripe += stripen + i;
+
+ paddr = fsw_u64_le_swap (stripe->offset) + stripe_offset;
+
+ DPRINT (L"btrfs: chunk 0x%lx+0x%lx (%d stripes (%d substripes) of %lx) stripe %lx maps to 0x%lx\n",
+ fsw_u64_le_swap (key->offset),
+ fsw_u64_le_swap (chunk->size),
+ fsw_u16_le_swap (chunk->nstripes),
+ fsw_u16_le_swap (chunk->nsubstripes),
+ fsw_u64_le_swap (chunk->stripe_length),
+ stripen, stripe->offset);
+ DPRINT (L"btrfs: reading paddr 0x%lx for laddr 0x%lx\n", paddr, addr);
+
+ dev = find_device (vol, stripe->device_id, j);
+ if (!dev)
+ {
+ err = FSW_VOLUME_CORRUPTED;
+ continue;
+ }
+
+ uint32_t off = paddr & (vol->sectorsize - 1);
+ paddr >>= vol->sectorshift;
+ uint64_t n = 0;
+ while(n < csize) {
+ char *buffer;
+ err = fsw_block_get(dev, paddr, cache_level, (void **)&buffer);
+ if(err)
+ break;
+ int s = vol->sectorsize - off;
+ if(s > csize - n)
+ s = csize - n;
+ fsw_memcpy(buf+n, buffer+off, s);
+ fsw_block_release(dev, paddr, (void *)buffer);
+
+ n += s;
+ off = 0;
+ paddr++;
+ }
+ DPRINT (L"read logical: err %d csize %d got %d\n",
+ err, csize, n);
+ if(n>=csize)
+ break;
+ }
+ if (i != redundancy)
+ break;
+ }
+ if (err)
+ return err;
+ }
+ size -= csize;
+ buf = (uint8_t *) buf + csize;
+ addr += csize;
+ if (challoc && chunk)
+ FreePool (chunk);
- struct btrfs_key key_in, key_out;
- uint64_t elemaddr;
- fsw_size_t elemsize;
-
- if(vol->extent) {
- FreePool (vol->extent);
- vol->extent = NULL;
- }
- key_in.object_id = ino;
- key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM;
- key_in.offset = fsw_u64_le_swap (pos);
- err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0);
- if (err)
- return FSW_VOLUME_CORRUPTED;
- if (key_out.object_id != ino
- || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
- {
- return FSW_VOLUME_CORRUPTED;
- }
- if ((fsw_ssize_t) elemsize < ((char *) &vol->extent->inl
- - (char *) vol->extent))
- {
- return FSW_VOLUME_CORRUPTED;
- }
- vol->extstart = fsw_u64_le_swap (key_out.offset);
- vol->extsize = elemsize;
- vol->extent = AllocatePool (elemsize);
- vol->extino = ino;
- vol->exttree = tree;
- if (!vol->extent)
- return FSW_OUT_OF_MEMORY;
-
- err = fsw_btrfs_read_logical (vol, elemaddr, vol->extent, elemsize, 0, 1);
- if (err)
- return err;
-
- vol->extend = vol->extstart + fsw_u64_le_swap (vol->extent->size);
- if (vol->extent->type == GRUB_BTRFS_EXTENT_REGULAR
- && (char *) &vol->extent + elemsize
- >= (char *) &vol->extent->filled + sizeof (vol->extent->filled))
- vol->extend =
- vol->extstart + fsw_u64_le_swap (vol->extent->filled);
-
- DPRINT (L"btrfs: %lx +0x%lx\n", fsw_u64_le_swap (key_out.offset), fsw_u64_le_swap (vol->extent->size));
- if (vol->extend <= pos)
- {
- return FSW_VOLUME_CORRUPTED;
- }
+ struct btrfs_key key_in, key_out;
+ uint64_t elemaddr;
+ fsw_size_t elemsize;
+
+ if(vol->extent) {
+ FreePool (vol->extent);
+ vol->extent = NULL;
+ }
+ key_in.object_id = ino;
+ key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM;
+ key_in.offset = fsw_u64_le_swap (pos);
+ err = lower_bound (vol, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, 0);
+ if (err)
+ return FSW_VOLUME_CORRUPTED;
+ if (key_out.object_id != ino
+ || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM)
+ {
+ return FSW_VOLUME_CORRUPTED;
+ }
+ if ((fsw_ssize_t) elemsize < ((char *) &vol->extent->inl
+ - (char *) vol->extent))
+ {
+ return FSW_VOLUME_CORRUPTED;
+ }
+ vol->extstart = fsw_u64_le_swap (key_out.offset);
+ vol->extsize = elemsize;
+ vol->extent = AllocatePool (elemsize);
+ vol->extino = ino;
+ vol->exttree = tree;
+ if (!vol->extent)
+ return FSW_OUT_OF_MEMORY;
+
+ err = fsw_btrfs_read_logical (vol, elemaddr, vol->extent, elemsize, 0, 1);
+ if (err)
+ return err;
+
+ vol->extend = vol->extstart + fsw_u64_le_swap (vol->extent->size);
+ if (vol->extent->type == GRUB_BTRFS_EXTENT_REGULAR
+ && (char *) &vol->extent + elemsize
+ >= (char *) &vol->extent->filled + sizeof (vol->extent->filled))
+ vol->extend =
+ vol->extstart + fsw_u64_le_swap (vol->extent->filled);
+
+ DPRINT (L"btrfs: %lx +0x%lx\n", fsw_u64_le_swap (key_out.offset), fsw_u64_le_swap (vol->extent->size));
+ if (vol->extend <= pos)
+ {
+ return FSW_VOLUME_CORRUPTED;
+ }
- case GRUB_BTRFS_EXTENT_INLINE:
- buf = AllocatePool( count << vol->sectorshift);
- if(!buf)
- return FSW_OUT_OF_MEMORY;
- if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
- {
- if (grub_zlib_decompress (vol->extent->inl, vol->extsize -
- ((uint8_t *) vol->extent->inl
- - (uint8_t *) vol->extent),
- extoff, buf, csize)
- != (fsw_ssize_t) csize)
- {
- FreePool(buf);
- return FSW_VOLUME_CORRUPTED;
- }
- }
- else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
- {
- if (grub_btrfs_lzo_decompress(vol->extent->inl, vol->extsize -
- ((uint8_t *) vol->extent->inl
- - (uint8_t *) vol->extent),
- extoff, buf, csize)
- != (fsw_ssize_t) csize)
- {
- FreePool(buf);
- return -FSW_VOLUME_CORRUPTED;
- }
- }
- else
- fsw_memcpy (buf, vol->extent->inl + extoff, csize);
- break;
-
- case GRUB_BTRFS_EXTENT_REGULAR:
- if (!vol->extent->laddr)
- break;
-
- if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_NONE)
- {
- if( count > 64 ) {
- count = 64;
- csize = count << vol->sectorshift;
- }
- buf = AllocatePool( count << vol->sectorshift);
- if(!buf)
- return FSW_OUT_OF_MEMORY;
- err = fsw_btrfs_read_logical (vol,
- fsw_u64_le_swap (vol->extent->laddr)
- + fsw_u64_le_swap (vol->extent->offset)
- + extoff, buf, csize, 0, 0);
- if (err) {
- FreePool(buf);
- return err;
- }
- break;
- }
- if (vol->extent->compression != GRUB_BTRFS_COMPRESSION_NONE)
- {
- char *tmp;
- uint64_t zsize;
- fsw_ssize_t ret;
-
- zsize = fsw_u64_le_swap (vol->extent->compressed_size);
- tmp = AllocatePool (zsize);
- if (!tmp)
- return -FSW_OUT_OF_MEMORY;
- err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (vol->extent->laddr), tmp, zsize, 0, 0);
- if (err)
- {
- FreePool (tmp);
- return -FSW_VOLUME_CORRUPTED;
- }
-
- buf = AllocatePool( count << vol->sectorshift);
- if(!buf) {
- FreePool(tmp);
- return FSW_OUT_OF_MEMORY;
- }
-
- if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
- {
- ret = grub_zlib_decompress (tmp, zsize, extoff
- + fsw_u64_le_swap (vol->extent->offset),
- buf, csize);
- }
- else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
- ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff
- + fsw_u64_le_swap (vol->extent->offset),
- buf, csize);
- else
- ret = -1;
-
- FreePool (tmp);
-
- if (ret != (fsw_ssize_t) csize) {
- FreePool(tmp);
- return -FSW_VOLUME_CORRUPTED;
- }
-
- break;
- }
- break;
- default:
- return -FSW_VOLUME_CORRUPTED;
+ case GRUB_BTRFS_EXTENT_INLINE:
+ buf = AllocatePool( count << vol->sectorshift);
+ if(!buf)
+ return FSW_OUT_OF_MEMORY;
+ if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
+ {
+ if (grub_zlib_decompress (vol->extent->inl, vol->extsize -
+ ((uint8_t *) vol->extent->inl
+ - (uint8_t *) vol->extent),
+ extoff, buf, csize)
+ != (fsw_ssize_t) csize)
+ {
+ FreePool(buf);
+ return FSW_VOLUME_CORRUPTED;
+ }
+ }
+ else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
+ {
+ if (grub_btrfs_lzo_decompress(vol->extent->inl, vol->extsize -
+ ((uint8_t *) vol->extent->inl
+ - (uint8_t *) vol->extent),
+ extoff, buf, csize)
+ != (fsw_ssize_t) csize)
+ {
+ FreePool(buf);
+ return -FSW_VOLUME_CORRUPTED;
+ }
+ }
+ else
+ fsw_memcpy (buf, vol->extent->inl + extoff, csize);
+ break;
+
+ case GRUB_BTRFS_EXTENT_REGULAR:
+ if (!vol->extent->laddr)
+ break;
+
+ if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_NONE)
+ {
+ if( count > 64 ) {
+ count = 64;
+ csize = count << vol->sectorshift;
+ }
+ buf = AllocatePool( count << vol->sectorshift);
+ if(!buf)
+ return FSW_OUT_OF_MEMORY;
+ err = fsw_btrfs_read_logical (vol,
+ fsw_u64_le_swap (vol->extent->laddr)
+ + fsw_u64_le_swap (vol->extent->offset)
+ + extoff, buf, csize, 0, 0);
+ if (err) {
+ FreePool(buf);
+ return err;
+ }
+ break;
+ }
+ if (vol->extent->compression != GRUB_BTRFS_COMPRESSION_NONE)
+ {
+ char *tmp;
+ uint64_t zsize;
+ fsw_ssize_t ret;
+
+ zsize = fsw_u64_le_swap (vol->extent->compressed_size);
+ tmp = AllocatePool (zsize);
+ if (!tmp)
+ return -FSW_OUT_OF_MEMORY;
+ err = fsw_btrfs_read_logical (vol, fsw_u64_le_swap (vol->extent->laddr), tmp, zsize, 0, 0);
+ if (err)
+ {
+ FreePool (tmp);
+ return -FSW_VOLUME_CORRUPTED;
+ }
+
+ buf = AllocatePool( count << vol->sectorshift);
+ if(!buf) {
+ FreePool(tmp);
+ return FSW_OUT_OF_MEMORY;
+ }
+
+ if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
+ {
+ ret = grub_zlib_decompress (tmp, zsize, extoff
+ + fsw_u64_le_swap (vol->extent->offset),
+ buf, csize);
+ }
+ else if (vol->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
+ ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff
+ + fsw_u64_le_swap (vol->extent->offset),
+ buf, csize);
+ else
+ ret = -1;
+
+ FreePool (tmp);
+
+ if (ret != (fsw_ssize_t) csize) {
+ FreePool(tmp);
+ return -FSW_VOLUME_CORRUPTED;
+ }
+
+ break;
+ }
+ break;
+ default:
+ return -FSW_VOLUME_CORRUPTED;
- struct btrfs_dir_item *cdirel;
- if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM ||
- key_out.object_id != key_in.object_id)
- {
- r = 0;
- break;
- }
- if (elemsize > allocated)
- {
- allocated = 2 * elemsize;
- if(direl)
- FreePool (direl);
- direl = AllocatePool (allocated + 1);
- if (!direl)
- {
- r = -FSW_OUT_OF_MEMORY;
- break;
- }
- }
-
- err = fsw_btrfs_read_logical (vol, elemaddr, direl, elemsize, 0, 1);
- if (err)
- {
- r = -err;
- break;
- }
-
- for (cdirel = direl;
- (uint8_t *) cdirel - (uint8_t *) direl
- < (fsw_ssize_t) elemsize;
- cdirel = (void *) ((uint8_t *) (direl + 1)
- + fsw_u16_le_swap (cdirel->n)
- + fsw_u16_le_swap (cdirel->m)))
- {
- struct fsw_string s;
- s.type = FSW_STRING_TYPE_UTF8;
- s.size = s.len = fsw_u16_le_swap (cdirel->n);
- s.data = cdirel->name;
- DPRINT(L"item key %lx:%x%lx, type %lx, namelen=%lx\n",
- cdirel->key.object_id, cdirel->key.type, cdirel->key.offset, cdirel->type, s.size);
- if(!err) {
- err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, &s, child_dno_out);
- if(direl)
- FreePool (direl);
- free_iterator (&desc);
- shand->pos = key_out.offset;
- return FSW_SUCCESS;
- }
- }
- r = next (vol, &desc, &elemaddr, &elemsize, &key_out);
- DPRINT(L"next2 out %lx:%x:%lx\n",
- key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize);
+ struct btrfs_dir_item *cdirel;
+ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM ||
+ key_out.object_id != key_in.object_id)
+ {
+ r = 0;
+ break;
+ }
+ if (elemsize > allocated)
+ {
+ allocated = 2 * elemsize;
+ if(direl)
+ FreePool (direl);
+ direl = AllocatePool (allocated + 1);
+ if (!direl)
+ {
+ r = -FSW_OUT_OF_MEMORY;
+ break;
+ }
+ }
+
+ err = fsw_btrfs_read_logical (vol, elemaddr, direl, elemsize, 0, 1);
+ if (err)
+ {
+ r = -err;
+ break;
+ }
+
+ for (cdirel = direl;
+ (uint8_t *) cdirel - (uint8_t *) direl
+ < (fsw_ssize_t) elemsize;
+ cdirel = (void *) ((uint8_t *) (direl + 1)
+ + fsw_u16_le_swap (cdirel->n)
+ + fsw_u16_le_swap (cdirel->m)))
+ {
+ struct fsw_string s;
+ s.type = FSW_STRING_TYPE_UTF8;
+ s.size = s.len = fsw_u16_le_swap (cdirel->n);
+ s.data = cdirel->name;
+ DPRINT(L"item key %lx:%x%lx, type %lx, namelen=%lx\n",
+ cdirel->key.object_id, cdirel->key.type, cdirel->key.offset, cdirel->type, s.size);
+ if(!err) {
+ err = fsw_btrfs_get_sub_dnode(vol, dno, cdirel, &s, child_dno_out);
+ if(direl)
+ FreePool (direl);
+ free_iterator (&desc);
+ shand->pos = key_out.offset;
+ return FSW_SUCCESS;
+ }
+ }
+ r = next (vol, &desc, &elemaddr, &elemsize, &key_out);
+ DPRINT(L"next2 out %lx:%x:%lx\n",
+ key_out.object_id, key_out.type, key_out.offset, elemaddr, elemsize);