@@ -115,6 +115,67 @@ int fs_mount(struct udevice *dev)
return 0;
}
+int fs_do_ln(struct udevice *dev, const char *path, const char *target)
+{
+ struct fs_ops *ops = fs_get_ops(dev);
+
+ if (!ops->ln)
+ return log_msg_ret("fln", -ENOSYS);
+
+ return ops->ln(dev, path, target);
+}
+
+int fs_do_rename(struct udevice *dev, const char *old_path,
+ const char *new_path)
+{
+ struct fs_ops *ops = fs_get_ops(dev);
+
+ if (!ops->rename)
+ return log_msg_ret("frn", -ENOSYS);
+
+ return ops->rename(dev, old_path, new_path);
+}
+
+int fs_readlink(struct udevice *dev, const char *path, char *buf, int size)
+{
+ struct fs_ops *ops = fs_get_ops(dev);
+
+ if (!ops->readlink)
+ return log_msg_ret("frl", -ENOSYS);
+
+ return ops->readlink(dev, path, buf, size);
+}
+
+int fs_do_statfs(struct udevice *dev, struct fs_statfs *stats)
+{
+ struct fs_ops *ops = fs_get_ops(dev);
+
+ if (!ops->statfs)
+ return log_msg_ret("fss", -ENOSYS);
+
+ return ops->statfs(dev, stats);
+}
+
+int fs_do_unlink(struct udevice *dev, const char *path)
+{
+ struct fs_ops *ops = fs_get_ops(dev);
+
+ if (!ops->unlink)
+ return log_msg_ret("fsu", -ENOSYS);
+
+ return ops->unlink(dev, path);
+}
+
+int fs_do_mkdir(struct udevice *dev, const char *path)
+{
+ struct fs_ops *ops = fs_get_ops(dev);
+
+ if (!ops->mkdir)
+ return log_msg_ret("fsm", -ENOSYS);
+
+ return ops->mkdir(dev, path);
+}
+
int fs_unmount(struct udevice *dev)
{
struct fs_ops *ops = fs_get_ops(dev);
@@ -417,6 +417,34 @@ static int sandbox_fs_lookup_dir(struct udevice *dev, const char *path,
return 0;
}
+static int sandbox_fs_ln(struct udevice *dev, const char *path,
+ const char *target)
+{
+ return os_symlink(target, path);
+}
+
+static int sandbox_fs_rename(struct udevice *dev, const char *old_path,
+ const char *new_path)
+{
+ return os_rename(old_path, new_path);
+}
+
+static int sandbox_fs_readlink(struct udevice *dev, const char *path,
+ char *buf, int size)
+{
+ return os_readlink(path, buf, size);
+}
+
+static int sandbox_fs_unlink(struct udevice *dev, const char *path)
+{
+ return os_unlink(path);
+}
+
+static int sandbox_fs_mkdir(struct udevice *dev, const char *path)
+{
+ return os_mkdir(path, 0755);
+}
+
static int sandbox_fs_remove(struct udevice *dev)
{
return 0;
@@ -426,6 +454,11 @@ static const struct fs_ops sandbox_fs_ops = {
.mount = sandbox_fs_mount,
.unmount = sandbox_fs_unmount,
.lookup_dir = sandbox_fs_lookup_dir,
+ .ln = sandbox_fs_ln,
+ .rename = sandbox_fs_rename,
+ .readlink = sandbox_fs_readlink,
+ .unlink = sandbox_fs_unlink,
+ .mkdir = sandbox_fs_mkdir,
};
static const struct udevice_id sandbox_fs_ids[] = {
@@ -19,6 +19,7 @@
#include <file.h>
#include <fs.h>
#include <fs_common.h>
+#include <fs_legacy.h>
#include <malloc.h>
#include <part.h>
#include <vfs.h>
@@ -431,8 +432,8 @@ static int vfs_resolve_dir(const char *path, struct udevice **dirp,
char *sub;
int ret;
- ret = vfs_resolve_mount(path, resolved, sizeof(resolved),
- &mnt, &subpath);
+ ret = vfs_resolve_mount(path, resolved,
+ sizeof(resolved), &mnt, &subpath);
if (ret)
return log_msg_ret("vdm", ret);
@@ -536,6 +537,36 @@ bool vfs_is_mount_point(struct udevice *dir)
return !find_mount(dir, &mnt);
}
+int vfs_umount_all(void)
+{
+ struct udevice *dev, *next;
+ struct uclass *uc;
+ int ret, err = 0;
+
+ ret = uclass_get(UCLASS_MOUNT, &uc);
+ if (ret)
+ return ret;
+
+ uclass_foreach_dev_safe(dev, next, uc) {
+ struct vfsmount *mnt = dev_get_uclass_priv(dev);
+
+ if (!device_active(dev))
+ continue;
+
+ ret = fs_unmount(mnt->target);
+ if (ret && ret != -ENOTCONN) {
+ err = ret;
+ continue;
+ }
+
+ ret = fs_mount_uninit(dev);
+ if (ret)
+ err = ret;
+ }
+
+ return err;
+}
+
void vfs_print_mounts(void)
{
struct vfsmount *mnt;
@@ -568,6 +599,175 @@ int vfs_open_file(const char *path, enum dir_open_flags_t oflags,
return 0;
}
+void vfs_print_df(void)
+{
+ struct vfsmount *mnt;
+ struct udevice *dev;
+
+ vfs_foreach_mount(mnt, dev) {
+ char path[FILE_MAX_PATH_LEN];
+ struct fs_statfs stats;
+ int ret;
+
+ if (vfs_mount_path(dev, path, sizeof(path)))
+ continue;
+
+ ret = fs_do_statfs(mnt->target, &stats);
+ if (!ret) {
+ u64 used = stats.blocks - stats.bfree;
+
+ printf("%-16s %6lu %10llu %10llu %10llu\n", path,
+ stats.bsize, stats.blocks * stats.bsize,
+ used * stats.bsize,
+ stats.bfree * stats.bsize);
+ } else {
+ printf("%-16s %6s %10s %10s %10s\n", path,
+ "-", "-", "-", "-");
+ }
+ }
+}
+
+int vfs_ln(const char *path, const char *target)
+{
+ char resolved[FILE_MAX_PATH_LEN];
+ struct udevice *vfs, *mnt;
+ const char *subpath;
+ struct vfsmount *mnt_priv;
+ int ret;
+
+ vfs = vfs_root();
+ if (!vfs)
+ return log_msg_ret("vli", -ENXIO);
+
+ path = vfs_path_resolve(vfs_getcwd(), path, resolved, sizeof(resolved));
+
+ if (!path)
+ return log_msg_ret("vrp", -ENAMETOOLONG);
+ ret = vfs_find_mount(vfs, path, &mnt, &subpath);
+ if (ret)
+ return log_msg_ret("vlm", ret);
+
+ mnt_priv = dev_get_uclass_priv(mnt);
+
+ return fs_do_ln(mnt_priv->target, subpath, target);
+}
+
+int vfs_rename(const char *old_path, const char *new_path)
+{
+ char resolved_old[FILE_MAX_PATH_LEN];
+ char resolved_new[FILE_MAX_PATH_LEN];
+ struct udevice *mnt_old, *mnt_new;
+ const char *sub_old, *sub_new;
+ struct vfsmount *mnt_priv;
+ int ret;
+
+ ret = vfs_resolve_mount(old_path, resolved_old,
+ sizeof(resolved_old),
+ &mnt_old, &sub_old);
+ if (ret)
+ return log_msg_ret("vro", ret);
+
+ ret = vfs_resolve_mount(new_path, resolved_new,
+ sizeof(resolved_new),
+ &mnt_new, &sub_new);
+ if (ret)
+ return log_msg_ret("vrn", ret);
+
+ /* Both paths must be on the same mount */
+ if (mnt_old != mnt_new)
+ return log_msg_ret("vrx", -EXDEV);
+
+ mnt_priv = dev_get_uclass_priv(mnt_old);
+
+ return fs_do_rename(mnt_priv->target, sub_old, sub_new);
+}
+
+int vfs_readlink(const char *path, char *buf, int size)
+{
+ char resolved[FILE_MAX_PATH_LEN];
+ struct udevice *mnt;
+ struct vfsmount *mnt_priv;
+ const char *subpath;
+ int ret;
+
+ ret = vfs_resolve_mount(path, resolved,
+ sizeof(resolved), &mnt, &subpath);
+ if (ret)
+ return log_msg_ret("rlm", ret);
+
+ mnt_priv = dev_get_uclass_priv(mnt);
+
+ return fs_readlink(mnt_priv->target, subpath, buf, size);
+}
+
+int vfs_statfs(const char *path, struct fs_statfs *stats)
+{
+ char resolved[FILE_MAX_PATH_LEN];
+ struct udevice *mnt;
+ struct vfsmount *mnt_priv;
+ const char *subpath;
+ int ret;
+
+ ret = vfs_resolve_mount(path, resolved,
+ sizeof(resolved), &mnt, &subpath);
+ if (ret)
+ return log_msg_ret("dfm", ret);
+
+ mnt_priv = dev_get_uclass_priv(mnt);
+
+ return fs_do_statfs(mnt_priv->target, stats);
+}
+
+int vfs_unlink(const char *path)
+{
+ char resolved[FILE_MAX_PATH_LEN];
+ struct udevice *vfs, *mnt;
+ struct vfsmount *mnt_priv;
+ const char *subpath;
+ int ret;
+
+ vfs = vfs_root();
+ if (!vfs)
+ return log_msg_ret("vui", -ENXIO);
+
+ path = vfs_path_resolve(vfs_getcwd(), path, resolved, sizeof(resolved));
+ if (!path)
+ return log_msg_ret("vup", -ENAMETOOLONG);
+
+ ret = vfs_find_mount(vfs, path, &mnt, &subpath);
+ if (ret)
+ return log_msg_ret("vum", ret);
+
+ mnt_priv = dev_get_uclass_priv(mnt);
+
+ return fs_do_unlink(mnt_priv->target, subpath);
+}
+
+int vfs_mkdir(const char *path)
+{
+ char resolved[FILE_MAX_PATH_LEN];
+ struct udevice *vfs, *mnt;
+ struct vfsmount *mnt_priv;
+ const char *subpath;
+ int ret;
+
+ vfs = vfs_root();
+ if (!vfs)
+ return log_msg_ret("vmi", -ENXIO);
+
+ path = vfs_path_resolve(vfs_getcwd(), path, resolved, sizeof(resolved));
+ if (!path)
+ return log_msg_ret("vmp", -ENAMETOOLONG);
+
+ ret = vfs_find_mount(vfs, path, &mnt, &subpath);
+ if (ret)
+ return log_msg_ret("vmm", ret);
+
+ mnt_priv = dev_get_uclass_priv(mnt);
+
+ return fs_do_mkdir(mnt_priv->target, subpath);
+}
+
int vfs_stat(const char *path, struct fs_dirent *dent)
{
struct fs_dir_stream *strm;
@@ -612,8 +812,8 @@ int vfs_ls(const char *path)
bool empty = true;
int ret;
- ret = vfs_resolve_mount(path, resolved, sizeof(resolved),
- &mnt, &subpath);
+ ret = vfs_resolve_mount(path, resolved,
+ sizeof(resolved), &mnt, &subpath);
if (ret)
return ret;
@@ -14,6 +14,7 @@
#include <fs_common.h>
#include <part.h>
+struct fs_statfs;
struct udevice;
enum {
@@ -79,6 +80,66 @@ struct fs_ops {
*/
int (*lookup_dir)(struct udevice *dev, const char *path,
struct udevice **dirp);
+
+ /**
+ * rename() - Rename or move a file or directory
+ *
+ * @dev: Filesystem device
+ * @old_path: Current path
+ * @new_path: New path
+ * Return 0 if OK, -ve on error
+ */
+ int (*rename)(struct udevice *dev, const char *old_path,
+ const char *new_path);
+
+ /**
+ * ln() - Create a symbolic link
+ *
+ * @dev: Filesystem device
+ * @path: Path of symlink to create
+ * @target: Target the symlink points to
+ * Return 0 if OK, -ve on error
+ */
+ int (*ln)(struct udevice *dev, const char *path, const char *target);
+
+ /**
+ * readlink() - Read the target of a symbolic link
+ *
+ * @dev: Filesystem device
+ * @path: Path to the symbolic link
+ * @buf: Buffer to receive the target path
+ * @size: Size of buffer
+ * Return: length of target string, or -ve on error
+ */
+ int (*readlink)(struct udevice *dev, const char *path, char *buf,
+ int size);
+
+ /**
+ * statfs() - Get filesystem statistics
+ *
+ * @dev: Filesystem device
+ * @stats: Returns filesystem statistics
+ * Return 0 if OK, -ve on error
+ */
+ int (*statfs)(struct udevice *dev, struct fs_statfs *stats);
+
+ /**
+ * unlink() - Delete a file
+ *
+ * @dev: Filesystem device
+ * @path: Path of the file to delete
+ * Return 0 if OK, -ve on error
+ */
+ int (*unlink)(struct udevice *dev, const char *path);
+
+ /**
+ * mkdir() - Create a directory
+ *
+ * @dev: Filesystem device
+ * @path: Path of the directory to create
+ * Return 0 if OK, -ve on error
+ */
+ int (*mkdir)(struct udevice *dev, const char *path);
};
/* Get access to a filesystem's operations */
@@ -112,6 +173,67 @@ int fs_unmount(struct udevice *dev);
*/
int fs_lookup_dir(struct udevice *dev, const char *path, struct udevice **dirp);
+/**
+ * fs_do_ln() - Create a symbolic link on a filesystem
+ *
+ * @dev: Filesystem device
+ * @path: Path of symlink to create (within the filesystem)
+ * @target: Target the symlink points to
+ * Return: 0 if OK, -ENOSYS if not supported, other -ve on error
+ */
+int fs_do_ln(struct udevice *dev, const char *path, const char *target);
+
+/**
+ * fs_do_rename() - Rename or move a file on a filesystem
+ *
+ * Both paths must be within the same filesystem.
+ *
+ * @dev: Filesystem device
+ * @old_path: Current path (within the filesystem)
+ * @new_path: New path (within the filesystem)
+ * Return: 0 if OK, -ENOSYS if not supported, other -ve on error
+ */
+int fs_do_rename(struct udevice *dev, const char *old_path,
+ const char *new_path);
+
+/**
+ * fs_readlink() - Read a symbolic link target on a filesystem
+ *
+ * @dev: Filesystem device
+ * @path: Path to the symbolic link (within the filesystem)
+ * @buf: Buffer to receive the target path
+ * @size: Size of buffer
+ * Return: length of target, -ENOSYS if not supported, other -ve on error
+ */
+int fs_readlink(struct udevice *dev, const char *path, char *buf, int size);
+
+/**
+ * fs_do_statfs() - Get filesystem statistics
+ *
+ * @dev: Filesystem device
+ * @stats: Returns filesystem statistics
+ * Return: 0 if OK, -ENOSYS if not supported, other -ve on error
+ */
+int fs_do_statfs(struct udevice *dev, struct fs_statfs *stats);
+
+/**
+ * fs_do_unlink() - Delete a file on a filesystem
+ *
+ * @dev: Filesystem device
+ * @path: Path of the file to delete (within the filesystem)
+ * Return: 0 if OK, -ENOSYS if not supported, other -ve on error
+ */
+int fs_do_unlink(struct udevice *dev, const char *path);
+
+/**
+ * fs_do_mkdir() - Create a directory on a filesystem
+ *
+ * @dev: Filesystem device
+ * @path: Path of the directory to create (within the filesystem)
+ * Return: 0 if OK, -ENOSYS if not supported, other -ve on error
+ */
+int fs_do_mkdir(struct udevice *dev, const char *path);
+
/**
* fs_split_path() - Get a list of subdirs in a filename
*
@@ -131,6 +131,15 @@ int vfs_umount(struct udevice *mnt_dev);
*/
int vfs_umount_path(struct udevice *vfs, const char *path);
+/**
+ * vfs_umount_all() - Unmount all filesystems
+ *
+ * Unmounts all mounted filesystems. Returns an error if any unmount fails.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int vfs_umount_all(void);
+
/**
* vfs_find_mount() - Find the mount covering a path
*
@@ -292,6 +301,14 @@ int fs_mount_blkdev(const char *type, struct blk_desc *desc, int part_num,
*/
void vfs_print_mounts(void);
+/**
+ * vfs_print_df() - Print filesystem usage for all mounts
+ *
+ * Iterates all mounts and prints statfs info for those that support it.
+ * Mounts that do not support statfs are listed with dashes.
+ */
+void vfs_print_df(void);
+
/**
* do_cp() - Copy a file within the VFS
*