912 lines
24 KiB
C
912 lines
24 KiB
C
/*
|
|
* Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "vfs_jffs2.h"
|
|
|
|
#include "fcntl.h"
|
|
#include "sys/stat.h"
|
|
#include "sys/statfs.h"
|
|
#include "errno.h"
|
|
|
|
#include "los_config.h"
|
|
#include "los_typedef.h"
|
|
#include "los_mux.h"
|
|
#include "los_tables.h"
|
|
#include "los_vm_filemap.h"
|
|
#include "los_crc32.h"
|
|
#include "capability_type.h"
|
|
#include "capability_api.h"
|
|
|
|
#include "fs/dirent_fs.h"
|
|
#include "fs/fs.h"
|
|
#include "fs/driver.h"
|
|
#include "vnode.h"
|
|
#include "mtd_list.h"
|
|
#include "mtd_partition.h"
|
|
#include "jffs2_hash.h"
|
|
|
|
#include "os-linux.h"
|
|
#include "jffs2/nodelist.h"
|
|
|
|
#ifdef LOSCFG_FS_JFFS
|
|
|
|
/* forward define */
|
|
struct VnodeOps g_jffs2Vops;
|
|
struct file_operations_vfs g_jffs2Fops;
|
|
|
|
static LosMux g_jffs2FsLock; /* lock for all jffs2 ops */
|
|
|
|
static pthread_mutex_t g_jffs2NodeLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
|
struct Vnode *g_jffs2PartList[CONFIG_MTD_PATTITION_NUM];
|
|
|
|
static void Jffs2SetVtype(struct jffs2_inode *node, struct Vnode *pVnode)
|
|
{
|
|
switch (node->i_mode & S_IFMT) {
|
|
case S_IFREG:
|
|
pVnode->type = VNODE_TYPE_REG;
|
|
break;
|
|
case S_IFDIR:
|
|
pVnode->type = VNODE_TYPE_DIR;
|
|
break;
|
|
case S_IFLNK:
|
|
pVnode->type = VNODE_TYPE_LNK;
|
|
break;
|
|
default:
|
|
pVnode->type = VNODE_TYPE_UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
time_t Jffs2CurSec(void)
|
|
{
|
|
struct timeval tv;
|
|
if (gettimeofday(&tv, NULL))
|
|
return 0;
|
|
return (uint32_t)(tv.tv_sec);
|
|
}
|
|
|
|
void Jffs2NodeLock(void)
|
|
{
|
|
(void)pthread_mutex_lock(&g_jffs2NodeLock);
|
|
}
|
|
|
|
void Jffs2NodeUnlock(void)
|
|
{
|
|
(void)pthread_mutex_unlock(&g_jffs2NodeLock);
|
|
}
|
|
|
|
int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data)
|
|
{
|
|
int ret;
|
|
int partNo;
|
|
mtd_partition *p = NULL;
|
|
struct MtdDev *mtd = NULL;
|
|
struct Vnode *pv = NULL;
|
|
struct jffs2_inode *rootNode = NULL;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
p = (mtd_partition *)((struct drv_data *)blkDriver->data)->priv;
|
|
mtd = (struct MtdDev *)(p->mtd_info);
|
|
|
|
/* find a empty mte in partition table */
|
|
if (mtd == NULL || mtd->type != MTD_NORFLASH) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return -EINVAL;
|
|
}
|
|
|
|
partNo = p->patitionnum;
|
|
|
|
ret = jffs2_mount(partNo, &rootNode, mnt->mountFlags);
|
|
if (ret != 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
ret = VnodeAlloc(&g_jffs2Vops, &pv);
|
|
if (ret != 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
goto ERROR_WITH_VNODE;
|
|
}
|
|
pv->type = VNODE_TYPE_DIR;
|
|
pv->data = (void *)rootNode;
|
|
pv->originMount = mnt;
|
|
pv->fop = &g_jffs2Fops;
|
|
mnt->data = p;
|
|
mnt->vnodeCovered = pv;
|
|
pv->uid = rootNode->i_uid;
|
|
pv->gid = rootNode->i_gid;
|
|
pv->mode = rootNode->i_mode;
|
|
|
|
(void)VfsHashInsert(pv, rootNode->i_ino);
|
|
|
|
g_jffs2PartList[partNo] = blkDriver;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return 0;
|
|
ERROR_WITH_VNODE:
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Unbind(struct Mount *mnt, struct Vnode **blkDriver)
|
|
{
|
|
int ret;
|
|
mtd_partition *p = NULL;
|
|
int partNo;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
p = (mtd_partition *)mnt->data;
|
|
if (p == NULL) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return -EINVAL;
|
|
}
|
|
|
|
partNo = p->patitionnum;
|
|
ret = jffs2_umount((struct jffs2_inode *)mnt->vnodeCovered->data);
|
|
if (ret) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
free(p->mountpoint_name);
|
|
p->mountpoint_name = NULL;
|
|
*blkDriver = g_jffs2PartList[partNo];
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct Vnode **ppVnode)
|
|
{
|
|
int ret;
|
|
struct Vnode *newVnode = NULL;
|
|
struct jffs2_inode *node = NULL;
|
|
struct jffs2_inode *parentNode = NULL;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
parentNode = (struct jffs2_inode *)parentVnode->data;
|
|
node = jffs2_lookup(parentNode, (const unsigned char *)path, len);
|
|
if (!node) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return -ENOENT;
|
|
}
|
|
|
|
(void)VfsHashGet(parentVnode->originMount, node->i_ino, &newVnode, NULL, NULL);
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
if (newVnode) {
|
|
if (newVnode->data == NULL) {
|
|
LOS_Panic("#####VfsHashGet error#####\n");
|
|
}
|
|
newVnode->parent = parentVnode;
|
|
*ppVnode = newVnode;
|
|
return 0;
|
|
}
|
|
ret = VnodeAlloc(&g_jffs2Vops, &newVnode);
|
|
if (ret != 0) {
|
|
PRINT_ERR("%s-%d, ret: %x\n", __FUNCTION__, __LINE__, ret);
|
|
(void)jffs2_iput(node);
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
Jffs2SetVtype(node, newVnode);
|
|
newVnode->fop = parentVnode->fop;
|
|
newVnode->data = node;
|
|
newVnode->parent = parentVnode;
|
|
newVnode->originMount = parentVnode->originMount;
|
|
newVnode->uid = node->i_uid;
|
|
newVnode->gid = node->i_gid;
|
|
newVnode->mode = node->i_mode;
|
|
|
|
(void)VfsHashInsert(newVnode, node->i_ino);
|
|
|
|
*ppVnode = newVnode;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Create(struct Vnode *parentVnode, const char *path, int mode, struct Vnode **ppVnode)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *newNode = NULL;
|
|
struct Vnode *newVnode = NULL;
|
|
|
|
ret = VnodeAlloc(&g_jffs2Vops, &newVnode);
|
|
if (ret != 0) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
ret = jffs2_create((struct jffs2_inode *)parentVnode->data, (const unsigned char *)path, mode, &newNode);
|
|
if (ret != 0) {
|
|
VnodeFree(newVnode);
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
newVnode->type = VNODE_TYPE_REG;
|
|
newVnode->fop = parentVnode->fop;
|
|
newVnode->data = newNode;
|
|
newVnode->parent = parentVnode;
|
|
newVnode->originMount = parentVnode->originMount;
|
|
newVnode->uid = newNode->i_uid;
|
|
newVnode->gid = newNode->i_gid;
|
|
newVnode->mode = newNode->i_mode;
|
|
|
|
(void)VfsHashInsert(newVnode, newNode->i_ino);
|
|
|
|
*ppVnode = newVnode;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Close(struct file *filep)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ssize_t VfsJffs2Read(struct file *filep, char *buffer, size_t bufLen)
|
|
{
|
|
struct jffs2_inode *node = NULL;
|
|
struct jffs2_inode_info *f = NULL;
|
|
struct jffs2_sb_info *c = NULL;
|
|
int ret;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
node = (struct jffs2_inode *)filep->f_vnode->data;
|
|
f = JFFS2_INODE_INFO(node);
|
|
c = JFFS2_SB_INFO(node->i_sb);
|
|
|
|
off_t pos = min(node->i_size, filep->f_pos);
|
|
off_t len = min(bufLen, (node->i_size - pos));
|
|
ret = jffs2_read_inode_range(c, f, (unsigned char *)buffer, filep->f_pos, len);
|
|
if (ret) {
|
|
PRINTK("VfsJffs2Read(): read_inode_range failed %d\n", ret);
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
node->i_atime = Jffs2CurSec();
|
|
filep->f_pos += len;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return len;
|
|
}
|
|
|
|
ssize_t VfsJffs2Write(struct file *filep, const char *buffer, size_t bufLen)
|
|
{
|
|
struct jffs2_inode *node = NULL;
|
|
struct jffs2_inode_info *f = NULL;
|
|
struct jffs2_sb_info *c = NULL;
|
|
struct jffs2_raw_inode ri = {0};
|
|
struct IATTR attr = {0};
|
|
int ret;
|
|
off_t pos;
|
|
uint32_t writtenLen;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
node = (struct jffs2_inode *)filep->f_vnode->data;
|
|
f = JFFS2_INODE_INFO(node);
|
|
c = JFFS2_SB_INFO(node->i_sb);
|
|
pos = filep->f_pos;
|
|
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
struct super_block *sb = node->i_sb;
|
|
UINT16 gcCpuMask = LOS_TaskCpuAffiGet(sb->s_gc_thread);
|
|
UINT32 curTaskId = LOS_CurTaskIDGet();
|
|
UINT16 curCpuMask = LOS_TaskCpuAffiGet(curTaskId);
|
|
if (curCpuMask != gcCpuMask) {
|
|
if (curCpuMask != LOSCFG_KERNEL_CPU_MASK) {
|
|
(void)LOS_TaskCpuAffiSet(sb->s_gc_thread, curCpuMask);
|
|
} else {
|
|
(void)LOS_TaskCpuAffiSet(curTaskId, gcCpuMask);
|
|
}
|
|
}
|
|
#endif
|
|
if (pos < 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ri.ino = cpu_to_je32(f->inocache->ino);
|
|
ri.mode = cpu_to_jemode(node->i_mode);
|
|
ri.uid = cpu_to_je16(node->i_uid);
|
|
ri.gid = cpu_to_je16(node->i_gid);
|
|
ri.atime = ri.ctime = ri.mtime = cpu_to_je32(Jffs2CurSec());
|
|
|
|
if (pos > node->i_size) {
|
|
int err;
|
|
attr.attr_chg_valid = CHG_SIZE;
|
|
attr.attr_chg_size = pos;
|
|
err = jffs2_setattr(node, &attr);
|
|
if (err) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return err;
|
|
}
|
|
}
|
|
ri.isize = cpu_to_je32(node->i_size);
|
|
|
|
ret = jffs2_write_inode_range(c, f, &ri, (unsigned char *)buffer, pos, bufLen, &writtenLen);
|
|
if (ret) {
|
|
pos += writtenLen;
|
|
|
|
node->i_mtime = node->i_ctime = je32_to_cpu(ri.mtime);
|
|
if (pos > node->i_size)
|
|
node->i_size = pos;
|
|
|
|
filep->f_pos = pos;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
if (writtenLen != bufLen) {
|
|
pos += writtenLen;
|
|
|
|
node->i_mtime = node->i_ctime = je32_to_cpu(ri.mtime);
|
|
if (pos > node->i_size)
|
|
node->i_size = pos;
|
|
|
|
filep->f_pos = pos;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return -ENOSPC;
|
|
}
|
|
|
|
pos += bufLen;
|
|
|
|
node->i_mtime = node->i_ctime = je32_to_cpu(ri.mtime);
|
|
if (pos > node->i_size)
|
|
node->i_size = pos;
|
|
|
|
filep->f_pos = pos;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return writtenLen;
|
|
}
|
|
|
|
off_t VfsJffs2Seek(struct file *filep, off_t offset, int whence)
|
|
{
|
|
struct jffs2_inode *node = NULL;
|
|
loff_t filePos;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
node = (struct jffs2_inode *)filep->f_vnode->data;
|
|
filePos = filep->f_pos;
|
|
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
filePos = offset;
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
filePos += offset;
|
|
break;
|
|
|
|
case SEEK_END:
|
|
filePos = node->i_size + offset;
|
|
break;
|
|
|
|
default:
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return -EINVAL;
|
|
}
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
if (filePos < 0)
|
|
return -EINVAL;
|
|
|
|
return filePos;
|
|
}
|
|
|
|
int VfsJffs2Ioctl(struct file *filep, int cmd, unsigned long arg)
|
|
{
|
|
PRINT_DEBUG("%s NOT SUPPORT\n", __FUNCTION__);
|
|
return -ENOSYS;
|
|
}
|
|
|
|
int VfsJffs2Fsync(struct file *filep)
|
|
{
|
|
/* jffs2_write directly write to flash, sync is OK.
|
|
BUT after pagecache enabled, pages need to be flushed to flash */
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Dup(const struct file *oldFile, struct file *newFile)
|
|
{
|
|
PRINT_DEBUG("%s NOT SUPPORT\n", __FUNCTION__);
|
|
return -ENOSYS;
|
|
}
|
|
|
|
int VfsJffs2Opendir(struct Vnode *pVnode, struct fs_dirent_s *dir)
|
|
{
|
|
dir->fd_int_offset = 0;
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Readdir(struct Vnode *pVnode, struct fs_dirent_s *dir)
|
|
{
|
|
int ret;
|
|
int i = 0;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
/* set jffs2_d */
|
|
while (i < dir->read_cnt) {
|
|
ret = jffs2_readdir((struct jffs2_inode *)pVnode->data, &dir->fd_position,
|
|
&dir->fd_int_offset, &dir->fd_dir[i]);
|
|
if (ret) {
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return i;
|
|
}
|
|
|
|
int VfsJffs2Seekdir(struct Vnode *pVnode, struct fs_dirent_s *dir, unsigned long offset)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Rewinddir(struct Vnode *pVnode, struct fs_dirent_s *dir)
|
|
{
|
|
dir->fd_int_offset = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Closedir(struct Vnode *node, struct fs_dirent_s *dir)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Mkdir(struct Vnode *parentNode, const char *dirName, mode_t mode, struct Vnode **ppVnode)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *node = NULL;
|
|
struct Vnode *newVnode = NULL;
|
|
|
|
ret = VnodeAlloc(&g_jffs2Vops, &newVnode);
|
|
if (ret != 0) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
ret = jffs2_mkdir((struct jffs2_inode *)parentNode->data, (const unsigned char *)dirName, mode, &node);
|
|
if (ret != 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
VnodeFree(newVnode);
|
|
return ret;
|
|
}
|
|
|
|
newVnode->type = VNODE_TYPE_DIR;
|
|
newVnode->fop = parentNode->fop;
|
|
newVnode->data = node;
|
|
newVnode->parent = parentNode;
|
|
newVnode->originMount = parentNode->originMount;
|
|
newVnode->uid = node->i_uid;
|
|
newVnode->gid = node->i_gid;
|
|
newVnode->mode = node->i_mode;
|
|
|
|
*ppVnode = newVnode;
|
|
|
|
(void)VfsHashInsert(newVnode, node->i_ino);
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Jffs2Truncate(struct Vnode *pVnode, unsigned int len)
|
|
{
|
|
int ret;
|
|
struct IATTR attr = {0};
|
|
|
|
attr.attr_chg_size = len;
|
|
attr.attr_chg_valid = CHG_SIZE;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
ret = jffs2_setattr((struct jffs2_inode *)pVnode->data, &attr);
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Truncate(struct Vnode *pVnode, off_t len)
|
|
{
|
|
int ret = Jffs2Truncate(pVnode, (unsigned int)len);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Truncate64(struct Vnode *pVnode, off64_t len)
|
|
{
|
|
int ret = Jffs2Truncate(pVnode, (unsigned int)len);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Chattr(struct Vnode *pVnode, struct IATTR *attr)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *node = NULL;
|
|
|
|
if (pVnode == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
node = pVnode->data;
|
|
ret = jffs2_setattr(node, attr);
|
|
if (ret == 0) {
|
|
pVnode->uid = node->i_uid;
|
|
pVnode->gid = node->i_gid;
|
|
pVnode->mode = node->i_mode;
|
|
}
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Rmdir(struct Vnode *parentVnode, struct Vnode *targetVnode, const char *path)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *parentInode = NULL;
|
|
struct jffs2_inode *targetInode = NULL;
|
|
|
|
if (!parentVnode || !targetVnode) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
parentInode = (struct jffs2_inode *)parentVnode->data;
|
|
targetInode = (struct jffs2_inode *)targetVnode->data;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
ret = jffs2_rmdir(parentInode, targetInode, (const unsigned char *)path);
|
|
|
|
if (ret == 0) {
|
|
(void)jffs2_iput(targetInode);
|
|
}
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Link(struct Vnode *oldVnode, struct Vnode *newParentVnode, struct Vnode **newVnode, const char *newName)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *oldInode = oldVnode->data;
|
|
struct jffs2_inode *newParentInode = newParentVnode->data;
|
|
struct Vnode *pVnode = NULL;
|
|
|
|
ret = VnodeAlloc(&g_jffs2Vops, &pVnode);
|
|
if (ret != 0) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
ret = jffs2_link(oldInode, newParentInode, (const unsigned char *)newName);
|
|
if (ret != 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
VnodeFree(pVnode);
|
|
return ret;
|
|
}
|
|
|
|
pVnode->type = VNODE_TYPE_REG;
|
|
pVnode->fop = &g_jffs2Fops;
|
|
pVnode->parent = newParentVnode;
|
|
pVnode->originMount = newParentVnode->originMount;
|
|
pVnode->data = oldInode;
|
|
pVnode->uid = oldVnode->uid;
|
|
pVnode->gid = oldVnode->gid;
|
|
pVnode->mode = oldVnode->mode;
|
|
|
|
*newVnode = pVnode;
|
|
(void)VfsHashInsert(*newVnode, oldInode->i_ino);
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Symlink(struct Vnode *parentVnode, struct Vnode **newVnode, const char *path, const char *target)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *inode = NULL;
|
|
struct Vnode *pVnode = NULL;
|
|
|
|
ret = VnodeAlloc(&g_jffs2Vops, &pVnode);
|
|
if (ret != 0) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
ret = jffs2_symlink((struct jffs2_inode *)parentVnode->data, &inode, (const unsigned char *)path, target);
|
|
if (ret != 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
VnodeFree(pVnode);
|
|
return ret;
|
|
}
|
|
|
|
pVnode->type = VNODE_TYPE_LNK;
|
|
pVnode->fop = &g_jffs2Fops;
|
|
pVnode->parent = parentVnode;
|
|
pVnode->originMount = parentVnode->originMount;
|
|
pVnode->data = inode;
|
|
pVnode->uid = inode->i_uid;
|
|
pVnode->gid = inode->i_gid;
|
|
pVnode->mode = inode->i_mode;
|
|
|
|
*newVnode = pVnode;
|
|
(void)VfsHashInsert(*newVnode, inode->i_ino);
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
ssize_t VfsJffs2Readlink(struct Vnode *vnode, char *buffer, size_t bufLen)
|
|
{
|
|
ssize_t ret = 0;
|
|
struct jffs2_inode *inode = NULL;
|
|
struct jffs2_inode_info *f = NULL;
|
|
ssize_t targetLen;
|
|
ssize_t cnt;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
inode = (struct jffs2_inode *)vnode->data;
|
|
f = JFFS2_INODE_INFO(inode);
|
|
targetLen = strlen((const char *)f->target);
|
|
if (bufLen == 0) {
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return 0;
|
|
}
|
|
|
|
cnt = (bufLen - 1) < targetLen ? (bufLen - 1) : targetLen;
|
|
if (LOS_CopyFromKernel(buffer, bufLen, (const char *)f->target, cnt) != 0) {
|
|
cnt = 0;
|
|
ret = -EFAULT;
|
|
}
|
|
buffer[cnt] = '\0';
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
int VfsJffs2Unlink(struct Vnode *parentVnode, struct Vnode *targetVnode, const char *path)
|
|
{
|
|
int ret;
|
|
struct jffs2_inode *parentInode = NULL;
|
|
struct jffs2_inode *targetInode = NULL;
|
|
|
|
if (!parentVnode || !targetVnode) {
|
|
PRINTK("%s-%d parentVnode=%x, targetVnode=%x\n", __FUNCTION__, __LINE__, parentVnode, targetVnode);
|
|
return -EINVAL;
|
|
}
|
|
|
|
parentInode = (struct jffs2_inode *)parentVnode->data;
|
|
targetInode = (struct jffs2_inode *)targetVnode->data;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
ret = jffs2_unlink(parentInode, targetInode, (const unsigned char *)path);
|
|
|
|
if (ret == 0) {
|
|
(void)jffs2_iput(targetInode);
|
|
}
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
|
|
int VfsJffs2Rename(struct Vnode *fromVnode, struct Vnode *toParentVnode, const char *fromName, const char *toName)
|
|
{
|
|
int ret;
|
|
struct Vnode *fromParentVnode = NULL;
|
|
struct Vnode *toVnode = NULL;
|
|
struct jffs2_inode *fromNode = NULL;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
fromParentVnode = fromVnode->parent;
|
|
|
|
ret = VfsJffs2Lookup(toParentVnode, toName, strlen(toName), &toVnode);
|
|
if (ret == 0) {
|
|
if (toVnode->type == VNODE_TYPE_DIR) {
|
|
ret = VfsJffs2Rmdir(toParentVnode, toVnode, (char *)toName);
|
|
} else {
|
|
ret = VfsJffs2Unlink(toParentVnode, toVnode, (char *)toName);
|
|
}
|
|
if (ret) {
|
|
PRINTK("%s-%d remove newname(%s) failed ret=%d\n", __FUNCTION__, __LINE__, toName, ret);
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return ret;
|
|
}
|
|
}
|
|
fromNode = (struct jffs2_inode *)fromVnode->data;
|
|
ret = jffs2_rename((struct jffs2_inode *)fromParentVnode->data, fromNode,
|
|
(const unsigned char *)fromName, (struct jffs2_inode *)toParentVnode->data, (const unsigned char *)toName);
|
|
fromVnode->parent = toParentVnode;
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Stat(struct Vnode *pVnode, struct stat *buf)
|
|
{
|
|
struct jffs2_inode *node = NULL;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
node = (struct jffs2_inode *)pVnode->data;
|
|
switch (node->i_mode & S_IFMT) {
|
|
case S_IFREG:
|
|
case S_IFDIR:
|
|
case S_IFLNK:
|
|
buf->st_mode = node->i_mode;
|
|
break;
|
|
|
|
default:
|
|
buf->st_mode = DT_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
buf->st_dev = 0;
|
|
buf->st_ino = node->i_ino;
|
|
buf->st_nlink = node->i_nlink;
|
|
buf->st_uid = node->i_uid;
|
|
buf->st_gid = node->i_gid;
|
|
buf->st_size = node->i_size;
|
|
buf->st_blksize = BLOCK_SIZE;
|
|
buf->st_blocks = buf->st_size / buf->st_blksize;
|
|
buf->st_atime = node->i_atime;
|
|
buf->st_mtime = node->i_mtime;
|
|
buf->st_ctime = node->i_ctime;
|
|
|
|
/* Adapt to kstat member long tv_sec */
|
|
buf->__st_atim32.tv_sec = (long)node->i_atime;
|
|
buf->__st_mtim32.tv_sec = (long)node->i_mtime;
|
|
buf->__st_ctim32.tv_sec = (long)node->i_ctime;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Reclaim(struct Vnode *pVnode)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int VfsJffs2Statfs(struct Mount *mnt, struct statfs *buf)
|
|
{
|
|
unsigned long freeSize;
|
|
struct jffs2_sb_info *c = NULL;
|
|
struct jffs2_inode *rootNode = NULL;
|
|
|
|
LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER);
|
|
|
|
rootNode = (struct jffs2_inode *)mnt->vnodeCovered->data;
|
|
c = JFFS2_SB_INFO(rootNode->i_sb);
|
|
|
|
freeSize = c->free_size + c->dirty_size;
|
|
buf->f_type = JFFS2_SUPER_MAGIC;
|
|
buf->f_bsize = PAGE_SIZE;
|
|
buf->f_blocks = (((uint64_t)c->nr_blocks) * c->sector_size) / PAGE_SIZE;
|
|
buf->f_bfree = freeSize / PAGE_SIZE;
|
|
buf->f_bavail = buf->f_bfree;
|
|
buf->f_namelen = NAME_MAX;
|
|
buf->f_fsid.__val[0] = JFFS2_SUPER_MAGIC;
|
|
buf->f_fsid.__val[1] = 1;
|
|
buf->f_frsize = BLOCK_SIZE;
|
|
buf->f_files = 0;
|
|
buf->f_ffree = 0;
|
|
buf->f_flags = mnt->mountFlags;
|
|
|
|
LOS_MuxUnlock(&g_jffs2FsLock);
|
|
return 0;
|
|
}
|
|
|
|
int Jffs2MutexCreate(void)
|
|
{
|
|
if (LOS_MuxInit(&g_jffs2FsLock, NULL) != LOS_OK) {
|
|
PRINT_ERR("%s, LOS_MuxCreate failed\n", __FUNCTION__);
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void Jffs2MutexDelete(void)
|
|
{
|
|
(void)LOS_MuxDestroy(&g_jffs2FsLock);
|
|
}
|
|
|
|
const struct MountOps jffs_operations = {
|
|
.Mount = VfsJffs2Bind,
|
|
.Unmount = VfsJffs2Unbind,
|
|
.Statfs = VfsJffs2Statfs,
|
|
};
|
|
|
|
struct VnodeOps g_jffs2Vops = {
|
|
.Lookup = VfsJffs2Lookup,
|
|
.Create = VfsJffs2Create,
|
|
.Rename = VfsJffs2Rename,
|
|
.Mkdir = VfsJffs2Mkdir,
|
|
.Getattr = VfsJffs2Stat,
|
|
.Opendir = VfsJffs2Opendir,
|
|
.Readdir = VfsJffs2Readdir,
|
|
.Closedir = VfsJffs2Closedir,
|
|
.Rewinddir = VfsJffs2Rewinddir,
|
|
.Unlink = VfsJffs2Unlink,
|
|
.Rmdir = VfsJffs2Rmdir,
|
|
.Chattr = VfsJffs2Chattr,
|
|
.Reclaim = VfsJffs2Reclaim,
|
|
.Truncate = VfsJffs2Truncate,
|
|
.Truncate64 = VfsJffs2Truncate64,
|
|
.Link = VfsJffs2Link,
|
|
.Symlink = VfsJffs2Symlink,
|
|
.Readlink = VfsJffs2Readlink,
|
|
};
|
|
|
|
struct file_operations_vfs g_jffs2Fops = {
|
|
.read = VfsJffs2Read,
|
|
.write = VfsJffs2Write,
|
|
.mmap = OsVfsFileMmap,
|
|
.seek = VfsJffs2Seek,
|
|
.close = VfsJffs2Close,
|
|
.fsync = VfsJffs2Fsync,
|
|
};
|
|
|
|
|
|
FSMAP_ENTRY(jffs_fsmap, "jffs2", jffs_operations, TRUE, TRUE);
|
|
|
|
#endif
|