| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-02-25 GuEe-GUI the first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <rtservice.h>
- #define DBG_TAG "dfs.9p"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #include "dfs_9pfs.h"
- #include <drivers/misc.h>
- #include <drivers/byteorder.h>
- #include <posix/string.h>
- #define OREAD 0 /* open for read */
- #define OWRITE 1 /* write */
- #define ORDWR 2 /* read and write */
- #define OEXEC 3 /* execute, == read but check execute permission */
- #define OEXCL 4
- #define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
- #define OCEXEC 32 /* or'ed in, close on exec */
- #define ORCLOSE 64 /* or'ed in, remove on close */
- #define OAPPEND 128 /* or'ed in, append */
- #define NOTAG ((rt_uint16_t)~0)
- #define NOFID ((rt_uint32_t)~0)
- #define TAG 1
- static rt_list_t _protocol_nodes = RT_LIST_OBJECT_INIT(_protocol_nodes);
- static struct rt_spinlock _protocol_lock = { 0 };
- #ifndef rt_le8_to_cpu
- #define rt_le8_to_cpu
- #endif
- #ifndef rt_cpu_to_le8
- #define rt_cpu_to_le8
- #endif
- #define P9_OF_OPS_GET(width, dir) \
- rt_inline rt_uint##width##_t get_##dir##_##value##width##_of( \
- struct p9_connection *conn, unsigned idx) \
- { \
- rt_uint##width##_t *vp = (void *)&conn->dir##_buffer[idx]; \
- return rt_le##width##_to_cpu(*vp); \
- }
- #define P9_OF_OPS_PUT(width, dir) \
- rt_inline void put_##dir##_##value##width##_of( \
- struct p9_connection *conn, unsigned idx, \
- rt_uint##width##_t value) \
- { \
- rt_uint##width##_t *vp = (void *)&conn->dir##_buffer[idx]; \
- *vp = rt_cpu_to_le##width(value); \
- }
- #define P9_OPS_PUT(width) \
- rt_inline rt_off_t put_value##width(struct p9_connection *conn, \
- rt_off_t off, rt_uint##width##_t value) \
- { \
- ((rt_uint##width##_t *)(conn->tx_buffer + off))[0] = \
- rt_cpu_to_le##width(value); \
- return off + sizeof(value); \
- }
- #define P9_OPS_GROUP(width) \
- P9_OF_OPS_GET(width, rx) \
- P9_OF_OPS_GET(width, tx) \
- P9_OF_OPS_PUT(width, rx) \
- P9_OF_OPS_PUT(width, tx) \
- P9_OPS_PUT(width)
- P9_OPS_GROUP(8)
- P9_OPS_GROUP(16)
- P9_OPS_GROUP(32)
- P9_OPS_GROUP(64)
- #undef P9_OF_OPS_GET
- #undef P9_OF_OPS_PUT
- #undef P9_OPS_GET
- #undef P9_OPS_GROUP
- rt_inline rt_uint32_t put_header(struct p9_connection *conn,
- rt_uint8_t hd, rt_uint16_t tag_flags)
- {
- rt_uint8_t *stack = conn->tx_buffer;
- ((rt_uint32_t *)stack)[0] = rt_cpu_to_le32(0);
- stack += sizeof(rt_uint32_t);
- stack[0] = hd;
- stack += sizeof(rt_uint8_t);
- ((rt_uint16_t *)stack)[0] = rt_cpu_to_le16(tag_flags);
- stack += sizeof(rt_uint16_t);
- return stack - conn->tx_buffer;
- }
- rt_inline rt_off_t put_bytes(struct p9_connection *conn, rt_off_t off,
- rt_uint8_t *bytes, rt_uint32_t count)
- {
- rt_uint8_t *stack = conn->tx_buffer + off;
- ((rt_uint16_t *)stack)[0] = rt_cpu_to_le16(count);
- stack += sizeof(rt_uint16_t);
- rt_memcpy(stack, bytes, count);
- stack += count;
- return stack - conn->tx_buffer;
- }
- rt_inline rt_off_t put_string(struct p9_connection *conn, rt_off_t off,
- char *string)
- {
- rt_uint32_t len = rt_strlen(string);
- rt_uint8_t *stack = conn->tx_buffer + off;
- ((rt_uint16_t *)stack)[0] = rt_cpu_to_le16(len);
- stack += sizeof(rt_uint16_t);
- rt_memcpy(stack, string, len);
- stack += len;
- return stack - conn->tx_buffer;
- }
- struct p9_connection *p9_connection_alloc(struct p9_protocol *p9p,
- const char *aname, rt_uint32_t buffer_size)
- {
- struct p9_connection *conn;
- if (!p9p || !aname)
- {
- return RT_NULL;
- }
- /* Buffer size expected to be 1M */
- buffer_size = rt_max_t(rt_uint32_t, buffer_size, 0x100000);
- if (!(conn = rt_malloc(sizeof(*conn) + buffer_size)))
- {
- return RT_NULL;
- }
- conn->msg_size = buffer_size;
- conn->fid = P9_ROOT_FID;
- #ifdef RT_USING_SMART
- conn->uname = "rt-smart";
- #else
- conn->uname = "rt-thread";
- #endif
- conn->aname = (char *)aname;
- conn->rx_buffer = (void *)conn + sizeof(*conn);
- conn->tx_buffer = conn->rx_buffer + buffer_size / 2;
- rt_mutex_init(&conn->lock, conn->aname, RT_IPC_FLAG_PRIO);
- conn->protocol = p9p;
- return conn;
- }
- rt_err_t p9_connection_free(struct p9_connection *conn)
- {
- rt_free(conn);
- return RT_EOK;
- }
- int p9_transaction(struct p9_connection *conn,
- rt_uint32_t tx_size, rt_uint32_t *out_rx_size)
- {
- rt_err_t err;
- rt_uint32_t rx_size;
- RT_ASSERT(conn != RT_NULL);
- RT_ASSERT(conn->protocol != RT_NULL);
- rx_size = conn->msg_size;
- if ((err = conn->protocol->transport(conn->protocol,
- conn->tx_buffer, tx_size, conn->rx_buffer, &rx_size)))
- {
- return P9_TRANSPORT_ERROR;
- }
- if (get_rx_value16_of(conn, P9_MSG_TAG) !=
- get_tx_value16_of(conn, P9_MSG_TAG))
- {
- return P9_UNEXPECTED_TAG;
- }
- if (get_rx_value8_of(conn, P9_MSG_ID) == P9_MSG_ERR)
- {
- rt_uint32_t err_len = rt_min_t(rt_uint32_t, sizeof(conn->error) - 1,
- get_rx_value16_of(conn, P9_MSG_ERR_STR_LEN));
- rt_strncpy(conn->error, (void *)&conn->rx_buffer[P9_MSG_ERR_STR], err_len);
- return P9_R_ERROR;
- }
- if ((get_tx_value8_of(conn, P9_MSG_ID) + 1) !=
- get_rx_value8_of(conn, P9_MSG_ID))
- {
- return P9_UNEXPECTED_MSG;
- }
- if (out_rx_size)
- {
- *out_rx_size = rx_size;
- }
- return 0;
- }
- int p9_version(struct p9_connection *conn)
- {
- int rc;
- rt_uint32_t size;
- RT_ASSERT(conn != RT_NULL);
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- /*
- * size[4] Tversion tag[2] msize[4] version[s]
- * size[4] Rversion tag[2] msize[4] version[s]
- */
- size = put_header(conn, P9_HD_TVERSION, NOTAG);
- size = put_value32(conn, size, conn->msg_size);
- size = put_string(conn, size, P9_VERSION);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- char *version;
- rt_uint32_t version_len;
- rt_uint32_t msg_size = get_rx_value32_of(conn, P9_MSG_VER_MSIZE);
- conn->msg_size = rt_min_t(rt_uint32_t, conn->msg_size, msg_size);
- version = (char *)&conn->rx_buffer[P9_MSG_VER_STR];
- version_len = get_rx_value16_of(conn, P9_MSG_VER_STR_LEN);
- LOG_D("Version: %s", version);
- if (!rt_strncmp(P9_VERSION_UNKNOWN, version, version_len))
- {
- rc = P9_UNKNOWN_VERSION;
- }
- }
- rt_mutex_release(&conn->lock);
- return rc;
- }
- int p9_attach(struct p9_connection *conn)
- {
- int rc;
- rt_uint32_t size;
- RT_ASSERT(conn != RT_NULL);
- if (19 + rt_strlen(conn->uname) + rt_strlen(conn->aname) > conn->msg_size)
- {
- return P9_MSG_TOO_LONG;
- }
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- /*
- * size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s]
- * size[4] Rattach tag[2] qid[13]
- */
- size = put_header(conn, P9_HD_TATTACH, TAG);
- size = put_value32(conn, size, conn->fid);
- size = put_value32(conn, size, NOFID);
- size = put_string(conn, size, conn->uname);
- size = put_string(conn, size, conn->aname);
- size = put_value32(conn, size, RT_UINT32_MAX);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- rc = p9_transaction(conn, size, RT_NULL);
- rt_mutex_release(&conn->lock);
- return rc;
- }
- static int p9_clunk_lockess(struct p9_connection *conn, rt_uint32_t fid)
- {
- rt_uint32_t size;
- /*
- * size[4] Tclunk tag[2] fid[4]
- * size[4] Rclunk tag[2]
- */
- size = put_header(conn, P9_HD_TCLUNK, TAG);
- size = put_value32(conn, size, fid);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- return p9_transaction(conn, size, RT_NULL);
- }
- int p9_clunk(struct p9_connection *conn, rt_uint32_t fid)
- {
- int rc;
- RT_ASSERT(conn != RT_NULL);
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- rc = p9_clunk_lockess(conn, fid);
- rt_mutex_release(&conn->lock);
- return rc;
- }
- rt_err_t dfs_9pfs_add_tag(struct p9_protocol *p9p)
- {
- rt_ubase_t level;
- if (!p9p || !p9p->tag || !p9p->transport)
- {
- return -RT_EINVAL;
- }
- rt_list_init(&p9p->list);
- level = rt_spin_lock_irqsave(&_protocol_lock);
- rt_list_insert_before(&_protocol_nodes, &p9p->list);
- rt_spin_unlock_irqrestore(&_protocol_lock, level);
- LOG_D("Add tag(%s) on %s", p9p->tag, p9p->name);
- return RT_EOK;
- }
- rt_err_t dfs_9pfs_del_tag(struct p9_protocol *p9p)
- {
- rt_ubase_t level;
- if (!p9p)
- {
- return -RT_EINVAL;
- }
- level = rt_spin_lock_irqsave(&_protocol_lock);
- rt_list_remove(&p9p->list);
- rt_spin_unlock_irqrestore(&_protocol_lock, level);
- LOG_D("Delete tag(%s) on %s", p9p->tag, p9p->name);
- return RT_EOK;
- }
- static int p9_to_fs_err(int rc)
- {
- const int p9_err[] =
- {
- [0] = RT_EOK,
- [-P9_ERROR] = -EIO,
- [-P9_UNKNOWN_VERSION] = -ENOSYS,
- [-P9_R_ERROR] = -EIO,
- [-P9_MSG_TOO_LONG] = -ENOSPC,
- [-P9_UNEXPECTED_MSG] = -EINVAL,
- [-P9_UNEXPECTED_TAG] = -EINVAL,
- [-P9_TRANSPORT_ERROR] = -EIO,
- [-P9_NO_TRANSPORT] = -EINVAL,
- [-P9_NULL_PATH] = -EINVAL,
- [-P9_PATH_ELEMENT_TOO_LONG] = -EINVAL,
- [-P9_READ_UNEXPECTED_DATA] = -EINVAL,
- [-P9_NO_BUFFER] = -ENOSPC,
- [-P9_MSG_SIZE_TOO_BIG] = -ENOSPC,
- };
- return p9_err[-rc];
- }
- static int p9_alloc_fid(struct p9_connection *conn)
- {
- int fid = rt_bitmap_next_clear_bit(conn->fid_map, 0, DFS_FD_MAX);
- if (fid < DFS_FD_MAX)
- {
- rt_bitmap_set_bit(conn->fid_map, fid);
- return fid + P9_FILE_FID;
- }
- return NOFID;
- }
- static void p9_free_fid(struct p9_connection *conn, int fid)
- {
- if (fid >= P9_FILE_FID)
- {
- rt_bitmap_clear_bit(conn->fid_map, fid - P9_FILE_FID);
- }
- }
- static int p9_free_fid_clunk(struct p9_connection *conn, int fid)
- {
- int rc;
- if (!(rc = p9_clunk_lockess(conn, fid)))
- {
- p9_free_fid(conn, fid);
- }
- return rc;
- }
- static rt_uint8_t fs_to_p9_flags(rt_uint32_t raw_flags)
- {
- rt_uint8_t flags = 0;
- switch (raw_flags & 3)
- {
- case O_RDONLY: flags = OREAD; break;
- case O_WRONLY: flags = OWRITE; break;
- case O_RDWR: flags = ORDWR; break;
- default: RT_ASSERT(0); break;
- }
- if (raw_flags & O_TRUNC)
- {
- flags |= OTRUNC;
- }
- if (raw_flags & O_APPEND)
- {
- flags |= OAPPEND;
- }
- if (raw_flags & O_EXCL)
- {
- flags |= OEXCL;
- }
- return flags;
- }
- static char *p9_basename(const char *path)
- {
- const char *basename = strrchr(path, '/');
- return (char *)(basename ? basename + 1 : path);
- }
- static int p9_walk_path_raw(struct p9_connection *conn, const char *path,
- rt_bool_t submode)
- {
- rt_uint32_t size;
- const char *split;
- int rc, count = 0, len, fid = conn->fid, new_fid;
- new_fid = p9_alloc_fid(conn);
- if (new_fid < 0)
- {
- return P9_NO_BUFFER;
- }
- if (submode)
- {
- --count;
- }
- /* Pass '/' */
- ++path;
- /*
- * size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
- * size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13])
- */
- size = put_header(conn, P9_HD_TWALK, TAG);
- size = put_value32(conn, size, fid);
- size = put_value32(conn, size, new_fid);
- size = put_value16(conn, size, 0); /* Fill later */
- do {
- split = strchrnul(path, '/');
- len = split - path;
- size = put_bytes(conn, size, (rt_uint8_t *)path, len);
- path += len + 1;
- ++count;
- } while (*split && count < P9_MSG_WALK_MAX_ELMT);
- if (count < P9_MSG_WALK_MAX_ELMT)
- {
- put_value16(conn, P9_MSG_WALK_TX_ELMT, count);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- if (count == get_rx_value16_of(conn, P9_MSG_WALK_RX_ELMT))
- {
- rc = new_fid;
- }
- else
- {
- /* Should be `P9_PARTIAL_WALK` if support longer path. */
- rc = P9_ERROR;
- p9_free_fid(conn, new_fid);
- }
- }
- }
- else
- {
- rc = P9_PATH_ELEMENT_TOO_LONG;
- p9_free_fid(conn, new_fid);
- }
- return rc;
- }
- rt_inline int p9_walk_path(struct p9_connection *conn, const char *path)
- {
- return p9_walk_path_raw(conn, path, RT_FALSE);
- }
- rt_inline int p9_walk_subpath(struct p9_connection *conn, const char *path)
- {
- return p9_walk_path_raw(conn, path, RT_TRUE);
- }
- static int dfs_9pfs_open(struct dfs_file *fd)
- {
- int rc;
- rt_uint32_t size;
- rt_bool_t is_root;
- struct p9_connection *conn;
- struct p9_file *p9f = rt_calloc(1, sizeof(*p9f));
- if (!p9f)
- {
- return -RT_ENOMEM;
- }
- conn = fd->vnode->fs->data;
- p9f->fid = conn->fid;
- p9f->connection = conn;
- is_root = !rt_strcmp(fd->vnode->path, "/");
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- if (!is_root)
- {
- if ((rc = p9_walk_path(p9f->connection, fd->vnode->path)) > 0)
- {
- p9f->fid = rc;
- }
- else if (fd->flags & O_CREAT)
- {
- rt_uint32_t parent_fid, perm = 0755;
- if (fd->flags & O_DIRECTORY)
- {
- perm |= P9_STAT_MODE_DIR;
- }
- parent_fid = p9_walk_subpath(conn, fd->vnode->path);
- /*
- * size[4] Tcreate tag[2] fid[4] name[s] perm[4] mode[1] extension[s]
- * size[4] Rcreate tag[2] qid[13] iounit[4]
- */
- size = put_header(conn, P9_HD_TCREATE, TAG);
- size = put_value32(conn, size, parent_fid);
- size = put_string(conn, size, p9_basename(fd->vnode->path));
- size = put_value32(conn, size, perm);
- size = put_value8(conn, size, fs_to_p9_flags(fd->flags));
- size = put_string(conn, size, "");
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- p9f->iounit = get_rx_value32_of(conn, P9_MSG_CREATE_IOUNIT);
- if ((rc = p9_walk_path(p9f->connection, fd->vnode->path)) > 0)
- {
- p9f->fid = rc;
- }
- }
- p9_free_fid_clunk(conn, parent_fid);
- }
- }
- if (is_root || rc >= 0)
- {
- /*
- * size[4] Tstat tag[2] fid[4]
- * size[4] Rstat tag[2] stat[n]
- */
- size = put_header(conn, P9_HD_TSTAT, TAG);
- size = put_value32(conn, size, p9f->fid);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- fd->vnode->size = get_rx_value64_of(conn, P9_MSG_STAT_LEN);
- /*
- * size[4] Topen tag[2] fid[4] mode[1]
- * size[4] Ropen tag[2] qid[13] iounit[4]
- */
- size = put_header(conn, P9_HD_TOPEN, TAG);
- size = put_value32(conn, size, p9f->fid);
- size = put_value8(conn, size, fs_to_p9_flags(fd->flags));
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- p9f->iounit = get_rx_value32_of(conn, P9_MSG_OPEN_IOUNIT);
- }
- }
- }
- rt_mutex_release(&conn->lock);
- if (!is_root && rc)
- {
- if (p9f->fid != conn->fid)
- {
- p9_free_fid(conn, p9f->fid);
- }
- rt_free(p9f);
- return p9_to_fs_err(rc);
- }
- fd->vnode->data = p9f;
- return 0;
- }
- static int dfs_9pfs_close(struct dfs_file *fd)
- {
- int rc = 0;
- struct p9_file *p9f = fd->vnode->data;
- struct p9_connection *conn = p9f->connection;
- if (p9f->fid != conn->fid)
- {
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- rc = p9_free_fid_clunk(conn, p9f->fid);
- rt_mutex_release(&conn->lock);
- }
- if (!rc)
- {
- rt_free(p9f);
- }
- return p9_to_fs_err(rc);
- }
- static ssize_t dfs_9pfs_read(struct dfs_file *fd, void *buf, size_t count)
- {
- int rc;
- size_t tcount = 0;
- rt_uint32_t max_count, set, size, got;
- struct p9_file *p9f = fd->vnode->data;
- struct p9_connection *conn = p9f->connection;
- max_count = conn->msg_size - P9_MSG_READ_DATA;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- while ((ssize_t)count > 0)
- {
- set = rt_min_t(rt_uint32_t, max_count, count);
- /*
- * size[4] Tread tag[2] fid[4] offset[8] count[4]
- * size[4] Rread tag[2] count[4] data[count]
- */
- size = put_header(conn, P9_HD_TREAD, TAG);
- size = put_value32(conn, size, p9f->fid);
- size = put_value64(conn, size, fd->pos);
- size = put_value32(conn, size, set);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- got = get_rx_value32_of(conn, P9_MSG_READ_COUNT);
- if (got == 0)
- {
- break;
- }
- else if (got <= set)
- {
- fd->pos += got;
- rt_memcpy(buf, conn->rx_buffer + P9_MSG_READ_DATA, got);
- }
- else
- {
- tcount = p9_to_fs_err(P9_READ_UNEXPECTED_DATA);
- break;
- }
- count -= got;
- tcount += got;
- }
- }
- rt_mutex_release(&conn->lock);
- return tcount;
- }
- static ssize_t dfs_9pfs_write(struct dfs_file *fd, const void *buf, size_t count)
- {
- int rc;
- size_t tcount = 0;
- rt_uint32_t max_count, set, size, got;
- struct p9_file *p9f = fd->vnode->data;
- struct p9_connection *conn = p9f->connection;
- max_count = conn->msg_size - P9_MSG_WRITE_DATA;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- while ((ssize_t)count > 0)
- {
- set = rt_min_t(rt_uint32_t, max_count, count);
- /*
- * size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]
- * size[4] Rwrite tag[2] count[4]
- */
- size = put_header(conn, P9_HD_TWRITE, TAG);
- size = put_value32(conn, size, p9f->fid);
- size = put_value64(conn, size, fd->pos);
- size = put_value32(conn, size, set);
- rt_memcpy(conn->tx_buffer + P9_MSG_WRITE_DATA, buf, set);
- size += set;
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- got = get_rx_value32_of(conn, P9_MSG_WRITE_COUNT);
- if (got <= set)
- {
- fd->pos += set;
- }
- else
- {
- tcount = p9_to_fs_err(P9_READ_UNEXPECTED_DATA);
- break;
- }
- count -= got;
- tcount += got;
- }
- }
- rt_mutex_release(&conn->lock);
- return tcount;
- }
- static int dfs_9pfs_flush(struct dfs_file *fd)
- {
- int rc;
- rt_uint32_t size;
- struct p9_file *p9f = fd->vnode->data;
- struct p9_connection *conn = p9f->connection;
- /*
- * size[4] Tfsync tag[2] fid[4] datasync[4]
- * size[4] Rfsync tag[2]
- */
- size = put_header(conn, P9_HD_TFSYNC, TAG);
- size = put_value32(conn, size, p9f->fid);
- size = put_value32(conn, size, 1);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- rc = p9_transaction(conn, size, RT_NULL);
- return p9_to_fs_err(rc);
- }
- static off_t dfs_9pfs_lseek(struct dfs_file *fd, off_t offset)
- {
- int ret = -EIO;
- if (offset <= fd->vnode->size)
- {
- fd->pos = offset;
- ret = fd->pos;
- }
- return ret;
- }
- static int dfs_9pfs_getdents(struct dfs_file *fd, struct dirent *dirp, uint32_t count)
- {
- int rc;
- rt_uint64_t off;
- rt_uint32_t ret, end, stat_size, size;
- struct p9_file *p9f = fd->vnode->data;
- struct p9_connection *conn = p9f->connection;
- count = (count / sizeof(struct dirent));
- if (!count)
- {
- return -EINVAL;
- }
- end = fd->pos + count;
- count = 0;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- /*
- * size[4] Tread tag[2] fid[4] offset[8] count[4]
- * size[4] Rread tag[2] count[4] stat[n]
- */
- size = put_header(conn, P9_HD_TREAD, TAG);
- size = put_value32(conn, size, p9f->fid);
- size = put_value64(conn, size, 0);
- size = put_value32(conn, size, fd->vnode->size);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- ret = get_rx_value32_of(conn, P9_MSG_READ_COUNT);
- off = P9_MSG_READ_DATA - P9_MSG_STAT_SIZE;
- for (int i = 0; (rt_int32_t)ret > 0; off += stat_size, ret -= stat_size, ++i)
- {
- /*
- * size[2] type[2] dev[4] qid[1+4+8] mode[4] atime[4] mtime[4] length[8]
- */
- stat_size = get_rx_value16_of(conn, off + P9_MSG_STAT_SIZE) + sizeof(rt_uint16_t);
- if (i < fd->pos)
- {
- continue;
- }
- if (get_rx_value16_of(conn, off + P9_MSG_STAT_TYPE) & P9_STAT_MODE_DIR)
- {
- dirp->d_type = DT_DIR;
- }
- else
- {
- dirp->d_type = DT_REG;
- }
- /*
- * name_size[2] name[name_size]
- * uid_size[2] uid[uid_size]
- * gid_size[2] gid[gid_size]
- * muid_size[2] muid[muid_size]
- * extension_size[2] extension[extension_size]
- * n_uid[4]
- * n_gid[4]
- * n_muid[4]
- */
- dirp->d_namlen = get_rx_value16_of(conn, off + P9_MSG_STAT_NAME_LEN);
- dirp->d_reclen = (rt_uint16_t)sizeof(struct dirent);
- rt_strncpy(dirp->d_name,
- (void *)conn->rx_buffer + off + P9_MSG_STAT_NAME,
- dirp->d_namlen);
- dirp->d_name[dirp->d_namlen] = '\0';
- if (!rt_strcmp(dirp->d_name, ".") || !rt_strcmp(dirp->d_name, ".."))
- {
- ++fd->pos;
- continue;
- }
- ++fd->pos;
- ++dirp;
- ++count;
- if (fd->pos >= end)
- {
- break;
- }
- }
- }
- rt_mutex_release(&conn->lock);
- count *= sizeof(struct dirent);
- return count;
- }
- static const struct dfs_file_ops _9pfs_fops =
- {
- .open = dfs_9pfs_open,
- .close = dfs_9pfs_close,
- .read = dfs_9pfs_read,
- .write = dfs_9pfs_write,
- .flush = dfs_9pfs_flush,
- .lseek = dfs_9pfs_lseek,
- .getdents = dfs_9pfs_getdents,
- };
- static int dfs_9pfs_mount(struct dfs_filesystem *fs,
- unsigned long rwflag, const void *data)
- {
- rt_ubase_t level;
- struct p9_protocol *p9p, *p9p_tmp;
- struct p9_connection *conn = RT_NULL;
- if (!data)
- {
- return (int)-RT_EINVAL;
- }
- level = rt_spin_lock_irqsave(&_protocol_lock);
- rt_list_for_each_entry(p9p_tmp, &_protocol_nodes, list)
- {
- if (!rt_strcmp(p9p_tmp->tag, data))
- {
- p9p = p9p_tmp;
- break;
- }
- }
- rt_spin_unlock_irqrestore(&_protocol_lock, level);
- if (!p9p)
- {
- return (int)-RT_EINVAL;
- }
- if (!(conn = p9_connection_alloc(p9p, p9p->tag, 0)))
- {
- return (int)-RT_ENOMEM;
- }
- if (p9_version(conn) || p9_attach(conn))
- {
- p9_connection_free(conn);
- return (int)-RT_EINVAL;
- }
- fs->data = conn;
- return (int)RT_EOK;
- }
- static int dfs_9pfs_unmount(struct dfs_filesystem *fs)
- {
- struct p9_connection *conn = fs->data;
- p9_clunk(conn, conn->fid);
- return p9_connection_free(conn);
- }
- static int dfs_9pfs_statfs(struct dfs_filesystem *fs, struct statfs *buf)
- {
- int rc;
- rt_uint32_t size;
- struct p9_connection *conn = fs->data;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- /*
- * size[4] Tstatfs tag[2] fid[4]
- * size[4] Rstatfs tag[2]
- * f_type[4]
- * f_bsize[4]
- * f_blocks[8]
- * f_bfree[8]
- * f_bavail[8]
- * f_files[8]
- * f_ffree[8]
- * fsid_val[8]
- * f_namelen[4]
- */
- size = put_header(conn, P9_HD_TSTATFS, TAG);
- size = put_value32(conn, size, conn->fid);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- buf->f_bsize = get_rx_value32_of(conn, P9_MSG_F_BSIZE);
- buf->f_blocks = get_rx_value64_of(conn, P9_MSG_F_BLOCKS);
- buf->f_bfree = get_rx_value64_of(conn, P9_MSG_F_BFREE);
- buf->f_bavail = get_rx_value64_of(conn, P9_MSG_F_BAVAIL);
- }
- rt_mutex_release(&conn->lock);
- return p9_to_fs_err(rc);
- }
- static int dfs_9pfs_unlink(struct dfs_filesystem *fs, const char *pathname)
- {
- rt_uint32_t size;
- int rc = 0, fid;
- struct p9_connection *conn = fs->data;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- if ((rc = p9_walk_path(conn, pathname)) > 0)
- {
- fid = rc;
- /*
- * size[4] Tremove tag[2] fid[4]
- * size[4] Rremove tag[2]
- */
- size = put_header(conn, P9_HD_TREMOVE, TAG);
- size = put_value32(conn, size, fid);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- rc = p9_transaction(conn, size, RT_NULL);
- p9_free_fid_clunk(conn, fid);
- }
- rt_mutex_release(&conn->lock);
- return p9_to_fs_err(rc);
- }
- static int dfs_9pfs_stat(struct dfs_filesystem *fs,
- const char *filename, struct stat *st)
- {
- int rc = 0, fid;
- rt_uint32_t size, mode;
- struct p9_connection *conn = fs->data;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- if ((rc = p9_walk_path(conn, filename)) > 0)
- {
- fid = rc;
- /*
- * size[4] Tstat tag[2] fid[4]
- * size[4] Rstat tag[2] stat[n]
- */
- size = put_header(conn, P9_HD_TSTAT, TAG);
- size = put_value32(conn, size, fid);
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- if (!(rc = p9_transaction(conn, size, RT_NULL)))
- {
- st->st_dev = 0;
- mode = get_rx_value32_of(conn, P9_MSG_STAT_MODE);
- st->st_mode = 0;
- if (mode & P9_STAT_MODE_DIR)
- {
- st->st_mode |= S_IFDIR;
- }
- else
- {
- st->st_mode |= S_IFREG;
- }
- if (mode & P9_STAT_MODE_SYMLINK)
- {
- st->st_mode |= S_IFLNK;
- }
- if (mode & P9_STAT_MODE_SOCKET)
- {
- st->st_mode |= S_IFSOCK;
- }
- if (mode & P9_STAT_MODE_NAMED_PIPE)
- {
- st->st_mode |= S_IFIFO;
- }
- if (mode & P9_STAT_MODE_SETUID)
- {
- st->st_mode |= S_ISUID;
- }
- if (mode & P9_STAT_MODE_SETGID)
- {
- st->st_mode |= S_ISGID;
- }
- if (mode & P9_STAT_MODE_SETVTX)
- {
- st->st_mode |= S_ISVTX;
- }
- st->st_atime = get_rx_value32_of(conn, P9_MSG_STAT_ATIME);
- st->st_mtime = get_rx_value32_of(conn, P9_MSG_STAT_MTIME);
- st->st_size = get_rx_value64_of(conn, P9_MSG_STAT_LEN);
- /*
- * name_size[2] name[name_size]
- * uid_size[2] uid[uid_size]
- * gid_size[2] gid[gid_size]
- * muid_size[2] muid[muid_size]
- * extension_size[2] extension[extension_size]
- * n_uid[4]
- * n_gid[4]
- * n_muid[4]
- */
- size = P9_MSG_STAT_NAME_LEN;
- size += sizeof(rt_uint16_t) + get_rx_value16_of(conn, size);
- size += sizeof(rt_uint16_t) + get_rx_value16_of(conn, size);
- size += sizeof(rt_uint16_t) + get_rx_value16_of(conn, size);
- size += sizeof(rt_uint16_t) + get_rx_value16_of(conn, size);
- st->st_uid = get_rx_value32_of(conn, size) + sizeof(rt_uint32_t);
- st->st_gid = get_rx_value32_of(conn, size) + sizeof(rt_uint32_t);
- }
- p9_free_fid_clunk(conn, fid);
- }
- rt_mutex_release(&conn->lock);
- return p9_to_fs_err(rc);
- }
- static int dfs_9pfs_rename(struct dfs_filesystem *fs,
- const char *oldpath, const char *newpath)
- {
- int rc = 0, fid;
- rt_uint32_t size;
- struct p9_connection *conn = fs->data;
- rt_mutex_take(&conn->lock, RT_WAITING_FOREVER);
- if ((fid = p9_walk_path(conn, oldpath)) > 0)
- {
- /*
- * size[4] Trename tag[2] fid[4] new_fid[4] name[s]
- * size[4] Rrename tag[2]
- */
- size = put_header(conn, P9_HD_TRENAME, TAG);
- size = put_value32(conn, size, fid);
- size = put_value32(conn, size, NOFID);
- size = put_string(conn, size, p9_basename(newpath));
- put_tx_value32_of(conn, P9_MSG_SIZE, size);
- rc = p9_transaction(conn, size, RT_NULL);
- p9_free_fid_clunk(conn, fid);
- }
- rt_mutex_release(&conn->lock);
- return p9_to_fs_err(rc);
- }
- static const struct dfs_filesystem_ops _9pfs =
- {
- .name = "9p",
- .flags = DFS_FS_FLAG_DEFAULT,
- .fops = &_9pfs_fops,
- .mount = dfs_9pfs_mount,
- .unmount = dfs_9pfs_unmount,
- .statfs = dfs_9pfs_statfs,
- .unlink = dfs_9pfs_unlink,
- .stat = dfs_9pfs_stat,
- .rename = dfs_9pfs_rename,
- };
- int dfs_9pfs_init(void)
- {
- /* register 9p file system */
- return dfs_register(&_9pfs);
- }
- INIT_COMPONENT_EXPORT(dfs_9pfs_init);
|