walnux/fs/v9fs/client.c
Lars Kruse e5b675d4dc refactor: fix spelling in private field names
Fix some misspelled field names.
These field names seem to be used only in private contexts.
Thus, the probability of external code accessing these fields is very
low.
In the rare case of external usage, compile time errors will easily
direct users to the new field name.
2025-05-24 09:44:22 -03:00

1823 lines
48 KiB
C

/****************************************************************************
* fs/v9fs/client.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/param.h>
#include <fcntl.h>
#include <nuttx/semaphore.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/lib/lib.h>
#include "client.h"
#include "fs_heap.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* 9P Magic Numbers */
#define V9FS_NOTAG ((uint16_t)(~0))
#define V9FS_NOFID ((uint32_t)(~0))
#define V9FS_HDRSZ 7 /* size[4] type[1] tag[2] */
#define V9FS_IOHDRSZ 24 /* Reserve enough space for
* TWRITE/TREAD
*/
#define V9FS_READDIRHDRSZ 24 /* Reserve enough space for
* READDIR
*/
#define V9FS_BIT8SZ 1 /* uint8 -> V9FS_BIT8SZ */
#define V9FS_BIT16SZ 2 /* uint16 -> V9FS_BIT16SZ */
#define V9FS_BIT32SZ 4 /* uint32 -> V9FS_BIT32SZ */
#define V9FS_BIT64SZ 8 /* uint64 -> V9FS_BIT64SZ */
#define V9FS_DEFAULT_VERSION "9P2000.L" /* Current implementations are
* based on the "9P2000L"
* protocol.
*/
/* 9P setattr valid bits */
#define V9FS_SETATTR_MODE (1 << 0)
#define V9FS_SETATTR_UID (1 << 1)
#define V9FS_SETATTR_GID (1 << 2)
#define V9FS_SETATTR_SIZE (1 << 3)
#define V9FS_SETATTR_ATIME (1 << 4)
#define V9FS_SETATTR_MTIME (1 << 5)
#define V9FS_SETATTR_CTIME (1 << 6)
#define V9FS_SETATTR_ATIMESET (1 << 7)
#define V9FS_SETATTR_MTIMESET (1 << 8)
/* 9P2000.L open flags */
#define V9FS_RDONLY 00000000
#define V9FS_WRONLY 00000001
#define V9FS_RDWR 00000002
#define V9FS_CREATE 00000100
#define V9FS_EXCL 00000200
#define V9FS_NOCTTY 00000400
#define V9FS_TRUNC 00001000
#define V9FS_APPEND 00002000
#define V9FS_NONBLOCK 00004000
#define V9FS_DSYNC 00010000
#define V9FS_FASYNC 00020000
#define V9FS_DIRECT 00040000
#define V9FS_DIRECTORY 00200000
#define V9FS_NOFOLLOW 00400000
#define V9FS_NOATIME 01000000
#define V9FS_CLOEXEC 02000000
#define V9FS_SYNC 04000000
/* 9P2000.L stat flags */
#define V9FS_STATS_ALL 0x00003fff
/* 9P2000.L unlink flags */
#define V9FS_REMOVEDIR 0x200
/* QID = uint8_t (type) + uint32_t (version) + uint64_t (path) */
#define V9FS_QIDSZ (V9FS_BIT8SZ + V9FS_BIT32SZ + V9FS_BIT64SZ)
/****************************************************************************
* Private Types
****************************************************************************/
enum v9fs_flags_e
{
V9FS_TLERROR = 6,
V9FS_RLERROR,
V9FS_TSTATFS = 8,
V9FS_RSTATFS,
V9FS_TLOPEN = 12,
V9FS_RLOPEN,
V9FS_TLCREATE = 14,
V9FS_RLCREATE,
V9FS_TRENAME = 20,
V9FS_RRENAME,
V9FS_TGETATTR = 24,
V9FS_RGETATTR,
V9FS_TSETATTR = 26,
V9FS_RSETATTR,
V9FS_TREADDIR = 40,
V9FS_RREADDIR,
V9FS_TFSYNC = 50,
V9FS_RFSYNC,
V9FS_TMKDIR = 72,
V9FS_RMKDIR,
V9FS_TRENAMEAT = 74,
V9FS_RRENAMEAT,
V9FS_TUNLINKAT = 76,
V9FS_RUNLINKAT,
V9FS_TVERSION = 100,
V9FS_RVERSION,
V9FS_TATTACH = 104,
V9FS_RATTACH,
V9FS_TERROR = 106,
V9FS_RERROR,
V9FS_TWALK = 110,
V9FS_RWALK,
V9FS_TREAD = 116,
V9FS_RREAD,
V9FS_TWRITE = 118,
V9FS_RWRITE,
V9FS_TCLUNK = 120,
V9FS_RCLUNK,
V9FS_TREMOVE = 122,
V9FS_RREMOVE,
V9FS_TSTAT = 124,
V9FS_RSTAT,
V9FS_TWSTAT = 126,
V9FS_RWSTAT,
};
begin_packed_struct struct v9fs_qid_s
{
uint8_t type;
uint32_t version;
uint64_t path;
} end_packed_struct;
begin_packed_struct struct v9fs_header_s
{
uint32_t size;
uint8_t type;
uint16_t tag;
} end_packed_struct;
begin_packed_struct struct v9fs_attach_s
{
struct v9fs_header_s header;
uint32_t fid;
uint32_t afid;
uint8_t buffer[2 * (V9FS_BIT16SZ + NAME_MAX) + V9FS_BIT32SZ];
} end_packed_struct;
begin_packed_struct struct v9fs_rattach_s
{
struct v9fs_header_s header;
struct v9fs_qid_s qid;
} end_packed_struct;
begin_packed_struct struct v9fs_clunk_s
{
struct v9fs_header_s header;
uint32_t fid;
} end_packed_struct;
#define v9fs_remove_s v9fs_clunk_s
begin_packed_struct struct v9fs_version_s
{
struct v9fs_header_s header;
uint32_t msize;
uint16_t version_len;
char version[NAME_MAX];
} end_packed_struct;
begin_packed_struct struct v9fs_setattr_s
{
struct v9fs_header_s header;
uint32_t fid;
uint32_t valid;
uint32_t mode;
uint32_t uid;
uint32_t gid;
uint64_t size;
uint64_t atime_sec;
uint64_t atime_nsec;
uint64_t mtime_sec;
uint64_t mtime_nsec;
} end_packed_struct;
begin_packed_struct struct v9fs_mkdir_s
{
struct v9fs_header_s header;
uint32_t fid;
uint16_t name_len;
uint8_t buffer[NAME_MAX + V9FS_BIT32SZ * 2];
} end_packed_struct;
#define v9fs_rmkdir_s v9fs_rattach_s
begin_packed_struct struct v9fs_unlink_s
{
struct v9fs_header_s header;
uint32_t fid;
uint16_t name_len;
uint8_t buffer[NAME_MAX + V9FS_BIT32SZ];
} end_packed_struct;
begin_packed_struct struct v9fs_lerror_s
{
struct v9fs_header_s header;
uint32_t ecode;
} end_packed_struct;
begin_packed_struct struct v9fs_open_s
{
struct v9fs_header_s header;
uint32_t fid;
uint32_t flags;
} end_packed_struct;
begin_packed_struct struct v9fs_ropen_s
{
struct v9fs_header_s header;
struct v9fs_qid_s qid;
uint32_t iounit;
} end_packed_struct;
begin_packed_struct struct v9fs_create_s
{
struct v9fs_header_s header;
uint32_t fid;
uint16_t name_len;
uint8_t buffer[NAME_MAX + V9FS_BIT32SZ * 3];
} end_packed_struct;
#define v9fs_rcreate_s v9fs_ropen_s
begin_packed_struct struct v9fs_walk_s
{
struct v9fs_header_s header;
uint32_t fid;
uint32_t newfid;
uint16_t nwname;
} end_packed_struct;
begin_packed_struct struct v9fs_rwalk_s
{
struct v9fs_header_s header;
uint16_t nwqid;
struct v9fs_qid_s wqid[1];
} end_packed_struct;
begin_packed_struct struct v9fs_write_s
{
struct v9fs_header_s header;
uint32_t fid;
uint64_t offset;
uint32_t count;
} end_packed_struct;
begin_packed_struct struct v9fs_rwrite_s
{
struct v9fs_header_s header;
uint32_t count;
} end_packed_struct;
#define v9fs_read_s v9fs_write_s
#define v9fs_rread_s v9fs_rwrite_s
#define v9fs_readdir_s v9fs_write_s
#define v9fs_rreaddir_s v9fs_rwrite_s
begin_packed_struct struct v9fs_fsync_s
{
struct v9fs_header_s header;
uint32_t fid;
uint32_t datasync;
} end_packed_struct;
begin_packed_struct struct v9fs_rename_s
{
struct v9fs_header_s header;
uint32_t fid;
uint32_t newfid;
uint16_t name_len;
uint8_t buffer[NAME_MAX];
} end_packed_struct;
begin_packed_struct struct v9fs_stat_s
{
struct v9fs_header_s header;
uint32_t fid;
uint64_t mask;
} end_packed_struct;
begin_packed_struct struct v9fs_rstat_s
{
struct v9fs_header_s header;
uint64_t valid;
struct v9fs_qid_s qid;
uint32_t mode;
uint32_t uid;
uint32_t gid;
uint64_t nlink;
uint64_t rdev;
uint64_t size;
uint64_t blksize;
uint64_t blocks;
uint64_t atime_sec;
uint64_t atime_nsec;
uint64_t mtime_sec;
uint64_t mtime_nsec;
uint64_t ctime_sec;
uint64_t ctime_nsec;
uint64_t btime_sec;
uint64_t btime_nsec;
uint64_t gen;
uint64_t data_version;
} end_packed_struct;
#define v9fs_statfs_s v9fs_clunk_s
begin_packed_struct struct v9fs_rstatfs_s
{
struct v9fs_header_s header;
uint32_t type; /* Type of file system (see below) */
uint32_t bsize; /* Optimal transfer block size */
uint64_t blocks; /* Total data blocks in file system */
uint64_t bfree; /* Free blocks in fs */
uint64_t bavail; /* Free blocks avail to non-superuser */
uint64_t files; /* Total file nodes in file system */
uint64_t ffree; /* Free file nodes in fs */
uint64_t fsid; /* File system id */
uint32_t namelen; /* Maximum length of filenames */
} end_packed_struct;
struct v9fs_map_s
{
int original;
int conversion;
};
struct v9fs_fid_s
{
uint32_t iounit;
uint32_t refcount;
char relpath[1];
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* v9fs_get_tagid
****************************************************************************/
static inline uint16_t v9fs_get_tagid(FAR struct v9fs_client_s *client)
{
uint16_t tag;
nxmutex_lock(&client->lock);
tag = client->tag_id;
client->tag_id++;
if (client->tag_id == V9FS_NOTAG)
{
/* Bypassing V9FS_NOTAG */
client->tag_id = 1;
}
nxmutex_unlock(&client->lock);
return tag;
}
/****************************************************************************
* v9fs_map_setattr_flags
****************************************************************************/
static uint32_t v9fs_map_setattr_flags(int flags)
{
uint32_t rflags = 0;
size_t i;
static const struct v9fs_map_s flags_map[] =
{
{ CH_STAT_MODE, V9FS_SETATTR_MODE },
{ CH_STAT_UID, V9FS_SETATTR_UID },
{ CH_STAT_GID, V9FS_SETATTR_GID },
{ CH_STAT_SIZE, V9FS_SETATTR_SIZE },
{ CH_STAT_ATIME, V9FS_SETATTR_ATIMESET },
{ CH_STAT_MTIME, V9FS_SETATTR_MTIMESET },
};
for (i = 0; i < nitems(flags_map); i++)
{
if (flags & flags_map[i].original)
{
rflags |= flags_map[i].conversion;
}
}
return rflags;
}
/****************************************************************************
* v9fs_map_open_flags
****************************************************************************/
static uint32_t v9fs_map_open_flags(int flags)
{
uint32_t rflags = 0;
size_t i;
static const struct v9fs_map_s flags_map[] =
{
{ O_CREAT, V9FS_CREATE },
{ O_NOCTTY, V9FS_NOCTTY },
{ O_TRUNC, V9FS_TRUNC},
{ O_APPEND, V9FS_APPEND },
{ O_NONBLOCK, V9FS_NONBLOCK },
{ O_DSYNC, V9FS_DSYNC },
{ FASYNC, V9FS_FASYNC },
{ O_DIRECT, V9FS_DIRECT },
{ O_DIRECTORY, V9FS_DIRECTORY },
{ O_NOFOLLOW, V9FS_NOFOLLOW },
{ O_NOATIME, V9FS_NOATIME },
{ O_CLOEXEC, V9FS_CLOEXEC },
{ O_EXCL, V9FS_EXCL },
{ O_SYNC, V9FS_SYNC},
};
switch (flags & 3)
{
case O_RDONLY:
rflags |= V9FS_RDONLY;
break;
case O_WRONLY:
rflags |= V9FS_WRONLY;
break;
case O_RDWR:
rflags |= V9FS_RDWR;
break;
}
for (i = 0; i < nitems(flags_map); i++)
{
if (flags & flags_map[i].original)
{
rflags |= flags_map[i].conversion;
}
}
return rflags;
}
/****************************************************************************
* v9fs_fid_create
****************************************************************************/
static int v9fs_fid_create(FAR struct v9fs_client_s *client,
FAR const char *relpath)
{
FAR struct v9fs_fid_s *fid;
size_t len;
int ret;
len = strlen(relpath);
fid = fs_heap_zalloc(sizeof(struct v9fs_fid_s) + len);
if (fid == NULL)
{
return -ENOMEM;
}
fid->refcount = 1;
nxmutex_lock(&client->lock);
ret = idr_alloc(client->fids, fid, 0, 0);
nxmutex_unlock(&client->lock);
if (ret >= 0)
{
memcpy(fid->relpath, relpath, len + 1);
return ret;
}
/* Failed to initialize fid */
fs_heap_free(fid);
return ret;
}
/****************************************************************************
* v9fs_fid_destroy
****************************************************************************/
static void v9fs_fid_destroy(FAR struct v9fs_client_s *client,
uint32_t fid)
{
FAR struct v9fs_fid_s *fidp;
nxmutex_lock(&client->lock);
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
nxmutex_unlock(&client->lock);
return;
}
idr_remove(client->fids, fid);
nxmutex_unlock(&client->lock);
fs_heap_free(fidp);
}
/****************************************************************************
* v9fs_client_rpc
****************************************************************************/
static int v9fs_client_rpc(FAR struct v9fs_transport_s *transport,
FAR struct iovec *wiov, size_t wcount,
FAR struct iovec *riov, size_t rcount,
uint16_t tag)
{
struct v9fs_payload_s payload;
int ret;
nxsem_init(&payload.resp, 0, 0);
payload.wiov = wiov;
payload.riov = riov;
payload.wcount = wcount;
payload.rcount = rcount;
payload.tag = tag;
payload.ret = -EIO;
ret = v9fs_transport_request(transport, &payload);
if (ret < 0)
{
nxsem_destroy(&payload.resp);
return ret;
}
nxsem_wait(&payload.resp);
nxsem_destroy(&payload.resp);
return payload.ret;
}
/****************************************************************************
* v9fs_client_clunk
****************************************************************************/
static int v9fs_client_clunk(FAR struct v9fs_client_s *client,
uint32_t fid)
{
struct v9fs_clunk_s request;
struct v9fs_lerror_s response;
struct iovec wiov[1];
struct iovec riov[1];
int ret;
/* size[4] Tclunk tag[2] fid[4]
* size[4] Rclunk tag[2]
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ;
request.header.type = V9FS_TCLUNK;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
/* A free buffer is reserved at the time of receipt to handle whether
* there is an error number message
*/
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
/* Even if the clunk returns an error, the fid is no longer valid for
* the server, so we need to remove the fid on the client side.
*/
v9fs_fid_destroy(client, fid);
return ret;
}
/****************************************************************************
* v9fs_client_attach
****************************************************************************/
static int v9fs_client_attach(FAR struct v9fs_client_s *client, uint32_t fid,
FAR const char *uname, FAR const char *aname)
{
struct v9fs_attach_s request;
struct v9fs_rattach_s response;
struct iovec wiov[1];
struct iovec riov[1];
uint16_t uname_len = strlen(uname);
uint16_t aname_len = strlen(aname);
uint32_t uid = getuid();
off_t offset = 0;
uint32_t newfid;
int ret;
/* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4]
* size[4] Rattach tag[2] qid[13]
*/
ret = v9fs_fid_create(client, "");
if (ret < 0)
{
return ret;
}
newfid = ret;
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 3 + V9FS_BIT16SZ * 2 +
uname_len + aname_len;
request.header.type = V9FS_TATTACH;
request.header.tag = v9fs_get_tagid(client);
request.fid = newfid;
request.afid = fid;
memcpy(&request.buffer[offset], &uname_len, V9FS_BIT16SZ);
offset += V9FS_BIT16SZ;
memcpy(&request.buffer[offset], uname, uname_len);
offset += uname_len;
memcpy(&request.buffer[offset], &aname_len, V9FS_BIT16SZ);
offset += V9FS_BIT16SZ;
memcpy(&request.buffer[offset], aname, aname_len);
offset += aname_len;
memcpy(&request.buffer[offset], &uid, V9FS_BIT32SZ);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 3 + V9FS_BIT16SZ * 2 +
uname_len + aname_len;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_QIDSZ;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
v9fs_fid_destroy(client, newfid);
return ret;
}
return newfid;
}
/****************************************************************************
* v9fs_client_version
****************************************************************************/
static int v9fs_client_version(FAR struct v9fs_client_s *client)
{
struct v9fs_version_s request;
struct v9fs_version_s response;
struct iovec wiov[1];
struct iovec riov[1];
int len = strlen(V9FS_DEFAULT_VERSION);
int ret;
/* size[4] Tversion tag[2] msize[4] version[s]
* size[4] Rversion tag[2] msize[4] version[s]
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT16SZ + len;
request.header.type = V9FS_TVERSION;
request.header.tag = V9FS_NOTAG;
request.msize = client->msize;
request.version_len = len;
memcpy(request.version, V9FS_DEFAULT_VERSION, len);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT16SZ + len;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT16SZ + len;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
return ret;
}
if (memcmp(response.version, V9FS_DEFAULT_VERSION, len))
{
return -EREMOTEIO;
}
if (response.msize < client->msize)
{
client->msize = response.msize;
}
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* v9fs_client_statfs
****************************************************************************/
int v9fs_client_statfs(FAR struct v9fs_client_s *client,
FAR struct statfs *buf)
{
struct v9fs_statfs_s request;
struct v9fs_rstatfs_s response;
struct iovec wiov[1];
struct iovec riov[1];
int ret;
/* size[4] Tstatfs tag[2] fid[4]
* size[4] Rstatfs tag[2] type[4] bsize[4] blocks[8] bfree[8] bavail[8]
* files[8] ffree[8] fsid[8] namelen[4]
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ;
request.header.type = V9FS_TSTATFS;
request.header.tag = v9fs_get_tagid(client);
request.fid = client->root_fid;
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
riov[0].iov_base = &response;
riov[0].iov_len = sizeof(response);
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
return ret;
}
buf->f_bsize = response.bsize;
buf->f_blocks = response.blocks;
buf->f_bfree = response.bfree;
buf->f_bavail = response.bavail;
buf->f_files = response.files;
buf->f_ffree = response.ffree;
buf->f_namelen = response.namelen;
buf->f_type = V9FS_MAGIC;
return 0;
}
/****************************************************************************
* v9fs_client_stat
****************************************************************************/
int v9fs_client_stat(FAR struct v9fs_client_s *client, uint32_t fid,
FAR struct stat *buf)
{
struct v9fs_stat_s request;
struct v9fs_rstat_s response;
struct iovec wiov[1];
struct iovec riov[1];
int ret;
/* size[4] Tgetattr tag[2] fid[4] request_mask[8]
* size[4] Rgetattr tag[2] valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8]
* rdev[8] size[8] blksize[8] blocks[8]
* atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
* ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]
* gen[8] data_version[8]
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ;
request.header.type = V9FS_TGETATTR;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
request.mask = V9FS_STATS_ALL;
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ;
riov[0].iov_base = &response;
riov[0].iov_len = sizeof(response);
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
return ret;
}
buf->st_mode = response.mode;
buf->st_uid = response.uid;
buf->st_gid = response.gid;
buf->st_nlink = response.nlink;
buf->st_rdev = response.rdev;
buf->st_size = response.size;
buf->st_blksize = response.blksize;
buf->st_blocks = response.blocks;
buf->st_atim.tv_sec = response.atime_sec;
buf->st_atim.tv_nsec = response.atime_nsec;
buf->st_mtim.tv_sec = response.mtime_sec;
buf->st_mtim.tv_nsec = response.mtime_nsec;
buf->st_ctim.tv_sec = response.ctime_sec;
buf->st_ctim.tv_nsec = response.ctime_nsec;
return 0;
}
/****************************************************************************
* v9fs_client_getsize
****************************************************************************/
off_t v9fs_client_getsize(FAR struct v9fs_client_s *client, uint32_t fid)
{
struct stat buf;
int ret;
ret = v9fs_client_stat(client, fid, &buf);
if (ret < 0)
{
return ret;
}
return buf.st_size;
}
/****************************************************************************
* v9fs_client_chstat
****************************************************************************/
int v9fs_client_chstat(FAR struct v9fs_client_s *client, uint32_t fid,
FAR const struct stat *buf, int flags)
{
struct v9fs_setattr_s request;
struct v9fs_lerror_s response;
struct iovec wiov[1];
struct iovec riov[1];
/* size[4] Tsetattr tag[2] fid[4] valid[4] mode[4] uid[4] gid[4] size[8]
* atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
* size[4] Rsetattr tag[2]
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 5 + V9FS_BIT64SZ * 5;
request.header.type = V9FS_TSETATTR;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
request.valid = v9fs_map_setattr_flags(flags);
request.mode = v9fs_map_open_flags(buf->st_mode);
request.uid = buf->st_uid;
request.gid = buf->st_gid;
request.size = buf->st_size;
request.atime_sec = buf->st_atim.tv_sec;
request.atime_nsec = buf->st_atim.tv_nsec;
request.mtime_sec = buf->st_mtim.tv_sec;
request.mtime_nsec = buf->st_mtim.tv_nsec;
/* A free buffer is reserved at the time of receipt to handle whether
* there is an error number message
*/
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 5 + V9FS_BIT64SZ * 5;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
return v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
}
/****************************************************************************
* v9fs_client_read
****************************************************************************/
ssize_t v9fs_client_read(FAR struct v9fs_client_s *client, uint32_t fid,
FAR void *buffer, off_t offset, size_t buflen)
{
FAR struct v9fs_fid_s *fidp;
struct v9fs_read_s request;
struct v9fs_rread_s response;
struct iovec wiov[1];
struct iovec riov[2];
size_t nread = 0;
int ret = 0;
/* size[4] Tread tag[2] fid[4] offset[8] count[4]
* size[4] Rread tag[2] count[4] data[count]
*/
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
return -ENOENT;
}
while (buflen > 0)
{
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ +
V9FS_BIT32SZ;
request.header.type = V9FS_TREAD;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
request.offset = offset;
request.count = buflen > fidp->iounit ? fidp->iounit : buflen;
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ +
V9FS_BIT32SZ;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
riov[1].iov_base = (FAR void *)buffer;
riov[1].iov_len = request.count;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 2,
request.header.tag);
if (ret < 0)
{
break;
}
if (response.count == 0)
{
break;
}
nread += response.count;
offset += response.count;
buffer += response.count;
buflen -= response.count;
}
return nread ? nread : ret;
}
/****************************************************************************
* v9fs_client_readdir
****************************************************************************/
ssize_t v9fs_client_readdir(FAR struct v9fs_client_s *client, uint32_t fid,
FAR void *buffer, off_t offset, size_t buflen)
{
FAR struct v9fs_fid_s *fidp;
struct v9fs_readdir_s request;
struct v9fs_rreaddir_s response;
struct iovec wiov[1];
struct iovec riov[2];
int ret;
/* size[4] Treaddir tag[2] fid[4] offset[8] count[4]
* size[4] Rreaddir tag[2] count[4] data[count]
*/
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
return -ENOENT;
}
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ +
V9FS_BIT32SZ;
request.header.type = V9FS_TREADDIR;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
request.offset = offset;
request.count = buflen > fidp->iounit ? fidp->iounit : buflen;
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ + V9FS_BIT32SZ;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
riov[1].iov_base = buffer;
riov[1].iov_len = request.count;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 2,
request.header.tag);
if (ret < 0)
{
return ret;
}
return response.count;
}
/****************************************************************************
* v9fs_client_convertdir
****************************************************************************/
ssize_t v9fs_client_convertdir(FAR const uint8_t *buffer, size_t bufsize,
off_t head, FAR off_t *offset,
FAR struct dirent *entry)
{
uint64_t off;
uint16_t name_len;
off_t next = head;
/* Ensure there is enough data for the fixed parts
* (qid, offset, type, name_len)
*/
if (bufsize < V9FS_QIDSZ + V9FS_BIT64SZ + V9FS_BIT8SZ + V9FS_BIT16SZ)
{
return -EIO;
}
/* Skip the qid part (13 Bytes) */
next += V9FS_QIDSZ;
/* Read the offset (8 bytes) */
memcpy(&off, buffer + next, sizeof(uint64_t));
next += sizeof(uint64_t);
/* Read the type (1 byte) */
memcpy(&entry->d_type, buffer + next, sizeof(uint8_t));
next += sizeof(uint8_t);
/* Read the name_len (2 bytes) */
memcpy(&name_len, buffer + next, sizeof(uint16_t));
next += sizeof(uint16_t);
/* Ensure there is enough data for the name */
if (bufsize - next < name_len)
{
return -EIO;
}
/* Copy the file name to entry->d_name and null-terminate it */
if (name_len > NAME_MAX)
{
return -ENAMETOOLONG;
}
memcpy(entry->d_name, buffer + next, name_len);
entry->d_name[name_len] = '\0';
next += name_len;
*offset = off;
return next - head;
}
/****************************************************************************
* v9fs_client_write
****************************************************************************/
ssize_t v9fs_client_write(FAR struct v9fs_client_s *client, uint32_t fid,
FAR const void *buffer, off_t offset,
size_t buflen)
{
FAR struct v9fs_fid_s *fidp;
struct v9fs_write_s request;
struct v9fs_rwrite_s response;
struct iovec wiov[2];
struct iovec riov[1];
size_t nwrite = 0;
int ret = 0;
/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count]
* size[4] Rwrite tag[2] count[4]
*/
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
return -ENOENT;
}
while (buflen > 0)
{
request.count = buflen > fidp->iounit ? fidp->iounit : buflen;
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ +
V9FS_BIT32SZ + request.count;
request.header.type = V9FS_TWRITE;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
request.offset = offset;
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ + V9FS_BIT64SZ +
V9FS_BIT32SZ;
wiov[1].iov_base = (FAR void *)buffer;
wiov[1].iov_len = request.count;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
ret = v9fs_client_rpc(client->transport, wiov, 2, riov, 1,
request.header.tag);
if (ret < 0)
{
break;
}
nwrite += response.count;
offset += response.count;
buffer += response.count;
buflen -= response.count;
}
return nwrite ? nwrite : ret;
}
/****************************************************************************
* v9fs_client_fsync
****************************************************************************/
int v9fs_client_fsync(FAR struct v9fs_client_s *client, uint32_t fid)
{
struct v9fs_fsync_s request;
struct v9fs_lerror_s response;
struct iovec wiov[1];
struct iovec riov[1];
/* size[4] Tfsync tag[2] fid[4] datasync[4]
* size[4] Rfsync tag[2]
* 0x01 - Sync data only
* 0x00 - Complete update data (including timestamps and permissions)
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 2;
request.header.type = V9FS_TFSYNC;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
request.datasync = 0;
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 2;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
return v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
}
/****************************************************************************
* v9fs_client_rename
****************************************************************************/
int v9fs_client_rename(FAR struct v9fs_client_s *client, uint32_t fid,
uint32_t newfid, FAR const char *name)
{
struct v9fs_rename_s request;
struct v9fs_lerror_s response;
struct iovec wiov[1];
struct iovec riov[1];
/* size[4] Trename tag[2] fid[4] dfid[4] name[s]
* size[4] Rrename tag[2]
*/
request.name_len = strlen(name);
request.fid = fid;
request.newfid = newfid;
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 2 + V9FS_BIT16SZ +
request.name_len;
request.header.type = V9FS_TRENAME;
request.header.tag = v9fs_get_tagid(client);
memcpy(&request.buffer, name, request.name_len);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 2 + V9FS_BIT16SZ +
request.name_len;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
return v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
}
/****************************************************************************
* v9fs_client_remove
****************************************************************************/
int v9fs_client_remove(FAR struct v9fs_client_s *client, uint32_t fid)
{
struct v9fs_remove_s request;
struct v9fs_lerror_s response;
struct iovec wiov[1];
struct iovec riov[1];
/* size[4] Tremove tag[2] fid[4]
* size[4] Rremove tag[2]
*/
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ;
request.header.type = V9FS_TREMOVE;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
/* A free buffer is reserved at the time of receipt to handle whether
* there is an error number message
*/
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
return v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
}
/****************************************************************************
* v9fs_client_unlink
****************************************************************************/
int v9fs_client_unlink(FAR struct v9fs_client_s *client, uint32_t fid,
FAR const char *name, bool isdir)
{
struct v9fs_unlink_s request;
struct v9fs_lerror_s response;
struct iovec wiov[1];
struct iovec riov[1];
int flags = isdir ? V9FS_REMOVEDIR : 0;
int ret;
/* size[4] Tunlinkat tag[2] dirfd[4] name[s] flags[4]
* size[4] Runlinkat tag[2]
*/
request.name_len = strlen(name);
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 2 + V9FS_BIT16SZ +
request.name_len;
request.header.type = V9FS_TUNLINKAT;
request.header.tag = v9fs_get_tagid(client);
request.fid = fid;
memcpy(&request.buffer, name, request.name_len);
memcpy(&request.buffer[request.name_len], &flags, V9FS_BIT32SZ);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 2 + V9FS_BIT16SZ +
request.name_len;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
return ret;
}
return v9fs_client_clunk(client, fid);
}
/****************************************************************************
* v9fs_client_mkdir
****************************************************************************/
int v9fs_client_mkdir(FAR struct v9fs_client_s *client, uint32_t fid,
FAR const char *name, int mode)
{
struct v9fs_mkdir_s request;
struct v9fs_rmkdir_s response;
struct iovec wiov[1];
struct iovec riov[1];
uint32_t gid = getgid();
off_t offset = 0;
/* size[4] Tmkdir tag[2] dfid[4] name[s] mode[4] gid[4]
* size[4] Rmkdir tag[2] qid[13]
*/
request.fid = fid;
request.name_len = strlen(name);
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 3 + V9FS_BIT16SZ +
request.name_len;
request.header.type = V9FS_TMKDIR;
request.header.tag = v9fs_get_tagid(client);
memcpy(&request.buffer[offset], name, request.name_len);
offset += request.name_len;
memcpy(&request.buffer[offset], &mode, V9FS_BIT32SZ);
offset += V9FS_BIT32SZ;
memcpy(&request.buffer[offset], &gid, V9FS_BIT32SZ);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 3 + V9FS_BIT16SZ +
request.name_len;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_QIDSZ;
return v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
}
/****************************************************************************
* v9fs_client_create
****************************************************************************/
int v9fs_client_create(FAR struct v9fs_client_s *client, uint32_t fid,
FAR const char *name, int oflags, int mode)
{
FAR struct v9fs_fid_s *fidp;
struct v9fs_create_s request;
struct v9fs_rcreate_s response;
struct iovec wiov[1];
struct iovec riov[1];
uint32_t flags = v9fs_map_open_flags(oflags);
uint32_t gid = getgid();
off_t offset = 0;
int ret;
/* size[4] Tlcreate tag[2] fid[4] name[s] flags[4] mode[4] gid[4]
* size[4] Rlcreate tag[2] qid[13] iounit[4]
*/
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
return -ENOENT;
}
request.fid = fid;
request.name_len = strlen(name);
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 4 + V9FS_BIT16SZ +
request.name_len;
request.header.type = V9FS_TLCREATE;
request.header.tag = v9fs_get_tagid(client);
memcpy(&request.buffer[offset], name, request.name_len);
offset += request.name_len;
memcpy(&request.buffer[offset], &flags, V9FS_BIT32SZ);
offset += V9FS_BIT32SZ;
memcpy(&request.buffer[offset], &mode, V9FS_BIT32SZ);
offset += V9FS_BIT32SZ;
memcpy(&request.buffer[offset], &gid, V9FS_BIT32SZ);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 4 + V9FS_BIT16SZ +
request.name_len;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_QIDSZ + V9FS_BIT32SZ;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
return ret;
}
fidp->iounit = response.iounit;
if (!fidp->iounit || fidp->iounit > client->msize - V9FS_IOHDRSZ)
{
fidp->iounit = client->msize - V9FS_IOHDRSZ;
}
return 0;
}
/****************************************************************************
* v9fs_client_open
****************************************************************************/
int v9fs_client_open(FAR struct v9fs_client_s *client,
uint32_t fid, int oflags)
{
FAR struct v9fs_fid_s *fidp;
struct v9fs_open_s request;
struct v9fs_ropen_s response;
struct iovec wiov[1];
struct iovec riov[1];
int ret;
/* size[4] Tlopen tag[2] fid[4] flags[4]
* size[4] Rlopen tag[2] qid[13] iounit[4]
*/
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
return -ENOENT;
}
request.fid = fid;
request.flags = v9fs_map_open_flags(oflags);
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 2;
request.header.type = V9FS_TLOPEN;
request.header.tag = v9fs_get_tagid(client);
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 2;
riov[0].iov_base = &response;
riov[0].iov_len = V9FS_HDRSZ + V9FS_QIDSZ + V9FS_BIT32SZ;
ret = v9fs_client_rpc(client->transport, wiov, 1, riov, 1,
request.header.tag);
if (ret < 0)
{
return ret;
}
fidp->iounit = response.iounit;
if (!fidp->iounit || fidp->iounit > client->msize - V9FS_IOHDRSZ)
{
fidp->iounit = client->msize - V9FS_IOHDRSZ;
}
return 0;
}
/****************************************************************************
* v9fs_client_getname
****************************************************************************/
int v9fs_client_getname(FAR struct v9fs_client_s *client, uint32_t fid,
FAR char *path)
{
FAR struct v9fs_fid_s *fidp;
nxmutex_lock(&client->lock);
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
nxmutex_unlock(&client->lock);
return -ENOENT;
}
strlcat(path, fidp->relpath, PATH_MAX);
nxmutex_unlock(&client->lock);
return 0;
}
/****************************************************************************
* v9fs_client_walk
****************************************************************************/
int v9fs_client_walk(FAR struct v9fs_client_s *client, FAR const char *path,
FAR const char **childname)
{
struct v9fs_walk_s request;
struct v9fs_rwalk_s response;
FAR char *request_payload;
FAR char *response_payload;
FAR const char *start;
FAR const char *end;
struct iovec wiov[2];
struct iovec riov[2];
uint16_t nwname = 0;
uint32_t newfid = V9FS_NOFID;
size_t total_len = 0;
size_t offset = 0;
size_t name_len;
int ret;
/* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
* size[4] Rwalk tag[2] nwqid[2] nwqid*(wqid[13])
*/
/* Parse path info, We need to skip parsing the root path */
start = path;
while (*start != '\0')
{
end = strchr(start, '/');
if (end == NULL)
{
if (childname == NULL)
{
nwname++;
total_len += strlen(start);
}
break;
}
else if (end != start)
{
nwname++;
total_len += end - start;
}
start = end + 1;
}
/* Request = sizeof(struct v9fs_walk_s) + nwname * sizeof(uint16_t) +
* total_len
* Response = sizeof(struct v9fs_rwalk_s) + V9FS_QIDSZ * (nwname + 1)
* When PATH_MAX = 255, we support a maximum recursive depth of
* (255 - 7 - 2) / 13 = 18 layers, PATH MAX size affects recursion depth
*/
total_len += V9FS_BIT16SZ * nwname;
if (total_len > PATH_MAX || nwname * V9FS_QIDSZ > PATH_MAX)
{
return -ENAMETOOLONG;
}
request_payload = lib_get_pathbuffer();
if (request_payload == NULL)
{
return -ENOMEM;
}
response_payload = lib_get_pathbuffer();
if (response_payload == NULL)
{
lib_put_pathbuffer(request_payload);
return -ENOMEM;
}
ret = v9fs_fid_create(client, path);
if (ret < 0)
{
goto err;
}
newfid = ret;
request.header.size = V9FS_HDRSZ + V9FS_BIT32SZ * 2 + V9FS_BIT16SZ +
total_len;
request.header.type = V9FS_TWALK;
request.header.tag = v9fs_get_tagid(client);
request.fid = client->root_fid;
request.newfid = newfid;
request.nwname = nwname;
start = path;
while (*start != '\0')
{
end = strchr(start, '/');
if (end == start)
{
start++;
continue;
}
if (end == NULL)
{
if (childname != NULL)
{
*childname = start;
break;
}
name_len = strlen(start);
end = start + name_len - 1;
}
else
{
name_len = end - start;
}
memcpy(&request_payload[offset], &name_len, sizeof(uint16_t));
offset += sizeof(uint16_t);
memcpy(&request_payload[offset], start, name_len);
offset += name_len;
start = end + 1;
}
wiov[0].iov_base = &request;
wiov[0].iov_len = V9FS_HDRSZ + V9FS_BIT32SZ * 2 + V9FS_BIT16SZ;
wiov[1].iov_base = request_payload;
wiov[1].iov_len = total_len;
riov[0].iov_base = &response;
riov[0].iov_len = sizeof(response);
riov[1].iov_base = response_payload;
riov[1].iov_len = V9FS_QIDSZ * (nwname + 1);
ret = v9fs_client_rpc(client->transport, wiov, total_len ? 2 : 1,
riov, 2, request.header.tag);
if (ret < 0)
{
v9fs_fid_destroy(client, newfid);
goto err;
}
/* There are differences in different server implementations, so it is
* necessary to check whether the returned nwqid satisfies the requested
* number.
*/
if (response.nwqid != nwname)
{
ret = -ENOENT;
}
err:
lib_put_pathbuffer(request_payload);
lib_put_pathbuffer(response_payload);
return ret == 0 ? newfid : ret;
}
/****************************************************************************
* v9fs_client_init
****************************************************************************/
int v9fs_client_init(FAR struct v9fs_client_s *client,
FAR const char *data)
{
FAR const char *options;
FAR char *aname;
char transport[NAME_MAX];
char uname[NAME_MAX] =
{
0
};
size_t length;
int ret;
aname = lib_get_pathbuffer();
if (aname == NULL)
{
return -ENOMEM;
}
aname[0] = '\0';
/* Parse commandline */
options = data;
while (*options != '\0')
{
FAR const char *sep = strchr(options, ',');
length = sep ? sep - options : strlen(options);
if (strncmp(options, "uname=", 6) == 0)
{
strlcpy(uname, options + 6, length - 5);
}
else if (strncmp(options, "aname=", 6) == 0)
{
strlcpy(aname, options + 6, length - 5);
}
else if (strncmp(options, "trans=", 6) == 0)
{
strlcpy(transport, options + 6, length - 5);
}
else if (strncmp(options, "msize=", 6) == 0)
{
client->msize = atoi(options + 6);
}
options += length + 1;
}
if (client->msize == 0)
{
/* Set default size */
client->msize = (CONFIG_V9FS_DEFAULT_MSIZE + V9FS_IOHDRSZ);
}
/* Initialize the client function */
ret = v9fs_transport_create(&client->transport, transport, data);
if (ret < 0)
{
lib_put_pathbuffer(aname);
return ret;
}
client->fids = idr_init_base(1);
if (client->fids == NULL)
{
v9fs_transport_destroy(client->transport);
lib_put_pathbuffer(aname);
return -ENOMEM;
}
nxmutex_init(&client->lock);
/* Do Version */
ret = v9fs_client_version(client);
if (ret < 0)
{
goto out;
}
/* Do Attach */
ret = v9fs_client_attach(client, V9FS_NOFID, uname, aname);
if (ret < 0)
{
goto out;
}
client->root_fid = ret;
client->tag_id = 1;
lib_put_pathbuffer(aname);
return 0;
out:
v9fs_transport_destroy(client->transport);
nxmutex_destroy(&client->lock);
idr_destroy(client->fids);
lib_put_pathbuffer(aname);
return ret;
}
/****************************************************************************
* v9fs_client_uninit
****************************************************************************/
int v9fs_client_uninit(FAR struct v9fs_client_s *client)
{
int ret;
ret = v9fs_client_clunk(client, client->root_fid);
if (ret < 0)
{
return ret;
}
v9fs_transport_destroy(client->transport);
nxmutex_destroy(&client->lock);
idr_destroy(client->fids);
return 0;
}
/****************************************************************************
* v9fs_transport_done
****************************************************************************/
void v9fs_transport_done(FAR struct v9fs_payload_s *cookie, int ret)
{
FAR struct v9fs_lerror_s *error = cookie->riov[0].iov_base;
/* Receive message = riov[0] (Header) + iov[1] (Payload) + ...
* So we first check if the type on the rheader is RLERROR. If it is,
* it means that payload[1] is ecode.
*/
if (error->header.type == V9FS_RLERROR)
{
/* Therefore, we assign the error code to the ecode of the cookie
* and check it in the next process
*/
cookie->ret = -error->ecode;
}
else
{
cookie->ret = ret;
}
nxsem_post(&cookie->resp);
}
/****************************************************************************
* v9fs_fid_put
****************************************************************************/
int v9fs_fid_put(FAR struct v9fs_client_s *client, uint32_t fid)
{
FAR struct v9fs_fid_s *fidp;
nxmutex_lock(&client->lock);
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
nxmutex_unlock(&client->lock);
return -ENOENT;
}
fidp->refcount--;
if (fidp->refcount > 0)
{
nxmutex_unlock(&client->lock);
return fidp->refcount;
}
nxmutex_unlock(&client->lock);
return v9fs_client_clunk(client, fid);
}
/****************************************************************************
* v9fs_fid_get
****************************************************************************/
int v9fs_fid_get(FAR struct v9fs_client_s *client, uint32_t fid)
{
FAR struct v9fs_fid_s *fidp;
nxmutex_lock(&client->lock);
fidp = idr_find(client->fids, fid);
if (fidp == NULL)
{
nxmutex_unlock(&client->lock);
return -ENOENT;
}
fidp->refcount++;
nxmutex_unlock(&client->lock);
return 0;
}
/****************************************************************************
* v9fs_parse_size
****************************************************************************/
ssize_t v9fs_parse_size(FAR const void *buffer)
{
FAR const struct v9fs_header_s *ptr = buffer;
return ptr->size;
}