u-boot/fs/btrfs/btrfs.c
Dominique Martinet 6e988fde65 fs: btrfs: hide duplicate 'Cannot lookup file' error on 'load'
Running commands such as 'load mmc 2:1 $addr $path' when path does not
exists will print an error twice if the file does not exist, e.g.:
```
Cannot lookup file boot/boot.scr
Failed to load 'boot/boot.scr'
```
(where the first line is printed by btrfs and the second by common fs
code)

Historically other filesystems such as ext4 or fat have not been
printing a message here, so do the same here to avoid duplicate.

The other error messages in this function are also somewhat redundant,
but bring useful diagnostics if they happen somewhere, so have been left
as printf.

Note that if a user wants no message to be printed for optional file
loads, they have to check for file existence first with other commands
such as 'size'.

Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
2024-11-15 13:11:47 -06:00

285 lines
6.4 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* BTRFS filesystem implementation for U-Boot
*
* 2017 Marek Behún, CZ.NIC, kabel@kernel.org
*/
#include <config.h>
#include <malloc.h>
#include <u-boot/uuid.h>
#include <linux/time.h>
#include "btrfs.h"
#include "crypto/hash.h"
#include "disk-io.h"
struct btrfs_fs_info *current_fs_info;
static int show_dir(struct btrfs_root *root, struct extent_buffer *eb,
struct btrfs_dir_item *di)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_inode_item ii;
struct btrfs_key key;
static const char* dir_item_str[] = {
[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",
};
u8 type = btrfs_dir_type(eb, di);
char namebuf[BTRFS_NAME_LEN];
char *target = NULL;
char filetime[32];
time_t mtime;
int ret = 0;
/* skip XATTRs in directory listing */
if (type == BTRFS_FT_XATTR)
return 0;
btrfs_dir_item_key_to_cpu(eb, di, &key);
if (key.type == BTRFS_ROOT_ITEM_KEY) {
struct btrfs_root *subvol;
/* It's a subvolume, get its mtime from root item */
subvol = btrfs_read_fs_root(fs_info, &key);
if (IS_ERR(subvol)) {
ret = PTR_ERR(subvol);
error("Can't find root %llu", key.objectid);
return ret;
}
mtime = btrfs_stack_timespec_sec(&subvol->root_item.otime);
} else {
struct btrfs_path path;
/* It's regular inode, get its mtime from inode item */
btrfs_init_path(&path);
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret > 0)
ret = -ENOENT;
if (ret < 0) {
error("Can't find inode %llu", key.objectid);
btrfs_release_path(&path);
return ret;
}
read_extent_buffer(path.nodes[0], &ii,
btrfs_item_ptr_offset(path.nodes[0], path.slots[0]),
sizeof(ii));
btrfs_release_path(&path);
mtime = btrfs_stack_timespec_sec(&ii.mtime);
}
ctime_r(&mtime, filetime);
if (type == BTRFS_FT_SYMLINK) {
target = malloc(fs_info->sectorsize);
if (!target) {
error("Can't alloc memory for symlink %llu",
key.objectid);
return -ENOMEM;
}
ret = btrfs_readlink(root, key.objectid, target);
if (ret < 0) {
error("Failed to read symlink %llu", key.objectid);
goto out;
}
target[ret] = '\0';
}
if (type < ARRAY_SIZE(dir_item_str) && dir_item_str[type])
printf("<%s> ", dir_item_str[type]);
else
printf("?%3u? ", type);
if (type == BTRFS_FT_CHRDEV || type == BTRFS_FT_BLKDEV) {
ASSERT(key.type == BTRFS_INODE_ITEM_KEY);
printf("%4llu,%5llu ", btrfs_stack_inode_rdev(&ii) >> 20,
btrfs_stack_inode_rdev(&ii) & 0xfffff);
} else {
if (key.type == BTRFS_INODE_ITEM_KEY)
printf("%10llu ", btrfs_stack_inode_size(&ii));
else
printf("%10llu ", 0ULL);
}
read_extent_buffer(eb, namebuf, (unsigned long)(di + 1),
btrfs_dir_name_len(eb, di));
printf("%24.24s %.*s", filetime, btrfs_dir_name_len(eb, di), namebuf);
if (type == BTRFS_FT_SYMLINK)
printf(" -> %s", target ? target : "?");
printf("\n");
out:
free(target);
return ret;
}
int btrfs_probe(struct blk_desc *fs_dev_desc,
struct disk_partition *fs_partition)
{
struct btrfs_fs_info *fs_info;
int ret = -1;
btrfs_hash_init();
fs_info = open_ctree_fs_info(fs_dev_desc, fs_partition);
if (fs_info) {
current_fs_info = fs_info;
ret = 0;
}
return ret;
}
int btrfs_ls(const char *path)
{
struct btrfs_fs_info *fs_info = current_fs_info;
struct btrfs_root *root = fs_info->fs_root;
u64 ino = BTRFS_FIRST_FREE_OBJECTID;
u8 type;
int ret;
ASSERT(fs_info);
ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
path, &root, &ino, &type, 40);
if (ret < 0) {
printf("Cannot lookup path %s\n", path);
return ret;
}
if (type != BTRFS_FT_DIR) {
error("Not a directory: %s", path);
return -ENOENT;
}
ret = btrfs_iter_dir(root, ino, show_dir);
if (ret < 0) {
error("An error occurred while listing directory %s", path);
return ret;
}
return 0;
}
int btrfs_exists(const char *file)
{
struct btrfs_fs_info *fs_info = current_fs_info;
struct btrfs_root *root;
u64 ino;
u8 type;
int ret;
ASSERT(fs_info);
ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
file, &root, &ino, &type, 40);
if (ret < 0)
return 0;
if (type == BTRFS_FT_REG_FILE)
return 1;
return 0;
}
int btrfs_size(const char *file, loff_t *size)
{
struct btrfs_fs_info *fs_info = current_fs_info;
struct btrfs_inode_item *ii;
struct btrfs_root *root;
struct btrfs_path path;
struct btrfs_key key;
u64 ino;
u8 type;
int ret;
ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
file, &root, &ino, &type, 40);
if (ret < 0) {
debug("Cannot lookup file %s\n", file);
return ret;
}
if (type != BTRFS_FT_REG_FILE) {
printf("Not a regular file: %s\n", file);
return -ENOENT;
}
btrfs_init_path(&path);
key.objectid = ino;
key.type = BTRFS_INODE_ITEM_KEY;
key.offset = 0;
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0) {
printf("Cannot lookup ino %llu\n", ino);
return ret;
}
if (ret > 0) {
printf("Ino %llu does not exist\n", ino);
ret = -ENOENT;
goto out;
}
ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
struct btrfs_inode_item);
*size = btrfs_inode_size(path.nodes[0], ii);
out:
btrfs_release_path(&path);
return ret;
}
int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
loff_t *actread)
{
struct btrfs_fs_info *fs_info = current_fs_info;
struct btrfs_root *root;
loff_t real_size;
u64 ino;
u8 type;
int ret;
ASSERT(fs_info);
ret = btrfs_lookup_path(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
file, &root, &ino, &type, 40);
if (ret < 0) {
error("Cannot lookup file %s", file);
return ret;
}
if (type != BTRFS_FT_REG_FILE) {
error("Not a regular file: %s", file);
return -EINVAL;
}
ret = btrfs_size(file, &real_size);
if (ret < 0) {
error("Failed to get inode size: %s", file);
return ret;
}
if (!len || len > real_size - offset)
len = real_size - offset;
ret = btrfs_file_read(root, ino, offset, len, buf);
if (ret < 0) {
error("An error occurred while reading file %s", file);
return ret;
}
*actread = len;
return 0;
}
void btrfs_close(void)
{
if (current_fs_info) {
close_ctree_fs_info(current_fs_info);
current_fs_info = NULL;
}
}
int btrfs_uuid(char *uuid_str)
{
#ifdef CONFIG_LIB_UUID
if (current_fs_info)
uuid_bin_to_str(current_fs_info->super_copy->fsid, uuid_str,
UUID_STR_FORMAT_STD);
return 0;
#endif
return -ENOSYS;
}