mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-16 17:58:23 +00:00
4aebb99486
This patch uses generic code from btrfs-progs to read one super block from block device. To support the btrfs-progs coding style, the following is also crossported: - BTRFS_SETGET_FUNC for btrfs_super_block - btrfs_check_super() function - Move btrfs_read_superblock() to disk-io.[ch] Since super.c only contains pretty small amount of code, and the extra check will be covered in later root read patches. Differences between this implementation and btrfs-progs: - No sbflags/sb_bytenr support Since we only need to read the primary super block (like kernel), sbflags/sb_bytenr used by super block recovery is not needed. This also changes the following behavior of U-Boot btrfs: - Only reads the primary super block The old implementation reads all 3 super blocks, and also one non-existing backup. This is not correct, especially if there is another filesystem created on the device but old superblocks are not rewritten. Just like kernel, we only check the primary super block. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: Marek Behún <marek.behun@nic.cz> [trini: Change error to be a define in compat.h] Signed-off-by: Tom Rini <trini@konsulko.com>
227 lines
4.8 KiB
C
227 lines
4.8 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* BTRFS filesystem implementation for U-Boot
|
|
*
|
|
* 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <malloc.h>
|
|
#include <uuid.h>
|
|
#include <linux/time.h>
|
|
#include "btrfs.h"
|
|
#include "crypto/hash.h"
|
|
#include "disk-io.h"
|
|
|
|
struct btrfs_info btrfs_info;
|
|
|
|
static int readdir_callback(const struct btrfs_root *root,
|
|
struct btrfs_dir_item *item)
|
|
{
|
|
static const char typestr[BTRFS_FT_MAX][4] = {
|
|
[BTRFS_FT_UNKNOWN] = " ? ",
|
|
[BTRFS_FT_REG_FILE] = " ",
|
|
[BTRFS_FT_DIR] = "DIR",
|
|
[BTRFS_FT_CHRDEV] = "CHR",
|
|
[BTRFS_FT_BLKDEV] = "BLK",
|
|
[BTRFS_FT_FIFO] = "FIF",
|
|
[BTRFS_FT_SOCK] = "SCK",
|
|
[BTRFS_FT_SYMLINK] = "SYM",
|
|
[BTRFS_FT_XATTR] = " ? ",
|
|
};
|
|
struct btrfs_inode_item inode;
|
|
const char *name = (const char *) (item + 1);
|
|
char filetime[32], *target = NULL;
|
|
time_t mtime;
|
|
|
|
if (btrfs_lookup_inode(root, (struct btrfs_key *)&item->location,
|
|
&inode, NULL)) {
|
|
printf("%s: Cannot find inode item for directory entry %.*s!\n",
|
|
__func__, item->name_len, name);
|
|
return 0;
|
|
}
|
|
|
|
mtime = inode.mtime.sec;
|
|
ctime_r(&mtime, filetime);
|
|
|
|
if (item->type == BTRFS_FT_SYMLINK) {
|
|
target = malloc(min(inode.size + 1,
|
|
(u64) btrfs_info.sb.sectorsize));
|
|
|
|
if (target && btrfs_readlink(root, item->location.objectid,
|
|
target)) {
|
|
free(target);
|
|
target = NULL;
|
|
}
|
|
|
|
if (!target)
|
|
printf("%s: Cannot read symlink target!\n", __func__);
|
|
}
|
|
|
|
printf("<%s> ", typestr[item->type]);
|
|
if (item->type == BTRFS_FT_CHRDEV || item->type == BTRFS_FT_BLKDEV)
|
|
printf("%4u,%5u ", (unsigned int) (inode.rdev >> 20),
|
|
(unsigned int) (inode.rdev & 0xfffff));
|
|
else
|
|
printf("%10llu ", inode.size);
|
|
|
|
printf("%24.24s %.*s", filetime, item->name_len, name);
|
|
|
|
if (item->type == BTRFS_FT_SYMLINK) {
|
|
printf(" -> %s", target ? target : "?");
|
|
if (target)
|
|
free(target);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int btrfs_probe(struct blk_desc *fs_dev_desc,
|
|
struct disk_partition *fs_partition)
|
|
{
|
|
btrfs_blk_desc = fs_dev_desc;
|
|
btrfs_part_info = fs_partition;
|
|
|
|
memset(&btrfs_info, 0, sizeof(btrfs_info));
|
|
|
|
btrfs_hash_init();
|
|
if (btrfs_read_superblock())
|
|
return -1;
|
|
|
|
if (btrfs_chunk_map_init()) {
|
|
printf("%s: failed to init chunk map\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
btrfs_info.tree_root.objectid = 0;
|
|
btrfs_info.tree_root.bytenr = btrfs_info.sb.root;
|
|
btrfs_info.chunk_root.objectid = 0;
|
|
btrfs_info.chunk_root.bytenr = btrfs_info.sb.chunk_root;
|
|
|
|
if (btrfs_read_chunk_tree()) {
|
|
printf("%s: failed to read chunk tree\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
if (btrfs_find_root(btrfs_get_default_subvol_objectid(),
|
|
&btrfs_info.fs_root, NULL)) {
|
|
printf("%s: failed to find default subvolume\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int btrfs_ls(const char *path)
|
|
{
|
|
struct btrfs_root root = btrfs_info.fs_root;
|
|
u64 inr;
|
|
u8 type;
|
|
|
|
inr = btrfs_lookup_path(&root, root.root_dirid, path, &type, NULL, 40);
|
|
|
|
if (inr == -1ULL) {
|
|
printf("Cannot lookup path %s\n", path);
|
|
return -1;
|
|
}
|
|
|
|
if (type != BTRFS_FT_DIR) {
|
|
printf("Not a directory: %s\n", path);
|
|
return -1;
|
|
}
|
|
|
|
if (btrfs_readdir(&root, inr, readdir_callback)) {
|
|
printf("An error occured while listing directory %s\n", path);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int btrfs_exists(const char *file)
|
|
{
|
|
struct btrfs_root root = btrfs_info.fs_root;
|
|
u64 inr;
|
|
u8 type;
|
|
|
|
inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, NULL, 40);
|
|
|
|
return (inr != -1ULL && type == BTRFS_FT_REG_FILE);
|
|
}
|
|
|
|
int btrfs_size(const char *file, loff_t *size)
|
|
{
|
|
struct btrfs_root root = btrfs_info.fs_root;
|
|
struct btrfs_inode_item inode;
|
|
u64 inr;
|
|
u8 type;
|
|
|
|
inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
|
|
40);
|
|
|
|
if (inr == -1ULL) {
|
|
printf("Cannot lookup file %s\n", file);
|
|
return -1;
|
|
}
|
|
|
|
if (type != BTRFS_FT_REG_FILE) {
|
|
printf("Not a regular file: %s\n", file);
|
|
return -1;
|
|
}
|
|
|
|
*size = inode.size;
|
|
return 0;
|
|
}
|
|
|
|
int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
|
|
loff_t *actread)
|
|
{
|
|
struct btrfs_root root = btrfs_info.fs_root;
|
|
struct btrfs_inode_item inode;
|
|
u64 inr, rd;
|
|
u8 type;
|
|
|
|
inr = btrfs_lookup_path(&root, root.root_dirid, file, &type, &inode,
|
|
40);
|
|
|
|
if (inr == -1ULL) {
|
|
printf("Cannot lookup file %s\n", file);
|
|
return -1;
|
|
}
|
|
|
|
if (type != BTRFS_FT_REG_FILE) {
|
|
printf("Not a regular file: %s\n", file);
|
|
return -1;
|
|
}
|
|
|
|
if (!len)
|
|
len = inode.size;
|
|
|
|
if (len > inode.size - offset)
|
|
len = inode.size - offset;
|
|
|
|
rd = btrfs_file_read(&root, inr, offset, len, buf);
|
|
if (rd == -1ULL) {
|
|
printf("An error occured while reading file %s\n", file);
|
|
return -1;
|
|
}
|
|
|
|
*actread = rd;
|
|
return 0;
|
|
}
|
|
|
|
void btrfs_close(void)
|
|
{
|
|
btrfs_chunk_map_exit();
|
|
}
|
|
|
|
int btrfs_uuid(char *uuid_str)
|
|
{
|
|
#ifdef CONFIG_LIB_UUID
|
|
uuid_bin_to_str(btrfs_info.sb.fsid, uuid_str, UUID_STR_FORMAT_STD);
|
|
return 0;
|
|
#endif
|
|
return -ENOSYS;
|
|
}
|