diff --git a/fs/userfs/fs_userfs.c b/fs/userfs/fs_userfs.c index abf620443d..c1427bbb57 100644 --- a/fs/userfs/fs_userfs.c +++ b/fs/userfs/fs_userfs.c @@ -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 ****************************************************************************/ diff --git a/include/nuttx/fs/userfs.h b/include/nuttx/fs/userfs.h index 8d0316704c..21fb491c57 100644 --- a/include/nuttx/fs/userfs.h +++ b/include/nuttx/fs/userfs.h @@ -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 ****************************************************************************/ diff --git a/libs/libc/userfs/lib_userfs.c b/libs/libc/userfs/lib_userfs.c index 0b0c414bc8..44f1150993 100644 --- a/libs/libc/userfs/lib_userfs.c +++ b/libs/libc/userfs/lib_userfs.c @@ -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);