提交 d9707508 编写于 作者: W wangchenyang 提交者: mamingshuai

Description:vfs refactoring

Feature or Bugfix:Feature
Binary Source:Huawei
PrivateCode(Yes/No):Yes

Change-Id: I175d2648bc6f9078c34de2c0a5c93fda10b86c47
ChangeID:13306388
上级 eb474b86
...@@ -93,12 +93,27 @@ source "../../kernel/liteos_a/fs/ramfs/Kconfig" ...@@ -93,12 +93,27 @@ source "../../kernel/liteos_a/fs/ramfs/Kconfig"
source "../../kernel/liteos_a/fs/nfs/Kconfig" source "../../kernel/liteos_a/fs/nfs/Kconfig"
source "../../kernel/liteos_a/fs/proc/Kconfig" source "../../kernel/liteos_a/fs/proc/Kconfig"
source "../../kernel/liteos_a/fs/jffs2/Kconfig" source "../../kernel/liteos_a/fs/jffs2/Kconfig"
source "../../kernel/liteos_a/fs/zpfs/Kconfig"
config ENABLE_READ_BUFFER config ENABLE_READ_BUFFER
bool "Enable read buffer Option" bool "Enable read buffer Option"
default n default n
help help
Answer Y to add enable read buffer Option. Answer Y to add enable read buffer Option.
config MAX_VNODE_SIZE
int "Vnode max number"
range 0 512
default 512
depends on FS_VFS
help
vnode number, range from 0 to 512.
config MAX_PATH_CACHE_SIZE
int "PathCache max number"
range 0 1024
default 512
depends on FS_VFS
help
pathCache number, range from 0 to 1024.
endmenu endmenu
######################## config options of net ############################ ######################## config options of net ############################
......
...@@ -453,6 +453,7 @@ unsigned int OsCmdKeyShift(const char *cmdKey, char *cmdOut, unsigned int size) ...@@ -453,6 +453,7 @@ unsigned int OsCmdKeyShift(const char *cmdKey, char *cmdOut, unsigned int size)
free(outputBak); free(outputBak);
return SH_OK; return SH_OK;
} }
int OsTabCompletion(char *cmdKey, unsigned int *len) int OsTabCompletion(char *cmdKey, unsigned int *len)
{ {
int count; int count;
......
...@@ -37,7 +37,9 @@ LOCAL_SRCS += $(wildcard $(LITEOSTHIRDPARTY)/FatFs/source/*.c) ...@@ -37,7 +37,9 @@ LOCAL_SRCS += $(wildcard $(LITEOSTHIRDPARTY)/FatFs/source/*.c)
LOCAL_INCLUDE := \ LOCAL_INCLUDE := \
-I $(LITEOSTHIRDPARTY)/FatFs/source \ -I $(LITEOSTHIRDPARTY)/FatFs/source \
-I $(LITEOSTOPDIR)/fs/fat/os_adapt \ -I $(LITEOSTOPDIR)/fs/fat/os_adapt \
-I $(LITEOSTOPDIR)/fs/fat/virpart/include -I $(LITEOSTOPDIR)/fs/fat/virpart/include \
-I $(LITEOSTOPDIR)/fs/vfs \
-I $(LITEOSTHIRDPARTY)/NuttX/include
LOCAL_FLAGS := $(LOCAL_INCLUDE) $(LITEOS_GCOV_OPTS) LOCAL_FLAGS := $(LOCAL_INCLUDE) $(LITEOS_GCOV_OPTS)
......
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-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 "dirop_fat.h"
#include "fatfs.h"
#include "errno.h"
#include "fs/fs.h"
#include "inode/inode.h"
#include "integer.h"
#include "string.h"
#ifdef LOSCFG_FS_FAT
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */
extern const struct mountpt_operations fat_operations;
#define SECTOR_SIZE 512
#define FIRST_MALLOC_SIZE 10
static INT vfat_check_path(const char *path)
{
struct inode *inode_ptr = NULL;
char *fullpath = NULL;
INT ret = vfs_normalize_path((const char *)NULL, path, &fullpath);
struct inode_search_s desc;
if (ret < ENOERR) {
ret = -ret;
set_errno(ret);
return FAT_ERROR;
}
SETUP_SEARCH(&desc, fullpath, false);
ret = inode_find(&desc);
if (ret < 0) {
PRINT_ERR("ERROR: Failed to find %s\n", fullpath);
ret = -ret;
set_errno(ret);
return FAT_ERROR;
}
inode_ptr = desc.node;
free(fullpath);
if (inode_ptr && (inode_ptr->u.i_mops == &fat_operations)) {
inode_release(inode_ptr);
return ENOERR;
}
return FAT_ERROR;
}
static DIR_FAT *initdir_fat(DIR *dp)
{
DIR_FAT *dir_fat = NULL;
if (dp != NULL) {
dir_fat = (DIR_FAT *)malloc(sizeof(DIR_FAT) + PATH_MAX);
if (dir_fat != NULL) {
(void)memset_s(dir_fat, sizeof(DIR_FAT) + PATH_MAX, 0, sizeof(DIR_FAT) + PATH_MAX);
dir_fat->stDirStream.dd_nextloc = 0;
dir_fat->stDirStream.dd_size = 0;
dir_fat->stBuf.d_count = SECTOR_SIZE;
dir_fat->stBuf.d_usecount = 0;
(void)pthread_mutex_init(&(dir_fat->stDirStream.dd_lock), (const pthread_mutexattr_t *)NULL);
dir_fat->stDirStream.dp = dp;
return dir_fat;
}
(void)closedir(dp);
}
return NULL;
}
DIR_FAT *opendir_fat(const char *name)
{
INT ret;
DIR *dp = NULL;
ret = vfat_check_path(name);
if (ret) {
return NULL;
}
dp = opendir(name);
return initdir_fat(dp);
}
int closedir_fat(DIR_FAT *dir_fat)
{
INT ret;
if (dir_fat == NULL) {
return FAT_ERROR;
}
ret = closedir(dir_fat->stDirStream.dp);
if (ret == ENOERR) {
(void)pthread_mutex_destroy(&(dir_fat->stDirStream.dd_lock));
free(dir_fat);
}
return ret;
}
extern int fatfs_readdir_all(DIR_FAT *dir_fat);
struct fat_direntall *readdir_fat(DIR_FAT *dir_fat)
{
INT ret;
struct fat_direntall *de = (struct fat_direntall *)NULL;
if (dir_fat == NULL) {
return NULL;
}
if (pthread_mutex_lock(&(dir_fat->stDirStream.dd_lock)) != ENOERR) {
return NULL;
}
ret = fatfs_readdir_all(dir_fat);
if (!ret) {
de = &(dir_fat->stBuf.direntall);
}
if (pthread_mutex_unlock(&(dir_fat->stDirStream.dd_lock)) != ENOERR)
PRINT_ERR("readdir_fat mutex unlock error \n");
return de;
}
static struct fat_direntall **scandir_fat_remalloc_names(struct fat_direntall **names,
UINT *names_size, UINT pos, bool *failed)
{
struct fat_direntall **new_direntall = NULL;
INT32 ret;
if (pos == *names_size) {
if (*names_size == 0) {
*names_size = FIRST_MALLOC_SIZE;
} else {
*names_size <<= 1;
}
new_direntall = (struct fat_direntall **)malloc(*names_size * sizeof(struct fat_direntall *));
if (new_direntall == NULL) {
*failed = 1;
return names;
}
if (names != NULL) {
ret = memcpy_s(new_direntall, (*names_size) * sizeof(struct fat_direntall *),
names, pos * sizeof(struct fat_direntall *));
if (ret != EOK){
*failed = 1;
free(new_direntall);
return names;
}
free(names);
}
return new_direntall;
}
return names;
}
int scandir_fat(const char *dir, struct fat_direntall ***namelist,
int (*selector) (const struct fat_direntall *),
int (*compar) (const struct fat_direntall **, const struct fat_direntall **))
{
DIR_FAT *dp = opendir_fat(dir);
struct fat_direntall *current = NULL;
struct fat_direntall **names = NULL;
struct fat_direntall *vnew = NULL;
UINT names_size = 0;
UINT pos = 0;
UINT dsize;
bool failed = 0;
INT use_it;
if (dp == NULL) {
return FAT_ERROR;
}
current = readdir_fat(dp);
while (current != NULL) {
use_it = (selector == NULL);
if (!use_it) {
use_it = (*selector) (current);
}
if (use_it) {
names = scandir_fat_remalloc_names(names, &names_size, pos, &failed);
if (failed == 1) {
break;
}
dsize = current->d_reclen;
vnew = (struct fat_direntall *)malloc(dsize);
if (vnew == NULL) {
failed = 1;
break;
}
(void)memcpy_s(vnew, dsize, current, dsize);
names[pos++] = vnew;
}
current = readdir_fat(dp);
}
if (failed == 1) {
(void)closedir_fat(dp);
while (pos > 0) {
free(names[--pos]);
}
if (names != NULL) {
free(names);
}
return FAT_ERROR;
}
(void)closedir_fat(dp);
/* Sort the list if we have a comparison function to sort with. */
if (compar != NULL && names != NULL) {
qsort((void *)names, pos, sizeof (struct fat_direntall *), (int (*)(const void *, const void *))*compar);
}
*namelist = names;
return pos;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* CONFIG_FS_FAT */
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-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.
*/
/**
* @defgroup fat Fat
* @ingroup filesystem
*/
#ifndef _DIROP_FAT_H
#define _DIROP_FAT_H
#include "pthread.h"
#include "dirent.h"
#ifdef LOSCFG_FS_FAT
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */
#define TIME_LENGTH 8
struct fat_direntall {
unsigned long d_ino;
unsigned long d_off;
unsigned char d_type;
unsigned int d_size;
char d_createtime[TIME_LENGTH];
unsigned short d_reclen;
char d_name[1];
};
struct fat_direntall_buf {
int d_count;
int d_usecount;
struct fat_direntall direntall;
};
struct dirstream_fat {
DIR *dp;
/* offset of the next dir entry in buffer */
unsigned int dd_nextloc;
/* bytes of valid entries in buffer */
unsigned int dd_size;
pthread_mutex_t dd_lock;
};
typedef struct fat_dir{
struct dirstream_fat stDirStream;
struct fat_direntall_buf stBuf;
} DIR_FAT;
/**
* @ingroup fat
* @brief open a directory
*
* @par Description:
* This API is used to open a directory stream corresponding to the directory name, and
* returns a pointer to the directory stream.
*
* @attention
* <ul>
* <li>The parameter name should be a valid string.</li>
* </ul>
*
* @param name [IN] the directory to open.
*
* @retval #NULL Open directory unsuccessfully and set errno.
* @retval #DIR_FAT* A pointer to the directory stream.
* @par Dependency:
* <ul><li>dirop_fat.h: the header file that contains the API declaration.</li></ul>
* @see closedir_fat
*/
DIR_FAT *opendir_fat(const char *name);
/**
* @ingroup fat
* @brief close a directory
*
* @par Description:
* This API is used to close the directory stream associated with dirp.
*
* @attention
* <ul>
* <li>The parameter dir_fat should be a valid pointer which opendir_fat returns.</li>
* </ul>
*
* @param dir_fat [IN] Directory object structure pointer which opendir_fat returns.
*
* @retval #FAT_ERROR The directory dirp close unsuccessfully and set errno.
* @retval #OK The directory dirp close successfully.
* @par Dependency:
* <ul><li>dirop_fat.h: the header file that contains the API declaration.</li></ul>
* @see opendir_fat
*/
int closedir_fat(DIR_FAT *dir_fat);
/**
* @ingroup fat
* @brief read a directory
*
* @par Description:
* This API is used to get a pointer to a dirent structure
* representing the next directory entry in the directory stream pointed
* to by dirp.
*
* @attention
* <ul>
* <li>The parameter dir_fat should be a valid pointer which opendir_fat returns.</li>
* </ul>
*
* @param dir_fat [IN] An instance of type DIR created by a previous call to opendir_fat().
*
* @retval #NULL Reaching the end of the directory stream or if an error occurred and set errno.
* @retval #fat_direntall* A pointer to a dirent structure.
* @par Dependency:
* <ul><li>dirop_fat.h: the header file that contains the API declaration.</li></ul>
* @see opendir_fat
*/
struct fat_direntall *readdir_fat(DIR_FAT *dir_fat);
/**
* @ingroup fat
* @brief scan a directory for matching entries.
*
* @par Description:
* The scandir_fat() function scans the directory dirp, calling selector() in
* each directory entry. Entries for which selector() returns nonzero are
* stored in strings allocated via malloc, sorted using qsort with
* the comparison function compar(), and collected in array namelist
* which is allocated via malloc. If filter is NULL, all entries are
* selected, compare with scandir(), scandir_fat() can get the create-time of
* file.
*
* @attention
* <ul>
* <li></li>
* </ul>
*
* @param dir [IN] Type #const char* a pointer to directory information.
* @param namelist [OUT] Type #const struct fat_direntall*** a pointer to collected directory entries.
* @param selector [IN] Type #int(*selector)(const struct fat_direntall*) a filter type function.
* @param compar [IN] Type #int(*compar)(const struct fat_direntall**,const struct dirent**) a compar type function.
*
* @retval #int The number of directory entries selected.
* @retval #<0 An error occurred.
* @par Dependency:
* <ul><li>dirop_fat.h: the header file that contains the API declaration.</li></ul>
* @see readdir_fat
*/
int scandir_fat(const char *dir, struct fat_direntall ***namelist,
int (*selector) (const struct fat_direntall *),
int (*compar) (const struct fat_direntall **, const struct fat_direntall **));
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */
#endif /* LOSCFG_FS_FAT */
#endif /* _DIROP_FAT_H */
...@@ -45,8 +45,8 @@ int osShellCmdFormat(int argc, char **argv) ...@@ -45,8 +45,8 @@ int osShellCmdFormat(int argc, char **argv)
if (argc < 3) { /* 3, at least 3 params for this shell command. */ if (argc < 3) { /* 3, at least 3 params for this shell command. */
perror("format error"); perror("format error");
PRINTK("Usage :\n"); PRINTK("Usage :\n");
PRINTK(" format <dev_inodename> <sectors> <option> <label>\n"); PRINTK(" format <dev_vnodename> <sectors> <option> <label>\n");
PRINTK(" dev_inodename : the name of dev\n"); PRINTK(" dev_vnodename : the name of dev\n");
PRINTK(" sectors : Size of allocation unit in unit of byte or sector, "); PRINTK(" sectors : Size of allocation unit in unit of byte or sector, ");
PRINTK("0 instead of default size\n"); PRINTK("0 instead of default size\n");
PRINTK(" options : Index of filesystem. 1 for FAT filesystem, "); PRINTK(" options : Index of filesystem. 1 for FAT filesystem, ");
......
此差异已折叠。
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#ifndef _FATFS_H #ifndef _FATFS_H
#define _FATFS_H #define _FATFS_H
#include "ff.h"
#include "fs/fs.h" #include "fs/fs.h"
#include "disk.h" #include "disk.h"
#include "unistd.h" #include "unistd.h"
...@@ -42,10 +43,6 @@ ...@@ -42,10 +43,6 @@
#include "sys/stat.h" #include "sys/stat.h"
#include "sys/statfs.h" #include "sys/statfs.h"
#include "inode/inode.h"
#include "fs/dirent_fs.h"
#include "fcntl.h"
#ifdef __cplusplus #ifdef __cplusplus
#if __cplusplus #if __cplusplus
extern "C" { extern "C" {
...@@ -54,42 +51,92 @@ extern "C" { ...@@ -54,42 +51,92 @@ extern "C" {
#define MAX_LFNAME_LENTH 256 #define MAX_LFNAME_LENTH 256
#define LABEL_LEN 12 #define LABEL_LEN 12
#define FAT32_MAXSZIE 0x100000000 #define FAT_RESERVED_NUM 2
#define FAT32_MAXSIZE 0x100000000
#define BAD_CLUSTER 0x7FFFFFFF
#define DISK_ERROR 0xFFFFFFFF
#define END_OF_FILE 0x0FFFFFFF
#define FAT_ERROR (-1) #define FAT_ERROR (-1)
extern char FatLabel[LABEL_LEN];
/* MBR */
#define MBR_PRIMARY_PART_NUM 4
#define JUMP_CODE "\xEB\xFE\x90"
/* Partiton type */
#define FAT12 0x01 /* FAT12 as primary partition in first physical 32MB */
#define FAT16 0x04 /* FAT16 with less than 65536 sectors(32MB) */
#define EXTENDED_PARTITION_CHS 0x05
#define FAT16B 0x06 /* FAT16B with 65536 or more sectors */
#define FAT32_CHS 0x0B
#define FAT32_LBA 0x0C
#define EXTENDED_PARTITION_LBA 0x0F
#define GPT_PROTECTIVE_MBR 0xEE
/* volume boot record type */
#define VBR_FAT 0
#define VBR_BS_NOT_FAT 2
#define VBR_NOT_BS 3
#define VBR_DISK_ERR 4
/* Limit and boundary */
#define FAT_MAX_CLUSTER_SIZE 64 /* (sectors) */
#define FAT32_MAX_CLUSTER_SIZE 128 /* (sectors) */
#define FAT32_ENTRY_SIZE 4 /* (bytes) */
#define FAT16_ENTRY_SIZE 2 /* (bytes) */
#define VOL_MIN_SIZE 128 /* (sectors) */
#define SFD_START_SECTOR 63
#define MAX_BLOCK_SIZE 32768 /* (sectors) */
/* Sector */
#define FAT32_RESERVED_SECTOR 32
#define FAT_RESERVED_SECTOR 1
#define DIR_NAME_LEN 11
#define DIR_READ_COUNT 7
#define VOLUME_CHAR_LENGTH 4 #define VOLUME_CHAR_LENGTH 4
#define FAT_CHECK(ptr) \
do { \ #define FAT_DEBUG
if ((ptr) == NULL) \ #ifdef FAT_DEBUG
return -EINVAL; \ #define FDEBUG(format, ...) do { \
} while (0) PRINTK("[%s:%d]"format"\n", __func__, __LINE__, ##__VA_ARGS__); \
} while (0)
int fatfs_bind (struct inode *blkdriver, const void *data, void **handle, const char *realpath); #else
int fatfs_unbind (void *handle, struct inode **blkdriver); #define FDEBUG(...)
int fatfs_mkfs (const char *dev, int sectors, int option); #endif
int fatfs_statfs (struct inode *mountpt, struct statfs *buf);
int fatfs_open (struct file *filep, const char *relpath, int oflags, mode_t mode); int fatfs_2_vfs(int result);
int fatfs_close (struct file *filep); int fatfs_lookup(struct Vnode *parent, const char *name, int len, struct Vnode **vpp);
int fatfs_ioctl (FAR struct file *filep, int cmd, unsigned long arg); int fatfs_create(struct Vnode *parent, const char *name, int mode, struct Vnode **vpp);
ssize_t fatfs_read (struct file *filep, char *buffer, size_t buflen); int fatfs_read(struct file *filep, char *buff, size_t count);
ssize_t fatfs_write (struct file *filep, const char *buffer, size_t buflen); off_t fatfs_lseek64(struct file *filep, off64_t offset, int whence);
int fatfs_sync (struct file *filep); off64_t fatfs_lseek(struct file *filep, off_t offset, int whence);
int fatfs_virstatfs_internel (struct inode *mountpt, const char *relpath, struct statfs *buf); int fatfs_write(struct file *filep, const char *buff, size_t count);
int fatfs_dup (FAR const struct file *oldp, FAR struct file *newp); int fatfs_fsync(struct file *filep);
off_t fatfs_seek (struct file *filep, off_t offset, int whence); int fatfs_fallocate64(struct file *filep, int mode, off64_t offset, off64_t len);
int fatfs_unlink (struct inode *mountpt, const char *relpath); int fatfs_fallocate(struct file *filep, int mode, off_t offset, off_t len);
int fatfs_rename (struct inode *mountpt, const char *oldpath, const char *newpath); int fatfs_truncate64(struct Vnode *vnode, off64_t len);
int fatfs_stat (struct inode *mountpt, const char *path, struct stat *st); int fatfs_truncate(struct Vnode *vnode, off_t len);
int fatfs_opendir (struct inode *mountpt, const char *relpath, struct fs_dirent_s *dir); int fatfs_mount(struct Mount *mount, struct Vnode *device, const void *data);
int fatfs_closedir (struct inode *mountpt, struct fs_dirent_s *dir); int fatfs_umount(struct Mount *mount, struct Vnode **device);
int fatfs_readdir (struct inode *mountpt, struct fs_dirent_s *dir); int fatfs_statfs(struct Mount *mount, struct statfs *info);
int fatfs_rewinddir (struct inode *mountpt, struct fs_dirent_s *dir); int fatfs_stat(struct Vnode *vnode, struct stat *buff);
int fatfs_mkdir (struct inode *mountpt, const char *relpath, mode_t mode); int fatfs_chattr(struct Vnode *vnode, struct IATTR *attr);
int fatfs_rmdir (struct inode *mountpt, const char *relpath); int fatfs_opendir(struct Vnode *vnode, struct fs_dirent_s *idir);
int fatfs_utime (struct inode *mountpt, const char *pathname, const struct tm *times); int fatfs_readdir(struct Vnode *vnode, struct fs_dirent_s *idir);
int fatfs_getlabel (void *handle, char *label); int fatfs_rewinddir(struct Vnode *vnode, struct fs_dirent_s *dir);
int fatfs_2_vfs (int result); int fatfs_closedir(struct Vnode *vnode, struct fs_dirent_s *dir);
int fatfs_rename(struct Vnode *oldvnode, struct Vnode *newparent, const char *oldname, const char *newname);
int fatfs_mkfs (struct Vnode *device, int sectors, int option);
int fatfs_mkdir(struct Vnode *parent, const char *name, mode_t mode, struct Vnode **vpp);
int fatfs_rmdir(struct Vnode *parent, struct Vnode *vp, char *name);
int fatfs_unlink(struct Vnode *parent, struct Vnode *vp, char *name);
int fatfs_ioctl(struct file *filep, int req, unsigned long arg);
int fatfs_fscheck(struct Vnode* vnode, struct fs_dirent_s *dir);
FRESULT find_fat_partition(FATFS *fs, los_part *part, BYTE *format, QWORD *start_sector);
FRESULT init_fatobj(FATFS *fs, BYTE fmt, QWORD start_sector);
FRESULT _mkfs(los_part *partition, int sector, int opt, BYTE *work, UINT len);
#ifdef __cplusplus #ifdef __cplusplus
#if __cplusplus #if __cplusplus
......
...@@ -38,9 +38,12 @@ ...@@ -38,9 +38,12 @@
#include "integer.h" #include "integer.h"
#ifdef LOSCFG_FS_FAT #ifdef LOSCFG_FS_FAT
char FatLabel[LABEL_LEN];
#define DEV_NAME_SIZE 4 #define DEV_NAME_SIZE 4
int format(const char *dev, int sectors, int option) int format(const char *dev, int sectors, int option)
{ {
struct Vnode *device = NULL;
INT err; INT err;
if (dev == NULL) { if (dev == NULL) {
set_errno(EINVAL); set_errno(EINVAL);
...@@ -49,8 +52,8 @@ int format(const char *dev, int sectors, int option) ...@@ -49,8 +52,8 @@ int format(const char *dev, int sectors, int option)
if (strncmp(dev, "/dev", DEV_NAME_SIZE) != 0) { if (strncmp(dev, "/dev", DEV_NAME_SIZE) != 0) {
PRINTK("Usage :\n"); PRINTK("Usage :\n");
PRINTK(" format <dev_inodename> <sectors> <option> <label>\n"); PRINTK(" format <dev_vnodename> <sectors> <option> <label>\n");
PRINTK(" dev_inodename : the name of dev\n"); PRINTK(" dev_vnodename : the name of dev\n");
PRINTK(" sectors : Size of allocation unit in unit of byte or sector, "); PRINTK(" sectors : Size of allocation unit in unit of byte or sector, ");
PRINTK("0 instead of default size\n"); PRINTK("0 instead of default size\n");
PRINTK(" options : Index of filesystem. 1 for FAT filesystem, 2 for FAT32 filesystem, "); PRINTK(" options : Index of filesystem. 1 for FAT filesystem, 2 for FAT32 filesystem, ");
...@@ -62,7 +65,18 @@ int format(const char *dev, int sectors, int option) ...@@ -62,7 +65,18 @@ int format(const char *dev, int sectors, int option)
set_errno(EINVAL); set_errno(EINVAL);
return -1; return -1;
} }
err = fatfs_mkfs(dev, sectors, option); VnodeHold();
err = VnodeLookup(dev, &device, 0);
if (err == -ENOENT || err == -ENOSYS) {
VnodeDrop();
set_errno(ENODEV);
return -1;
} else if (err < 0) {
VnodeDrop();
set_errno(-err);
return -1;
}
err = fatfs_mkfs(device, sectors, option);
if (err < 0) { if (err < 0) {
set_errno(-err); set_errno(-err);
return -1; return -1;
...@@ -72,6 +86,7 @@ int format(const char *dev, int sectors, int option) ...@@ -72,6 +86,7 @@ int format(const char *dev, int sectors, int option)
set_errno(err); set_errno(err);
} }
#endif #endif
VnodeDrop();
return 0; return 0;
} }
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "virpart.h" #include "virpart.h"
#include "errno.h" #include "errno.h"
#include "fatfs.h" #include "fatfs.h"
#include "dirop_fat.h"
#include "errcode_fat.h" #include "errcode_fat.h"
#include "disk.h" #include "disk.h"
...@@ -442,15 +441,17 @@ INT FatFsMakeVirPart(void *handle, BYTE vol) ...@@ -442,15 +441,17 @@ INT FatFsMakeVirPart(void *handle, BYTE vol)
return fatfs_2_vfs(ret); return fatfs_2_vfs(ret);
} }
INT fatfs_virstatfs_internel(struct inode *mountpt, const char *relpath, struct statfs *buf) INT fatfs_virstatfs_internel(struct Vnode *mountpt, const char *relpath, struct statfs *buf)
{ {
char drive[MAX_LFNAME_LENTH]; char drive[MAX_LFNAME_LENTH];
DWORD freClust, allClust; DWORD freClust, allClust;
FATFS *fat = NULL; FATFS *fat = NULL;
INT result, vol; INT result, vol;
fat = (FATFS *)mountpt->i_private; fat = (FATFS *)(mountpt->originMount->data);
FAT_CHECK(fat); if (fat == NULL) {
return -EINVAL;
}
if (fat->vir_flag != FS_PARENT) { if (fat->vir_flag != FS_PARENT) {
return -EINVAL; return -EINVAL;
......
...@@ -36,39 +36,6 @@ ...@@ -36,39 +36,6 @@
#ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
#if FF_USE_LFN == 0 /* Non-LFN configuration */
#define DEF_NAMBUF
#define INIT_NAMBUF(fs)
#define FREE_NAMBUF()
#else /* LFN configuration */
#if (FF_MAX_LFN < 12) || (FF_MAX_LFN > 255)
#error Wrong _MAX_LFN value
#endif
#if FF_USE_LFN == 1 /* LFN enabled with static working buffer */
static WCHAR g_lfnBuf[FF_MAX_LFN + 1]; /* LFN enabled with static working buffer */
#define DEF_NAMBUF
#define INIT_NAMBUF(fs)
#define FREE_NAMBUF()
#elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */
#define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN + 1];
#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; }
#define FREE_NAMBUF()
#elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */
#define DEF_NAMBUF WCHAR *lfn;
#define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; }
#define FREE_NAMBUF() ff_memfree(lfn)
#else
#error Wrong FF_USE_LFN setting
#endif
#endif /* else FF_USE_LFN == 0 */
#if FF_FS_REENTRANT #if FF_FS_REENTRANT
#if FF_USE_LFN == 1 #if FF_USE_LFN == 1
#error Static LFN work area cannot be used at thread-safe configuration #error Static LFN work area cannot be used at thread-safe configuration
......
...@@ -41,10 +41,6 @@ ...@@ -41,10 +41,6 @@
#ifdef LOSCFG_FS_FAT_CACHE #ifdef LOSCFG_FS_FAT_CACHE
#include "bcache.h" #include "bcache.h"
#else
#include "inode/inode.h"
#endif #endif
#include "pthread.h" #include "pthread.h"
...@@ -178,7 +174,7 @@ typedef struct _los_disk_ { ...@@ -178,7 +174,7 @@ typedef struct _los_disk_ {
UINT32 disk_status : 2; /* status of disk */ UINT32 disk_status : 2; /* status of disk */
UINT32 part_count : 8; /* current partition count */ UINT32 part_count : 8; /* current partition count */
UINT32 reserved : 14; UINT32 reserved : 14;
struct inode *dev; /* device */ struct Vnode *dev; /* device */
#ifdef LOSCFG_FS_FAT_CACHE #ifdef LOSCFG_FS_FAT_CACHE
OsBcache *bcache; /* cache of the disk, shared in all partitions */ OsBcache *bcache; /* cache of the disk, shared in all partitions */
#endif #endif
...@@ -199,7 +195,7 @@ typedef struct _los_part_ { ...@@ -199,7 +195,7 @@ typedef struct _los_part_ {
UINT32 reserved : 3; UINT32 reserved : 3;
UINT8 filesystem_type; /* filesystem used in the partition */ UINT8 filesystem_type; /* filesystem used in the partition */
UINT8 type; UINT8 type;
struct inode *dev; /* dev devices used in the partition */ struct Vnode *dev; /* dev devices used in the partition */
CHAR *part_name; CHAR *part_name;
UINT64 sector_start; /* UINT64 sector_start; /*
* offset of a partition to the primary devices * offset of a partition to the primary devices
...@@ -249,7 +245,7 @@ struct disk_divide_info { ...@@ -249,7 +245,7 @@ struct disk_divide_info {
* *
* @param diskName [IN] Type #const CHAR * disk driver name. * @param diskName [IN] Type #const CHAR * disk driver name.
* @param bops [IN] Type #const struct block_operations * block driver control sturcture. * @param bops [IN] Type #const struct block_operations * block driver control sturcture.
* @param priv [IN] Type #VOID * private data of inode. * @param priv [IN] Type #VOID * private data of vnode.
* @param diskID [IN] Type #INT32 disk id number, less than SYS_MAX_DISK. * @param diskID [IN] Type #INT32 disk id number, less than SYS_MAX_DISK.
* @param info [IN] Type #VOID * disk driver partition information. * @param info [IN] Type #VOID * disk driver partition information.
* *
...@@ -537,14 +533,14 @@ INT32 los_part_access(const CHAR *dev, mode_t mode); ...@@ -537,14 +533,14 @@ INT32 los_part_access(const CHAR *dev, mode_t mode);
* @brief Find disk partition. * @brief Find disk partition.
* *
* @par Description: * @par Description:
* By driver partition inode to find disk partition. * By driver partition vnode to find disk partition.
* *
* @attention * @attention
* <ul> * <ul>
* None * None
* </ul> * </ul>
* *
* @param blkDriver [IN] Type #struct inode * partition driver inode. * @param blkDriver [IN] Type #struct Vnode * partition driver vnode.
* *
* @retval #NULL Can't find chosen disk partition. * @retval #NULL Can't find chosen disk partition.
* @retval #los_part * This is partition structure pointer of chosen disk partition. * @retval #los_part * This is partition structure pointer of chosen disk partition.
...@@ -554,7 +550,7 @@ INT32 los_part_access(const CHAR *dev, mode_t mode); ...@@ -554,7 +550,7 @@ INT32 los_part_access(const CHAR *dev, mode_t mode);
* @see None * @see None
* *
*/ */
los_part *los_part_find(struct inode *blkDriver); los_part *los_part_find(struct Vnode *blkDriver);
/** /**
* @ingroup disk * @ingroup disk
......
...@@ -82,38 +82,38 @@ extern struct page_mapping *find_mapping(const char *path); ...@@ -82,38 +82,38 @@ extern struct page_mapping *find_mapping(const char *path);
* *
****************************************************************************/ ****************************************************************************/
extern int remove_mapping(const char *fullpath, const struct file *ex_filp); extern int remove_mapping(const char *fullpath);
/**************************************************************************** /****************************************************************************
* Name: remove_mapping_nolock * Name: rename_mapping
* *
* Description: * Description:
* This function is similar with the function "remove_mapping" above, * Rename the mapping from global path <-> page_mapping list.
* except that this function do not protect global file list.
* *
****************************************************************************/ ****************************************************************************/
extern int remove_mapping_nolock(const char *fullpath, const struct file *ex_filp); extern void rename_mapping(const char *src, const char *dst);
/**************************************************************************** /****************************************************************************
* Name: rename_mapping * Name: dec_mapping
* *
* Description: * Description:
* Rename the mapping from global path <-> page_mapping list. * Decrease the refcnt of mapping.
* *
****************************************************************************/ ****************************************************************************/
extern void rename_mapping(const char *src, const char *dst); extern void dec_mapping_nolock(struct page_mapping *mapping);
/**************************************************************************** /****************************************************************************
* Name: dec_mapping * Name: update_file_path
* *
* Description: * Description:
* Decrease the refcnt of mapping. * Update the path in file descriptors when do renaming.
* *
****************************************************************************/ ****************************************************************************/
extern void dec_mapping(struct page_mapping *mapping); extern int update_file_path(char *old_path, char *new_path);
/** /**
* @ingroup fs * @ingroup fs
...@@ -317,7 +317,7 @@ extern int los_set_systime_status(BOOL b_status); ...@@ -317,7 +317,7 @@ extern int los_set_systime_status(BOOL b_status);
* *
*/ */
FAR int fscheck(FAR const char *path); int fscheck(const char *path);
#ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
/** /**
...@@ -347,7 +347,7 @@ FAR int fscheck(FAR const char *path); ...@@ -347,7 +347,7 @@ FAR int fscheck(FAR const char *path);
* *
*/ */
extern int virstatfs(FAR const char *path, FAR struct statfs *buf); extern int virstatfs(const char *path, struct statfs *buf);
/** /**
* @ingroup fs * @ingroup fs
...@@ -379,8 +379,9 @@ extern int virstatfs(FAR const char *path, FAR struct statfs *buf); ...@@ -379,8 +379,9 @@ extern int virstatfs(FAR const char *path, FAR struct statfs *buf);
* @see * @see
* *
*/ */
#ifdef VFS_IMPL_LATER
int los_set_virpartparam(virpartinfo virtualinfo); int los_set_virpartparam(virpartinfo virtualinfo);
#endif
#endif #endif
...@@ -416,6 +417,7 @@ int los_set_virpartparam(virpartinfo virtualinfo); ...@@ -416,6 +417,7 @@ int los_set_virpartparam(virpartinfo virtualinfo);
* @see None * @see None
*/ */
struct IATTR;
extern int chattr(const char *pathname, struct IATTR *attr); extern int chattr(const char *pathname, struct IATTR *attr);
......
/*
* 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.
*/
#ifndef _MOUNT_H_
#define _MOUNT_H_
#include "los_mux.h"
#include "fs/vfs_util.h"
#include "fs/vnode.h"
#include <sys/stat.h>
struct MountOps;
struct Mount {
LIST_ENTRY mountList; /* mount list */
const struct MountOps *ops; /* operations of mount */
struct Vnode *vnodeBeCovered; /* vnode we mounted on */
struct Vnode *vnodeCovered; /* syncer vnode */
LIST_HEAD vnodeList; /* list of vnodes */
int vnodeSize; /* size of vnode list */
LIST_HEAD activeVnodeList; /* list of active vnodes */
int activeVnodeSize; /* szie of active vnodes list */
void *data; /* private data */
uint32_t hashseed; /* Random seed for vfshash */
unsigned long mountFlags; /* Flags for mount */
};
struct MountOps {
int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data);
int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver);
int (*Statfs)(struct Mount *mount, struct statfs *sbp);
};
struct Mount* MountAlloc(struct Vnode* vnode, struct MountOps* mop);
LIST_HEAD* GetMountList(void);
#endif
/*
* 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.
*/
#ifndef _PATH_CACHE_H
#define _PATH_CACHE_H
#include "los_list.h"
#include "fs/mount.h"
#include "fs/vnode.h"
struct PathCache {
struct Vnode *parentVnode; /* vnode points to the cache */
struct Vnode *childVnode; /* vnode the cache points to */
LIST_ENTRY parentEntry; /* list entry for cache list in the parent vnode */
LIST_ENTRY childEntry; /* list entry for cache list in the child vnode */
LIST_ENTRY hashEntry; /* list entry for buckets in the hash table */
uint8_t nameLen; /* length of path component */
char name[0]; /* path component name */
};
int PathCacheInit(void);
int PathCacheFree(struct PathCache *cache);
struct PathCache *PathCacheAlloc(struct Vnode *parent, struct Vnode *vnode, const char *name, uint8_t len);
int PathCacheAllocDummy(struct Vnode *parent, struct Vnode **vnode, const char *name, uint8_t len);
int PathCacheLookup(struct Vnode *parent, const char *name, int len, struct Vnode **vnode);
void VnodePathCacheFree(struct Vnode *vnode);
void PathCacheMemoryDump(void);
#endif /* _PATH_CACHE_H */
此差异已折叠。
此差异已折叠。
...@@ -31,17 +31,12 @@ include $(LITEOSTOPDIR)/config.mk ...@@ -31,17 +31,12 @@ include $(LITEOSTOPDIR)/config.mk
MODULE_NAME := $(notdir $(shell pwd)) MODULE_NAME := $(notdir $(shell pwd))
LOCAL_SRCS := $(wildcard $(LITEOSTHIRDPARTY)/Linux_Kernel/fs/jffs2/*.c) \ LOCAL_SRCS := $(wildcard src/*.c) \
$(wildcard $(LITEOSTHIRDPARTY)/rt-thread/components/dfs/filesystems/jffs2/*.c) \ $(wildcard $(LITEOSTHIRDPARTY)/Linux_Kernel/fs/jffs2/*.c)
$(wildcard $(LITEOSTHIRDPARTY)/rt-thread/components/dfs/filesystems/jffs2/src/fs-ecos.c)
LOCAL_INCLUDE := \ LOCAL_INCLUDE := \
-I $(LITEOSTOPDIR)/fs/jffs2/include \
-I $(LITEOSTHIRDPARTY)/Linux_Kernel/fs/jffs2 \ -I $(LITEOSTHIRDPARTY)/Linux_Kernel/fs/jffs2 \
-I $(LITEOSTHIRDPARTY)/Linux_Kernel/fs \ -I $(LITEOSTHIRDPARTY)/Linux_Kernel/fs
-I $(LITEOSTHIRDPARTY)/rt-thread/components/dfs/filesystems/jffs2 \
-I $(LITEOSTHIRDPARTY)/rt-thread/components/dfs/filesystems/jffs2/src \
-I $(LITEOSTHIRDPARTY)/rt-thread/components/dfs/filesystems/jffs2/include/ \
-I $(LITEOSTHIRDPARTY)/rt-thread/components/dfs/filesystems/jffs2/cyg/fileio
LOCAL_FLAGS := $(LOCAL_INCLUDE) $(LITEOS_GCOV_OPTS) LOCAL_FLAGS := $(LOCAL_INCLUDE) $(LITEOS_GCOV_OPTS)
include $(MODULE) include $(MODULE)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册