fs/userfs: Support fchstat and chstat callback

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao 2021-08-10 13:46:26 +08:00 committed by Gustavo Henrique Nihei
parent 9d96c54b1b
commit a09f262f1e
3 changed files with 298 additions and 4 deletions

View File

@ -131,6 +131,11 @@ static int userfs_rename(FAR struct inode *mountpt,
FAR const char *oldrelpath, FAR const char *newrelpath);
static int userfs_stat(FAR struct inode *mountpt,
FAR const char *relpath, FAR struct stat *buf);
static int userfs_fchstat(FAR const struct file *filep,
FAR const struct stat *buf, int flags);
static int userfs_chstat(FAR struct inode *mountpt,
FAR const char *relpath,
FAR const struct stat *buf, int flags);
/****************************************************************************
* Public Data
@ -153,7 +158,7 @@ const struct mountpt_operations userfs_operations =
userfs_sync, /* sync */
userfs_dup, /* dup */
userfs_fstat, /* fstat */
NULL, /* fchstat */
userfs_fchstat, /* fchstat */
userfs_truncate, /* truncate */
userfs_opendir, /* opendir */
@ -170,7 +175,7 @@ const struct mountpt_operations userfs_operations =
userfs_rmdir, /* rmdir */
userfs_rename, /* rename */
userfs_stat, /* stat */
NULL /* chstat */
userfs_chstat /* chstat */
};
/****************************************************************************
@ -899,6 +904,85 @@ static int userfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
return resp->ret;
}
/****************************************************************************
* Name: userfs_fchstat
*
* Description:
* Change information about an open file associated with the file
* descriptor 'filep'.
*
****************************************************************************/
static int userfs_fchstat(FAR const struct file *filep,
FAR const struct stat *buf, int flags)
{
FAR struct userfs_state_s *priv;
FAR struct userfs_fchstat_request_s *req;
FAR struct userfs_fchstat_response_s *resp;
ssize_t nsent;
ssize_t nrecvd;
int ret;
DEBUGASSERT(filep != NULL &&
filep->f_inode != NULL &&
filep->f_inode->i_private != NULL);
priv = filep->f_inode->i_private;
/* Get exclusive access */
ret = nxsem_wait(&priv->exclsem);
if (ret < 0)
{
return ret;
}
/* Construct and send the request to the server */
req = (FAR struct userfs_fchstat_request_s *)priv->iobuffer;
req->req = USERFS_REQ_FCHSTAT;
req->openinfo = filep->f_priv;
req->buf = *buf;
req->flags = flags;
nsent = psock_sendto(&priv->psock, priv->iobuffer,
sizeof(struct userfs_fchstat_request_s), 0,
(FAR struct sockaddr *)&priv->server,
sizeof(struct sockaddr_in));
if (nsent < 0)
{
ferr("ERROR: psock_sendto failed: %zd\n", nsent);
nxsem_post(&priv->exclsem);
return (int)nsent;
}
/* Then get the response from the server */
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
0, NULL, NULL);
nxsem_post(&priv->exclsem);
if (nrecvd < 0)
{
ferr("ERROR: psock_recvfrom failed: %zd\n", nrecvd);
return (int)nrecvd;
}
if (nrecvd != sizeof(struct userfs_fchstat_response_s))
{
ferr("ERROR: Response size incorrect: %zd\n", nrecvd);
return -EIO;
}
resp = (FAR struct userfs_fchstat_response_s *)priv->iobuffer;
if (resp->resp != USERFS_RESP_FCHSTAT)
{
ferr("ERROR: Incorrect response: %u\n", resp->resp);
return -EIO;
}
return resp->ret;
}
/****************************************************************************
* Name: userfs_truncate
*
@ -1986,6 +2070,94 @@ static int userfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
return resp->ret;
}
/****************************************************************************
* Name: userfs_chstat
*
* Description:
* Change information about a file or directory
*
****************************************************************************/
static int userfs_chstat(FAR struct inode *mountpt, FAR const char *relpath,
FAR const struct stat *buf, int flags)
{
FAR struct userfs_state_s *priv;
FAR struct userfs_chstat_request_s *req;
FAR struct userfs_chstat_response_s *resp;
ssize_t nsent;
ssize_t nrecvd;
int pathlen;
int ret;
DEBUGASSERT(mountpt != NULL &&
mountpt->i_private != NULL);
priv = mountpt->i_private;
/* Check the path length */
DEBUGASSERT(relpath != NULL);
pathlen = strlen(relpath);
if (pathlen > priv->mxwrite)
{
return -E2BIG;
}
/* Get exclusive access */
ret = nxsem_wait(&priv->exclsem);
if (ret < 0)
{
return ret;
}
/* Construct and send the request to the server */
req = (FAR struct userfs_chstat_request_s *)priv->iobuffer;
req->req = USERFS_REQ_CHSTAT;
req->buf = *buf;
req->flags = flags;
strncpy(req->relpath, relpath, priv->mxwrite);
nsent = psock_sendto(&priv->psock, priv->iobuffer,
SIZEOF_USERFS_CHSTAT_REQUEST_S(pathlen + 1), 0,
(FAR struct sockaddr *)&priv->server,
sizeof(struct sockaddr_in));
if (nsent < 0)
{
ferr("ERROR: psock_sendto failed: %zd\n", nsent);
nxsem_post(&priv->exclsem);
return (int)nsent;
}
/* Then get the response from the server */
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
0, NULL, NULL);
nxsem_post(&priv->exclsem);
if (nrecvd < 0)
{
ferr("ERROR: psock_recvfrom failed: %zd\n", nrecvd);
return (int)nrecvd;
}
if (nrecvd != sizeof(struct userfs_chstat_response_s))
{
ferr("ERROR: Response size incorrect: %zd\n", nrecvd);
return -EIO;
}
resp = (FAR struct userfs_chstat_response_s *)priv->iobuffer;
if (resp->resp != USERFS_RESP_STAT)
{
ferr("ERROR: Incorrect response: %u\n", resp->resp);
return -EIO;
}
return resp->ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/

View File

@ -136,7 +136,9 @@ enum userfs_req_e
USERFS_REQ_RMDIR,
USERFS_REQ_RENAME,
USERFS_REQ_STAT,
USERFS_REQ_DESTROY
USERFS_REQ_DESTROY,
USERFS_REQ_FCHSTAT,
USERFS_REQ_CHSTAT
};
/* This enumeration provides the type of each response returned from the
@ -164,7 +166,9 @@ enum userfs_resp_e
USERFS_RESP_RMDIR,
USERFS_RESP_RENAME,
USERFS_RESP_STAT,
USERFS_RESP_DESTROY
USERFS_RESP_DESTROY,
USERFS_RESP_FCHSTAT,
USERFS_RESP_CHSTAT
};
/* These structures are used by internal UserFS implementation and should not
@ -218,6 +222,10 @@ struct userfs_operations_s
int (*stat)(FAR void *volinfo, FAR const char *relpath,
FAR struct stat *buf);
int (*destroy)(FAR void *volinfo);
int (*fchstat)(FAR void *volinfo, FAR void *openinfo,
FAR const struct stat *buf, int flags);
int (*chstat)(FAR void *volinfo, FAR const char *relpath,
FAR const struct stat *buf, int flags);
};
/* The following structures describe the header on the marshaled data sent
@ -513,6 +521,36 @@ struct userfs_destroy_response_s
int ret; /* Result of the operation */
};
struct userfs_fchstat_request_s
{
uint8_t req; /* Must be USERFS_REQ_FCHSTAT */
FAR void *openinfo; /* Open file info as returned by open() */
struct stat buf; /* File system status */
int flags; /* The status to be change */
};
struct userfs_fchstat_response_s
{
uint8_t resp; /* Must be USERFS_RESP_FCHSTAT */
int ret; /* Result of the operation */
};
struct userfs_chstat_request_s
{
uint8_t req; /* Must be USERFS_REQ_CHSTAT */
struct stat buf; /* File system status */
int flags; /* The status to be change */
char relpath[1]; /* Relative path to the directory entry to be changed */
};
#define SIZEOF_USERFS_CHSTAT_REQUEST_S(n) (sizeof(struct userfs_chstat_request_s) + (n) - 1)
struct userfs_chstat_response_s
{
uint8_t resp; /* Must be USERFS_RESP_CHSTAT */
int ret; /* Result of the operation */
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/

View File

@ -864,6 +864,78 @@ static inline int userfs_destroy_dispatch(FAR struct userfs_info_s *info,
return resp.ret < 0 ? OK : -ENOTCONN;
}
static inline int userfs_fchstat_dispatch(FAR struct userfs_info_s *info,
FAR struct userfs_fchstat_request_s *req, size_t reqlen)
{
struct userfs_fchstat_response_s resp;
ssize_t nsent;
/* Verify the request size */
if (reqlen != sizeof(struct userfs_fchstat_request_s))
{
return -EINVAL;
}
/* Dispatch the request */
DEBUGASSERT(info->userops != NULL && info->userops->fchstat != NULL);
resp.ret = info->userops->fchstat(info->volinfo, req->openinfo,
&req->buf, req->flags);
/* Send the response */
resp.resp = USERFS_RESP_FCHSTAT;
nsent = sendto(info->sockfd, &resp,
sizeof(struct userfs_fchstat_response_s),
0, (FAR struct sockaddr *)&info->client,
sizeof(struct sockaddr_in));
return nsent < 0 ? nsent : OK;
}
static inline int userfs_chstat_dispatch(FAR struct userfs_info_s *info,
FAR struct userfs_chstat_request_s *req, size_t reqlen)
{
struct userfs_chstat_response_s resp;
int pathlen;
size_t expected;
ssize_t nsent;
/* Verify the request size */
if (reqlen < SIZEOF_USERFS_CHSTAT_REQUEST_S(0))
{
return -EINVAL;
}
pathlen = strlen(req->relpath);
if (pathlen > info->mxwrite)
{
return -EINVAL;
}
expected = SIZEOF_USERFS_CHSTAT_REQUEST_S(pathlen);
if (expected >= reqlen)
{
return -EINVAL;
}
/* Dispatch the request */
DEBUGASSERT(info->userops != NULL && info->userops->chstat != NULL);
resp.ret = info->userops->chstat(info->volinfo, req->relpath,
&req->buf, req->flags);
/* Send the response */
resp.resp = USERFS_RESP_CHSTAT;
nsent = sendto(info->sockfd, &resp,
sizeof(struct userfs_chstat_response_s),
0, (FAR struct sockaddr *)&info->client,
sizeof(struct sockaddr_in));
return nsent < 0 ? nsent : OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -1136,6 +1208,18 @@ int userfs_run(FAR const char *mountpt,
nread);
break;
case USERFS_REQ_FCHSTAT:
ret = userfs_fchstat_dispatch(info,
(FAR struct userfs_fchstat_request_s *)info->iobuffer,
nread);
break;
case USERFS_REQ_CHSTAT:
ret = userfs_chstat_dispatch(info,
(FAR struct userfs_chstat_request_s *)info->iobuffer,
nread);
break;
default:
ferr("ERROR: Unrecognized request received: %u\n",
*info->iobuffer);