2017-10-31 01:04:28 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* fs/userfs/fs_userfs.c
|
|
|
|
*
|
2021-02-03 14:47:23 +01:00
|
|
|
* 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
|
2017-10-31 01:04:28 +01:00
|
|
|
*
|
2021-02-03 14:47:23 +01:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2017-10-31 01:04:28 +01:00
|
|
|
*
|
2021-02-03 14:47:23 +01:00
|
|
|
* 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.
|
2017-10-31 01:04:28 +01:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Included Files
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/statfs.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <debug.h>
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include <nuttx/fs/fs.h>
|
|
|
|
#include <nuttx/fs/userfs.h>
|
|
|
|
#include <nuttx/fs/ioctl.h>
|
|
|
|
#include <nuttx/net/net.h>
|
2022-09-06 08:18:45 +02:00
|
|
|
#include <nuttx/mutex.h>
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2024-09-09 14:28:16 +02:00
|
|
|
#include "fs_heap.h"
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Pre-processor Definitions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#define IOBUFFER_SIZE(p) (USERFS_REQ_MAXSIZE + (p)->mxwrite)
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Types
|
|
|
|
****************************************************************************/
|
|
|
|
|
2022-08-05 06:31:25 +02:00
|
|
|
struct userfs_dir_s
|
|
|
|
{
|
|
|
|
struct fs_dirent_s base;
|
|
|
|
FAR void *dir;
|
|
|
|
};
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* This structure holds the internal state of the UserFS proxy */
|
|
|
|
|
|
|
|
struct userfs_state_s
|
|
|
|
{
|
|
|
|
/* Fields copied from struct userfs_config_s */
|
|
|
|
|
|
|
|
size_t mxwrite; /* The max size of a write data */
|
|
|
|
|
|
|
|
/* Internal state */
|
|
|
|
|
|
|
|
struct socket psock; /* Client socket instance */
|
2017-11-05 19:25:58 +01:00
|
|
|
struct sockaddr_in server; /* Server address */
|
2022-09-06 08:18:45 +02:00
|
|
|
mutex_t lock; /* Exclusive access for request-response sequence */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
/* I/O Buffer (actual size depends on USERFS_REQ_MAXSIZE and the configured
|
|
|
|
* mxwrite).
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint8_t iobuffer[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SIZEOF_USERFS_STATE_S(n) (sizeof(struct userfs_state_s) + (n) - 1)
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_open(FAR struct file *filep, const char *relpath,
|
|
|
|
int oflags, mode_t mode);
|
|
|
|
static int userfs_close(FAR struct file *filep);
|
|
|
|
static ssize_t userfs_read(FAR struct file *filep, char *buffer,
|
|
|
|
size_t buflen);
|
|
|
|
static ssize_t userfs_read(FAR struct file *filep, FAR char *buffer,
|
|
|
|
size_t buflen);
|
|
|
|
static ssize_t userfs_write(FAR struct file *filep, FAR const char *buffer,
|
|
|
|
size_t buflen);
|
|
|
|
static off_t userfs_seek(FAR struct file *filep, off_t offset, int whence);
|
|
|
|
static int userfs_ioctl(FAR struct file *filep, int cmd,
|
|
|
|
unsigned long arg);
|
|
|
|
|
|
|
|
static int userfs_sync(FAR struct file *filep);
|
2020-07-02 16:03:27 +02:00
|
|
|
static int userfs_dup(FAR const struct file *oldp,
|
|
|
|
FAR struct file *newp);
|
2017-10-31 01:04:28 +01:00
|
|
|
static int userfs_fstat(FAR const struct file *filep,
|
|
|
|
FAR struct stat *buf);
|
2018-01-03 23:03:56 +01:00
|
|
|
static int userfs_truncate(FAR struct file *filep, off_t length);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
static int userfs_opendir(FAR struct inode *mountpt,
|
2022-08-05 06:31:25 +02:00
|
|
|
FAR const char *relpath, FAR struct fs_dirent_s **dir);
|
2017-10-31 01:04:28 +01:00
|
|
|
static int userfs_closedir(FAR struct inode *mountpt,
|
|
|
|
FAR struct fs_dirent_s *dir);
|
|
|
|
static int userfs_readdir(FAR struct inode *mountpt,
|
2022-07-26 08:56:41 +02:00
|
|
|
FAR struct fs_dirent_s *dir,
|
|
|
|
FAR struct dirent *entry);
|
2017-10-31 01:04:28 +01:00
|
|
|
static int userfs_rewinddir(FAR struct inode *mountpt,
|
|
|
|
FAR struct fs_dirent_s *dir);
|
|
|
|
|
|
|
|
static int userfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
|
|
|
FAR void **handle);
|
|
|
|
static int userfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
|
|
|
unsigned int flags);
|
|
|
|
static int userfs_statfs(FAR struct inode *mountpt,
|
|
|
|
FAR struct statfs *buf);
|
|
|
|
|
|
|
|
static int userfs_unlink(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath);
|
|
|
|
static int userfs_mkdir(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath, mode_t mode);
|
|
|
|
static int userfs_rmdir(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath);
|
|
|
|
static int userfs_rename(FAR struct inode *mountpt,
|
|
|
|
FAR const char *oldrelpath, FAR const char *newrelpath);
|
2020-07-02 16:03:27 +02:00
|
|
|
static int userfs_stat(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath, FAR struct stat *buf);
|
2021-08-10 07:46:26 +02:00
|
|
|
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);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Data
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* See fs_mount.c -- this structure is explicitly extern'ed there.
|
|
|
|
* We use the old-fashioned kind of initializers so that this will compile
|
|
|
|
* with any compiler.
|
|
|
|
*/
|
|
|
|
|
2023-04-22 16:53:42 +02:00
|
|
|
const struct mountpt_operations g_userfs_operations =
|
2017-10-31 01:04:28 +01:00
|
|
|
{
|
|
|
|
userfs_open, /* open */
|
|
|
|
userfs_close, /* close */
|
|
|
|
userfs_read, /* read */
|
|
|
|
userfs_write, /* write */
|
|
|
|
userfs_seek, /* seek */
|
|
|
|
userfs_ioctl, /* ioctl */
|
2023-01-02 14:02:51 +01:00
|
|
|
NULL, /* mmap */
|
2023-01-02 18:06:12 +01:00
|
|
|
userfs_truncate, /* truncate */
|
2023-11-25 13:11:03 +01:00
|
|
|
NULL, /* poll */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
userfs_sync, /* sync */
|
|
|
|
userfs_dup, /* dup */
|
|
|
|
userfs_fstat, /* fstat */
|
2021-08-10 07:46:26 +02:00
|
|
|
userfs_fchstat, /* fchstat */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
userfs_opendir, /* opendir */
|
|
|
|
userfs_closedir, /* closedir */
|
|
|
|
userfs_readdir, /* readdir */
|
|
|
|
userfs_rewinddir, /* rewinddir */
|
|
|
|
|
|
|
|
userfs_bind, /* bind */
|
|
|
|
userfs_unbind, /* unbind */
|
|
|
|
userfs_statfs, /* statfs */
|
|
|
|
|
|
|
|
userfs_unlink, /* unlink */
|
|
|
|
userfs_mkdir, /* mkdir */
|
|
|
|
userfs_rmdir, /* rmdir */
|
|
|
|
userfs_rename, /* rename */
|
2021-07-09 07:43:26 +02:00
|
|
|
userfs_stat, /* stat */
|
2021-08-10 07:46:26 +02:00
|
|
|
userfs_chstat /* chstat */
|
2017-10-31 01:04:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_open
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_open(FAR struct file *filep, FAR const char *relpath,
|
|
|
|
int oflags, mode_t mode)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_open_request_s *req;
|
|
|
|
FAR struct userfs_open_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int pathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
finfo("Open '%s'\n", relpath);
|
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path length */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(relpath != NULL);
|
2017-11-05 19:25:58 +01:00
|
|
|
pathlen = strlen(relpath);
|
2017-10-31 01:04:28 +01:00
|
|
|
if (pathlen > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_open_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_OPEN;
|
|
|
|
req->oflags = oflags;
|
|
|
|
req->mode = mode;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_OPEN_REQUEST_S(pathlen + 1), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_open_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the returned openinfo as the filep private data. */
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_open_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_OPEN)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
filep->f_priv = resp->openinfo;
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_close
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_close(FAR struct file *filep)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_close_request_s *req;
|
|
|
|
FAR struct userfs_close_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_close_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_CLOSE;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_close_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_close_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_close_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_CLOSE)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
if (resp->ret >= 0)
|
|
|
|
{
|
|
|
|
filep->f_priv = NULL;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_read
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static ssize_t userfs_read(FAR struct file *filep, char *buffer,
|
|
|
|
size_t buflen)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_read_request_s *req;
|
|
|
|
FAR struct userfs_read_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int respsize;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2020-11-24 23:47:34 +01:00
|
|
|
finfo("Read %zu bytes from offset %jd\n", buflen, (intmax_t)filep->f_pos);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_read_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_READ;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
req->readlen = buflen;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_read_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd < SIZEOF_USERFS_READ_RESPONSE_S(0))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response too small: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_read_response_s *)priv->iobuffer;
|
2017-11-01 23:57:59 +01:00
|
|
|
if (resp->resp != USERFS_RESP_READ)
|
2017-10-31 01:04:28 +01:00
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resp->nread > buflen)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size too large: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
respsize = SIZEOF_USERFS_READ_RESPONSE_S(resp->nread);
|
|
|
|
if (respsize != nrecvd)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response size: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the received data to the user buffer */
|
|
|
|
|
|
|
|
memcpy(buffer, resp->rddata, resp->nread);
|
|
|
|
return resp->nread;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_write
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static ssize_t userfs_write(FAR struct file *filep, FAR const char *buffer,
|
|
|
|
size_t buflen)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_write_request_s *req;
|
|
|
|
FAR struct userfs_write_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2020-11-24 23:47:34 +01:00
|
|
|
finfo("Write %zu bytes to offset %jd\n", buflen, (intmax_t)filep->f_pos);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2019-10-27 18:48:14 +01:00
|
|
|
/* Perform multiple writes if the write length exceeds the configured
|
|
|
|
* maximum (mxwrite).
|
2017-10-31 01:04:28 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (buflen > priv->mxwrite)
|
|
|
|
{
|
2020-02-23 09:50:23 +01:00
|
|
|
return -E2BIG; /* No implemented yet */
|
2017-10-31 01:04:28 +01:00
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_write_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_WRITE;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
req->writelen = buflen;
|
|
|
|
memcpy(req->wrdata, buffer, buflen);
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_WRITE_REQUEST_S(buflen), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_write_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_write_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_WRITE)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->nwritten;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_seek
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static off_t userfs_seek(FAR struct file *filep, off_t offset, int whence)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_seek_request_s *req;
|
|
|
|
FAR struct userfs_seek_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
finfo("Offset %lu bytes to whence=%d\n", (unsigned long)offset, whence);
|
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_seek_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_SEEK;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
req->offset = offset;
|
|
|
|
req->whence = whence;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_seek_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_seek_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_seek_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_SEEK)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_ioctl
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_ioctl_request_s *req;
|
|
|
|
FAR struct userfs_ioctl_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
finfo("cmd: %d arg: %08lx\n", cmd, arg);
|
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
req = (FAR struct userfs_ioctl_request_s *)priv->iobuffer;
|
2017-10-31 01:04:28 +01:00
|
|
|
req->req = USERFS_REQ_IOCTL;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
req->cmd = cmd;
|
|
|
|
req->arg = arg;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_ioctl_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_ioctl_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_ioctl_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_IOCTL)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_sync
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_sync(FAR struct file *filep)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_sync_request_s *req;
|
|
|
|
FAR struct userfs_sync_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_sync_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_SYNC;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_sync_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_sync_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_sync_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_SYNC)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_dup
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Duplicate open file data in the new file structure.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_dup(FAR const struct file *oldp, FAR struct file *newp)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_dup_request_s *req;
|
|
|
|
FAR struct userfs_dup_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
finfo("Dup %p->%p\n", oldp, newp);
|
|
|
|
|
|
|
|
DEBUGASSERT(oldp != NULL &&
|
|
|
|
oldp->f_inode != NULL &&
|
|
|
|
oldp->f_inode->i_private != NULL);
|
|
|
|
priv = oldp->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_dup_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_DUP;
|
|
|
|
req->openinfo = oldp->f_priv;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_dup_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_dup_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_dup_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_DUP)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
newp->f_priv = resp->openinfo;
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_fstat
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Obtain information about an open file associated with the file
|
|
|
|
* descriptor 'fd', and will write it to the area pointed to by 'buf'.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_fstat_request_s *req;
|
|
|
|
FAR struct userfs_fstat_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2017-10-31 01:04:28 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_fstat_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_FSTAT;
|
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_fstat_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_fstat_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_fstat_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_FSTAT)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the status of the directory entry */
|
|
|
|
|
|
|
|
DEBUGASSERT(buf != NULL);
|
|
|
|
memcpy(buf, &resp->buf, sizeof(struct stat));
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:46:26 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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;
|
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2021-08-10 07:46:26 +02:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2021-08-10 07:46:26 +02:00
|
|
|
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);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2021-08-10 07:46:26 +02:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2021-08-10 07:46:26 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-01-03 23:03:56 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_truncate
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Set the size of the regular file referred to by 'filep' to 'length'
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_truncate(FAR struct file *filep, off_t length)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_truncate_request_s *req;
|
|
|
|
FAR struct userfs_truncate_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int ret;
|
|
|
|
|
2023-08-28 11:17:05 +02:00
|
|
|
DEBUGASSERT(
|
2018-01-03 23:03:56 +01:00
|
|
|
filep->f_inode != NULL &&
|
|
|
|
filep->f_inode->i_private != NULL);
|
|
|
|
priv = filep->f_inode->i_private;
|
|
|
|
|
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2018-01-03 23:03:56 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_truncate_request_s *)priv->iobuffer;
|
2018-01-22 14:14:32 +01:00
|
|
|
req->req = USERFS_REQ_TRUNCATE;
|
2018-01-03 23:03:56 +01:00
|
|
|
req->openinfo = filep->f_priv;
|
|
|
|
req->length = length;
|
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_truncate_request_s), 0,
|
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2018-01-03 23:03:56 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2018-01-03 23:03:56 +01:00
|
|
|
|
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_truncate_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_truncate_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_FSTAT)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the result of truncate operation */
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_opendir
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Open a directory
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
|
2022-08-05 06:31:25 +02:00
|
|
|
FAR struct fs_dirent_s **dir)
|
2017-10-31 01:04:28 +01:00
|
|
|
{
|
2022-08-05 06:31:25 +02:00
|
|
|
FAR struct userfs_dir_s *udir;
|
2017-10-31 01:04:28 +01:00
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_opendir_request_s *req;
|
|
|
|
FAR struct userfs_opendir_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int pathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
finfo("relpath: \"%s\"\n", relpath ? relpath : "NULL");
|
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path length */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(relpath != NULL);
|
2017-11-05 19:25:58 +01:00
|
|
|
pathlen = strlen(relpath);
|
2017-10-31 01:04:28 +01:00
|
|
|
if (pathlen > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_opendir_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_OPENDIR;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_OPENDIR_REQUEST_S(pathlen + 1), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_opendir_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_opendir_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_OPENDIR)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the opaque dir reference in struct fs_dirent_s */
|
|
|
|
|
|
|
|
DEBUGASSERT(dir != NULL);
|
2024-09-09 14:28:16 +02:00
|
|
|
udir = fs_heap_zalloc(sizeof(struct userfs_dir_s));
|
2022-08-05 06:31:25 +02:00
|
|
|
if (udir == NULL)
|
|
|
|
{
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
udir->dir = resp->dir;
|
|
|
|
*dir = (FAR struct fs_dirent_s *)udir;
|
2017-10-31 01:04:28 +01:00
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_closedir
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Close a directory
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_closedir(FAR struct inode *mountpt,
|
|
|
|
FAR struct fs_dirent_s *dir)
|
|
|
|
{
|
2022-08-05 06:31:25 +02:00
|
|
|
FAR struct userfs_dir_s *udir;
|
2017-10-31 01:04:28 +01:00
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_closedir_request_s *req;
|
|
|
|
FAR struct userfs_closedir_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
2022-08-05 06:31:25 +02:00
|
|
|
udir = (FAR struct userfs_dir_s *)dir;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
req = (FAR struct userfs_closedir_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_CLOSEDIR;
|
2022-08-05 06:31:25 +02:00
|
|
|
req->dir = udir->dir;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_closedir_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_closedir_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_closedir_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_CLOSEDIR)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2024-09-09 14:28:16 +02:00
|
|
|
fs_heap_free(udir);
|
2017-10-31 01:04:28 +01:00
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_readdir
|
|
|
|
*
|
|
|
|
* Description: Read the next directory entry
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_readdir(FAR struct inode *mountpt,
|
2022-07-26 08:56:41 +02:00
|
|
|
FAR struct fs_dirent_s *dir,
|
|
|
|
FAR struct dirent *entry)
|
2017-10-31 01:04:28 +01:00
|
|
|
{
|
2022-08-05 06:31:25 +02:00
|
|
|
FAR struct userfs_dir_s *udir;
|
2017-10-31 01:04:28 +01:00
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_readdir_request_s *req;
|
|
|
|
FAR struct userfs_readdir_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
2022-08-05 06:31:25 +02:00
|
|
|
udir = (FAR struct userfs_dir_s *)dir;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
req = (FAR struct userfs_readdir_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_READDIR;
|
2022-08-05 06:31:25 +02:00
|
|
|
req->dir = udir->dir;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_readdir_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_readdir_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_readdir_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_READDIR)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the dirent */
|
|
|
|
|
|
|
|
DEBUGASSERT(dir != NULL);
|
2022-07-26 08:56:41 +02:00
|
|
|
memcpy(entry, &resp->entry, sizeof(struct dirent));
|
2017-10-31 01:04:28 +01:00
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_rewindir
|
|
|
|
*
|
|
|
|
* Description: Reset directory read to the first entry
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_rewinddir(FAR struct inode *mountpt,
|
|
|
|
FAR struct fs_dirent_s *dir)
|
|
|
|
{
|
2022-08-05 06:31:25 +02:00
|
|
|
FAR struct userfs_dir_s *udir;
|
2017-10-31 01:04:28 +01:00
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_rewinddir_request_s *req;
|
|
|
|
FAR struct userfs_rewinddir_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
2022-08-05 06:31:25 +02:00
|
|
|
udir = (FAR struct userfs_dir_s *)dir;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
req = (FAR struct userfs_rewinddir_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_REWINDDIR;
|
2022-08-05 06:31:25 +02:00
|
|
|
req->dir = udir->dir;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_rewinddir_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_rewinddir_response_s))
|
|
|
|
{
|
2019-09-20 02:19:18 +02:00
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
2017-10-31 01:04:28 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_rewinddir_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_REWINDDIR)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_bind
|
|
|
|
*
|
|
|
|
* Description: This implements a portion of the mount operation. This
|
|
|
|
* function allocates and initializes the mountpoint private data and
|
|
|
|
* binds the blockdriver inode to the filesystem private data. The final
|
|
|
|
* binding of the private data (containing the blockdriver) to the
|
|
|
|
* mountpoint is performed by mount().
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_bind(FAR struct inode *blkdriver, FAR const void *data,
|
|
|
|
FAR void **handle)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR const struct userfs_config_s *config;
|
2017-11-05 19:25:58 +01:00
|
|
|
struct sockaddr_in client;
|
2017-10-31 01:04:28 +01:00
|
|
|
unsigned int iolen;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
DEBUGASSERT(data != NULL && handle != NULL);
|
|
|
|
config = (FAR const struct userfs_config_s *)data;
|
|
|
|
|
|
|
|
/* Allocate an instance of the UserFS state structure */
|
|
|
|
|
|
|
|
iolen = USERFS_REQ_MAXSIZE + config->mxwrite;
|
2024-09-09 14:28:16 +02:00
|
|
|
priv = fs_heap_malloc(SIZEOF_USERFS_STATE_S(iolen));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (priv == NULL)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Failed to allocate state structure\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
/* Initialize the mutex that assures mutually exclusive access through
|
2017-11-05 19:25:58 +01:00
|
|
|
* the entire request-response sequence.
|
|
|
|
*/
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_init(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Copy the configuration data into the allocated structure. Why? First
|
|
|
|
* we can't be certain of the life time of the memory underlying the config
|
|
|
|
* reference. Also, in the KERNEL build, the config data will like in
|
|
|
|
* process-specific memory and cannot be shared across processes.
|
|
|
|
*/
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
priv->mxwrite = config->mxwrite;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
/* Preset the server address */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
priv->server.sin_family = AF_INET;
|
2022-01-18 08:38:00 +01:00
|
|
|
priv->server.sin_port = HTONS(config->portno);
|
2017-11-05 19:25:58 +01:00
|
|
|
priv->server.sin_addr.s_addr = HTONL(INADDR_LOOPBACK);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Create a LocalHost UDP client socket */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
ret = psock_socket(PF_INET, SOCK_DGRAM, 0, &priv->psock);
|
2017-10-31 01:04:28 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
2018-03-03 22:20:21 +01:00
|
|
|
ferr("ERROR: socket() failed: %d\n", ret);
|
2017-10-31 01:04:28 +01:00
|
|
|
goto errout_with_alloc;
|
|
|
|
}
|
|
|
|
|
2017-10-31 17:33:30 +01:00
|
|
|
/* Bind the socket to the client address */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
client.sin_family = AF_INET;
|
|
|
|
client.sin_port = 0;
|
|
|
|
client.sin_addr.s_addr = HTONL(INADDR_LOOPBACK);
|
2017-10-31 17:33:30 +01:00
|
|
|
|
2019-03-01 22:00:00 +01:00
|
|
|
ret = psock_bind(&priv->psock, (FAR struct sockaddr *)&client,
|
2017-11-05 19:25:58 +01:00
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 17:33:30 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: bind() failed: %d\n", ret);
|
|
|
|
goto errout_with_psock;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Mounted! */
|
|
|
|
|
|
|
|
*handle = (FAR void *)priv;
|
|
|
|
return OK;
|
|
|
|
|
2017-10-31 17:33:30 +01:00
|
|
|
errout_with_psock:
|
|
|
|
psock_close(&priv->psock);
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
errout_with_alloc:
|
2022-11-20 14:36:28 +01:00
|
|
|
nxmutex_destroy(&priv->lock);
|
2024-09-09 14:28:16 +02:00
|
|
|
fs_heap_free(priv);
|
2017-10-31 01:04:28 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_unbind
|
|
|
|
*
|
|
|
|
* Description: This implements the filesystem portion of the umount
|
|
|
|
* operation.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv = (FAR struct userfs_state_s *)handle;
|
|
|
|
FAR struct userfs_destroy_request_s *req;
|
|
|
|
FAR struct userfs_destroy_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(priv != NULL);
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
req = (FAR struct userfs_destroy_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_DESTROY;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_destroy_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_destroy_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_destroy_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_DESTROY)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the destruction failed, then refuse to unmount at this time */
|
|
|
|
|
|
|
|
if (resp->ret < 0)
|
|
|
|
{
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free resources and return success */
|
|
|
|
|
|
|
|
psock_close(&priv->psock);
|
2022-11-20 14:36:28 +01:00
|
|
|
nxmutex_destroy(&priv->lock);
|
2024-09-09 14:28:16 +02:00
|
|
|
fs_heap_free(priv);
|
2017-10-31 01:04:28 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_statfs
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Return filesystem statistics
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_statfs_request_s *req;
|
|
|
|
FAR struct userfs_statfs_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
req = (FAR struct userfs_statfs_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_STATFS;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
sizeof(struct userfs_statfs_request_s), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
if (nrecvd != sizeof(struct userfs_statfs_response_s))
|
2017-10-31 01:04:28 +01:00
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_statfs_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_STATFS)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the status of the file system */
|
|
|
|
|
|
|
|
DEBUGASSERT(buf != NULL);
|
|
|
|
memcpy(buf, &resp->buf, sizeof(struct statfs));
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_unlink
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Remove a directory entry
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_unlink(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_unlink_request_s *req;
|
|
|
|
FAR struct userfs_unlink_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int pathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path length */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(relpath != NULL);
|
|
|
|
pathlen = strlen(relpath);
|
|
|
|
if (pathlen > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_unlink_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_UNLINK;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_UNLINK_REQUEST_S(pathlen + 1), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_unlink_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_unlink_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_UNLINK)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_mkdir
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Create a new directory
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_mkdir(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath, mode_t mode)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_mkdir_request_s *req;
|
|
|
|
FAR struct userfs_mkdir_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int pathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path length */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(relpath != NULL);
|
2017-11-05 19:25:58 +01:00
|
|
|
pathlen = strlen(relpath);
|
2017-10-31 01:04:28 +01:00
|
|
|
if (pathlen > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_mkdir_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_MKDIR;
|
|
|
|
req->mode = mode;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_MKDIR_REQUEST_S(pathlen + 1), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_mkdir_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_mkdir_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_MKDIR)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_rmdir
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Remove a directory
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_rmdir(FAR struct inode *mountpt,
|
|
|
|
FAR const char *relpath)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_rmdir_request_s *req;
|
|
|
|
FAR struct userfs_rmdir_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int pathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path length */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(relpath != NULL);
|
2017-11-05 19:25:58 +01:00
|
|
|
pathlen = strlen(relpath);
|
2017-10-31 01:04:28 +01:00
|
|
|
if (pathlen > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_rmdir_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_RMDIR;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_RMDIR_REQUEST_S(pathlen + 1), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_rmdir_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_rmdir_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_RMDIR)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_rename
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Rename a directory entry
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_rename(FAR struct inode *mountpt,
|
|
|
|
FAR const char *oldrelpath,
|
|
|
|
FAR const char *newrelpath)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_rename_request_s *req;
|
|
|
|
FAR struct userfs_rename_response_s *resp;
|
|
|
|
int oldpathlen;
|
|
|
|
int newpathlen;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path lengths */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(oldrelpath != NULL && newrelpath != NULL);
|
2017-11-05 19:25:58 +01:00
|
|
|
oldpathlen = strlen(oldrelpath) + 1;
|
|
|
|
newpathlen = strlen(newrelpath) + 1;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
if ((oldpathlen + newpathlen) > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_rename_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_RENAME;
|
2017-10-31 01:04:28 +01:00
|
|
|
req->newoffset = oldpathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->oldrelpath, oldrelpath, oldpathlen);
|
|
|
|
strlcpy(&req->oldrelpath[oldpathlen], newrelpath, newpathlen);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
2020-07-02 16:03:27 +02:00
|
|
|
SIZEOF_USERFS_RENAME_REQUEST_S(oldpathlen, newpathlen),
|
|
|
|
0, (FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_rename_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_rename_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_RENAME)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: userfs_stat
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Return information about a file or directory
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int userfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
|
|
|
|
FAR struct stat *buf)
|
|
|
|
{
|
|
|
|
FAR struct userfs_state_s *priv;
|
|
|
|
FAR struct userfs_stat_request_s *req;
|
|
|
|
FAR struct userfs_stat_response_s *resp;
|
|
|
|
ssize_t nsent;
|
|
|
|
ssize_t nrecvd;
|
|
|
|
int pathlen;
|
2017-11-05 19:25:58 +01:00
|
|
|
int ret;
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(mountpt != NULL &&
|
|
|
|
mountpt->i_private != NULL);
|
|
|
|
priv = mountpt->i_private;
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Check the path length */
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
DEBUGASSERT(relpath != NULL);
|
2017-11-05 19:25:58 +01:00
|
|
|
pathlen = strlen(relpath);
|
2017-10-31 01:04:28 +01:00
|
|
|
if (pathlen > priv->mxwrite)
|
|
|
|
{
|
|
|
|
return -E2BIG;
|
|
|
|
}
|
|
|
|
|
2017-11-05 19:25:58 +01:00
|
|
|
/* Get exclusive access */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct and send the request to the server */
|
|
|
|
|
|
|
|
req = (FAR struct userfs_stat_request_s *)priv->iobuffer;
|
|
|
|
req->req = USERFS_REQ_STAT;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2017-10-31 01:04:28 +01:00
|
|
|
|
|
|
|
nsent = psock_sendto(&priv->psock, priv->iobuffer,
|
|
|
|
SIZEOF_USERFS_STAT_REQUEST_S(pathlen + 1), 0,
|
2017-11-05 19:25:58 +01:00
|
|
|
(FAR struct sockaddr *)&priv->server,
|
|
|
|
sizeof(struct sockaddr_in));
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nsent < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_sendto failed: %d\n", (int)nsent);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-10-31 01:04:28 +01:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-05 19:25:58 +01:00
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
if (nrecvd < 0)
|
|
|
|
{
|
|
|
|
ferr("ERROR: psock_recvfrom failed: %d\n", (int)nrecvd);
|
|
|
|
return (int)nrecvd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nrecvd != sizeof(struct userfs_stat_response_s))
|
|
|
|
{
|
|
|
|
ferr("ERROR: Response size incorrect: %u\n", (unsigned int)nrecvd);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp = (FAR struct userfs_stat_response_s *)priv->iobuffer;
|
|
|
|
if (resp->resp != USERFS_RESP_STAT)
|
|
|
|
{
|
|
|
|
ferr("ERROR: Incorrect response: %u\n", resp->resp);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the directory entry status */
|
|
|
|
|
|
|
|
DEBUGASSERT(buf != NULL);
|
|
|
|
memcpy(buf, &resp->buf, sizeof(struct stat));
|
|
|
|
return resp->ret;
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:46:26 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* 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 */
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2021-08-10 07:46:26 +02:00
|
|
|
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;
|
|
|
|
|
2022-08-24 04:23:20 +02:00
|
|
|
strlcpy(req->relpath, relpath, priv->mxwrite);
|
2021-08-10 07:46:26 +02:00
|
|
|
|
|
|
|
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);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2021-08-10 07:46:26 +02:00
|
|
|
return (int)nsent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then get the response from the server */
|
|
|
|
|
|
|
|
nrecvd = psock_recvfrom(&priv->psock, priv->iobuffer, IOBUFFER_SIZE(priv),
|
|
|
|
0, NULL, NULL);
|
2022-09-06 08:18:45 +02:00
|
|
|
nxmutex_unlock(&priv->lock);
|
2021-08-10 07:46:26 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:04:28 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|