Files
u-boot/fs/file-uclass.c
Simon Glass ab25244811 fs: Add support for a file
Directories can have a number of files within them. U-Boot only needs to
create a file object for those that have been opened for read/write. Add
the concept of a file, with its directory as parent.

Signed-off-by: Simon Glass <sjg@chromium.org>
2025-06-28 12:30:56 -06:00

104 lines
2.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Implementation of files on a filesystem
*
* Copyright 2025 Simon Glass <sjg@chromium.org>
*/
#include <dir.h>
#include <dm.h>
#include <file.h>
#include <malloc.h>
#include <dm/device-internal.h>
int file_add_probe(struct udevice *dir, struct driver *drv, const char *leaf,
size_t size, enum dir_open_flags_t flags,
struct udevice **devp)
{
char dev_name[30], *str, *dup_leaf;
struct file_uc_priv *uc_priv;
struct udevice *dev;
int ret;
snprintf(dev_name, sizeof(dev_name), "%s.file.%x", dir->name,
device_get_child_count(dir) + 1);
ret = -ENOMEM;
str = strdup(dev_name);
if (!str)
goto no_dev_name;
dup_leaf = strdup(leaf);
if (!str)
goto no_dev_path;
ret = device_bind_with_driver_data(dir, drv, str, 0 /* data */,
ofnode_null(), &dev);
if (ret) {
log_debug("bind failed %d\n", ret);
goto no_bind;
}
device_set_name_alloced(dev);
ret = device_probe(dev);
if (ret)
goto no_probe;
uc_priv = dev_get_uclass_priv(dev);
uc_priv->leaf = dup_leaf;
uc_priv->size = size;
*devp = dev;
return 0;
no_probe:
device_unbind(dir);
no_bind:
free(dup_leaf);
no_dev_path:
free(str);
no_dev_name:
return ret;
}
long file_read(struct udevice *dev, void *buf, long len)
{
struct file_uc_priv *uc_priv = dev_get_uclass_priv(dev);
struct file_ops *ops = file_get_ops(dev);
struct iov_iter iter;
ssize_t ret;
iter_ubuf(&iter, true, buf, len);
ret = ops->read_iter(dev, &iter, uc_priv->pos);
if (ret < 0)
return log_msg_ret("fir", ret);
uc_priv->pos += ret;
return ret;
}
long file_read_at(struct udevice *dev, void *buf, loff_t offset, long len)
{
struct file_uc_priv *uc_priv = dev_get_uclass_priv(dev);
struct file_ops *ops = file_get_ops(dev);
struct iov_iter iter;
ssize_t ret;
if (!len)
len = uc_priv->size - offset;
iter_ubuf(&iter, true, buf, len);
ret = ops->read_iter(dev, &iter, offset);
if (ret < 0)
return log_msg_ret("fir", ret);
uc_priv->pos = offset + ret;
return ret;
}
UCLASS_DRIVER(file) = {
.name = "file",
.id = UCLASS_FILE,
.per_device_auto = sizeof(struct file_uc_priv),
};