diff options
author | Jan Luebbe <jlu@pengutronix.de> | 2016-01-07 12:39:12 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-01-18 09:25:44 +0100 |
commit | ec95d547e721d2762c3cb66572528028f2a56483 (patch) | |
tree | 5fdc34c9582ec14385b3a44e28d2e0e3e9b03f39 /fs/ratpfs.c | |
parent | 266057337402f45adf707ef59beebd2a6821a749 (diff) | |
download | barebox-ec95d547e721d2762c3cb66572528028f2a56483.tar.gz barebox-ec95d547e721d2762c3cb66572528028f2a56483.tar.xz |
fs: Add RATP fs support
This adds file transfer support over RATP. The host can export a
directory using the bbremote tool which can then be mounted under
barebox as a filesystem.
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Tested-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Diffstat (limited to 'fs/ratpfs.c')
-rw-r--r-- | fs/ratpfs.c | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/fs/ratpfs.c b/fs/ratpfs.c new file mode 100644 index 0000000000..902289bab1 --- /dev/null +++ b/fs/ratpfs.c @@ -0,0 +1,476 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#define pr_fmt(fmt) "barebox-ratpfs: " fmt + +#include <common.h> +#include <command.h> +#include <init.h> +#include <malloc.h> +#include <fs.h> +#include <errno.h> +#include <linux/stat.h> +#include <asm/unaligned.h> +#include <ratp_bb.h> + +#define RATPFS_TYPE_MOUNT_CALL 1 +#define RATPFS_TYPE_MOUNT_RETURN 2 +#define RATPFS_TYPE_READDIR_CALL 3 +#define RATPFS_TYPE_READDIR_RETURN 4 +#define RATPFS_TYPE_STAT_CALL 5 +#define RATPFS_TYPE_STAT_RETURN 6 +#define RATPFS_TYPE_OPEN_CALL 7 +#define RATPFS_TYPE_OPEN_RETURN 8 +#define RATPFS_TYPE_READ_CALL 9 +#define RATPFS_TYPE_READ_RETURN 10 +#define RATPFS_TYPE_WRITE_CALL 11 +#define RATPFS_TYPE_WRITE_RETURN 12 +#define RATPFS_TYPE_CLOSE_CALL 13 +#define RATPFS_TYPE_CLOSE_RETURN 14 +#define RATPFS_TYPE_TRUNCATE_CALL 15 +#define RATPFS_TYPE_TRUNCATE_RETURN 16 + +struct ratpfs_file { + uint32_t handle; +}; + +struct ratpfs_dir { + char *entries; + int len, off; + DIR dir; +}; + +static int ratpfs_create(struct device_d __always_unused *dev, + const char __always_unused *pathname, + mode_t __always_unused mode) +{ + pr_debug("%s\n", __func__); + + return 0; +} + +static int ratpfs_mkdir(struct device_d __always_unused *dev, + const char __always_unused *pathname) +{ + pr_debug("%s\n", __func__); + + return -ENOSYS; +} + +static int ratpfs_rm(struct device_d __always_unused *dev, + const char *pathname) +{ + pr_debug("%s\n", __func__); + + /* Get rid of leading '/' */ + pathname = &pathname[1]; + + return 0; +} + +static int ratpfs_truncate(struct device_d __always_unused *dev, + FILE *f, ulong size) +{ + int len_tx = 1 /* type */ + + 4 /* handle */ + + 4 /* size */; + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx)+len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + struct ratpfs_file *rfile = f->priv; + int ret; + + pr_debug("%s: len_tx=%i handle=%i size=%i\n", __func__, + len_tx, rfile->handle, (int)size); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_TRUNCATE_CALL; + put_unaligned_be32(rfile->handle, &pkt_tx->data[1]); + put_unaligned_be32(size, &pkt_tx->data[5]); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) { + ret = -EIO; + goto out; + } + + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_TRUNCATE_RETURN) { + pr_err("invalid truncate response\n"); + ret = -EIO; + goto out; + } + +out: + free(pkt_rx); + return ret; +} + +static int ratpfs_open(struct device_d __always_unused *dev, + FILE *file, const char *filename) +{ + int len_name = strlen(filename); + int len_tx = 1 /* type */ + + 4 /* flags */ + + len_name /* path */; + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + struct ratpfs_file *rfile = xzalloc(sizeof(*rfile)); + int ret; + + pr_debug("%s: len_tx=%i filename='%s'\n", __func__, len_tx, filename); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_OPEN_CALL; + put_unaligned_be32(file->flags, &pkt_tx->data[1]); + memcpy(&pkt_tx->data[5], filename, len_name); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) { + ret = -EIO; + goto err; + } + + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_OPEN_RETURN) { + pr_err("invalid open response\n"); + ret = -EIO; + goto err; + } + rfile->handle = get_unaligned_be32(&pkt_rx->data[1]); + if (rfile->handle == 0) { + ret = -get_unaligned_be32(&pkt_rx->data[5]); /* errno */ + goto err; + } + file->priv = rfile; + file->size = get_unaligned_be32(&pkt_rx->data[5]); + + goto out; + +err: + file->priv = NULL; + free(rfile); +out: + free(pkt_rx); + return ret; +} + +static int ratpfs_close(struct device_d __always_unused *dev, + FILE *f) +{ + int len_tx = 1 /* type */ + + 4 /* handle */; + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + struct ratpfs_file *rfile = f->priv; + int ret; + + pr_debug("%s: len_tx=%i handle=%i\n", __func__, + len_tx, rfile->handle); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_CLOSE_CALL; + put_unaligned_be32(rfile->handle, &pkt_tx->data[1]); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) { + ret = -EIO; + goto out; + } + + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_CLOSE_RETURN) { + pr_err("invalid close response\n"); + goto out; + } + +out: + free(pkt_rx); + return ret; +} + +static int ratpfs_write(struct device_d __always_unused *dev, + FILE *f, const void *buf, size_t orig_size) +{ + int size = min((int)orig_size, 4096); + int len_tx = 1 /* type */ + + 4 /* handle */ + + 4 /* pos */ + + size /* data */; + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + struct ratpfs_file *rfile = f->priv; + int ret; + + pr_debug("%s: len_tx=%i handle=%i pos=%i size=%i\n", __func__, + len_tx, rfile->handle, (int)f->pos, size); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_WRITE_CALL; + put_unaligned_be32(rfile->handle, &pkt_tx->data[1]); + put_unaligned_be32(f->pos, &pkt_tx->data[5]); + memcpy(&pkt_tx->data[9], buf, size); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) { + ret = -EIO; + goto out; + } + + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_WRITE_RETURN) { + pr_err("invalid write response\n"); + ret = -EIO; + goto out; + } + + ret = size; +out: + free(pkt_rx); + + return ret; +} + +static int ratpfs_read(struct device_d __always_unused *dev, + FILE *f, void *buf, size_t orig_size) +{ + int size = min((int)orig_size, 4096); + int len_tx = 1 /* type */ + + 4 /* handle */ + + 4 /* pos */ + + 4 /* size */; + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + struct ratpfs_file *rfile = f->priv; + int ret; + + pr_debug("%s: len_tx=%i handle=%i pos=%i size=%i\n", __func__, + len_tx, rfile->handle, (int)f->pos, size); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_READ_CALL; + put_unaligned_be32(rfile->handle, &pkt_tx->data[1]); + put_unaligned_be32(f->pos, &pkt_tx->data[5]); + put_unaligned_be32(size, &pkt_tx->data[9]); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) { + ret = -EIO; + goto out; + } + + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_READ_RETURN) { + pr_err("invalid read response\n"); + ret = -EIO; + goto out; + } + size = pkt_rx->len - 1; + memcpy(buf, &pkt_rx->data[1], size); + ret = size; + +out: + free(pkt_rx); + return ret; +} + +static loff_t ratpfs_lseek(struct device_d __always_unused *dev, + FILE *f, loff_t pos) +{ + pr_debug("%s\n", __func__); + f->pos = pos; + return f->pos; +} + +static DIR* ratpfs_opendir(struct device_d __always_unused *dev, + const char *pathname) +{ + int len_name = strlen(pathname); + int len_tx = 1 /* type */ + + len_name /* path */; + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx)+len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + struct ratpfs_dir *rdir = xzalloc(sizeof(*rdir)); + int ret; + + pr_debug("%s: len_tx=%i pathname='%s'\n", __func__, len_tx, pathname); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_READDIR_CALL; + memcpy(&pkt_tx->data[1], pathname, len_name); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (!ret) { + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_READDIR_RETURN) { + pr_err("invalid readdir response\n"); + free(pkt_rx); + return NULL; + } + rdir->len = pkt_rx->len - 1; + rdir->entries = xmemdup(&pkt_rx->data[1], rdir->len); + free(pkt_rx); + return &rdir->dir; + } else { + return NULL; + } +} + +static struct dirent *ratpfs_readdir(struct device_d *dev, DIR *dir) +{ + struct ratpfs_dir *rdir = container_of(dir, struct ratpfs_dir, dir); + int i; + + pr_debug("%s\n", __func__); + + if (rdir->len <= rdir->off) + return NULL; + + for (i = 0; rdir->off < rdir->len; rdir->off++, i++) { + dir->d.d_name[i] = rdir->entries[rdir->off]; + if (dir->d.d_name[i] == 0) + break; + } + rdir->off++; + + return &dir->d; +} + +static int ratpfs_closedir(struct device_d *dev, DIR *dir) +{ + struct ratpfs_dir *rdir = container_of(dir, struct ratpfs_dir, dir); + + pr_debug("%s\n", __func__); + + free(rdir->entries); + free(rdir); + + return 0; +} + +static int ratpfs_stat(struct device_d __always_unused *dev, + const char *filename, struct stat *s) +{ + int len_name = strlen(filename); + int len_tx = 1 /* type */ + + len_name; /* path */ + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + int ret; + + pr_debug("%s: len_tx=%i filename='%s'\n", __func__, len_tx, filename); + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_STAT_CALL; + memcpy(&pkt_tx->data[1], filename, len_name); + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) { + ret = -EIO; + goto out; + } + + pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len); + if (pkt_rx->len < 6 || pkt_rx->data[0] != RATPFS_TYPE_STAT_RETURN) { + pr_err("invalid stat response\n"); + goto out; + } + switch (pkt_rx->data[1]) { + case 0: + ret = -ENOENT; + break; + case 1: + s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO; + break; + case 2: + s->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; + break; + } + s->st_size = get_unaligned_be32(&pkt_rx->data[2]); + +out: + free(pkt_rx); + return ret; +} + +static int ratpfs_probe(struct device_d *dev) +{ + int len_tx = 1; /* type */ + struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx); + struct ratp_bb_pkt *pkt_rx = NULL; + int ret; + struct fs_device_d *fsdev = dev_to_fs_device(dev); + + pr_debug("%s\n", __func__); + + ret = barebox_ratp_fs_mount(fsdev->path); + if (ret) + return ret; + + pkt_tx->len = len_tx; + pkt_tx->data[0] = RATPFS_TYPE_MOUNT_CALL; + + ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx); + if (ret) + goto out; + + if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_MOUNT_RETURN) { + pr_err("invalid mount response\n"); + ret = -EINVAL; + goto out; + } + +out: + free(pkt_rx); + + if (ret) + barebox_ratp_fs_mount(NULL); + + return ret; +} + +static void ratpfs_remove(struct device_d __always_unused *dev) +{ + pr_debug("%s\n", __func__); + + barebox_ratp_fs_mount(NULL); +} + +static struct fs_driver_d ratpfs_driver = { + .open = ratpfs_open, + .close = ratpfs_close, + .read = ratpfs_read, + .lseek = ratpfs_lseek, + .opendir = ratpfs_opendir, + .readdir = ratpfs_readdir, + .closedir = ratpfs_closedir, + .stat = ratpfs_stat, + .create = ratpfs_create, + .unlink = ratpfs_rm, + .mkdir = ratpfs_mkdir, + .rmdir = ratpfs_rm, + .write = ratpfs_write, + .truncate = ratpfs_truncate, + .flags = FS_DRIVER_NO_DEV, + .drv = { + .probe = ratpfs_probe, + .remove = ratpfs_remove, + .name = "ratpfs", + } +}; + +static int ratpfs_init(void) +{ + return register_fs_driver(&ratpfs_driver); +} +coredevice_initcall(ratpfs_init);
\ No newline at end of file |