文件系统
简介
文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型,是一种用于向用户提供底层数据访问的机制。文件系统存储的基本单位是文件,即数据是按照一个个文件的方式进行组织。当文件比较多时,将导致文件繁多,不易分类、重名的问题。而文件夹作为一个容纳多个文件的容器而存在。
在本操作系统中,为了能够支持多种文件系统,实现了虚拟文件系统。对上而言,可以提供统一的POSIX接口,方便用户使用。对下而言,可以注册不同的具体文件系统类型。整个文件系统的层次架构如下:
POSIX接口层
POSIX表示可移植操作系统接口(Portable OperaTIng System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003。POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。
本操作系统支持POSIX标准接口,因此可以很方便的将 Linux/Unix 的程序移植到本操作系统上。
虚拟文件系统
本操作系统支持多种文件系统,如FATFS、CUTEFS、NFS、YAFFS2等。不同的文件系统有各自不同的管理文件的方式,对于用户而言,最好不用去关心每种文件系统的文件存取方式。因此本操作系统在POSIX接口层和具体文件系统之间引入了一个抽象层,这个抽象层称之为虚拟文件系统(Virtual File System)。
为了能够支持多种实际文件系统,VFS定义了各种文件系统都支持的基本的、概念上的接口和数据结构,VFS不用关心具体文件系统的实现细节。
具体文件系统
本操作系统目前支持以下文件系统,方便用户根据实际情况选用:
FATFS:本组件支持的FAT文件系统是移植的一个兼容微软FAT格式的通用FAT文件系统模块(presented by ChaN),非常适合小型嵌入式设备开发。
CUTEFS:一种小巧的文件系统,支持各种文件及目录操作,目前需要配合RAMDISK使用。
DEVFS:设备文件系统,可以将系统中的设备在/dev文件夹下虚拟成文件。
NFS:网络文件系统,本系统移植了一个网络文件系统客户端,可以通过操作本地文件系统一样的方式去访问服务器端的文件。
JFFS2:JFFS(Journalling Flash FileSystem)文件系统最早是由瑞典Axis Communications AB在嵌入式系统上开发的Flash文件系统,而JFFS2是RedHat公司在JFFS的基础上开发的文件系统。这是一种日志型文件系统,主要用于Nor Flash,支持数据压缩功能,支持磨损均衡可延长FLASH使用寿命,支持垃圾回收机制。
YAFFS2:YAFFS(Yet Another Flash File System)文件系统是一种针对Nand Flash特性而设计的嵌入式文件系统。目前有两个版本,Yaffs1支持page大小512byte的Nand Flash,Yaffs2支持更大page(2kbyte)的Nand Flash。这也是一种日志型文件系统,主要用于Nand Flash,支持磨损均衡,支持垃圾回收。
设备抽象层
设备抽象层将物理设备,如SD Card、Flash等抽象成文件系统能够访问的设备,例如FAT文件系统要求存储设备是块设备类型。不同的文件系统一般是独立于存储设备驱动而实现的,因此需要把底层存储设备驱动接口与具体文件系统对接起来,文件系统才能正常使用。
初始化和挂载文件系统
文件系统要能够正常使用,一般需要先经过以下几个步骤:
初始化VFS组件
注册具体的文件系统
在存储器上创建块设备
在块设备上格式化文件系统
挂载设备到某个路径
文件系统不再使用时,可以卸载
初始化VFS组件
VFS组件的的初始化是由函数vfs_init()完成。vfs_init() 函数会初始化 VFS 所需的相关资源,创建一些关键的数据结构(包括文件系统操作表,文件系统表,文件描述符表等)。有了这些数据结构,VFS便能在系统中记录和访问特定的文件系统,并获得对文件的操作方法。本操作系统中有自动初始化功能,该函数将会被自动调用。
注册文件系统
用户根据自己的需要选择具体的文件系统并注册到VFS中,通过函数vfs_register()实现,它会将具体文件系统的操作接口与VFS中的文件系统操作表关联起来。本操作系统中在配置时如果打开了某种文件系统,那么在初始化阶段将会调用该函数注册该文件系统。
将存储设备注册为块设备
存储设备初始化后,需要将该存储设备注册为块设备,通过函数os_device_register()实现,它会将设备的操作接口与设备名关联起来。以后需要设备时,可以使用os_device_find()通过设备名找到实际设备,进而可以获取到实际设备的操作接口。
格式化文件系统
不同具体文件系统的组织方式是不一样的,所以在使用具体文件系统之前,需要将块设备按照某种文件系统进行格式化,通过函数vfs_mkfs()实现。它会在设备的某个区域上,写入一些符合具体文件系统格式的数据,表明该文件系统的一些特征。后续在访问该设备时,就能识别到该设备上的数据是否是按照该文件系统组织的,才能根据该文件系统的操作接口去访问文件。
挂载文件系统
我们访问文件时是根据路径来访问的,所以在使用文件系统前,还需要将存储文件的设备与一个路径关联起来,这就是文件系统的挂载,通过函数vfs_mount()实现。之后就可以通过这个路径来访问存储设备。
卸载文件系统
当某个文件系统不再需要使用时,可以通过函数vfs_unmount()卸载掉。
文件系统操作接口
接口 | 说明 |
---|---|
vfs_register | 注册某种类型的文件系统到VFS中 |
vfs_mkfs | 将设备格式化成某种文件系统 |
vfs_mount | 将设备挂载到某个路径上 |
vfs_unmount | 卸载某个路径上的文件系统 |
vfs_register
该函数用于注册某种类型的文件系统到VFS中,函数原型如下:
int vfs_register(const struct vfs_filesystem_ops *ops);
参数 | 说明 |
---|---|
ops | VFS操作结构体,该结构体中包含了实际文件系统对应的操作接口,如mount/unmount/open/close/read/write等。每个具体的文件系统不一定支持所有接口。 |
返回 | 说明 |
0 | 注册成功 |
-1 | 注册失败 |
vfs_mkfs
该函数用于将设备格式化成某种文件系统,函数原型如下:
int vfs_mkfs(const char *fs_name, const char *device_name);
参数 | 说明 |
---|---|
fs_name | 文件系统类型名字,例如:对于FATFS名字为fat,对于JFFS2文件系统名字为jffs2,对于YAFFS文件系统名字为yaffs;CUTEFS、DEVFS、NFS不需要格式化,不支持此操作 |
device_name | 设备名 |
返回 | 说明 |
0 | 格式化成功 |
其它值 | 格式化失败 |
vfs_mount
该函数用于将设备挂载到某个路径上,函数原型如下:
int vfs_mount(const char *device_name,
const char *path,
const char *filesystemtype,
unsigned long rwflag,
const void *data);
参数 | 说明 |
---|---|
device_name | 设备名 |
path | 挂载路径 |
filesystemtype | 文件系统类型 |
rwflag | 读写设备的标记,暂未使用该参数 |
data | 私有数据 |
返回 | 说明 |
0 | 挂载成功 |
其它值 | 挂载失败 |
vfs_unmount
该函数用于将某个路径上的文件系统卸载掉,函数原型如下:
int vfs_unmount(const char *path);
参数 | 说明 |
---|---|
path | 文件系统的路径(与挂载时的路径相同) |
返回 | 说明 |
0 | 卸载成功 |
其它值 | 卸载失败 |
POSIX文件操作接口
接口 | 说明 |
---|---|
open | 打开指定文件,并返回文件描述符 |
close | 关闭文件 |
read | 从文件中读取指定长度的数据 |
write | 写指定长度的数据到文件 |
lseek | 设置读写位置 |
rename | 重命名文件 |
unlink | 移除文件 |
stat | 根据文件路径获取文件信息 |
fstat | 根据文件描述符获取文件信息 |
fsync | 同步缓存数据到存储设备 |
fcntl | 对文件描述符的控制操作 |
ioctl | 对(设备)文件的控制操作 |
access | 查看用户访问权限 |
open
该函数用于打开指定文件,并返回文件描述符,函数原型如下:
int open(const char *file, int flags, ...);
参数 | 说明 |
---|---|
file | 文件名 |
flags | 打开文件的方式 |
... | 可变参数 |
返回 | 说明 |
非负值 | 文件描述符 |
-1 | 打开失败,errno可通过os_get_errno()查看 |
close
该函数用于关闭指定文件,函数原型如下:
int close(int fd);
参数 | 说明 |
---|---|
fd | 文件描述符 |
返回 | 说明 |
0 | 关闭成功 |
-1 | 关闭失败,errno可通过os_get_errno()查看 |
read
该函数用于从文件中读取指定长度的数据,函数原型如下:
int read(int fd, void *buf, size_t len);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 保存读取到数据的缓存区 |
len | 期望读取数据的长度 |
返回 | 说明 |
正数 | 实际读取到数据的长度 |
0 | 已到达文件尾部 |
-1 | 失败,errno可通过os_get_errno()查看 |
write
该函数用于将将指定长度的数据写入文件,函数原型如下:
int write(int fd, const void *buf, size_t len);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 待写入数据的地址 |
len | 写入数据的长度 |
返回 | 说明 |
非负数 | 实际写入数据的长度 |
-1 | 写入失败,errno可通过os_get_errno()查看 |
lseek
该函数用于修改文件的读写位置,函数原型如下:
off_t lseek(int fd, off_t offset, int whence);
参数 | 说明 |
---|---|
fd | 文件描述符 |
offset | 位置偏移量 |
whence | 偏移的位置,包括SEEK_SET、SEEK_CUR、SEEK_END |
返回 | 说明 |
非负数 | 当前读写位置距离文件头部的字节数 |
-1 | 失败,errno可通过os_get_errno()查看 |
rename
该函数用于重命名文件,按照如下语义实现:a)将一个文件重命名为一个目录,或将一个目录重命名为一个文件将会失败;b)将旧文件重命名为一个已经存在的新文件将会成功,原本存在的新文件会先被删除;c)将旧目录重命名为一个已经存在的、且非空的新目录会失败;d)将旧目录重命名为一个已经存在的、空的新目录会成功,原本存在的新目录会先被删除;e)新路径以旧路径作为前缀会失败;f)新路径包含不存在的父目录会失败。注意:在某些文件系统上,该操作无法保证原子性。函数原型如下:
int rename(const char *old, const char *new);
参数 | 说明 |
---|---|
old | 旧文件名 |
new | 新文件名 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
unlink
该函数用于移除文件,函数原型如下:
int unlink(const char *pathname);
参数 | 说明 |
---|---|
pathname | 文件名 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
stat
该函数用于根据文件路径获取文件状态信息,函数原型如下:
int stat(const char *path, struct stat *buf);
参数 | 说明 |
---|---|
path | 文件名(文件路径) |
buf | 用于保存获取到的文件信息的缓存区地址 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
fstat
该函数用于根据文件描述符获取文件状态信息,函数原型如下:
int fstat(int fd, struct stat *buf);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 用于保存获取到的文件信息的缓存区地址 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
fsync
该函数用于同步缓存数据到存储设备,函数原型如下:
int fsync(int fd);
参数 | 说明 |
---|---|
fd | 文件描述符 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
fcntl
该函数用于设置或者获取文件描述符的特殊属性,函数原型如下:
int fcntl(int fd, int cmd, ...);
参数 | 说明 |
---|---|
fd | 文件描述符 |
cmd | 控制命令,目前支持F_GETFL、F_SETFL |
... | 可变参数 |
返回 | 说明 |
非负数 | 若是设置属性,正确时返回0;若是读取属性,正确时返回该属性值 |
-1 | 失败,errno可通过os_get_errno()查看 |
ioctl
该函数用于对(设备)文件的控制操作,函数原型如下:
int ioctl(int fd, int cmd, ...);
参数 | 说明 |
---|---|
fd | 文件描述符 |
cmd | 控制命令,依赖于具体的(设备)文件的支持 |
... | 可变参数 |
返回 | 说明 |
非负数 | 取决于具体的命令 |
-1 | 失败,errno可通过os_get_errno()查看 |
access
该函数用于查看是否有权限访问指定文件,函数原型如下:
int access(const char *path, int amode);
参数 | 说明 |
---|---|
path | 文件名(文件路径) |
amode | 检查模式,该参数暂未使用 |
返回 | 说明 |
0 | 成功,目前仅支持查看文件是否存在,忽略读、写、可执行权限 |
-1 | 失败,errno可通过os_get_errno()查看 |
POSIX目录操作接口
接口 | 说明 |
---|---|
mkdir | 创建目录 |
rmdir | 删除目录 |
opendir | 打开目录 |
closedir | 关闭目录 |
readdir | 读取目录内容 |
telldir | 获取与目录流相关联的当前位置 |
seekdir | 设置下一个读取目录(readdir)操作的位置 |
rewinddir | 重置目录流的读取位置到目录开头 |
getcwd | 获取当前工作路径 |
chdir | 修改当前工作路径 |
mkdir
该函数用于创建目录,函数原型如下:
int mkdir(const char *path, mode_t mode);
参数 | 说明 |
---|---|
path | 路径 |
mode | 权限,该参数暂未使用 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
rmdir
该函数用于删除目录,函数原型如下:
int rmdir(const char *path);
参数 | 说明 |
---|---|
path | 路径 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
opendir
该函数用于打开目录,函数原型如下:
DIR *opendir(const char *name)
参数 | 说明 |
---|---|
name | 路径 |
返回 | 说明 |
非NULL值 | 打开成功,返回目录流指针 |
NULL | 打开失败,errno可通过os_get_errno()查看 |
closedir
该函数用于关闭目录,函数原型如下:
int closedir(DIR *d);
参数 | 说明 |
---|---|
d | 目录流指针 |
返回 | 说明 |
0 | 关闭成功 |
-1 | 关闭失败,errno可通过os_get_errno()查看 |
readdir
该函数用于读取目录内容,且每调用一次该函数,则目录条目的指针就会移向下一个,函数原型如下:
struct dirent *readdir(DIR *d);
参数 | 说明 |
---|---|
d | 目录流指针 |
返回 | 说明 |
非NULL值 | 目录条目的指针 |
NULL | 错误或者已经到达目录结尾,errno可通过os_get_errno()查看 |
telldir
该函数用于获取与目录流相关联的当前位置,函数原型如下:
long telldir(DIR *d);
参数 | 说明 |
---|---|
d | 目录流指针 |
返回 | 说明 |
其它值 | 该返回值记录着一个目录流的当前位置,代表距离目录文件开头的偏移量。此偏移量可以用于seekdir()函数 |
-1 | 错误,errno可通过os_get_errno()查看 |
seekdir
该函数用于设置下一个读取目录(readdir)操作的位置,函数原型如下:
void seekdir(DIR *d, off_t offset);
参数 | 说明 |
---|---|
d | 目录流指针 |
offset | 偏移量 |
rewinddir
该函数用于重置目录流的读取位置到目录开头,函数原型如下:
void rewinddir(DIR *d);
参数 | 说明 |
---|---|
d | 目录流指针 |
getcwd
该函数用于获取当前工作路径,函数原型如下:
char *getcwd(char *buf, size_t size);
参数 | 说明 |
---|---|
buf | 保存路径的缓存区 |
size | 缓存区的大小 |
返回 | 说明 |
char * | 缓存区的指针 |
chdir
该函数用于修改当前工作路径,函数原型如下:
int chdir(const char *path);
参数 | 说明 |
---|---|
path | 新路径 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
文件操作shell命令
支持常用的文件操作命令,具体如下:
命令 | 用法 | 说明 |
---|---|---|
ls | ls [DIRNAME] | 列出DIRNAME目录下的信息;若无参数DIRNAME,则列出当前目录下信息 |
cp | cp <SOURCE> <DEST> | 把SOURCE文件或文件夹复制到DEST |
mv | mv <SOURCE> <DEST> | 把SOURCE文件或文件夹重命名成DEST |
echo | echo <string> [FILE] | 把字符串sting写入到FILE中;若无参数FILE,则回显字符string串 |
cat | cat <FILE> ... | 查看文件FILE的内容,可同时查看多个文件内容 |
rm | rm <FILE> ... | 删除文件或文件夹的内容,可同时删除多个;删除文件夹前,需确认该文件夹为空 |
cd | cd [PATH] | 切换到PATH所在路径;若无参数PATH,则仍为当前路径 |
pwd | pwd | 显示当前工作路径 |
mkdir | mkdir <DIRNAME> | 创建目录DIRNAME |
另外还支持几个跟文件系统相关的命令,具体如下:
命令 | 用法 | 说明 |
---|---|---|
mkfs | mkfs [-t TYPE] <DEVICENAME> | 在设备DEVICENAME上创建TYPE类型的文件系统;当前TYPE支持fat、jffs2、yaffs;若无-t TYPE参数时,相当于mkfs -t fat <DEVICENAME> |
df | df [PATH] | 查看磁盘剩余空间 |
使用示例
文件操作接口使用示例
本例演示了文件操作常用接口的使用方法
#include <oneos_config.h>
#include <os_dbg.h>
#include <shell.h>
#include <string.h>
#include <vfs_posix.h>
#define TEST_TAG "TEST"
#define FILE_NAME "test.txt"
#define FILE_NAME_NEW "test_new.txt"
void file_operation_sample(void)
{
int fd, size, str_len;
char *str[3] = {"1234567890", "ABCDEFGHIJ", "abcdefghij"};
char bufread[35];
off_t offset = 0;
char* str_ptr;
struct stat filestat;
fd = open(FILE_NAME, O_RDWR | O_CREAT);
if (fd < 0)
{
LOG_E(TEST_TAG, "open file err");
return;
}
else
{
LOG_W(TEST_TAG, "open(create) file:%s", FILE_NAME);
str_ptr = str[0];
str_len = strlen(str_ptr);
size = write(fd, str_ptr, str_len);
LOG_W(TEST_TAG, "write %d byte from offset %d :%s", size, offset, str_ptr);
}
offset = 20;
if (lseek(fd, offset, SEEK_SET) != -1)
{
str_ptr = str[1];
str_len = strlen(str_ptr);
size = write(fd, str_ptr, str_len);
LOG_W(TEST_TAG, "write %d byte from offset %d :%s", size, offset, str_ptr);
}
offset = 10;
if (lseek(fd, offset, SEEK_SET) != -1)
{
str_ptr = str[2];
str_len = strlen(str_ptr);
size = write(fd, str_ptr, str_len);
LOG_W(TEST_TAG, "write %d byte from offset %d :%s", size, offset, str_ptr);
}
offset = 0;
if (lseek(fd, offset, SEEK_SET) != -1)
{
memset(bufread, 0, sizeof(bufread));
size = read(fd, bufread, sizeof(bufread));
LOG_W(TEST_TAG, "read %d byte from offset %d :%s", size, offset, bufread);
}
if(fstat(fd, &filestat) != -1)
{
LOG_W(TEST_TAG, "the filesize of %s is :%d", FILE_NAME, filestat.st_size);
}
if(close(fd) != -1)
{
LOG_W(TEST_TAG, "close file:%s", FILE_NAME);
}
if(rename(FILE_NAME, FILE_NAME_NEW) != -1)
{
LOG_W(TEST_TAG, "rename %s to %s", FILE_NAME, FILE_NAME_NEW);
}
if(stat(FILE_NAME_NEW, &filestat) != -1)
{
LOG_W(TEST_TAG, "the filesize of %s is :%d", FILE_NAME_NEW, filestat.st_size);
}
if (unlink(FILE_NAME_NEW) != -1)
{
LOG_W(TEST_TAG, "rm file:%s", FILE_NAME_NEW);
}
}
SH_CMD_EXPORT(test_file, file_operation_sample, "test for file operation");
运行结果如下:
sh />test_file
W/TEST: open(create) file:test.txt
W/TEST: write 10 byte from offset 0 :1234567890
W/TEST: write 10 byte from offset 20 :ABCDEFGHIJ
W/TEST: write 10 byte from offset 10 :abcdefghij
W/TEST: read 30 byte from offset 0 :1234567890abcdefghijABCDEFGHIJ
W/TEST: the filesize of test.txt is :30
W/TEST: close file:test.txt
W/TEST: rename test.txt to test_new.txt
W/TEST: the filesize of test_new.txt is :30
W/TEST: rm file:test_new.txt
目录操作接口使用示例
本例演示了常用目录操作接口的使用方法
#include <oneos_config.h>
#include <os_dbg.h>
#include <shell.h>
#include <vfs_posix.h>
#define TEST_TAG "TEST"
#define DIR_NAME "/dir_test"
#define FILE_NUM 3
static char *file_name[FILE_NUM] = {"test1.txt", "test2.txt", "test3.txt"};
static void dir_operation_sample(void)
{
int i = 0;
int fd;
DIR *dirp;
int save_offset = 0;
struct dirent *dp;
char bufread[32];
char *str = "test";
if(mkdir(DIR_NAME, 0x777) == -1)
{
LOG_E(TEST_TAG, "mkdir err");
return;
}
else
{
LOG_W(TEST_TAG, "mkdir:%s", DIR_NAME);
}
if (chdir(DIR_NAME) != -1)
{
LOG_W(TEST_TAG, "chdir:%s", DIR_NAME);
}
getcwd(bufread, sizeof(bufread));
LOG_W(TEST_TAG, "getcwd:%s", bufread);
dirp = opendir(DIR_NAME);
dp = readdir(dirp);
if (dp == NULL)
{
LOG_W(TEST_TAG, "there is no dir entry");
}
closedir(dirp);
for (i = 0; i < FILE_NUM; i++)
{
fd = open(file_name[i], O_RDWR | O_CREAT);
if (fd != -1)
{
LOG_W(TEST_TAG, "open(create) file:%s", file_name[i]);
write(fd, str, strlen(str));
close(fd);
}
}
i = 0;
dirp = opendir(DIR_NAME);
for (dp = readdir(dirp); dp != OS_NULL; dp = readdir(dirp))
{
i++;
LOG_W(TEST_TAG, "readdir: %s (type:%d)", dp->d_name, dp->d_type);
if (i == 2)
{
save_offset = telldir(dirp);
LOG_W(TEST_TAG, "save the 2nd dir entry, it's offset:%d", save_offset);
}
}
LOG_W(TEST_TAG, "seek to the 2nd dir entry, then readdir from it");
seekdir(dirp, save_offset);
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
{
LOG_W(TEST_TAG, "readdir: %s (type:%d)", dp->d_name, dp->d_type);
}
closedir(dirp);
for (i = 0; i < FILE_NUM; i++)
{
LOG_W(TEST_TAG, "rm file:%s", file_name[i]);
unlink(file_name[i]);
}
if (chdir("/") != -1)
{
LOG_W(TEST_TAG, "chdir:/");
}
getcwd(bufread, sizeof(bufread));
LOG_W(TEST_TAG, "getcwd:%s", bufread);
LOG_W(TEST_TAG, "rm dir:%s", DIR_NAME);
unlink(DIR_NAME);
}
SH_CMD_EXPORT(test_dir, dir_operation_sample, "test for dir operation");
运行结果如下:
sh />test_dir
W/TEST: mkdir:/dir_test
W/TEST: chdir:/dir_test
W/TEST: getcwd:/dir_test
W/TEST: there is no dir entry
W/TEST: open(create) file:test1.txt
W/TEST: open(create) file:test2.txt
W/TEST: open(create) file:test3.txt
W/TEST: readdir: test1.txt (type:1)
W/TEST: readdir: test2.txt (type:1)
W/TEST: save the 2nd dir entry, it's offset:260
W/TEST: readdir: test3.txt (type:1)
W/TEST: seek to the 2nd dir entry, then readdir from it
W/TEST: readdir: test2.txt (type:1)
W/TEST: readdir: test3.txt (type:1)
W/TEST: rm file:test1.txt
W/TEST: rm file:test2.txt
W/TEST: rm file:test3.txt
W/TEST: chdir:/
W/TEST: getcwd:/
W/TEST: rm dir:/dir_test
文件操作shell命令使用示例
本例演示了常用shell命令的使用方法,包括ls/echo/cat/mkdir/pwd/rename/rm/cd等
sh />ls
Directory /:
sh />echo 111 test1.txt
sh />ls
Directory /:
test1.txt 3
sh />cat test1.txt
111
sh />mkdir dir_test
sh />ls
Directory /:
test1.txt 3
dir_test <DIR>
sh />cd dir_test
sh /dir_test>echo 222 test2.txt
sh /dir_test>ls
Directory /dir_test:
test2.txt 3
sh /dir_test>cat test2.txt
222
sh /dir_test>pwd
/dir_test
sh /dir_test>mv test2.txt test3.txt
test2.txt => test3.txt
sh /dir_test>ls
Directory /dir_test:
test3.txt 3
sh /dir_test>cat test3.txt
222
sh /dir_test>rm test3.txt
sh /dir_test>ls
Directory /dir_test:
sh /dir_test>cd ..
sh />ls
Directory /:
test1.txt 3
dir_test <DIR>
sh />rm dir_test
sh />ls
Directory /:
test1.txt 3
sh />