989 lines
27 KiB
C
989 lines
27 KiB
C
/****************************************************************************
|
|
* fs/v9fs/v9fs.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <debug.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <libgen.h>
|
|
#include <string.h>
|
|
|
|
#include <nuttx/fs/fs.h>
|
|
#include <nuttx/fs/ioctl.h>
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include "inode/inode.h"
|
|
#include "client.h"
|
|
#include "fs_heap.h"
|
|
|
|
/****************************************************************************
|
|
* Private Type
|
|
****************************************************************************/
|
|
|
|
struct v9fs_vfs_file_s
|
|
{
|
|
uint32_t fid;
|
|
mutex_t lock;
|
|
};
|
|
|
|
struct v9fs_vfs_dirent_s
|
|
{
|
|
struct fs_dirent_s base;
|
|
uint32_t fid;
|
|
mutex_t lock;
|
|
off_t offset;
|
|
off_t head;
|
|
size_t size;
|
|
uint8_t buffer[1];
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_open(FAR struct file *filep, FAR const char *relpath,
|
|
int oflags, mode_t mode);
|
|
static int v9fs_vfs_close(FAR struct file *filep);
|
|
static ssize_t v9fs_vfs_read(FAR struct file *filep, FAR char *buffer,
|
|
size_t buflen);
|
|
static ssize_t v9fs_vfs_write(FAR struct file *filep,
|
|
FAR const char *buffer, size_t buflen);
|
|
static off_t v9fs_vfs_seek(FAR struct file *filep, off_t offset,
|
|
int whence);
|
|
static int v9fs_vfs_ioctl(FAR struct file *filep, int cmd,
|
|
unsigned long arg);
|
|
static int v9fs_vfs_sync(FAR struct file *filep);
|
|
static int v9fs_vfs_dup(FAR const struct file *oldp, FAR struct file *newp);
|
|
static int v9fs_vfs_fstat(FAR const struct file *filep,
|
|
FAR struct stat *buf);
|
|
static int v9fs_vfs_fchstat(FAR const struct file *filep,
|
|
FAR const struct stat *buf, int flags);
|
|
static int v9fs_vfs_truncate(FAR struct file *filep, off_t length);
|
|
static int v9fs_vfs_opendir(FAR struct inode *mountpt,
|
|
FAR const char *relpath,
|
|
FAR struct fs_dirent_s **dir);
|
|
static int v9fs_vfs_closedir(FAR struct inode *mountpt,
|
|
FAR struct fs_dirent_s *dir);
|
|
static int v9fs_vfs_readdir(FAR struct inode *mountpt,
|
|
FAR struct fs_dirent_s *dir,
|
|
FAR struct dirent *entry);
|
|
static int v9fs_vfs_rewinddir(FAR struct inode *mountpt,
|
|
FAR struct fs_dirent_s *dir);
|
|
static int v9fs_vfs_statfs(FAR struct inode *mountpt,
|
|
FAR struct statfs *buf);
|
|
static int v9fs_vfs_unlink(FAR struct inode *mountpt,
|
|
FAR const char *relpath);
|
|
static int v9fs_vfs_mkdir(FAR struct inode *mountpt,
|
|
FAR const char *relpath, mode_t mode);
|
|
static int v9fs_vfs_rmdir(FAR struct inode *mountpt,
|
|
FAR const char *relpath);
|
|
static int v9fs_vfs_rename(FAR struct inode *mountpt,
|
|
FAR const char *oldrelpath,
|
|
FAR const char *newrelpath);
|
|
static int v9fs_vfs_stat(FAR struct inode *mountpt,
|
|
FAR const char *relpath, FAR struct stat *buf);
|
|
static int v9fs_vfs_chstat(FAR struct inode *mountpt,
|
|
FAR const char *relpath,
|
|
FAR const struct stat *buf, int flags);
|
|
static int v9fs_vfs_bind(FAR struct inode *driver, FAR const void *data,
|
|
FAR void **handle);
|
|
static int v9fs_vfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
|
unsigned int flags);
|
|
|
|
/****************************************************************************
|
|
* Public Data
|
|
****************************************************************************/
|
|
|
|
const struct mountpt_operations g_v9fs_operations =
|
|
{
|
|
v9fs_vfs_open, /* open */
|
|
v9fs_vfs_close, /* close */
|
|
v9fs_vfs_read, /* read */
|
|
v9fs_vfs_write, /* write */
|
|
v9fs_vfs_seek, /* seek */
|
|
v9fs_vfs_ioctl, /* ioctl */
|
|
NULL, /* mmap */
|
|
v9fs_vfs_truncate, /* truncate */
|
|
NULL, /* poll */
|
|
|
|
v9fs_vfs_sync, /* sync */
|
|
v9fs_vfs_dup, /* dup */
|
|
v9fs_vfs_fstat, /* fstat */
|
|
v9fs_vfs_fchstat, /* fchstat */
|
|
|
|
v9fs_vfs_opendir, /* opendir */
|
|
v9fs_vfs_closedir, /* closedir */
|
|
v9fs_vfs_readdir, /* readdir */
|
|
v9fs_vfs_rewinddir, /* rewinddir */
|
|
|
|
v9fs_vfs_bind, /* bind */
|
|
v9fs_vfs_unbind, /* unbind */
|
|
v9fs_vfs_statfs, /* statfs */
|
|
|
|
v9fs_vfs_unlink, /* unlink */
|
|
v9fs_vfs_mkdir, /* mkdir */
|
|
v9fs_vfs_rmdir, /* rmdir */
|
|
v9fs_vfs_rename, /* rename */
|
|
v9fs_vfs_stat, /* stat */
|
|
v9fs_vfs_chstat /* chstat */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_open
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_open(FAR struct file *filep, FAR const char *relpath,
|
|
int oflags, mode_t mode)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
|
|
file = fs_heap_zalloc(sizeof(struct v9fs_vfs_file_s));
|
|
if (file == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = v9fs_client_walk(client, relpath, NULL);
|
|
if (ret >= 0)
|
|
{
|
|
file->fid = ret;
|
|
ret = v9fs_client_open(client, file->fid, oflags);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Failed to open the fid: %d\n", ret);
|
|
goto err_put;
|
|
}
|
|
}
|
|
else if ((oflags & O_CREAT) != 0)
|
|
{
|
|
/* We expect to create this file */
|
|
|
|
ret = v9fs_client_walk(client, relpath, &relpath);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the parent fid of relpath: %d\n", ret);
|
|
goto err_free;
|
|
}
|
|
|
|
file->fid = ret;
|
|
ret = v9fs_client_create(client, file->fid, relpath, oflags, mode);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Failed to create the file: %d\n", ret);
|
|
goto err_put;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* We expect to open this file */
|
|
|
|
ferr("ERROR: Can't find the fid of relpath: %d\n", ret);
|
|
ret = -ENOENT;
|
|
goto err_free;
|
|
}
|
|
|
|
if ((oflags & O_APPEND) != 0)
|
|
{
|
|
filep->f_pos = v9fs_client_getsize(client, file->fid);
|
|
if (filep->f_pos < 0)
|
|
{
|
|
ret = filep->f_pos;
|
|
ferr("ERROR: Failed to get the file status: %d\n", ret);
|
|
goto err_put;
|
|
}
|
|
}
|
|
|
|
nxmutex_init(&file->lock);
|
|
filep->f_priv = file;
|
|
return 0;
|
|
|
|
err_put:
|
|
v9fs_fid_put(client, file->fid);
|
|
err_free:
|
|
fs_heap_free(file);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_close
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_close(FAR struct file *filep)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
v9fs_fid_put(client, file->fid);
|
|
nxmutex_destroy(&file->lock);
|
|
fs_heap_free(file);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_read
|
|
****************************************************************************/
|
|
|
|
static ssize_t v9fs_vfs_read(FAR struct file *filep, FAR char *buffer,
|
|
size_t buflen)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
ssize_t ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
nxmutex_lock(&file->lock);
|
|
ret = v9fs_client_read(client, file->fid, buffer, filep->f_pos, buflen);
|
|
if (ret > 0)
|
|
{
|
|
filep->f_pos += ret;
|
|
}
|
|
|
|
nxmutex_unlock(&file->lock);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_write
|
|
****************************************************************************/
|
|
|
|
static ssize_t v9fs_vfs_write(FAR struct file *filep, FAR const char *buffer,
|
|
size_t buflen)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
ssize_t ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
nxmutex_lock(&file->lock);
|
|
ret = v9fs_client_write(client, file->fid, buffer, filep->f_pos, buflen);
|
|
if (ret > 0)
|
|
{
|
|
filep->f_pos += ret;
|
|
}
|
|
|
|
nxmutex_unlock(&file->lock);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_seek
|
|
****************************************************************************/
|
|
|
|
static off_t v9fs_vfs_seek(FAR struct file *filep, off_t offset, int whence)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
off_t ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
nxmutex_lock(&file->lock);
|
|
switch (whence)
|
|
{
|
|
case SEEK_SET:
|
|
ret = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
ret = filep->f_pos + offset;
|
|
break;
|
|
case SEEK_END:
|
|
ret = v9fs_client_getsize(client, file->fid);
|
|
if (ret >= 0)
|
|
{
|
|
ret += offset;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
ferr("ERROR: Invalid whence: %d\n", whence);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (ret >= 0)
|
|
{
|
|
filep->f_pos = ret;
|
|
}
|
|
|
|
nxmutex_unlock(&file->lock);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_ioctl
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
int ret = -ENOTTY;
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
if (cmd == FIOC_FILEPATH)
|
|
{
|
|
FAR char *ptr = (FAR char *)((uintptr_t)arg);
|
|
inode_getpath(filep->f_inode, ptr, PATH_MAX);
|
|
ret = v9fs_client_getname(client, file->fid, ptr);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_sync
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_sync(FAR struct file *filep)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
return v9fs_client_fsync(client, file->fid);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_dup
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_dup(FAR const struct file *oldp, FAR struct file *newp)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *newfile;
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(oldp != NULL && oldp->f_inode != NULL &&
|
|
newp != NULL && newp->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = oldp->f_inode->i_private;
|
|
file = oldp->f_priv;
|
|
|
|
newfile = fs_heap_zalloc(sizeof(struct v9fs_vfs_file_s));
|
|
if (newfile == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = v9fs_fid_get(client, file->fid);
|
|
if (ret < 0)
|
|
{
|
|
fs_heap_free(newfile);
|
|
return ret;
|
|
}
|
|
|
|
nxmutex_init(&newfile->lock);
|
|
newfile->fid = file->fid;
|
|
newp->f_priv = newfile;
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_fstat
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_fstat(FAR const struct file *filep,
|
|
FAR struct stat *buf)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
memset(buf, 0, sizeof(struct stat));
|
|
|
|
return v9fs_client_stat(client, file->fid, buf);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_fchstat
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_fchstat(FAR const struct file *filep,
|
|
FAR const struct stat *buf, int flags)
|
|
{
|
|
FAR struct v9fs_vfs_file_s *file;
|
|
FAR struct v9fs_client_s *client;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = filep->f_inode->i_private;
|
|
file = filep->f_priv;
|
|
|
|
return v9fs_client_chstat(client, file->fid, buf, flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_truncate
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_truncate(FAR struct file *filep, off_t length)
|
|
{
|
|
struct stat buf;
|
|
|
|
buf.st_size = length;
|
|
return v9fs_vfs_fchstat(filep, &buf, CH_STAT_SIZE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_opendir
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_opendir(FAR struct inode *mountpt,
|
|
FAR const char *relpath,
|
|
FAR struct fs_dirent_s **dir)
|
|
{
|
|
FAR struct v9fs_vfs_dirent_s *fsdir;
|
|
FAR struct v9fs_client_s *client;
|
|
uint32_t fid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
fsdir = fs_heap_zalloc(sizeof(struct v9fs_vfs_dirent_s) + client->msize);
|
|
if (fsdir == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = v9fs_client_walk(client, relpath, NULL);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the fid of the relpath: %d\n", ret);
|
|
goto err;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_open(client, fid, 0);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Failed to open the fid: %d\n", ret);
|
|
v9fs_fid_put(client, fid);
|
|
goto err;
|
|
}
|
|
|
|
nxmutex_init(&fsdir->lock);
|
|
fsdir->fid = fid;
|
|
*dir = &fsdir->base;
|
|
return 0;
|
|
|
|
err:
|
|
fs_heap_free(fsdir);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_closedir
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_closedir(FAR struct inode *mountpt,
|
|
FAR struct fs_dirent_s *dir)
|
|
{
|
|
FAR struct v9fs_vfs_dirent_s *fsdir;
|
|
FAR struct v9fs_client_s *client;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
fsdir = (FAR struct v9fs_vfs_dirent_s *)dir;
|
|
client = mountpt->i_private;
|
|
|
|
v9fs_fid_put(client, fsdir->fid);
|
|
nxmutex_destroy(&fsdir->lock);
|
|
fs_heap_free(fsdir);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_readdir
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_readdir(FAR struct inode *mountpt,
|
|
FAR struct fs_dirent_s *dir,
|
|
FAR struct dirent *entry)
|
|
{
|
|
FAR struct v9fs_vfs_dirent_s *fsdir;
|
|
FAR struct v9fs_client_s *client;
|
|
ssize_t ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
fsdir = (FAR struct v9fs_vfs_dirent_s *)dir;
|
|
client = mountpt->i_private;
|
|
|
|
nxmutex_lock(&fsdir->lock);
|
|
for (; ; )
|
|
{
|
|
if (fsdir->head == fsdir->size)
|
|
{
|
|
ret = v9fs_client_readdir(client, fsdir->fid, fsdir->buffer,
|
|
fsdir->offset, client->msize);
|
|
if (ret < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
fsdir->head = 0;
|
|
fsdir->size = ret;
|
|
}
|
|
|
|
ret = v9fs_client_convertdir(fsdir->buffer, fsdir->size, fsdir->head,
|
|
&fsdir->offset, entry);
|
|
if (ret < 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
fsdir->head += ret;
|
|
if (strcmp(entry->d_name, ".") != 0 &&
|
|
strcmp(entry->d_name, "..") != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
nxmutex_unlock(&fsdir->lock);
|
|
return ret < 0 ? ret : 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_rewinddir
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_rewinddir(FAR struct inode *mountpt,
|
|
FAR struct fs_dirent_s *dir)
|
|
{
|
|
FAR struct v9fs_vfs_dirent_s *fsdir;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
fsdir = (FAR struct v9fs_vfs_dirent_s *)dir;
|
|
|
|
nxmutex_lock(&fsdir->lock);
|
|
fsdir->head = 0;
|
|
fsdir->offset = 0;
|
|
fsdir->size = 0;
|
|
nxmutex_unlock(&fsdir->lock);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_statfs
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_statfs(FAR struct inode *mountpt,
|
|
FAR struct statfs *buf)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
memset(buf, 0, sizeof(struct statfs));
|
|
return v9fs_client_statfs(client, buf);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_unlink
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_unlink(FAR struct inode *mountpt,
|
|
FAR const char *relpath)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
FAR const char *filename;
|
|
uint32_t fid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
ret = v9fs_client_walk(client, relpath, &filename);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the parent fid of relpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_unlink(client, fid, filename, false);
|
|
v9fs_fid_put(client, fid);
|
|
if (ret == -EOPNOTSUPP)
|
|
{
|
|
/* Maybe the server does not support this method of deletion.
|
|
* Let's change the protocol to send
|
|
*/
|
|
|
|
ret = v9fs_client_walk(client, relpath, NULL);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the fid of relpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_remove(client, fid);
|
|
v9fs_fid_put(client, fid);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_mkdir
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_mkdir(FAR struct inode *mountpt,
|
|
FAR const char *relpath, mode_t mode)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
uint32_t fid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
ret = v9fs_client_walk(client, relpath, &relpath);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the parent fid of relpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_mkdir(client, fid, relpath, mode);
|
|
v9fs_fid_put(client, fid);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_rmdir
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_rmdir(FAR struct inode *mountpt,
|
|
FAR const char *relpath)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
FAR const char *dirname;
|
|
uint32_t fid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
ret = v9fs_client_walk(client, relpath, &dirname);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the parent fid of relpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_unlink(client, fid, dirname, true);
|
|
v9fs_fid_put(client, fid);
|
|
if (ret == -EOPNOTSUPP)
|
|
{
|
|
/* Maybe the server does not support this method of deletion.
|
|
* Let's change the protocol to send
|
|
*/
|
|
|
|
ret = v9fs_client_walk(client, relpath, NULL);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the fid of relpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_remove(client, fid);
|
|
v9fs_fid_put(client, fid);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_rename
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_rename(FAR struct inode *mountpt,
|
|
FAR const char *oldrelpath,
|
|
FAR const char *newrelpath)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
uint32_t oldfid;
|
|
uint32_t newpfid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
ret = v9fs_client_walk(client, oldrelpath, NULL);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the fid of the oldrelpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
oldfid = ret;
|
|
ret = v9fs_client_walk(client, newrelpath, &newrelpath);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the new parent fid of the newrelpath: %d\n",
|
|
ret);
|
|
v9fs_fid_put(client, oldfid);
|
|
return ret;
|
|
}
|
|
|
|
newpfid = ret;
|
|
ret = v9fs_client_rename(client, oldfid, newpfid, newrelpath);
|
|
v9fs_fid_put(client, oldfid);
|
|
v9fs_fid_put(client, newpfid);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_stat
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
|
|
FAR struct stat *buf)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
uint32_t fid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
memset(buf, 0, sizeof(struct stat));
|
|
|
|
ret = v9fs_client_walk(client, relpath, NULL);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the fid of the relpath: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_stat(client, fid, buf);
|
|
v9fs_fid_put(client, fid);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_chstat
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_chstat(FAR struct inode *mountpt,
|
|
FAR const char *relpath,
|
|
FAR const struct stat *buf, int flags)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
uint32_t fid;
|
|
int ret;
|
|
|
|
/* Sanity checks */
|
|
|
|
DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
|
|
|
|
/* Recover out private data from the struct file instance */
|
|
|
|
client = mountpt->i_private;
|
|
|
|
ret = v9fs_client_walk(client, relpath, NULL);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Can't find the fid of the relpath %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
fid = ret;
|
|
ret = v9fs_client_chstat(client, fid, buf, flags);
|
|
v9fs_fid_put(client, fid);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_unbind
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
|
|
unsigned int flags)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
int ret;
|
|
|
|
client = handle;
|
|
|
|
ret = v9fs_client_uninit(client);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Failed to clunk root fid\n");
|
|
return ret;
|
|
}
|
|
|
|
fs_heap_free(client);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: v9fs_vfs_bind
|
|
****************************************************************************/
|
|
|
|
static int v9fs_vfs_bind(FAR struct inode *driver, FAR const void *data,
|
|
FAR void **handle)
|
|
{
|
|
FAR struct v9fs_client_s *client;
|
|
int ret;
|
|
|
|
client = fs_heap_zalloc(sizeof(struct v9fs_client_s));
|
|
if (client == NULL)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ret = v9fs_client_init(client, data);
|
|
if (ret < 0)
|
|
{
|
|
ferr("ERROR: Failed to initialize for client: %d\n", ret);
|
|
fs_heap_free(client);
|
|
return ret;
|
|
}
|
|
|
|
*handle = client;
|
|
return ret;
|
|
}
|