diff --git a/.vscode/settings.json b/.vscode/settings.json index 86abb35f..c173488d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -170,6 +170,8 @@ "assert.h": "c", "sys_version.h": "c", "cmd.h": "c", + "user_namespace.h": "c", + "sleep.h": "c", "net.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", diff --git a/docs/kernel/filesystem/devfs/index.md b/docs/kernel/filesystem/devfs/index.md deleted file mode 100644 index 0dc9ee16..00000000 --- a/docs/kernel/filesystem/devfs/index.md +++ /dev/null @@ -1,24 +0,0 @@ -# devFS 设备文件系统 - -  devfs是一种基于内存的伪文件系统,设备可注册到devfs中。对上层模块及应用程序而言,每个设备都是可操作的文件。 - -## 原理 - -  由于每个设备被抽象为文件,因此对于驱动程序而言,只需实现文件的操作接口,上层的应用程序以及其他系统组件即可操作文件操作接口来控制硬件设备。 - -## 目录结构 - -  按照设备的主类型的不同,将多种设备放置在devfs的不同文件夹下.请注意,同一设备可以出现在不同的文件夹下。 - -- `char` 字符设备 -- `block` 块设备 -- `usb` usb设备 -- stdio等设备放置在devfs的根目录下 - -## 设备注册 - -  驱动程序可使用`devfs_register_device()`函数将设备注册到devfs之中。 - -## 设备卸载 - -  【尚未实现】 diff --git a/docs/kernel/filesystem/fat32/index.md b/docs/kernel/filesystem/fat32/index.md deleted file mode 100644 index d3373a5a..00000000 --- a/docs/kernel/filesystem/fat32/index.md +++ /dev/null @@ -1,216 +0,0 @@ -# FAT32文件系统 - -## 简介 - -  FAT32文件系统是一种相对简单的文件系统。 - -  FAT32文件系统实现在`kernel/filesystem/fat32/`中。 - ---- - -## 相关数据结构 - -### struct fat32_BootSector_t - -  fat32启动扇区结构体 - -```c -struct fat32_BootSector_t -{ - uint8_t BS_jmpBoot[3]; // 跳转指令 - uint8_t BS_OEMName[8]; // 生产厂商名 - uint16_t BPB_BytesPerSec; // 每扇区字节数 - uint8_t BPB_SecPerClus; // 每簇扇区数 - uint16_t BPB_RsvdSecCnt; // 保留扇区数 - uint8_t BPB_NumFATs; // FAT表数量 - uint16_t BPB_RootEntCnt; // 根目录文件数最大值 - uint16_t BPB_TotSec16; // 16位扇区总数 - uint8_t BPB_Media; // 介质描述符 - uint16_t BPB_FATSz16; // FAT12/16每FAT扇区数 - uint16_t BPB_SecPerTrk; // 每磁道扇区数 - uint16_t BPB_NumHeads; // 磁头数 - uint32_t BPB_HiddSec; // 隐藏扇区数 - uint32_t BPB_TotSec32; // 32位扇区总数 - - uint32_t BPB_FATSz32; // FAT32每FAT扇区数 - uint16_t BPB_ExtFlags; // 扩展标志 - uint16_t BPB_FSVer; // 文件系统版本号 - uint32_t BPB_RootClus; // 根目录起始簇号 - uint16_t BPB_FSInfo; // FS info结构体的扇区号 - uint16_t BPB_BkBootSec; // 引导扇区的备份扇区号 - uint8_t BPB_Reserved0[12]; - - uint8_t BS_DrvNum; // int0x13的驱动器号 - uint8_t BS_Reserved1; - uint8_t BS_BootSig; // 扩展引导标记 - uint32_t BS_VolID; // 卷序列号 - uint8_t BS_VolLab[11]; // 卷标 - uint8_t BS_FilSysType[8]; // 文件系统类型 - - uint8_t BootCode[420]; // 引导代码、数据 - - uint16_t BS_TrailSig; // 结束标志0xAA55 -} __attribute__((packed)); -``` - -### struct fat32_FSInfo_t - -   该扇区存储了FAT32文件系统的一些参考信息。 - -```c -struct fat32_FSInfo_t -{ - uint32_t FSI_LeadSig; - uint8_t FSI_Reserved1[480]; - uint32_t FSI_StrucSig; - uint32_t FSI_Free_Count; - uint32_t FSI_Nxt_Free; - uint8_t FSI_Reserved2[12]; - uint32_t FSI_TrailSig; -} __attribute__((packed)); -``` - -**FSI_LeadSig** - -  FS info扇区标志符 数值为0x41615252 - -**FSI_Reserved1** - -  保留使用,全部置为0 - -**FSI_StrucSig** - -  FS_Info扇区的另一个标志符,数值为0x61417272 - -**FSI_Free_Count** - -  上一次记录的空闲簇数量,这是一个参考值 - -**FSI_Nxt_Free** - -  空闲簇的起始搜索位置,这是为驱动程序提供的参考值. - -**FSI_Reserved2** -  保留使用,全部置为0 - -**FSI_TrailSig** - -  FS_Info扇区结束标志,数值为0xaa550000 - -### struct fat32_Directory_t - -  短目录项结构体。 - -```c -struct fat32_Directory_t -{ - unsigned char DIR_Name[11]; - unsigned char DIR_Attr; - unsigned char DIR_NTRes; - unsigned char DIR_CrtTimeTenth; - unsigned short DIR_CrtTime; - unsigned short DIR_CrtDate; - unsigned short DIR_LastAccDate; - unsigned short DIR_FstClusHI; - unsigned short DIR_WrtTime; - unsigned short DIR_WrtDate; - unsigned short DIR_FstClusLO; - unsigned int DIR_FileSize; -} __attribute__((packed)); -``` - -**DIR_Name** - -  目录项名称。前8bytes为基础名,后3bytes为扩展名 - -**DIRAttr** - -  目录项属性。可选值有如下: - -> - ATTR_READ_ONLY -> -> - ATTR_HIDDEN -> -> - ATTR_SYSTEM -> -> - ATTR_VOLUME_ID -> -> - ATTR_DIRECTORY -> -> - ATTR_ARCHIVE -> -> - ATTR_LONG_NAME - -**DIR_NTRes** - -  该项为Windows下特有的表示区域,通过该项的值,表示基础名和扩展名的大小写情况。该项的值为`EXT|BASE`组合而成,其中,具有以下定义: - -> BASE:LowerCase(8),UpperCase(0) -> EXT:LowerCase(16),UpperCase(0) - -**DIR_CrtTimeTenth** - -  文件创建的毫秒级时间戳 - -**DIR_CrtTime** - -  文件创建时间 - -**DIR_CrtDate** - -  文件创建日期 - -**DIR_LastAccDate** - -  文件的最后访问日期 - -**DIR_FstClusHI** - -   文件起始簇号(高16bit) - -**DIR_WrtTime** - -  最后写入时间 - -**DIR_WrtDate** - -  最后写入日期 - -**DIR_FstClusLO** - -   文件起始簇号(低16bit) - -**DIR_FileSize** -  文件大小 - -### struct fat32_partition_info_t - -  该数据结构为FAT32分区的信息结构体,并不实际存在于物理磁盘上。这个结构体在挂载文件系统时被创建,作为文件系统的超级块的私有信息的一部分。 - -### struct fat32_inode_info_t - -  该结构体是VFS的inode结构体的私有信息部分的具体实现。 - ---- - -## 已知问题 - -1. 对目录项名称的检查没有按照标准严格实现 - -2. 当磁盘可用簇数量发生改变时,未更新FS_Info扇区 - -3. 未填写目录项的时间字段 - ---- - -## TODO - -- 完全实现VFS定义的文件接口 - -- 性能优化 - ---- - -## 参考资料 - -[FAT32 File System Specification - from Microsoft](http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc) \ No newline at end of file diff --git a/docs/kernel/filesystem/index.rst b/docs/kernel/filesystem/index.rst index 40184d12..73061581 100644 --- a/docs/kernel/filesystem/index.rst +++ b/docs/kernel/filesystem/index.rst @@ -3,11 +3,11 @@ DragonOS的文件系统模块由VFS(虚拟文件系统)及具体的文件系统组成。 +todo: 由于文件系统模块重构,文档暂时不可用,预计在2023年4月10日前补齐。 + .. toctree:: :maxdepth: 1 :caption: 目录 vfs/index - fat32/index - rootfs/index - devfs/index + diff --git a/docs/kernel/filesystem/rootfs/index.md b/docs/kernel/filesystem/rootfs/index.md deleted file mode 100644 index 91792f48..00000000 --- a/docs/kernel/filesystem/rootfs/index.md +++ /dev/null @@ -1,7 +0,0 @@ -# rootFS 根文件系统 - -  rootFS是DragonOS开启后挂载的第一个文件系统,它是一个基于内存的伪文件系统。rootfs的功能主要是在具体的磁盘文件系统被挂载之前,为其他的伪文件系统提供挂载点,使得系统能被正确的初始化。 - -  rootfs的初始化将与VFS一同初始化。rootfs将为系统的各项文件系统的挂载创建dentry,使得其他的文件系统如`devfs`等,能在磁盘文件系统被挂载之前被正确的初始化。 - -  当磁盘根文件系统被挂载后,将调用`rootfs_umount()`函数。该函数将会把原本挂载在rootfs上的各种伪文件系统迁移到磁盘根文件系统上。当迁移完成后,将会释放rootfs所占用的资源。 diff --git a/docs/kernel/filesystem/vfs/overview.md b/docs/kernel/filesystem/vfs/overview.md index 2767740c..30bd7b21 100644 --- a/docs/kernel/filesystem/vfs/overview.md +++ b/docs/kernel/filesystem/vfs/overview.md @@ -6,242 +6,6 @@   与VFS相关的系统调用有open(), read(), write(), create()等。 -### dentry对象 +## **TODO** -  dentry的全称为directory entry,是VFS中对于目录项的一种抽象数据结构。当读取具体文件系统时,将会由创建dentry对象。dentry对象中包含了指向inode的指针。 - -  dentry对象为真实文件系统上的目录结构建立了缓存,一旦内存中存在对应路径的dentry对象,我们就能直接获取其中的信息,而不需要进行费时的磁盘操作。请注意,dentry只是为提高文件系统性能而创建的一个缓存,它并不会被写入到磁盘之中。 - -### inode对象 - -  inode的全称叫做index node,即索引节点。一般来说,每个dentry都应当包含指向其inode的指针。inode是VFS提供的对文件对象的抽象。inode中的信息是从具体文件系统中读取而来,也可以被刷回具体的文件系统之中。并且,一个inode也可以被多个dentry所引用。 - -  要查找某个路径下的inode,我们需要调用父目录的inode的lookup()方法。请注意,该方法与具体文件系统有关,需要在具体文件系统之中实现。 - -### 文件描述符对象 - -  当一个进程试图通过VFS打开某个文件时,我们需要为这个进程创建文件描述符对象。每个文件对象都会绑定文件的dentry和文件操作方法结构体,还有文件对象的私有信息。 - -  文件描述符对象中还包含了诸如权限控制、当前访问位置信息等内容,以便VFS对文件进行操作。 - -  我们对文件进行操作都会使用到文件描述符,具体来说,就是要调用文件描述符之中的file_ops所包含的各种方法。 - ---- - -## 注册文件系统到VFS - -  如果需要注册或取消注册某个具体文件系统到VFS之中,则需要以下两个接口: - -```c -#include - -uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs); -uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs); -``` - -  这里需要通过`struct vfs_filesystem_type_t`来描述具体的文件系统。 - -### struct vfs_filesystem_type_t - -  这个数据结构描述了具体文件系统的一些信息。当我们挂载具体文件系统的时候,将会调用它的read_superblock方法,以确定要被挂载的文件系统的具体信息。 - -  该数据结构的定义在`kernel/filesystem/vfs/VFS.h`中,结构如下: - -```c -struct vfs_filesystem_type_t -{ - char *name; - int fs_flags; - // 解析文件系统引导扇区的函数,为文件系统创建超级块结构。其中DPTE为磁盘分区表entry(MBR、GPT不同) - struct vfs_superblock_t *(*read_superblock)(void *DPTE, uint8_t DPT_type, void *buf, int8_t ahci_ctrl_num, int8_t ahci_port_num, int8_t part_num); - struct vfs_filesystem_type_t *next; -}; -``` - -**name** - -  文件系统名称字符串 - -**fs_flags** - -  文件系统的一些标志位。目前,DragonOS尚未实现相关功能。 - -**read_superblock** - -  当新的文件系统实例将要被挂载时,将会调用此方法,以读取具体的实例的信息。 - -**next** - -  指向链表中下一个`struct vfs_filesystem_type_t`的指针。 - ---- - -## 超级块(superblock)对象 - -  一个超级块对象代表了一个被挂载到VFS中的具体文件系统。 - -### struct vfs_superblock_t - -  该数据结构为超级块结构体。 - -  该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下: - -```c -struct vfs_superblock_t -{ - struct vfs_dir_entry_t *root; - struct vfs_super_block_operations_t *sb_ops; - void *private_sb_info; -}; -``` - -**root** - -  该具体文件系统的根目录的dentry - -**sb_ops** - -  该超级块对象的操作方法。 - -**private_sb_info** - -  超级块的私有信息。包含了具体文件系统的私有的、全局性的信息。 - -### struct vfs_super_block_operations_t - -  该数据结构为超级块的操作接口。VFS通过这些接口来操作具体的文件系统的超级块。 - -  该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下: - -```c -struct vfs_super_block_operations_t -{ - void (*write_superblock)(struct vfs_superblock_t *sb); - void (*put_superblock)(struct vfs_superblock_t *sb); - void (*write_inode)(struct vfs_index_node_t *inode); // 将inode信息写入磁盘 -}; -``` - -**write_superblock** - -  将superblock中的信息写入磁盘 - -**put_superblock** - -  释放超级块 - -**write_inode** - -  将inode的信息写入磁盘 - ---- - -## 索引结点(inode)对象 - -  每个inode对象代表了具体的文件系统之中的一个对象(目录项)。 - -### struct vfs_index_node_t - -  该数据结构为inode对象的数据结构,与文件系统中的具体的文件结点对象具有一对一映射的关系。 - -  该数据结构定义在`kernel/filesystem/vfs/VFS.h`中,结构如下: - -```c -struct vfs_index_node_t -{ - uint64_t file_size; // 文件大小 - uint64_t blocks; // 占用的扇区数 - uint64_t attribute; - - struct vfs_superblock_t *sb; - struct vfs_file_operations_t *file_ops; - struct vfs_inode_operations_t *inode_ops; - - void *private_inode_info; -}; -``` - -**file_size** - -  文件的大小。若为文件夹,则该值为文件夹内所有文件的大小总和(估计值)。 - -**blocks** - -  文件占用的磁盘块数(扇区数) - -**attribute** - -  inode的属性。可选值如下: - -> - VFS_IF_FILE -> -> - VFS_IF_DIR -> -> - VFS_IF_DEVICE - -**sb** - -  指向文件系统超级块的指针 - -**file_ops** - -  当前文件的操作接口 - -**inode_ops** - -  当前inode的操作接口 - -**private_inode_info** - -  与具体文件系统相关的inode信息。该部分由具体文件系统实现,包含该inode在具体文件系统之中的特定格式信息。 - -### struct vfs_inode_operations_t - -  该接口为inode的操作方法接口,由具体文件系统实现。并与具体文件系统之中的inode相互绑定。 - -  该接口定义于`kernel/filesystem/vfs/VFS.h`中,结构如下: - -```c -struct vfs_inode_operations_t -{ - long (*create)(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode); - struct vfs_dir_entry_t *(*lookup)(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry); - long (*mkdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode); - long (*rmdir)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry); - long (*rename)(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry); - long (*getAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr); - long (*setAttr)(struct vfs_dir_entry_t *dEntry, uint64_t *attr); -}; -``` - -**create** - -  在父节点下,创建一个新的inode,并绑定到dest_dEntry上。 - -  该函数的应当被`sys_open()`系统调用在使用了`O_CREAT`选项打开文件时调用,从而创建一个新的文件。请注意,传递给create()函数的`dest_dEntry`参数不应包含一个inode,也就是说,inode对象应当被具体文件系统所创建。 - -**lookup** - -  当VFS需要在父目录中查找一个inode的时候,将会调用lookup方法。被查找的目录项的名称将会通过dest_dEntry传给lookup方法。 - -  若lookup方法找到对应的目录项,将填充完善dest_dEntry对象。否则,返回NULL。 - -**mkdir** - -  该函数被mkdir()系统调用所调用,用于在inode下创建子目录,并将子目录的inode绑定到dEntry对象之中。 - -**rmdir** - -  该函数被rmdir()系统调用所调用,用于删除给定inode下的子目录项。 - -**rename** - -  该函数被rename系统调用(尚未实现)所调用,用于将给定的目录项重命名。 - -**getAttr** - -  用来获取目录项的属性。 - -**setAttr** - -  用来设置目录项的属性 \ No newline at end of file +  VFS的设计与实现讲解 \ No newline at end of file diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index b1f312fa..03ee36b6 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -11,8 +11,9 @@ crate-type = ["staticlib"] # 运行时依赖项 [dependencies] x86_64 = "0.14.10" +bitflags = "1.3.2" virtio-drivers = "0.2.0" -bitflags = "1.3" + # 构建时依赖项 [build-dependencies] diff --git a/kernel/src/Makefile b/kernel/src/Makefile index bb60001a..9e222cd5 100644 --- a/kernel/src/Makefile +++ b/kernel/src/Makefile @@ -17,7 +17,7 @@ export ASFLAGS := --64 LD_LIST := head.o -kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest libs ipc io +kernel_subdirs := common driver process debug time arch exception mm smp sched syscall ktest libs ipc io diff --git a/kernel/src/common/errno.h b/kernel/src/common/errno.h index a1ebef05..5d093d00 100644 --- a/kernel/src/common/errno.h +++ b/kernel/src/common/errno.h @@ -10,59 +10,59 @@ */ #pragma once -#define E2BIG 1 /* 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */ -#define EACCES 2 /* 访问被拒绝 Permission denied */ -#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/ -#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/ -#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */ -#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/ -#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */ -#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */ -#define EBADMSG 9 /* 错误的消息 Bad message. */ +#define E2BIG 1 /* 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */ +#define EACCES 2 /* 访问被拒绝 Permission denied */ +#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/ +#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/ +#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */ +#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/ +#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */ +#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */ +#define EBADMSG 9 /* 错误的消息 Bad message. */ -#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */ -#define ECANCELED 11 /* 操作被取消 Operation canceled. */ -#define ECHILD 12 /* 没有子进程 No child processes. */ -#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */ -#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */ -#define ECONNRESET 15 /* 连接被重置 Connection reset. */ -#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */ -#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/ -#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */ -#define EDQUOT 19 /* 保留使用 Reserved */ +#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */ +#define ECANCELED 11 /* 操作被取消 Operation canceled. */ +#define ECHILD 12 /* 没有子进程 No child processes. */ +#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */ +#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */ +#define ECONNRESET 15 /* 连接被重置 Connection reset. */ +#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */ +#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/ +#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */ +#define EDQUOT 19 /* 保留使用 Reserved */ -#define EEXIST 20 /* 文件已存在 File exists. */ -#define EFAULT 21 /* 错误的地址 Bad address */ -#define EFBIG 22 /* 文件太大 File too large. */ -#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/ -#define EIDRM 24 /* 标志符被移除 Identifier removed. */ -#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */ -#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */ -#define EINTR 27 /* 被中断的函数 Interrupted function. */ -#define EINVAL 28 /* 不可用的参数 Invalid argument. */ -#define EIO 29 /* I/O错误 I/O error. */ +#define EEXIST 20 /* 文件已存在 File exists. */ +#define EFAULT 21 /* 错误的地址 Bad address */ +#define EFBIG 22 /* 文件太大 File too large. */ +#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/ +#define EIDRM 24 /* 标志符被移除 Identifier removed. */ +#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */ +#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */ +#define EINTR 27 /* 被中断的函数 Interrupted function. */ +#define EINVAL 28 /* 不可用的参数 Invalid argument. */ +#define EIO 29 /* I/O错误 I/O error. */ -#define EISCONN 30 /* 套接字已连接 Socket is connected. */ -#define EISDIR 31 /* 是一个目录 Is a directory */ -#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */ -#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */ -#define EMLINK 34 /* 链接数过多 Too many links. */ -#define EMSGSIZE 35 /* 消息过大 Message too large. */ -#define EMULTIHOP 36 /* 保留使用 Reserved. */ -#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */ -#define ENETDOWN 38 /* 网络已关闭 Network is down. */ -#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */ +#define EISCONN 30 /* 套接字已连接 Socket is connected. */ +#define EISDIR 31 /* 是一个目录 Is a directory */ +#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */ +#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */ +#define EMLINK 34 /* 链接数过多 Too many links. */ +#define EMSGSIZE 35 /* 消息过大 Message too large. */ +#define EMULTIHOP 36 /* 保留使用 Reserved. */ +#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */ +#define ENETDOWN 38 /* 网络已关闭 Network is down. */ +#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */ -#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */ -#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/ -#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */ -#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */ -#define ENODEV 44 /* 没有指定的设备 No such device. */ -#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */ -#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */ -#define ENOLCK 47 /* 没有可用的锁 No locks available. */ -#define ENOLINK 48 /* 保留 Reserved. */ -#define ENOMEM 49 /* 没有足够的空间 Not enough space. */ +#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */ +#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/ +#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */ +#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */ +#define ENODEV 44 /* 没有指定的设备 No such device. */ +#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */ +#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */ +#define ENOLCK 47 /* 没有可用的锁 No locks available. */ +#define ENOLINK 48 /* 保留 Reserved. */ +#define ENOMEM 49 /* 没有足够的空间 Not enough space. */ #define ENOMSG 50 /* 没有期待类型的消息 No message of the desired type. */ #define ENOPROTOOPT 51 /* 协议不可用 Protocol not available. */ @@ -73,29 +73,29 @@ #define ENOTCONN 56 /* 套接字未连接 The socket is not connected. */ #define ENOTDIR 57 /* 不是目录 Not a directory. */ #define ENOTEMPTY 58 /* 目录非空 Directory not empty. */ -#define ENOTRECOVERABLE 59 /* 状态不可覆盖 State not recoverable. */ +#define ENOTRECOVERABLE 59 /* 状态不可恢复 State not recoverable. */ -#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/ -#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */ -#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */ -#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */ -#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */ -#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */ -#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */ -#define EPERM 67 /* 操作不被允许 Operation not permitted. */ -#define EPIPE 68 /* 断开的管道 Broken pipe. */ -#define EPROTO 69 /* 协议错误 Protocol error. */ +#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/ +#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */ +#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */ +#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */ +#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */ +#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */ +#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */ +#define EPERM 67 /* 操作不被允许 Operation not permitted. */ +#define EPIPE 68 /* 断开的管道 Broken pipe. */ +#define EPROTO 69 /* 协议错误 Protocol error. */ #define EPROTONOSUPPORT 70 /* 协议不被支持 Protocol not supported. */ #define EPROTOTYPE 71 /* 对于套接字而言,错误的协议 Protocol wrong type for socket. */ #define ERANGE 72 /* 结果过大 Result too large. */ #define EROFS 73 /* 只读的文件系统 Read-only file system. */ -#define ESPIPE 74 /* 错误的寻道 Invalid seek. */ +#define ESPIPE 74 /* 错误的寻道.当前文件是pipe,不允许seek请求 Invalid seek. */ #define ESRCH 75 /* 没有这样的进程 No such process. */ #define ESTALE 76 /* 保留 Reserved. */ #define ETIME 77 /* 流式ioctl()超时 Stream ioctl() timeout */ #define ETIMEDOUT 78 /* 连接超时 Connection timed out.*/ #define ETXTBSY 79 /* 文本文件忙 Text file busy. */ -#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */ -#define EXDEV 81 /* 跨设备连接 Cross-device link. */ \ No newline at end of file +#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */ +#define EXDEV 81 /* 跨设备连接 Cross-device link. */ diff --git a/kernel/src/common/fcntl.h b/kernel/src/common/fcntl.h index 1c0226b8..ab25668f 100644 --- a/kernel/src/common/fcntl.h +++ b/kernel/src/common/fcntl.h @@ -25,10 +25,14 @@ #define O_NONBLOCK 00004000 // 非阻塞式IO模式 -#define O_EXEC 00010000 // 以仅执行的方式打开(非目录文件) -#define O_SEARCH 00020000 // Open the directory for search only -#define O_DIRECTORY 00040000 // 打开的必须是一个目录 -#define O_NOFOLLOW 00100000 // Do not follow symbolic links +#define O_DSYNC 00010000 // used to be O_SYNC, see below +#define FASYNC 00020000 // fcntl, for BSD compatibility +#define O_DIRECT 00040000 // direct disk access hint +#define O_LARGEFILE 00100000 +#define O_DIRECTORY 00200000 // 打开的必须是一个目录 +#define O_NOFOLLOW 00400000 // Do not follow symbolic links +#define O_NOATIME 01000000 +#define O_CLOEXEC 02000000 // set close_on_exec /* * The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is diff --git a/kernel/src/common/lockref.h b/kernel/src/common/lockref.h index c700c8f1..75a31bba 100644 --- a/kernel/src/common/lockref.h +++ b/kernel/src/common/lockref.h @@ -33,8 +33,8 @@ void lockref_inc(struct lockref *lock_ref); * @brief 原子地将引用计数加1.如果原来的count≤0,则操作失败。 * * @param lock_ref 指向要被操作的lockref变量的指针 - * @return int 操作成功=>true - * 操作失败=>false + * @return bool 操作成功=>true + * 操作失败=>false */ bool lockref_inc_not_zero(struct lockref *lock_ref); diff --git a/kernel/src/common/time.h b/kernel/src/common/time.h index 63aec605..0142c33d 100644 --- a/kernel/src/common/time.h +++ b/kernel/src/common/time.h @@ -24,8 +24,8 @@ struct tm struct timespec { - long int tv_sec; // 秒 - long long tv_nsec; // 纳秒 + int64_t tv_sec; // 秒 + int64_t tv_nsec; // 纳秒 }; /** diff --git a/kernel/src/driver/disk/ahci/ahci.c b/kernel/src/driver/disk/ahci/ahci.c index 3f50a45a..4da4d54b 100644 --- a/kernel/src/driver/disk/ahci/ahci.c +++ b/kernel/src/driver/disk/ahci/ahci.c @@ -1,636 +1,32 @@ #include "ahci.h" #include #include -#include -#include -#include #include #include -#include #include #include -struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES]; - -struct blk_gendisk ahci_gendisk0 = {0}; // 暂时硬性指定一个ahci_device -static int __first_port = -1; // 临时用于存储 ahci控制器的第一个可用端口 的变量 - -static uint32_t count_ahci_devices = 0; - -static uint64_t ahci_port_base_vaddr; // 端口映射base addr -static uint64_t ahci_port_base_phys_addr; // 端口映射的物理基地址(ahci控制器的参数的地址都是物理地址) - -static void start_cmd(HBA_PORT *port); -static void stop_cmd(HBA_PORT *port); -static void port_rebase(HBA_PORT *port, int portno); - -// 计算HBA_MEM的虚拟内存地址 -#define cal_HBA_MEM_VIRT_ADDR(device_num) (AHCI_MAPPING_BASE + (ul)(((struct pci_device_structure_general_device_t *)(ahci_devs[device_num]))->BAR5 - ((((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5) & PAGE_2M_MASK))) - -long ahci_open(); -long ahci_close(); -static long ahci_ioctl(long cmd, long arg); -static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf); - -struct block_device_operation ahci_operation = - { - .open = ahci_open, - .close = ahci_close, - .ioctl = ahci_ioctl, - .transfer = ahci_transfer, -}; - -/** - * @brief ahci驱动器在block_device中的私有数据结构体 - * - */ -struct ahci_blk_private_data -{ - uint16_t ahci_ctrl_num; // ahci控制器号 - uint16_t ahci_port_num; // ahci端口号 - struct MBR_disk_partition_table_t *part_table; // 分区表 -}; - -/** - * @brief 申请ahci设备的私有信息结构体 - * - * @return struct ahci_blk_private_data* 申请到的私有信息结构体 - */ -static struct ahci_blk_private_data *__alloc_private_data() -{ - struct ahci_blk_private_data *data = (struct ahci_blk_private_data *)kzalloc(sizeof(struct ahci_blk_private_data), 0); - data->part_table = (struct MBR_disk_partition_table_t *)kzalloc(512, 0); - return data; -} - -/** - * @brief 释放ahci设备的分区的私有信息结构体 - * - * @param pdata 待释放的结构体 - * @return int 错误码 - */ -static int __release_private_data(struct ahci_blk_private_data *pdata) -{ - kfree(pdata->part_table); - kfree(pdata); - return 0; -} - -/** - * @brief 初始化gendisk结构体(暂时只支持1个gendisk) - * - */ -static int ahci_init_gendisk() -{ - memset(&ahci_gendisk0, 0, sizeof(ahci_gendisk0)); - strcpy(ahci_gendisk0.disk_name, "ahci0"); - ahci_gendisk0.flags = BLK_GF_AHCI; - ahci_gendisk0.fops = &ahci_operation; - mutex_init(&ahci_gendisk0.open_mutex); - - // 为存储分区结构,分配内存空间 - ahci_gendisk0.private_data = __alloc_private_data(); - // 读取分区表 - // 暂时假设全都是MBR分区表的 - // todo: 支持GPT - - ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->ahci_ctrl_num = 0; - ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->ahci_port_num = __first_port; - - MBR_read_partition_table(&ahci_gendisk0, ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->part_table); - - struct MBR_disk_partition_table_t *ptable = ((struct ahci_blk_private_data *)ahci_gendisk0.private_data)->part_table; - - // 求出可用分区数量 - for (int i = 0; i < 4; ++i) - { - // 分区可用 - if (ptable->DPTE[i].type != 0) - ++ahci_gendisk0.part_cnt; - } - if (ahci_gendisk0.part_cnt) - { - // 分配分区结构体数组的空间 - ahci_gendisk0.partition = (struct block_device *)kzalloc(ahci_gendisk0.part_cnt * sizeof(struct block_device), 0); - int cnt = 0; - // 循环遍历每个分区 - for (int i = 0; i < 4; ++i) - { - // 分区可用 - if (ptable->DPTE[i].type != 0) - { - // 初始化分区结构体 - ahci_gendisk0.partition[cnt].bd_disk = &ahci_gendisk0; - ahci_gendisk0.partition[cnt].bd_partno = cnt; - // FIXME 需要注释 - ahci_gendisk0.partition[cnt].bd_sectors_num = ptable->DPTE[i].total_sectors; - ahci_gendisk0.partition[cnt].bd_start_sector = ptable->DPTE[i].starting_sector; - ahci_gendisk0.partition[cnt].bd_superblock = NULL; // 挂载文件系统时才会初始化superblock - ahci_gendisk0.partition[cnt].bd_start_LBA = ptable->DPTE[i].starting_LBA; - ++cnt; - } - } - } - - return 0; -}; - -/** - * @brief 初始化ahci模块 - * - */ -void ahci_init() +/// @brief 保留了对 pci设备获取 和 mm内存映射 的依赖 +void ahci_cpp_init(uint32_t *count_ahci_devices, struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES], struct pci_device_structure_general_device_t *gen_devs[MAX_AHCI_DEVICES]) { kinfo("Initializing AHCI..."); - pci_get_device_structure(0x1, 0x6, ahci_devs, &count_ahci_devices); - if (count_ahci_devices == 0) + pci_get_device_structure(0x1, 0x6, ahci_devs, count_ahci_devices); + + if (*count_ahci_devices == 0) { kwarn("There is no AHCI device found on this computer!"); return; } + + for (int i = 0; i < *count_ahci_devices; i++) + { + gen_devs[i] = ((struct pci_device_structure_general_device_t *)(ahci_devs[i])); + } + // 映射ABAR - kdebug("phys_2_virt(ahci_devs[0])= %#018lx", (ahci_devs[0])); - kdebug("((struct pci_device_structure_general_device_t *)phys_2_virt(ahci_devs[0])))->BAR5= %#018lx", ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5); - uint32_t bar5 = ((struct pci_device_structure_general_device_t *)(ahci_devs[0]))->BAR5; - + uint32_t bar5 = gen_devs[0]->BAR5; mm_map_phys_addr(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, false); - kdebug("ABAR mapped!"); - for (int i = 0; i < count_ahci_devices; ++i) - { - // kdebug("[%d] class_code=%d, sub_class=%d, progIF=%d, ABAR=%#010lx", i, ahci_devs[i]->Class_code, ahci_devs[i]->SubClass, ahci_devs[i]->ProgIF, ((struct pci_device_structure_general_device_t *)(ahci_devs[i]))->BAR5); - // 赋值HBA_MEM结构体 - ahci_devices[i].dev_struct = ahci_devs[i]; - ahci_devices[i].hba_mem = (HBA_MEM *)(cal_HBA_MEM_VIRT_ADDR(i)); - kdebug("ahci_devices[i].hba_mem = %#018lx", (ul)ahci_devices[i].hba_mem); - } - // todo: 支持多个ahci控制器。 - ahci_port_base_vaddr = (uint64_t)kmalloc(1048576, 0); - kdebug("ahci_port_base_vaddr=%#018lx", ahci_port_base_vaddr); - ahci_probe_port(0); - - BUG_ON(ahci_init_gendisk() != 0); - kinfo("AHCI initialized."); -} - -// Check device type -static int check_type(HBA_PORT *port) -{ - uint32_t ssts = port->ssts; - - uint8_t ipm = (ssts >> 8) & 0x0F; - uint8_t det = ssts & 0x0F; - - if (det != HBA_PORT_DET_PRESENT) // Check drive status - return AHCI_DEV_NULL; - if (ipm != HBA_PORT_IPM_ACTIVE) - return AHCI_DEV_NULL; - - switch (port->sig) - { - case SATA_SIG_ATAPI: - return AHCI_DEV_SATAPI; - case SATA_SIG_SEMB: - return AHCI_DEV_SEMB; - case SATA_SIG_PM: - return AHCI_DEV_PM; - default: - return AHCI_DEV_SATA; - } -} - -/** - * @brief 检测端口连接的设备的类型 - * - * @param device_num ahci控制器号 - */ -static void ahci_probe_port(const uint32_t device_num) -{ - HBA_MEM *abar = ahci_devices[device_num].hba_mem; - uint32_t pi = abar->pi; - - for (int i = 0; i < 32; ++i, (pi >>= 1)) - { - if (pi & 1) - { - uint dt = check_type(&abar->ports[i]); - ahci_devices[i].type = dt; - switch (dt) - { - case AHCI_DEV_SATA: - kdebug("SATA drive found at port %d", i); - goto found; - case AHCI_DEV_SATAPI: - kdebug("SATAPI drive found at port %d", i); - goto found; - case AHCI_DEV_SEMB: - kdebug("SEMB drive found at port %d", i); - goto found; - case AHCI_DEV_PM: - kdebug("PM drive found at port %d", i); - goto found; - found:; - port_rebase(&ahci_devices[0].hba_mem->ports[i], i); - if (__first_port == -1) - __first_port = i; - break; - default: - kdebug("No drive found at port %d", i); - break; - } - } - } -} - -// Start command engine -static void start_cmd(HBA_PORT *port) -{ - // Wait until CR (bit15) is cleared - while ((port->cmd) & HBA_PxCMD_CR) - ; - - // Set FRE (bit4) and ST (bit0) - port->cmd |= HBA_PxCMD_FRE; - port->cmd |= HBA_PxCMD_ST; -} - -// Stop command engine -static void stop_cmd(HBA_PORT *port) -{ - // Clear ST (bit0) - port->cmd &= ~HBA_PxCMD_ST; - - // Clear FRE (bit4) - port->cmd &= ~HBA_PxCMD_FRE; - - // Wait until FR (bit14), CR (bit15) are cleared - while (1) - { - if (port->cmd & HBA_PxCMD_FR) - continue; - if (port->cmd & HBA_PxCMD_CR) - continue; - break; - } -} - -static void port_rebase(HBA_PORT *port, int portno) -{ - - // Before rebasing Port memory space, OS must wait for current pending commands to finish - // and tell HBA to stop receiving FIS from the port. Otherwise an accidently incoming FIS may be - // written into a partially configured memory area. - - stop_cmd(port); // Stop command engine - - // Command list offset: 1K*portno - // Command list entry size = 32 - // Command list entry maxim count = 32 - // Command list maxim size = 32*32 = 1K per port - - port->clb = virt_2_phys(ahci_port_base_vaddr + (portno << 10)); - - memset((void *)(phys_2_virt(port->clb)), 0, 1024); - - // FIS offset: 32K+256*portno - // FIS entry size = 256 bytes per port - port->fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (portno << 8)); - - memset((void *)(phys_2_virt(port->fb)), 0, 256); - - // Command table offset: 40K + 8K*portno - // Command table size = 256*32 = 8K per port - HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)(phys_2_virt(port->clb)); - for (int i = 0; i < 32; ++i) - { - cmdheader[i].prdtl = 8; // 8 prdt entries per command table - // 256 bytes per command table, 64+16+48+16*8 - // Command table offset: 40K + 8K*portno + cmdheader_index*256 - cmdheader[i].ctba = virt_2_phys((ahci_port_base_vaddr + (40 << 10) + (portno << 13) + (i << 8))); - - memset((void *)phys_2_virt(cmdheader[i].ctba), 0, 256); - } - - start_cmd(port); // Start command engine -} - -/** - * @brief read data from SATA device using 48bit LBA address - * - * @param port HBA PORT - * @param startl low 32bits of start addr - * @param starth high 32bits of start addr - * @param count total sectors to read - * @param buf buffer - * @param ret_slot 执行命令的插槽号(传出参数) - * @return true done - * @return false failed - */ -static int ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf, int8_t *ret_slot) -{ - port->is = (uint32_t)-1; // Clear pending interrupt bits - - int spin = 0; // Spin lock timeout counter - int slot = ahci_find_cmdslot(port); - - if (slot == -1) - return E_NOEMPTYSLOT; - if (ret_slot) - { - *ret_slot = slot; - } - - HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb); - cmdheader += slot; - cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // Command FIS size - cmdheader->w = 0; // Read from device - cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count - - HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba); - memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY)); - - // 8K bytes (16 sectors) per PRDT - int i; - for (i = 0; i < cmdheader->prdtl - 1; ++i) - { - cmdtbl->prdt_entry[i].dba = virt_2_phys(buf); - cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes (this value should always be set to 1 less than the actual value) - cmdtbl->prdt_entry[i].i = 1; - buf += 4 * 1024; // 4K uint16_ts - count -= 16; // 16 sectors - } - - // Last entry - cmdtbl->prdt_entry[i].dba = virt_2_phys(buf); - cmdtbl->prdt_entry[i].dbc = (count << 9) - 1; // 512 bytes per sector - cmdtbl->prdt_entry[i].i = 1; - - // Setup command - FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis); - - cmdfis->fis_type = FIS_TYPE_REG_H2D; - cmdfis->c = 1; // Command - cmdfis->command = AHCI_CMD_READ_DMA_EXT; - - cmdfis->lba0 = (uint8_t)startl; - cmdfis->lba1 = (uint8_t)(startl >> 8); - cmdfis->lba2 = (uint8_t)(startl >> 16); - cmdfis->device = 1 << 6; // LBA mode - - cmdfis->lba3 = (uint8_t)(startl >> 24); - cmdfis->lba4 = (uint8_t)starth; - cmdfis->lba5 = (uint8_t)(starth >> 8); - - cmdfis->countl = count & 0xFF; - cmdfis->counth = (count >> 8) & 0xFF; - - // The below loop waits until the port is no longer busy before issuing a new command - while ((port->tfd & (AHCI_DEV_BUSY | AHCI_DEV_DRQ)) && spin < 1000000) - { - spin++; - } - if (spin == 1000000) - { - kerror("Port is hung"); - return E_PORT_HUNG; - } - - port->ci = 1 << slot; // Issue command - - return 0; -} - -/** - * @brief 检查请求包是否已完成 - * - * @param port_num HBA PORT 编号 - * @param ahci_ctrl_num ahci控制号 - * @param ret_slot 执行命令的插槽号 - * @param err 错误信息 - */ -int ahci_check_complete(uint8_t port_num, uint8_t ahci_ctrl_num, int8_t slot, char *err) -{ - - HBA_PORT *port = ahci_get_port(port_num, ahci_ctrl_num); - int retval = -EBUSY; - if (slot == -1) - retval = -EINVAL; - // In some longer duration reads, it may be helpful to spin on the DPS bit - // in the PxIS port field as well (1 << 5) - if ((port->ci & (1 << slot)) == 0) - retval = 0; - if (port->is & HBA_PxIS_TFES) // Task file error - { - if (err != NULL) - kerror(*err); - retval = E_TASK_FILE_ERROR; - } - return retval; -} - -/** - * @brief write data to SATA device using 48bit LBA address - * - * @param port HBA PORT - * @param startl low 32bits of start addr - * @param starth high 32bits of start addr - * @param count total sectors to read - * @param buf buffer - * @param ret_slot 执行命令的插槽号(传出参数) - * @return success 0 - */ -static int ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, - uint64_t buf, int8_t *ret_slot) -{ - port->is = 0xffff; // Clear pending interrupt bits - int slot = ahci_find_cmdslot(port); - if (slot == -1) - return E_NOEMPTYSLOT; - if (ret_slot) - { - *ret_slot = slot; - } - HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)phys_2_virt(port->clb); - - cmdheader += slot; - cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32_t); // Command FIS size - cmdheader->w = 1; - cmdheader->c = 1; - cmdheader->p = 1; - cmdheader->prdtl = (uint16_t)((count - 1) >> 4) + 1; // PRDT entries count - - HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL *)phys_2_virt(cmdheader->ctba); - memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl - 1) * sizeof(HBA_PRDT_ENTRY)); - - int i = 0; - for (i = 0; i < cmdheader->prdtl - 1; ++i) - { - cmdtbl->prdt_entry[i].dba = virt_2_phys(buf); - cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes - cmdtbl->prdt_entry[i].i = 0; - buf += 4 * 1024; // 4K words - count -= 16; // 16 sectors - } - cmdtbl->prdt_entry[i].dba = virt_2_phys(buf); - - cmdtbl->prdt_entry[i].dbc = count << 9; // 512 bytes per sector - cmdtbl->prdt_entry[i].i = 0; - FIS_REG_H2D *cmdfis = (FIS_REG_H2D *)(&cmdtbl->cfis); - cmdfis->fis_type = FIS_TYPE_REG_H2D; - cmdfis->c = 1; // Command - cmdfis->command = AHCI_CMD_WRITE_DMA_EXT; - cmdfis->lba0 = (uint8_t)startl; - cmdfis->lba1 = (uint8_t)(startl >> 8); - cmdfis->lba2 = (uint8_t)(startl >> 16); - cmdfis->lba3 = (uint8_t)(startl >> 24); - cmdfis->lba4 = (uint8_t)starth; - cmdfis->lba5 = (uint8_t)(starth >> 8); - - cmdfis->device = 1 << 6; // LBA mode - - cmdfis->countl = count & 0xff; - cmdfis->counth = count >> 8; - port->ci = 1; // Issue command - - return 0; -} - -// Find a free command list slot -int ahci_find_cmdslot(HBA_PORT *port) -{ - // If not set in SACT and CI, the slot is free - uint32_t slots = (port->sact | port->ci); - int num_of_cmd_clots = (ahci_devices[0].hba_mem->cap & 0x0f00) >> 8; // bit 12-8 - for (int i = 0; i < num_of_cmd_clots; i++) - { - if ((slots & 1) == 0) - return i; - slots >>= 1; - } - kerror("Cannot find free command list entry"); - return -1; -} - -long ahci_open() -{ - return 0; -} - -long ahci_close() -{ - return 0; -} - -/** - * @brief 创建ahci磁盘请求包 - * - * @param cmd 控制命令 - * @param base_addr 48位LBA地址 - * @param count total sectors to read - * @param buf 缓冲区线性地址 - * @param ahci_ctrl_num ahci控制器号 - * @param port_num ahci控制器端口号 - * @return struct block_device_request_packet* - */ -static struct ahci_request_packet_t *ahci_make_request(long cmd, uint64_t base_addr, uint64_t count, uint64_t buffer, uint8_t ahci_ctrl_num, uint8_t port_num) -{ - struct ahci_request_packet_t *pack = (struct ahci_request_packet_t *)kzalloc(sizeof(struct ahci_request_packet_t), 0); - pack->blk_pak.device_type = BLK_TYPE_AHCI; - - // 由于ahci不需要中断即可读取磁盘,因此end handler为空 - switch (cmd) - { - case AHCI_CMD_READ_DMA_EXT: - pack->blk_pak.end_handler = NULL; - pack->blk_pak.cmd = AHCI_CMD_READ_DMA_EXT; - break; - case AHCI_CMD_WRITE_DMA_EXT: - pack->blk_pak.end_handler = NULL; - pack->blk_pak.cmd = AHCI_CMD_WRITE_DMA_EXT; - break; - default: - pack->blk_pak.end_handler = NULL; - pack->blk_pak.cmd = cmd; - break; - } - - pack->blk_pak.LBA_start = base_addr; - pack->blk_pak.count = count; - pack->blk_pak.buffer_vaddr = buffer; - pack->ahci_ctrl_num = ahci_ctrl_num; - pack->port_num = port_num; - return pack; -} - -long ahci_query_disk(struct ahci_request_packet_t *pack, int8_t *ret_slot) -{ - - long ret_val = 0; - switch (pack->blk_pak.cmd) - { - case AHCI_CMD_READ_DMA_EXT: - ret_val = ahci_read(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr, ret_slot); - break; - case AHCI_CMD_WRITE_DMA_EXT: - ret_val = ahci_write(&(ahci_devices[pack->ahci_ctrl_num].hba_mem->ports[pack->port_num]), pack->blk_pak.LBA_start & 0xFFFFFFFF, ((pack->blk_pak.LBA_start) >> 32) & 0xFFFFFFFF, pack->blk_pak.count, pack->blk_pak.buffer_vaddr, ret_slot); - break; - default: - kerror("Unsupport ahci command: %#05lx", pack->blk_pak.cmd); - ret_val = E_UNSUPPORTED_CMD; - break; - } - - return ret_val; -} - -/** - * @brief ahci驱动程序的传输函数 - * - * @param gd 磁盘设备结构体 - * @param cmd 控制命令 - * @param base_addr 48位LBA地址 - * @param count total sectors to read - * @param buf 缓冲区线性地址 - * @return long - */ -static long ahci_transfer(struct blk_gendisk *gd, long cmd, uint64_t base_addr, uint64_t count, uint64_t buf) -{ - struct ahci_request_packet_t *pack = NULL; - struct ahci_blk_private_data *pdata = (struct ahci_blk_private_data *)gd->private_data; - - if (cmd == AHCI_CMD_READ_DMA_EXT || cmd == AHCI_CMD_WRITE_DMA_EXT) - { - pack = ahci_make_request(cmd, base_addr, count, buf, pdata->ahci_ctrl_num, pdata->ahci_port_num); - ahci_push_request(pack); - } - else - { - kdebug("ahci_transfer: E_UNSUPPORTED_CMD"); - return E_UNSUPPORTED_CMD; - } - - return AHCI_SUCCESS; -} - -/** - * @brief todo: io控制器函数 - * - * @param cmd 命令 - * @param arg 参数 - * @return long - */ -static long ahci_ioctl(long cmd, long arg) -{ - return 0; -} - -/** - * @brief 根据端口号获取端口结构体 - * @param port_num 端口号 - * @param ahci_ctrl_num 控制号 - */ -HBA_PORT *ahci_get_port(uint8_t port_num, uint8_t ahci_ctrl_num) -{ - return &(ahci_devices[ahci_ctrl_num].hba_mem->ports[port_num]); + kinfo("ABAR mapped!"); } diff --git a/kernel/src/driver/disk/ahci/ahci.h b/kernel/src/driver/disk/ahci/ahci.h index 0863a152..d518a541 100644 --- a/kernel/src/driver/disk/ahci/ahci.h +++ b/kernel/src/driver/disk/ahci/ahci.h @@ -363,70 +363,4 @@ struct ahci_request_packet_t * @brief 初始化ahci模块 * */ -void ahci_init(); - -/** - * @brief 检测端口连接的设备的类型 - * - * @param device_num ahci设备号 - */ -static void ahci_probe_port(const uint32_t device_num); - -/** - * @brief read data from SATA device using 48bit LBA address - * - * @param port HBA PORT - * @param startl low 32bits of start addr - * @param starth high 32bits of start addr - * @param count total sectors to read - * @param buf buffer - * @param ret_slot 执行命令的插槽号(传出参数) - * @return success 0 - */ -static int ahci_read(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, uint64_t buf, int8_t *ret_slot); - -/** - * @brief write data to SATA device using 48bit LBA address - * - * @param port HBA PORT - * @param startl low 32bits of start addr - * @param starth high 32bits of start addr - * @param count total sectors to read - * @param buf buffer - * @param ret_slot 执行命令的插槽号(传出参数) - * @return success 0 - */ -static int ahci_write(HBA_PORT *port, uint32_t startl, uint32_t starth, uint32_t count, - uint64_t buf, int8_t *ret_slot); - -void ahci_end_request(); - -/** - * @brief 检查请求包是否已完成 - * - * @param port_num HBA PORT 编号 - * @param ahci_ctrl_num ahci控制号 - * @param ret_slot 执行命令的插槽号 - * @param err 错误信息 - */ -int ahci_check_complete(uint8_t port_num, uint8_t ahci_ctrl_num, int8_t slot, char *err); - -/** - * @brief 根据端口号获取端口结构体 - * @param port_num 端口号 - * @param ahci_ctrl_num 控制号 - */ -HBA_PORT *ahci_get_port(uint8_t port_num, uint8_t ahci_ctrl_num); - -/** - * @brief Find a free command list slot - * @param port - */ -int ahci_find_cmdslot(HBA_PORT *port); - -/** - * @brief 读取磁盘信息 - * @param pack io请求包 - * @param ret_slot 执行命令的插槽号(传出参数) - */ -long ahci_query_disk(struct ahci_request_packet_t *pack, int8_t *ret_slot); +extern void ahci_init(); diff --git a/kernel/src/driver/disk/ahci/ahci_inode.rs b/kernel/src/driver/disk/ahci/ahci_inode.rs new file mode 100644 index 00000000..7fec3227 --- /dev/null +++ b/kernel/src/driver/disk/ahci/ahci_inode.rs @@ -0,0 +1,155 @@ +use crate::filesystem::devfs::{DevFS, DeviceINode}; +use crate::filesystem::vfs::{ + core::generate_inode_id, make_rawdev, FilePrivateData, FileSystem, FileType, IndexNode, + Metadata, PollStatus, +}; +use crate::io::device::BlockDevice; +use crate::{ + include::bindings::bindings::{EINVAL, ENOTSUP}, + libs::spinlock::SpinLock, + time::TimeSpec, +}; +use alloc::{ + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; + +use super::ahcidisk::LockedAhciDisk; + +#[derive(Debug)] +pub struct AhciInode { + /// uuid 暂时不知道有什么用(x + // uuid: Uuid, + /// 指向自身的弱引用 + self_ref: Weak, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + /// INode 元数据 + metadata: Metadata, + /// INode 对应的磁盘 + disk: Arc, +} + +#[derive(Debug)] +pub struct LockedAhciInode(pub SpinLock); + +impl LockedAhciInode { + pub fn new(disk: Arc) -> Arc { + let inode = AhciInode { + // uuid: Uuid::new_v5(), + self_ref: Weak::default(), + fs: Weak::default(), + disk: disk, + metadata: Metadata { + dev_id: 1, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::BlockDevice, // 文件夹,block设备,char设备 + mode: 0o666, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: make_rawdev(1, 3), // 这里用来作为device number + }, + }; + + let result = Arc::new(LockedAhciInode(SpinLock::new(inode))); + result.0.lock().self_ref = Arc::downgrade(&result); + + return result; + } +} + +impl DeviceINode for LockedAhciInode { + fn set_fs(&self, fs: Weak) { + self.0.lock().fs = fs; + } +} + +impl IndexNode for LockedAhciInode { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + Err(-(ENOTSUP as i32)) + } + + fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + Err(-(ENOTSUP as i32)) + } + + fn metadata(&self) -> Result { + return Ok(self.0.lock().metadata.clone()); + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn list(&self) -> Result, i32> { + Err(-(ENOTSUP as i32)) + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn poll(&self) -> Result { + return Ok(PollStatus { + flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK, + }); + } + + /// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn read_at( + &self, + offset: usize, // lba地址 + len: usize, + buf: &mut [u8], + data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + if let FilePrivateData::Unused = data { + return self.0.lock().disk.read_at(offset, len, buf); + } + + return Err(-(EINVAL as i32)); + } + + /// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn write_at( + &self, + offset: usize, // lba地址 + len: usize, + buf: &[u8], + data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + if let FilePrivateData::Unused = data { + return self.0.lock().disk.write_at(offset, len, buf); + } + + return Err(-(EINVAL as i32)); + } +} diff --git a/kernel/src/driver/disk/ahci/ahci_rust.h b/kernel/src/driver/disk/ahci/ahci_rust.h new file mode 100644 index 00000000..8d37743a --- /dev/null +++ b/kernel/src/driver/disk/ahci/ahci_rust.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 计算HBA_MEM的虚拟内存地址 +#define MAX_AHCI_DEVICES 100 +#define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + AHCI_MAPPING_OFFSET + +/// @brief 保留了对 pci设备获取 和 mm内存映射 的依赖 +void ahci_cpp_init(uint32_t *count_ahci_devices, struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES], struct pci_device_structure_general_device_t *gen_devs[MAX_AHCI_DEVICES]); \ No newline at end of file diff --git a/kernel/src/driver/disk/ahci/ahcidisk.rs b/kernel/src/driver/disk/ahci/ahcidisk.rs new file mode 100644 index 00000000..03a51c34 --- /dev/null +++ b/kernel/src/driver/disk/ahci/ahcidisk.rs @@ -0,0 +1,441 @@ +use super::{_port, hba::HbaCmdTable, virt_2_phys}; +use crate::driver::disk::ahci::HBA_PxIS_TFES; +use crate::filesystem::mbr::MbrDiskPartionTable; +use crate::include::bindings::bindings::{E2BIG, EIO}; +use crate::io::{device::BlockDevice, disk_info::Partition, SeekFrom}; + +use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor}; +use crate::mm::phys_2_virt; +use crate::{ + driver::disk::ahci::hba::{ + FisRegH2D, FisType, HbaCmdHeader, ATA_CMD_READ_DMA_EXT, ATA_CMD_WRITE_DMA_EXT, + ATA_DEV_BUSY, ATA_DEV_DRQ, + }, + kerror, +}; + +use alloc::sync::Weak; +use alloc::{string::String, sync::Arc, vec::Vec}; + +use core::fmt::Debug; +use core::sync::atomic::compiler_fence; +use core::{mem::size_of, ptr::write_bytes}; + +/// @brief: 只支持MBR分区格式的磁盘结构体 +pub struct AhciDisk { + pub name: String, + pub flags: u16, // 磁盘的状态flags + pub partitions: Vec>, // 磁盘分区数组 + // port: &'static mut HbaPort, // 控制硬盘的端口 + pub ctrl_num: u8, + pub port_num: u8, + /// 指向LockAhciDisk的弱引用 + self_ref: Weak, +} + +/// @brief: 带锁的AhciDisk +#[derive(Debug)] +pub struct LockedAhciDisk(pub SpinLock); +/// 函数实现 +impl Debug for AhciDisk { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{{ name: {}, flags: {}, part_s: {:?} }}", + self.name, self.flags, self.partitions + )?; + return Ok(()); + } +} + +impl AhciDisk { + fn read_at( + &self, + lba_id_start: crate::io::device::BlockId, // 起始lba编号 + count: usize, // 读取lba的数量 + buf: &mut [u8], + ) -> Result { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let check_length = ((count - 1) >> 4) + 1; // prdt length + if count * 512 > buf.len() || check_length > u16::MAX as usize { + kerror!("ahci read: e2big"); + // 不可能的操作 + return Err(-(E2BIG as i32)); + } else if count == 0 { + return Ok(0); + } + + let port = _port(self.ctrl_num, self.port_num); + volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits + + let slot = port.find_cmdslot().unwrap_or(u32::MAX); + + if slot == u32::MAX { + return Err(-(EIO as i32)); + } + + #[allow(unused_unsafe)] + let cmdheader: &mut HbaCmdHeader = unsafe { + (phys_2_virt( + volatile_read!(port.clb) as usize + + slot as usize * size_of::() as usize, + ) as *mut HbaCmdHeader) + .as_mut() + .unwrap() + }; + + volatile_write_bit!( + cmdheader.cfl, + (1 << 5) - 1 as u8, + (size_of::() / size_of::()) as u8 + ); // Command FIS size + + volatile_set_bit!(cmdheader.cfl, 1 << 6, false); // Read/Write bit : Read from device + volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count + + // 设置数据存放地址 + let mut buf_ptr = buf as *mut [u8] as *mut usize as usize; + #[allow(unused_unsafe)] + let cmdtbl = unsafe { + (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable) + .as_mut() + .unwrap() // 必须使用 as_mut ,得到的才是原来的变量 + }; + let mut tmp_count = count; + + unsafe { + // 清空整个table的旧数据 + write_bytes(cmdtbl, 0, 1); + } + + // 8K bytes (16 sectors) per PRDT + for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) { + volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64); + volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度 prdt_entry.dbc + volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 prdt_entry.i + buf_ptr += 8 * 1024; + tmp_count -= 16; + } + + // Last entry + let las = (volatile_read!(cmdheader.prdtl) - 1) as usize; + volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64); + volatile_write_bit!( + cmdtbl.prdt_entry[las].dbc, + (1 << 22) - 1, + ((tmp_count << 9) - 1) as u32 + ); // 数据长度 + volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断 + + // 设置命令 + let cmdfis = unsafe { + ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D) + .as_mut() + .unwrap() + }; + volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8); + volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set + volatile_write!(cmdfis.command, ATA_CMD_READ_DMA_EXT); + + volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8); + volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8); + volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8); + volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8); + volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8); + volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8); + + volatile_write!(cmdfis.countl, (count & 0xFF) as u8); + volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8); + + volatile_write!(cmdfis.device, 1 << 6); // LBA Mode + + // 等待之前的操作完成 + let mut spin_count = 0; + const SPIN_LIMIT: u32 = 10000; + + while (volatile_read!(port.tfd) as u8 & (ATA_DEV_BUSY | ATA_DEV_DRQ)) > 0 + && spin_count < SPIN_LIMIT + { + spin_count += 1; + } + + if spin_count == SPIN_LIMIT { + kerror!("Port is hung"); + return Err(-(EIO as i32)); + } + + volatile_set_bit!(port.ci, 1 << slot, true); // Issue command + // kdebug!("To wait ahci read complete."); + // 等待操作完成 + loop { + if (volatile_read!(port.ci) & (1 << slot)) == 0 { + break; + } + if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 { + kerror!("Read disk error"); + return Err(-(EIO as i32)); + } + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // successfully read + return Ok(count * 512); + } + + fn write_at( + &self, + lba_id_start: crate::io::device::BlockId, + count: usize, + buf: &[u8], + ) -> Result { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let check_length = ((count - 1) >> 4) + 1; // prdt length + if count * 512 > buf.len() || check_length > u16::MAX as usize { + // 不可能的操作 + return Err(-(E2BIG as i32)); + } else if count == 0 { + return Ok(0); + } + + let port = _port(self.ctrl_num, self.port_num); + + volatile_write!(port.is, u32::MAX); // Clear pending interrupt bits + + let slot = port.find_cmdslot().unwrap_or(u32::MAX); + + if slot == u32::MAX { + return Err(-(EIO as i32)); + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + #[allow(unused_unsafe)] + let cmdheader: &mut HbaCmdHeader = unsafe { + (phys_2_virt( + volatile_read!(port.clb) as usize + + slot as usize * size_of::() as usize, + ) as *mut HbaCmdHeader) + .as_mut() + .unwrap() + }; + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + volatile_write_bit!( + cmdheader.cfl, + (1 << 5) - 1 as u8, + (size_of::() / size_of::()) as u8 + ); // Command FIS size + + volatile_set_bit!(cmdheader.cfl, 7 << 5, true); // (p,c,w)都设置为1, Read/Write bit : Write from device + volatile_write!(cmdheader.prdtl, check_length as u16); // PRDT entries count + + // 设置数据存放地址 + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let mut buf_ptr = buf as *const [u8] as *mut usize as usize; + #[allow(unused_unsafe)] + let cmdtbl = unsafe { + (phys_2_virt(volatile_read!(cmdheader.ctba) as usize) as *mut HbaCmdTable) + .as_mut() + .unwrap() + }; + let mut tmp_count = count; + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + unsafe { + // 清空整个table的旧数据 + write_bytes(cmdtbl, 0, 1); + } + + // 8K bytes (16 sectors) per PRDT + for i in 0..((volatile_read!(cmdheader.prdtl) - 1) as usize) { + volatile_write!(cmdtbl.prdt_entry[i].dba, virt_2_phys(buf_ptr) as u64); + volatile_write_bit!(cmdtbl.prdt_entry[i].dbc, (1 << 22) - 1, 8 * 1024 - 1); // 数据长度 + volatile_set_bit!(cmdtbl.prdt_entry[i].dbc, 1 << 31, true); // 允许中断 + buf_ptr += 8 * 1024; + tmp_count -= 16; + } + + // Last entry + let las = (volatile_read!(cmdheader.prdtl) - 1) as usize; + volatile_write!(cmdtbl.prdt_entry[las].dba, virt_2_phys(buf_ptr) as u64); + volatile_set_bit!(cmdtbl.prdt_entry[las].dbc, 1 << 31, true); // 允许中断 + volatile_write_bit!( + cmdtbl.prdt_entry[las].dbc, + (1 << 22) - 1, + ((tmp_count << 9) - 1) as u32 + ); // 数据长度 + + // 设置命令 + let cmdfis = unsafe { + ((&mut cmdtbl.cfis) as *mut [u8] as *mut usize as *mut FisRegH2D) + .as_mut() + .unwrap() + }; + volatile_write!(cmdfis.fis_type, FisType::RegH2D as u8); + volatile_set_bit!(cmdfis.pm, 1 << 7, true); // command_bit set + volatile_write!(cmdfis.command, ATA_CMD_WRITE_DMA_EXT); + + volatile_write!(cmdfis.lba0, (lba_id_start & 0xFF) as u8); + volatile_write!(cmdfis.lba1, ((lba_id_start >> 8) & 0xFF) as u8); + volatile_write!(cmdfis.lba2, ((lba_id_start >> 16) & 0xFF) as u8); + volatile_write!(cmdfis.lba3, ((lba_id_start >> 24) & 0xFF) as u8); + volatile_write!(cmdfis.lba4, ((lba_id_start >> 32) & 0xFF) as u8); + volatile_write!(cmdfis.lba5, ((lba_id_start >> 40) & 0xFF) as u8); + + volatile_write!(cmdfis.countl, (count & 0xFF) as u8); + volatile_write!(cmdfis.counth, ((count >> 8) & 0xFF) as u8); + + volatile_write!(cmdfis.device, 1 << 6); // LBA Mode + + volatile_set_bit!(port.ci, 1 << slot, true); // Issue command + + // 等待操作完成 + loop { + if (volatile_read!(port.ci) & (1 << slot)) == 0 { + break; + } + if (volatile_read!(port.is) & HBA_PxIS_TFES) > 0 { + kerror!("Write disk error"); + return Err(-(EIO as i32)); + } + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // successfully read + return Ok(count * 512); + } + + fn sync(&self) -> Result<(), i32> { + // 由于目前没有block cache, 因此sync返回成功即可 + return Ok(()); + } +} + +impl LockedAhciDisk { + pub fn new( + name: String, + flags: u16, + ctrl_num: u8, + port_num: u8, + ) -> Result, i32> { + let mut part_s: Vec> = Vec::new(); + + // 构建磁盘结构体 + let result: Arc = Arc::new(LockedAhciDisk(SpinLock::new(AhciDisk { + name, + flags, + partitions: Default::default(), + ctrl_num, + port_num, + self_ref: Weak::default(), + }))); + + let table: MbrDiskPartionTable = result.read_mbr_table()?; + let weak_this: Weak = Arc::downgrade(&result); // 获取this的弱指针 + + // 求出有多少可用分区 + for i in 0..4 { + if table.dpte[i].part_type != 0 { + part_s.push(Partition::new( + table.dpte[i].starting_sector() as u64, + table.dpte[i].starting_lba as u64, + table.dpte[i].total_sectors as u64, + weak_this.clone(), + i as u16, + )); + } + } + + result.0.lock().partitions = part_s; + result.0.lock().self_ref = weak_this; + return Ok(result); + } + + /// @brief: 从磁盘中读取 MBR 分区表结构体 TODO: Cursor + pub fn read_mbr_table(&self) -> Result { + let mut table: MbrDiskPartionTable = Default::default(); + + // 数据缓冲区 + let mut buf: Vec = Vec::new(); + buf.resize(size_of::(), 0); + + self.read_at(0, 1, &mut buf)?; + + // 创建 Cursor 用于按字节读取 + let mut cursor = VecCursor::new(buf); + cursor.seek(SeekFrom::SeekCurrent(446))?; + + for i in 0..4 { + // kdebug!("infomation of partition {}:\n", i); + + table.dpte[i].flags = cursor.read_u8()?; + table.dpte[i].starting_head = cursor.read_u8()?; + table.dpte[i].starting_sector_cylinder = cursor.read_u16()?; + table.dpte[i].part_type = cursor.read_u8()?; + table.dpte[i].ending_head = cursor.read_u8()?; + table.dpte[i].ending_sector_cylingder = cursor.read_u16()?; + table.dpte[i].starting_lba = cursor.read_u32()?; + table.dpte[i].total_sectors = cursor.read_u32()?; + + // kdebug!("dpte[i] = {:?}", table.dpte[i]); + } + table.bs_trailsig = cursor.read_u16()?; + // kdebug!("bs_trailsig = {}", unsafe { + // read_unaligned(addr_of!(table.bs_trailsig)) + // }); + + return Ok(table); + } +} + +impl BlockDevice for LockedAhciDisk { + #[inline] + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + #[inline] + fn blk_size_log2(&self) -> u8 { + 9 + } + + #[inline] + fn read_at( + &self, + lba_id_start: crate::io::device::BlockId, + count: usize, + buf: &mut [u8], + ) -> Result { + // kdebug!( + // "ahci read at {lba_id_start}, count={count}, lock={:?}", + // self.0 + // ); + return self.0.lock().read_at(lba_id_start, count, buf); + } + + #[inline] + fn write_at( + &self, + lba_id_start: crate::io::device::BlockId, + count: usize, + buf: &[u8], + ) -> Result { + self.0.lock().write_at(lba_id_start, count, buf) + } + + fn sync(&self) -> Result<(), i32> { + return self.0.lock().sync(); + } + + #[inline] + fn device(&self) -> Arc { + return self.0.lock().self_ref.upgrade().unwrap(); + } + + fn block_size(&self) -> usize { + todo!() + } + + fn partitions(&self) -> Vec> { + return self.0.lock().partitions.clone(); + } +} diff --git a/kernel/src/driver/disk/ahci/hba.rs b/kernel/src/driver/disk/ahci/hba.rs new file mode 100644 index 00000000..a45357f4 --- /dev/null +++ b/kernel/src/driver/disk/ahci/hba.rs @@ -0,0 +1,408 @@ +use alloc::vec::Vec; +use core::{intrinsics::size_of, ptr}; + +use core::sync::atomic::compiler_fence; + +use crate::mm::phys_2_virt; + +/// 文件说明: 实现了 AHCI 中的控制器 HBA 的相关行为 + +/// 根据 AHCI 写出 HBA 的 Command +pub const ATA_CMD_READ_DMA_EXT: u8 = 0x25; // 读操作,并且退出 +pub const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; // 写操作,并且退出 +#[allow(dead_code)] +pub const ATA_CMD_IDENTIFY: u8 = 0xEC; +#[allow(dead_code)] +pub const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1; +#[allow(dead_code)] +pub const ATA_CMD_PACKET: u8 = 0xA0; +pub const ATA_DEV_BUSY: u8 = 0x80; +pub const ATA_DEV_DRQ: u8 = 0x08; + +pub const HBA_PORT_CMD_CR: u32 = 1 << 15; +pub const HBA_PORT_CMD_FR: u32 = 1 << 14; +pub const HBA_PORT_CMD_FRE: u32 = 1 << 4; +pub const HBA_PORT_CMD_ST: u32 = 1; +#[allow(dead_code)] +pub const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27; +pub const HBA_SSTS_PRESENT: u32 = 0x3; +pub const HBA_SIG_ATA: u32 = 0x00000101; +pub const HBA_SIG_ATAPI: u32 = 0xEB140101; +pub const HBA_SIG_PM: u32 = 0x96690101; +pub const HBA_SIG_SEMB: u32 = 0xC33C0101; + +/// 接入 Port 的 不同设备类型 +#[derive(Debug)] +pub enum HbaPortType { + None, + Unknown(u32), + SATA, + SATAPI, + PM, + SEMB, +} + +/// 声明了 HBA 的所有属性 +#[repr(packed)] +pub struct HbaPort { + pub clb: u64, // 0x00, command list base address, 1K-byte aligned + pub fb: u64, // 0x08, FIS base address, 256-byte aligned + pub is: u32, // 0x10, interrupt status + pub ie: u32, // 0x14, interrupt enable + pub cmd: u32, // 0x18, command and status + pub _rsv0: u32, // 0x1C, Reserved + pub tfd: u32, // 0x20, task file data + pub sig: u32, // 0x24, signature + pub ssts: u32, // 0x28, SATA status (SCR0:SStatus) + pub sctl: u32, // 0x2C, SATA control (SCR2:SControl) + pub serr: u32, // 0x30, SATA error (SCR1:SError) + pub sact: u32, // 0x34, SATA active (SCR3:SActive) + pub ci: u32, // 0x38, command issue + pub sntf: u32, // 0x3C, SATA notification (SCR4:SNotification) + pub fbs: u32, // 0x40, FIS-based switch control + pub _rsv1: [u32; 11], // 0x44 ~ 0x6F, Reserved + pub vendor: [u32; 4], // 0x70 ~ 0x7F, vendor specific +} + +/// 全称 HBA Memory Register,是HBA的寄存器在内存中的映射 +#[repr(packed)] +pub struct HbaMem { + pub cap: u32, // 0x00, Host capability + pub ghc: u32, // 0x04, Global host control + pub is: u32, // 0x08, Interrupt status + pub pi: u32, // 0x0C, Port implemented + pub vs: u32, // 0x10, Version + pub ccc_ctl: u32, // 0x14, Command completion coalescing control + pub ccc_pts: u32, // 0x18, Command completion coalescing ports + pub em_loc: u32, // 0x1C, Enclosure management location + pub em_ctl: u32, // 0x20, Enclosure management control + pub cap2: u32, // 0x24, Host capabilities extended + pub bohc: u32, // 0x28, BIOS/OS handoff control and status + pub _rsv: [u8; 116], // 0x2C - 0x9F, Reserved + pub vendor: [u8; 96], // 0xA0 - 0xFF, Vendor specific registers + pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers +} + +/// HBA Command Table 里面的 PRDT 项 +/// 作用: 记录了内存中读/写数据的位置,以及长度。你可以把他类比成一个指针? +#[repr(packed)] +pub struct HbaPrdtEntry { + pub dba: u64, // Data base address + _rsv0: u32, // Reserved + pub dbc: u32, // Byte count, 4M max, interrupt = 1 +} + +/// HAB Command Table +/// 每个 Port 一个 Table,主机和设备的交互都靠这个数据结构 +#[repr(packed)] +pub struct HbaCmdTable { + // 0x00 + pub cfis: [u8; 64], // Command FIS + // 0x40 + pub acmd: [u8; 16], // ATAPI command, 12 or 16 bytes + // 0x50 + _rsv: [u8; 48], // Reserved + // 0x80 + pub prdt_entry: [HbaPrdtEntry; 65535], // Physical region descriptor table entries, 0 ~ 65535, 需要注意不要越界 +} + +/// HBA Command Header +/// 作用: 你可以把他类比成 Command Table 的指针。 +/// 猜测: 这里多了一层 Header,而不是直接在 HbaMem 结构体指向 CmdTable,可能是为了兼容和可移植性? +#[repr(packed)] +pub struct HbaCmdHeader { + // DW0 + pub cfl: u8, + // Command FIS length in DWORDS: 5(len in [2, 16]), atapi: 1, write - host to device: 1, prefetchable: 1 + pub _pm: u8, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier + pub prdtl: u16, // Physical region descriptor table length in entries + // DW1 + pub _prdbc: u32, // Physical region descriptor byte count transferred + // DW2, 3 + pub ctba: u64, // Command table descriptor base address + // DW4 - 7 + pub _rsv1: [u32; 4], // Reserved +} + +/// Port 的函数实现 +impl HbaPort { + /// 获取设备类型 + pub fn check_type(&mut self) -> HbaPortType { + if volatile_read!(self.ssts) & HBA_SSTS_PRESENT > 0 { + let sig = volatile_read!(self.sig); + match sig { + HBA_SIG_ATA => HbaPortType::SATA, + HBA_SIG_ATAPI => HbaPortType::SATAPI, + HBA_SIG_PM => HbaPortType::PM, + HBA_SIG_SEMB => HbaPortType::SEMB, + _ => HbaPortType::Unknown(sig), + } + } else { + HbaPortType::None + } + } + + /// 启动该端口的命令引擎 + pub fn start(&mut self) { + while volatile_read!(self.cmd) & HBA_PORT_CMD_CR > 0 { + core::hint::spin_loop(); + } + let val: u32 = volatile_read!(self.cmd) | HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST; + volatile_write!(self.cmd, val); + } + + /// 关闭该端口的命令引擎 + pub fn stop(&mut self) { + #[allow(unused_unsafe)] + { + volatile_write!( + self.cmd, + (u32::MAX ^ HBA_PORT_CMD_ST) & volatile_read!(self.cmd) + ); + } + + while volatile_read!(self.cmd) & (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) + == (HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) + { + core::hint::spin_loop(); + } + + #[allow(unused_unsafe)] + { + volatile_write!( + self.cmd, + (u32::MAX ^ HBA_PORT_CMD_FRE) & volatile_read!(self.cmd) + ); + } + } + + /// @return: 返回一个空闲 cmd table 的 id; 如果没有,则返回 Option::None + pub fn find_cmdslot(&self) -> Option { + let slots = volatile_read!(self.sact) | volatile_read!(self.ci); + for i in 0..32 { + if slots & 1 << i == 0 { + return Some(i); + } + } + return None; + } + + /// 初始化, 把 CmdList 等变量的地址赋值到 HbaPort 上 - 这些空间由操作系统分配且固定 + /// 等价于原C版本的 port_rebase 函数 + pub fn init(&mut self, clb: u64, fb: u64, ctbas: &Vec) { + self.stop(); // 先暂停端口 + + // 赋值 command list base address + // Command list offset: 1K*portno + // Command list entry size = 32 + // Command list entry maxim count = 32 + // Command list maxim size = 32*32 = 1K per port + volatile_write!(self.clb, clb); + + unsafe { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + ptr::write_bytes(phys_2_virt(clb as usize) as *mut u64, 0, 1024); + } + + // 赋值 fis base address + // FIS offset: 32K+256*portno + // FIS entry size = 256 bytes per port + volatile_write!(self.fb, fb); + unsafe { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + ptr::write_bytes(phys_2_virt(fb as usize) as *mut u64, 0, 256); + } + + // 赋值 command table base address + // Command table offset: 40K + 8K*portno + // Command table size = 256*32 = 8K per port + let mut cmdheaders = phys_2_virt(clb as usize) as *mut u64 as *mut HbaCmdHeader; + for i in 0..32 as usize { + volatile_write!((*cmdheaders).prdtl, 0); // 一开始没有询问,prdtl = 0 + volatile_write!((*cmdheaders).ctba, ctbas[i]); + // 这里限制了 prdtl <= 8, 所以一共用了256bytes,如果需要修改,可以修改这里 + compiler_fence(core::sync::atomic::Ordering::SeqCst); + unsafe { + ptr::write_bytes(phys_2_virt(ctbas[i] as usize) as *mut u64, 0, 256); + } + cmdheaders = (cmdheaders as usize + size_of::()) as *mut HbaCmdHeader; + } + + #[allow(unused_unsafe)] + { + // 启动中断 + volatile_write!(self.ie, 0 /*TODO: Enable interrupts: 0b10111*/); + + // 错误码 + volatile_write!(self.serr, volatile_read!(self.serr)); + + // Disable power management + volatile_write!(self.sctl, volatile_read!(self.sctl) | 7 << 8); + + // Power on and spin up device + volatile_write!(self.cmd, volatile_read!(self.cmd) | 1 << 2 | 1 << 1); + } + self.start(); // 重新开启端口 + } +} + +#[repr(u8)] +#[allow(dead_code)] +pub enum FisType { + /// Register FIS - host to device + RegH2D = 0x27, + /// Register FIS - device to host + RegD2H = 0x34, + /// DMA activate FIS - device to host + DmaAct = 0x39, + /// DMA setup FIS - bidirectional + DmaSetup = 0x41, + /// Data FIS - bidirectional + Data = 0x46, + /// BIST activate FIS - bidirectional + Bist = 0x58, + /// PIO setup FIS - device to host + PioSetup = 0x5F, + /// Set device bits FIS - device to host + DevBits = 0xA1, +} + +#[repr(packed)] +pub struct FisRegH2D { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_REG_H2D + + pub pm: u8, // Port multiplier, 1: Command, 0: Control + // uint8_t pmport : 4; // Port multiplier 低4位 + // uint8_t rsv0 : 3; // Reserved + // uint8_t c : 1; // 1: Command, 0: Control + pub command: u8, // Command register + pub featurel: u8, // Feature register, 7:0 + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + pub featureh: u8, // Feature register, 15:8 + + // DWORD 3 + pub countl: u8, // Count register, 7:0 + pub counth: u8, // Count register, 15:8 + pub icc: u8, // Isochronous command completion + pub control: u8, // Control register + + // DWORD 4 + pub rsv1: [u8; 4], // Reserved +} + +#[repr(packed)] +#[allow(dead_code)] +pub struct FisRegD2H { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_REG_D2H + + pub pm: u8, // Port multiplier, Interrupt bit: 2 + + pub status: u8, // Status register + pub error: u8, // Error register + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + pub rsv2: u8, // Reserved + + // DWORD 3 + pub countl: u8, // Count register, 7:0 + pub counth: u8, // Count register, 15:8 + pub rsv3: [u8; 2], // Reserved + + // DWORD 4 + pub rsv4: [u8; 4], // Reserved +} + +#[repr(packed)] +#[allow(dead_code)] +pub struct FisData { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_DATA + + pub pm: u8, // Port multiplier + + pub rsv1: [u8; 2], // Reserved + + // DWORD 1 ~ N + pub data: [u8; 252], // Payload +} + +#[repr(packed)] +#[allow(dead_code)] +pub struct FisPioSetup { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_PIO_SETUP + + pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2 + + pub status: u8, // Status register + pub error: u8, // Error register + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + pub rsv2: u8, // Reserved + + // DWORD 3 + pub countl: u8, // Count register, 7:0 + pub counth: u8, // Count register, 15:8 + pub rsv3: u8, // Reserved + pub e_status: u8, // New value of status register + + // DWORD 4 + pub tc: u16, // Transfer count + pub rsv4: [u8; 2], // Reserved +} + +#[repr(packed)] +#[allow(dead_code)] +pub struct FisDmaSetup { + // DWORD 0 + pub fis_type: u8, // FIS_TYPE_DMA_SETUP + + pub pm: u8, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 + + pub rsv1: [u8; 2], // Reserved + + // DWORD 1&2 + pub dma_buffer_id: u64, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ + + // DWORD 3 + pub rsv3: u32, // More reserved + + // DWORD 4 + pub dma_buffer_offset: u32, // Byte offset into buffer. First 2 bits must be 0 + + // DWORD 5 + pub transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0 + + // DWORD 6 + pub rsv6: u32, // Reserved +} diff --git a/kernel/src/driver/disk/ahci/mod.rs b/kernel/src/driver/disk/ahci/mod.rs new file mode 100644 index 00000000..7ee0b787 --- /dev/null +++ b/kernel/src/driver/disk/ahci/mod.rs @@ -0,0 +1,215 @@ +// 导出 ahci 相关的 module +pub mod ahci_inode; +pub mod ahcidisk; +pub mod hba; + +use crate::io::device::BlockDevice; +// 依赖的rust工具包 +use crate::filesystem::devfs::devfs_register; +use crate::io::disk_info::BLK_GF_AHCI; +use crate::kerror; +use crate::libs::spinlock::{SpinLock, SpinLockGuard}; +use crate::mm::virt_2_phys; +use crate::{ + driver::disk::ahci::{ + ahcidisk::LockedAhciDisk, + hba::HbaMem, + hba::{HbaPort, HbaPortType}, + }, + kdebug, +}; +use ahci_inode::LockedAhciInode; +use alloc::boxed::Box; +use alloc::string::ToString; +use alloc::{format, string::String, sync::Arc, vec::Vec}; +use core::sync::atomic::compiler_fence; + +// 依赖的C结构体/常量 +use crate::include::bindings::bindings::{ + ahci_cpp_init, pci_device_structure_general_device_t, pci_device_structure_header_t, + AHCI_MAPPING_BASE, MAX_AHCI_DEVICES, PAGE_2M_MASK, +}; + +// 仅module内可见 全局数据区 hbr_port, disks +static LOCKED_HBA_MEM_LIST: SpinLock> = SpinLock::new(Vec::new()); +static LOCKED_DISKS_LIST: SpinLock>> = SpinLock::new(Vec::new()); + +/* TFES - Task File Error Status */ +#[allow(non_upper_case_globals)] +pub const HBA_PxIS_TFES: u32 = 1 << 30; + +#[no_mangle] +pub extern "C" fn ahci_init() -> i32 { + let r = ahci_rust_init(); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err(); + } +} +/// @brief: 初始化 ahci +pub fn ahci_rust_init() -> Result<(), i32> { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + let mut ahci_dev_counts: u32 = 0; + let mut ahci_devs: [*mut pci_device_structure_header_t; MAX_AHCI_DEVICES as usize] = + [0 as *mut pci_device_structure_header_t; MAX_AHCI_DEVICES as usize]; + let mut gen_devs: [*mut pci_device_structure_general_device_t; MAX_AHCI_DEVICES as usize] = + [0 as *mut pci_device_structure_general_device_t; MAX_AHCI_DEVICES as usize]; + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + unsafe { + // 单线程 init, 所以写 ahci_devs 全局变量不会出错? + ahci_cpp_init( + (&mut ahci_dev_counts) as *mut u32, + (&mut ahci_devs) as *mut *mut pci_device_structure_header_t, + (&mut gen_devs) as *mut *mut pci_device_structure_general_device_t, + ); + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + // 全局数据 - 列表 + let mut disks_list = LOCKED_DISKS_LIST.lock(); + + for i in 0..(ahci_dev_counts as usize) { + // 对于每一个ahci控制器分配一块空间 (目前slab algorithm最大支持1MB) + let ahci_port_base_vaddr = + Box::leak(Box::new([0u8; (1 << 20) as usize])) as *mut u8 as usize; + compiler_fence(core::sync::atomic::Ordering::SeqCst); + // 获取全局引用 : 计算 HBA_MEM 的虚拟地址 依赖于C的宏定义 cal_HBA_MEM_VIRT_ADDR + let virt_addr = AHCI_MAPPING_BASE as usize + unsafe { (*gen_devs[i]).BAR5 as usize } + - (unsafe { (*gen_devs[0]).BAR5 as usize } & PAGE_2M_MASK as usize); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + // 最后把这个引用列表放入到全局列表 + let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock(); + hba_mem_list.push(unsafe { (virt_addr as *mut HbaMem).as_mut().unwrap() }); + let pi = volatile_read!(hba_mem_list[i].pi); + drop(hba_mem_list); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + // 初始化所有的port + let mut id = 0; + for j in 0..32 { + if (pi >> j) & 1 > 0 { + let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock(); + let tp = hba_mem_list[i].ports[j].check_type(); + match tp { + HbaPortType::None => { + kdebug!(" Find a None type Disk."); + } + HbaPortType::Unknown(err) => { + kdebug!(" Find a Unknown({:?}) type Disk.", err); + } + _ => { + kdebug!(" Find a {:?} type Disk.", tp); + + // 计算地址 + let fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (j << 8)); + let clb = virt_2_phys(ahci_port_base_vaddr + (j << 10)); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let ctbas = (0..32) + .map(|x| { + virt_2_phys( + ahci_port_base_vaddr + (40 << 10) + (j << 13) + (x << 8), + ) as u64 + }) + .collect::>(); + + // 初始化 port + hba_mem_list[i].ports[j].init(clb as u64, fb as u64, &ctbas); + + // 释放锁 + drop(hba_mem_list); + compiler_fence(core::sync::atomic::Ordering::SeqCst); + + // 创建 disk + disks_list.push(LockedAhciDisk::new( + format!("ahci_disk_{}", id), + BLK_GF_AHCI, + i as u8, + j as u8, + )?); + id += 1; // ID 从0开始 + + kdebug!("start register ahci device"); + + // 挂载到devfs上面去 + let ret = devfs_register( + format!("ahci_{}", id).as_str(), + LockedAhciInode::new(disks_list.last().unwrap().clone()), + ); + if let Err(err) = ret { + kerror!( + "Ahci_{} ctrl = {}, port = {} failed to register, error code = {}", + id, + i, + j, + err + ); + } + } + } + } + } + } + + compiler_fence(core::sync::atomic::Ordering::SeqCst); + return Ok(()); +} + +/// @brief: 获取所有的 disk +#[allow(dead_code)] +pub fn disks() -> Vec> { + let disks_list = LOCKED_DISKS_LIST.lock(); + return disks_list.clone(); +} + +/// @brief: 通过 name 获取 disk +pub fn get_disks_by_name(name: String) -> Result, i32> { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let disks_list: SpinLockGuard>> = LOCKED_DISKS_LIST.lock(); + for i in 0..disks_list.len() { + if disks_list[i].0.lock().name == name { + return Ok(disks_list[i].clone()); + } + } + compiler_fence(core::sync::atomic::Ordering::SeqCst); + return Err(-1); +} + +/// @brief: 通过 ctrl_num 和 port_num 获取 port +pub fn _port(ctrl_num: u8, port_num: u8) -> &'static mut HbaPort { + compiler_fence(core::sync::atomic::Ordering::SeqCst); + let list: SpinLockGuard> = LOCKED_HBA_MEM_LIST.lock(); + let port: &HbaPort = &list[ctrl_num as usize].ports[port_num as usize]; + compiler_fence(core::sync::atomic::Ordering::SeqCst); + return unsafe { (port as *const HbaPort as *mut HbaPort).as_mut().unwrap() }; +} + +/// @brief: 测试函数 +pub fn __test_ahci() { + let _res = ahci_rust_init(); + let disk: Arc = get_disks_by_name("ahci_disk_0".to_string()).unwrap(); + #[deny(overflowing_literals)] + let mut buf = [0u8; 3000usize]; + + for i in 0..2000 { + buf[i] = i as u8; + } + + let _dd = disk; + + // 测试1, 写两个块,读4个块 + // _dd.write_at(123, 2, &buf).unwrap(); + let mut read_buf = [0u8; 3000usize]; + _dd.read_at(122, 4, &mut read_buf).unwrap(); + + // 测试2, 只读写一个字节 + for i in 0..512 { + buf[i] = 233; + } + // _dd.write_at(123, 2, &buf).unwrap(); + let mut read_buf2 = [0u8; 3000usize]; + _dd.read_at(122, 4, &mut read_buf2).unwrap(); +} diff --git a/kernel/src/driver/disk/mod.rs b/kernel/src/driver/disk/mod.rs new file mode 100644 index 00000000..a790baa5 --- /dev/null +++ b/kernel/src/driver/disk/mod.rs @@ -0,0 +1 @@ +pub mod ahci; diff --git a/kernel/src/driver/keyboard/mod.rs b/kernel/src/driver/keyboard/mod.rs new file mode 100644 index 00000000..d16c8b0f --- /dev/null +++ b/kernel/src/driver/keyboard/mod.rs @@ -0,0 +1,2 @@ +pub mod ps2_keyboard; +// pub mod ps2_keyboard_inode; \ No newline at end of file diff --git a/kernel/src/driver/keyboard/ps2_keyboard.c b/kernel/src/driver/keyboard/ps2_keyboard.c index 32bcca61..932e6e62 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.c +++ b/kernel/src/driver/keyboard/ps2_keyboard.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -14,6 +13,7 @@ static struct kfifo_t kb_buf; // 缓冲区等待队列 static wait_queue_node_t ps2_keyboard_wait_queue; +extern void ps2_keyboard_register(struct vfs_file_operations_t *); // 缓冲区读写锁 static spinlock_t ps2_kb_buf_rw_lock; @@ -48,7 +48,6 @@ hardware_intr_controller ps2_keyboard_intr_controller = */ long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp) { - filp->private_data = &kb_buf; ps2_keyboard_reset_buffer(&kb_buf); return 0; } @@ -62,7 +61,6 @@ long ps2_keyboard_open(struct vfs_index_node_t *inode, struct vfs_file_t *filp) */ long ps2_keyboard_close(struct vfs_index_node_t *inode, struct vfs_file_t *filp) { - filp->private_data = NULL; ps2_keyboard_reset_buffer(&kb_buf); return 0; } @@ -146,7 +144,7 @@ void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs) { unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA); - uint8_t count = kfifo_in((struct kfifo_t*)buf_vaddr, &x, sizeof(unsigned char)); + uint8_t count = kfifo_in((struct kfifo_t *)buf_vaddr, &x, sizeof(unsigned char)); if (count == 0) { kwarn("ps2 keyboard buffer full."); @@ -205,7 +203,8 @@ void ps2_keyboard_init() // 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。 io_in8(PORT_PS2_KEYBOARD_DATA); // 将设备挂载到devfs - devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_PS2_KEYBOARD, &ps2_keyboard_fops, NULL); + ps2_keyboard_register(&ps2_keyboard_fops); + kinfo("ps/2 keyboard registered."); } diff --git a/kernel/src/driver/keyboard/ps2_keyboard.rs b/kernel/src/driver/keyboard/ps2_keyboard.rs new file mode 100644 index 00000000..8fc64f2d --- /dev/null +++ b/kernel/src/driver/keyboard/ps2_keyboard.rs @@ -0,0 +1,155 @@ +use alloc::sync::{Arc, Weak}; + +use crate::{ + filesystem::{ + devfs::{devfs_register, DevFS, DeviceINode}, + vfs::{core::generate_inode_id, FileType, IndexNode, Metadata, PollStatus}, + }, + include::bindings::bindings::{vfs_file_operations_t, vfs_file_t, vfs_index_node_t, ENOTSUP}, + kdebug, + libs::spinlock::SpinLock, + time::TimeSpec, +}; + +#[derive(Debug)] +pub struct LockedPS2KeyBoardInode(SpinLock); + +#[derive(Debug)] +pub struct PS2KeyBoardInode { + /// uuid 暂时不知道有什么用(x + // uuid: Uuid, + /// 指向自身的弱引用 + self_ref: Weak, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + /// INode 元数据 + metadata: Metadata, + /// 键盘操作函数 + f_ops: vfs_file_operations_t, +} + +impl LockedPS2KeyBoardInode { + pub fn new(f_ops: &vfs_file_operations_t) -> Arc { + let inode = PS2KeyBoardInode { + // uuid: Uuid::new_v5(), + self_ref: Weak::default(), + fs: Weak::default(), + f_ops: f_ops.clone(), // 从引用复制一遍获取所有权 + metadata: Metadata { + dev_id: 1, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::CharDevice, // 文件夹,block设备,char设备 + mode: 0o666, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: 0, // 这里用来作为device number + }, + }; + + let result = Arc::new(LockedPS2KeyBoardInode(SpinLock::new(inode))); + result.0.lock().self_ref = Arc::downgrade(&result); + + return result; + } +} + +impl DeviceINode for LockedPS2KeyBoardInode { + fn set_fs(&self, fs: Weak) { + self.0.lock().fs = fs; + } +} + +#[no_mangle] // 不重命名 +pub extern "C" fn ps2_keyboard_register(f_ops: &vfs_file_operations_t) { + kdebug!("register keyboard = {:p}", f_ops); + devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new(f_ops)) + .expect("Failed to register ps/2 keyboard"); + kdebug!("register keyboard = {:p}", f_ops); +} + +impl IndexNode for LockedPS2KeyBoardInode { + fn read_at( + &self, + _offset: usize, + len: usize, + buf: &mut [u8], + _data: &mut crate::filesystem::vfs::FilePrivateData, + ) -> Result { + let guard = self.0.lock(); + let func = guard.f_ops.read.unwrap(); + let r = unsafe { + func( + 0 as *mut vfs_file_t, + &mut buf[0..len] as *mut [u8] as *mut i8, + len as i64, + 0 as *mut i64, + ) + }; + return Ok(r as usize); + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: &mut crate::filesystem::vfs::FilePrivateData, + ) -> Result { + return Err(-(ENOTSUP as i32)); + } + + fn open(&self, _data: &mut crate::filesystem::vfs::FilePrivateData) -> Result<(), i32> { + let guard = self.0.lock(); + let func = guard.f_ops.open.unwrap(); + let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; + return Ok(()); + } + + fn close(&self, _data: &mut crate::filesystem::vfs::FilePrivateData) -> Result<(), i32> { + let guard = self.0.lock(); + let func = guard.f_ops.close.unwrap(); + let _ = unsafe { func(0 as *mut vfs_index_node_t, 0 as *mut vfs_file_t) }; + return Ok(()); + } + + fn poll(&self) -> Result { + return Ok(PollStatus { + flags: PollStatus::READ_MASK, + }); + } + + fn metadata(&self) -> Result { + return Ok(self.0.lock().metadata.clone()); + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn fs(&self) -> alloc::sync::Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn list(&self) -> Result, i32> { + return Err(-(ENOTSUP as i32)); + } +} diff --git a/kernel/src/driver/mod.rs b/kernel/src/driver/mod.rs index 17902371..84a59263 100644 --- a/kernel/src/driver/mod.rs +++ b/kernel/src/driver/mod.rs @@ -1,3 +1,5 @@ +pub mod disk; +pub mod keyboard; pub mod pci; pub mod timers; pub mod uart; diff --git a/kernel/src/driver/pci/pci.rs b/kernel/src/driver/pci/pci.rs index 39d4e355..6672ba50 100644 --- a/kernel/src/driver/pci/pci.rs +++ b/kernel/src/driver/pci/pci.rs @@ -7,7 +7,6 @@ use bitflags::bitflags; use core::{ convert::TryFrom, fmt::{self, Display, Formatter}, - ptr::NonNull, }; //Bar0寄存器的offset const BAR0_OFFSET: u8 = 0x10; diff --git a/kernel/src/driver/tty/tty.c b/kernel/src/driver/tty/tty.c index 300a8f5e..b2d96cbf 100644 --- a/kernel/src/driver/tty/tty.c +++ b/kernel/src/driver/tty/tty.c @@ -1,4 +1,3 @@ -#include #include #include "tty.h" @@ -86,8 +85,8 @@ struct vfs_file_operations_t tty_fops={ .write = tty_write, }; -void tty_init(){ - //注册devfs - devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_TTY, &tty_fops, &tty_inode_private_data_ptr); - kinfo("tty driver registered. uuid=%d", tty_inode_private_data_ptr->uuid); -} \ No newline at end of file +// void tty_init(){ +// //注册devfs +// devfs_register_device(DEV_TYPE_CHAR, CHAR_DEV_STYPE_TTY, &tty_fops, &tty_inode_private_data_ptr); +// kinfo("tty driver registered. uuid=%d", tty_inode_private_data_ptr->uuid); +// } \ No newline at end of file diff --git a/kernel/src/driver/virtio/virtio.h b/kernel/src/driver/virtio/virtio.h index 7dc9d54d..1798d212 100644 --- a/kernel/src/driver/virtio/virtio.h +++ b/kernel/src/driver/virtio/virtio.h @@ -9,4 +9,4 @@ // 获取virtio-net 设备 uint8_t get_virtio_net_device(uint8_t * bus, uint8_t *device,uint8_t * function); //寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备后续也可添加) -void c_virtio_probe(); +extern void c_virtio_probe(); diff --git a/kernel/src/driver/virtio/virtio_impl.rs b/kernel/src/driver/virtio/virtio_impl.rs index 9201c803..0032148b 100644 --- a/kernel/src/driver/virtio/virtio_impl.rs +++ b/kernel/src/driver/virtio/virtio_impl.rs @@ -2,9 +2,9 @@ use crate::include::bindings::bindings::{ alloc_pages, free_pages, memory_management_struct, Page, PAGE_2M_SHIFT, PAGE_2M_SIZE, PAGE_OFFSET, PAGE_SHARED, ZONE_NORMAL, }; -use crate::kdebug; + use core::mem::size_of; -use core::{ptr::NonNull}; +use core::ptr::NonNull; use virtio_drivers::{BufferDirection, Hal, PhysAddr, VirtAddr, PAGE_SIZE}; pub struct HalImpl; @@ -50,7 +50,6 @@ impl Hal for HalImpl { /// @return VirtAddr 虚拟地址 fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { paddr + PAGE_OFFSET as usize - } /// @brief 与真实物理设备共享 /// @param buffer 要共享的buffer _direction:设备到driver或driver到设备 diff --git a/kernel/src/filesystem/MBR.c b/kernel/src/filesystem/MBR.c deleted file mode 100644 index 7ca4c739..00000000 --- a/kernel/src/filesystem/MBR.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "MBR.h" -#include -#include - -struct MBR_disk_partition_table_t MBR_partition_tables[MBR_MAX_AHCI_CTRL_NUM][MBR_MAX_AHCI_PORT_NUM] = {0}; - -/** - * @brief 读取磁盘的分区表 - * - * @param ahci_ctrl_num ahci控制器编号 - * @param ahci_port_num ahci端口编号 - * @param buf 输出缓冲区(512字节) - */ -int MBR_read_partition_table(struct blk_gendisk *gd, void *buf) -{ - return gd->fops->transfer(gd, AHCI_CMD_READ_DMA_EXT, 0, 1, (uint64_t)buf); -} \ No newline at end of file diff --git a/kernel/src/filesystem/MBR.h b/kernel/src/filesystem/MBR.h deleted file mode 100644 index aed7e9d8..00000000 --- a/kernel/src/filesystem/MBR.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file MBR.h - * @author fslongjin (longjin@RinGoTek.cn) - * @brief MBR分区表 - * @version 0.1 - * @date 2022-04-19 - * - * @copyright Copyright (c) 2022 - * - */ -#pragma once -#include -#include - -#define MBR_MAX_AHCI_CTRL_NUM 4 // 系统支持的最大的ahci控制器数量 -#define MBR_MAX_AHCI_PORT_NUM 32 // 系统支持的每个ahci控制器对应的MBR磁盘数量(对应ahci磁盘号) - -/** - * @brief MBR硬盘分区表项的结构 - * - */ -struct MBR_disk_partition_table_entry_t -{ - uint8_t flags; // 引导标志符,标记此分区为活动分区 - uint8_t starting_head; // 起始磁头号 - uint16_t starting_sector : 6, // 起始扇区号 - starting_cylinder : 10; // 起始柱面号 - uint8_t type; // 分区类型ID - uint8_t ending_head; // 结束磁头号 - - uint16_t ending_sector : 6, // 结束扇区号 - ending_cylinder : 10; // 结束柱面号 - - uint32_t starting_LBA; // 起始逻辑扇区 - uint32_t total_sectors; // 分区占用的磁盘扇区数 - -} __attribute__((packed)); - -/** - * @brief MBR磁盘分区表结构体 - * - */ -struct MBR_disk_partition_table_t -{ - uint8_t reserved[446]; - struct MBR_disk_partition_table_entry_t DPTE[4]; // 磁盘分区表项 - uint16_t BS_TrailSig; -} __attribute__((packed)); - -extern struct MBR_disk_partition_table_t MBR_partition_tables[MBR_MAX_AHCI_CTRL_NUM][MBR_MAX_AHCI_PORT_NUM]; // 导出全局的MBR磁盘分区表 - -/** - * @brief 读取磁盘的分区表 - * - * @param ahci_ctrl_num ahci控制器编号 - * @param ahci_port_num ahci端口编号 - * @param buf 输出缓冲区(512字节) - */ -int MBR_read_partition_table(struct blk_gendisk* gd, void *buf); \ No newline at end of file diff --git a/kernel/src/filesystem/Makefile b/kernel/src/filesystem/Makefile deleted file mode 100644 index d87a55c6..00000000 --- a/kernel/src/filesystem/Makefile +++ /dev/null @@ -1,20 +0,0 @@ - -CFLAGS += -I . - - -kernel_fs_objs:= $(shell find ./*.c) -kernel_fs_subdirs:= devfs vfs fat32 rootfs procfs - -ECHO: - @echo "$@" - - -$(kernel_fs_objs): ECHO - $(CC) $(CFLAGS) -c $@ -o $@.o - -$(kernel_fs_subdirs): ECHO - $(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)" - - -all: $(kernel_fs_objs) $(kernel_fs_subdirs) - diff --git a/kernel/src/filesystem/block.c b/kernel/src/filesystem/block.c deleted file mode 100644 index dcec79c4..00000000 --- a/kernel/src/filesystem/block.c +++ /dev/null @@ -1,13 +0,0 @@ -#include - -/** - * @brief 将磁盘注册到块设备框架中 - * - * @param gendisk 磁盘结构体 - * @return int 错误码 - */ -int blk_register_gendisk(struct blk_gendisk * gendisk) -{ - // todo: 将磁盘注册到devfs中 - return 0; -} \ No newline at end of file diff --git a/kernel/src/filesystem/devfs/Makefile b/kernel/src/filesystem/devfs/Makefile deleted file mode 100644 index ac658731..00000000 --- a/kernel/src/filesystem/devfs/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - -CFLAGS += -I . - - -kernel_fs_devfs_objs:= $(shell find ./*.c) - - -ECHO: - @echo "$@" - - -$(kernel_fs_devfs_objs): ECHO - $(CC) $(CFLAGS) -c $@ -o $@.o - - -all: $(kernel_fs_devfs_objs) - diff --git a/kernel/src/filesystem/devfs/chardev.c b/kernel/src/filesystem/devfs/chardev.c deleted file mode 100644 index 691060c3..00000000 --- a/kernel/src/filesystem/devfs/chardev.c +++ /dev/null @@ -1,88 +0,0 @@ -#include "chardev.h" -#include "internal.h" -#include - -#include -#include -#include -#include - -static struct vfs_dir_entry_t *chardev_folder_dentry = NULL; -extern struct vfs_dir_entry_t *devfs_root_dentry; - -/** - * @brief 字符设备名称前缀 - * - */ -static char chardev_name_prefix[CHAR_DEV_STYPE_END + 1][32] = { - [CHAR_DEV_STYPE_START] = "", - [CHAR_DEV_STYPE_PS2_KEYBOARD] = "ps2.kb", - [CHAR_DEV_STYPE_PS2_MOUSE] = "ps2.mse", - [CHAR_DEV_STYPE_USB_MOUSE] = "usb.mse", - [CHAR_DEV_STYPE_USB_KEYBOARD] = "usb.kb", - [CHAR_DEV_STYPE_BLUETOOTH_MOUSE] = "bt.mse", - [CHAR_DEV_STYPE_BLUETOOTH_KEYBOARD] = "bt.kb", - [CHAR_DEV_STYPE_TTY] = "vdev.tty", - [CHAR_DEV_STYPE_END] = "", -}; -/** - * @brief 为不同类型的字符设备分配的管理信息结构体 - * - */ -static struct chardev_manage_info_t -{ - mutex_t lock; // 操作互斥锁 - int count; -} chardev_manage_info[CHAR_DEV_STYPE_END + 1]; - -/** - * @brief 在devfs中注册字符设备(该函数只应被devfs调用) - * - * @param private_info inode私有信息 - * @param target_dentry 返回的dentry的指针 - * @return int 错误码 - */ -int __devfs_chardev_register(struct devfs_private_inode_info_t *private_info, struct vfs_dir_entry_t **target_dentry) -{ - // 检测subtype是否合法 - if (private_info->sub_type <= CHAR_DEV_STYPE_START || private_info->sub_type >= CHAR_DEV_STYPE_END) - return -EINVAL; - mutex_lock(&chardev_manage_info[private_info->sub_type].lock); - - // 拷贝名称 - char devname[64] = {0}; - strcpy(devname, chardev_name_prefix[private_info->sub_type]); - char *ptr = devname + strlen(chardev_name_prefix[private_info->sub_type]); - sprintk(ptr, "%d", chardev_manage_info[private_info->sub_type].count); - int namelen = strlen(devname); - - struct vfs_dir_entry_t *dentry = vfs_alloc_dentry(namelen + 1); - __devfs_fill_dentry(dentry, devname); - __devfs_fill_inode(dentry, vfs_alloc_inode(), VFS_IF_DEVICE, private_info); - - // 将dentry挂载到char文件夹下 - __devfs_dentry_bind_parent(chardev_folder_dentry, dentry); - - ++chardev_manage_info[private_info->sub_type].count; - mutex_unlock(&chardev_manage_info[private_info->sub_type].lock); - *target_dentry = dentry; - return 0; -} - -/** - * @brief 初始化chardev管理机制 - * - */ -void __devfs_chardev_init() -{ - // 初始化管理信息结构体 - for (int i = CHAR_DEV_STYPE_START + 1; i < CHAR_DEV_STYPE_END; ++i) - { - mutex_init(&chardev_manage_info[i].lock); - chardev_manage_info[i].count = 0; - } - - vfs_mkdir("/dev/char", 0, false); - // 获取char dev的dentry - chardev_folder_dentry = __devfs_find_dir(devfs_root_dentry, "char"); -} \ No newline at end of file diff --git a/kernel/src/filesystem/devfs/chardev.h b/kernel/src/filesystem/devfs/chardev.h deleted file mode 100644 index af4a6546..00000000 --- a/kernel/src/filesystem/devfs/chardev.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "devfs.h" - - diff --git a/kernel/src/filesystem/devfs/devfs-types.h b/kernel/src/filesystem/devfs/devfs-types.h deleted file mode 100644 index 7d9cac7d..00000000 --- a/kernel/src/filesystem/devfs/devfs-types.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include - -/** - * @brief devfs_private_file_info_t的type字段值 - * - */ -enum -{ - DEV_TYPE_UNDEF = 0, - DEV_TYPE_CHAR = 1, - DEV_TYPE_USB, - DEV_TYPE_BLOCK, - DEV_TYPE_NET, - DEV_TYPE_BUS, - -}; - -/** - * @brief 字符设备的sub_type字段值 - * - */ -enum -{ - CHAR_DEV_STYPE_START = 0, - CHAR_DEV_STYPE_PS2_KEYBOARD = 1, - CHAR_DEV_STYPE_USB_KEYBOARD, - CHAR_DEV_STYPE_PS2_MOUSE, - CHAR_DEV_STYPE_USB_MOUSE, - CHAR_DEV_STYPE_BLUETOOTH_MOUSE, - CHAR_DEV_STYPE_BLUETOOTH_KEYBOARD, - CHAR_DEV_STYPE_TTY, - CHAR_DEV_STYPE_END, // 结束标志 -}; - -/** - * @brief 设备文件私有信息结构体 - * - */ -struct devfs_private_inode_info_t -{ - uint16_t type; // 设备主类型 - uint16_t sub_type; // 设备子类型 - struct vfs_file_operations_t *f_ops; - uint64_t uuid; - struct vfs_index_node_t * inode; // 当前私有信息所绑定的inode -}; diff --git a/kernel/src/filesystem/devfs/devfs.c b/kernel/src/filesystem/devfs/devfs.c deleted file mode 100644 index c56401b6..00000000 --- a/kernel/src/filesystem/devfs/devfs.c +++ /dev/null @@ -1,335 +0,0 @@ -#include "devfs.h" -#include "internal.h" -#include -#include -#include -#include -#include -#include - -struct vfs_super_block_operations_t devfs_sb_ops; -struct vfs_dir_entry_operations_t devfs_dentry_ops; -struct vfs_file_operations_t devfs_file_ops; -struct vfs_inode_operations_t devfs_inode_ops; - -struct vfs_dir_entry_t *devfs_root_dentry; // 根结点的dentry -struct vfs_superblock_t devfs_sb = {0}; -const char __devfs_mount_path[] = "/dev"; - -static spinlock_t devfs_global_lock; // devfs的全局锁 -static uint64_t __tmp_uuid = 0; // devfs的临时uuid变量(todo:在引入uuid lib之后删除这里) - -static inline uint64_t __devfs_get_uuid() -{ - // todo : 更改为使用uuid库来生成uuid - return ++__tmp_uuid; -} - -/** - * @brief 创建devfs的super block - * - * @param blk 未使用(devfs为伪文件系统,不需要物理设备) - * @return struct vfs_superblock_t* - */ -struct vfs_superblock_t *devfs_read_superblock(struct block_device *blk) -{ - devfs_sb.blk_device = NULL; - devfs_sb.root = devfs_root_dentry; - devfs_sb.sb_ops = &devfs_sb_ops; - devfs_sb.dir_ops = &devfs_dentry_ops; - // todo: 为devfs增加私有信息 - devfs_sb.private_sb_info = NULL; - kdebug("devfs read superblock done"); - return &devfs_sb; -} - -static void devfs_write_superblock(struct vfs_superblock_t *sb) { return; } - -static void devfs_put_superblock(struct vfs_superblock_t *sb) { return; } - -static void devfs_write_inode(struct vfs_index_node_t *inode) { return; } -struct vfs_super_block_operations_t devfs_sb_ops = - { - .write_superblock = &devfs_write_superblock, - .put_superblock = &devfs_put_superblock, - .write_inode = &devfs_write_inode, -}; - -static long devfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) { return 0; } - -static long devfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) { return 0; } - -static long devfs_release(struct vfs_dir_entry_t *dEntry) { return 0; } - -static long devfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) { return 0; } - -struct vfs_dir_entry_operations_t devfs_dentry_ops = - { - .compare = &devfs_compare, - .hash = &devfs_hash, - .release = &devfs_release, - .iput = &devfs_iput, -}; - -static long devfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - return 0; -} -static long devfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { return 0; } -static long devfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; } -static long devfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; } -static long devfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) { return 0; } -static long devfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; } - -static long devfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler) -{ - // 循环读取目录下的目录项 - struct vfs_dir_entry_t *dentry = file_ptr->dEntry; - struct List *list = &dentry->subdirs_list; - // 先切换到position处 - for (int i = 0; i <= file_ptr->position; ++i) - { - list = list_next(list); - if (list == &dentry->subdirs_list) // 找完了 - goto failed; - } - - // 存在目录项 - // 增加偏移量 - ++file_ptr->position; - // 获取目标dentry(由于是子目录项,因此是child_node_list) - struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list); - // kdebug("target name=%s, namelen=%d", target_dent->name, target_dent->name_length); - - char *name = (char *)kzalloc(target_dent->name_length + 1, 0); - strncpy(name, target_dent->name, target_dent->name_length); - uint32_t dentry_type; - if (target_dent->dir_inode->attribute & VFS_IF_DIR) - dentry_type = VFS_IF_DIR; - else - dentry_type = VFS_IF_DEVICE; - - return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1); -failed:; - return 0; -} - -struct vfs_file_operations_t devfs_file_ops = - { - .open = &devfs_open, - .close = &devfs_close, - .read = &devfs_read, - .write = &devfs_write, - .lseek = &devfs_lseek, - .ioctl = &devfs_ioctl, - .readdir = &devfs_readdir, -}; - -/** - * @brief 创建新的文件 - * @param parent_inode 父目录的inode结构体 - * @param dest_dEntry 新文件的dentry - * @param mode 创建模式 - */ -static long devfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode) -{ - return 0; -} - -static struct vfs_dir_entry_t *devfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry) -{ - /* - 由于devfs是伪文件系统,其所有的搜索都依赖于dentry缓存。 - 因此,不需要根据inode来搜索目标目录项。除非目录项不存在,否则不会调用这个函数。 - 当本函数调用的时候,也就意味着devfs中没有这个文件/文件夹。 - 综上,本函数直接返回NULL即可 - */ - return NULL; -} -/** - * @brief 在devfs中创建文件夹(作用是完善子文件夹的inode信息) - * - * @param inode 父目录的inode - * @param dEntry 目标dentry - * @param mode 创建模式 - * @return long 错误码 - */ -static long devfs_mkdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode) -{ - dEntry->dir_inode = vfs_alloc_inode(); - dEntry->dir_inode->file_ops = &devfs_file_ops; - dEntry->dir_inode->inode_ops = &devfs_inode_ops; - dEntry->dir_ops = &devfs_dentry_ops; - // todo: 增加private inode info - dEntry->dir_inode->private_inode_info = NULL; - dEntry->dir_inode->sb = &devfs_sb; - dEntry->dir_inode->attribute = VFS_IF_DIR; - return 0; -} - -static long devfs_rmdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry) { return 0; } -static long devfs_rename(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry) { return 0; } -static long devfs_getAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) { return 0; } -static long devfs_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) { return 0; } -struct vfs_inode_operations_t devfs_inode_ops = { - .create = &devfs_create, - .lookup = &devfs_lookup, - .mkdir = &devfs_mkdir, - .rmdir = &devfs_rmdir, - .rename = &devfs_rename, - .getAttr = &devfs_getAttr, - .setAttr = &devfs_setAttr, -}; - -struct vfs_filesystem_type_t devfs_fs_type = - { - .name = "DEVFS", - .fs_flags = 0, - .read_superblock = devfs_read_superblock, - .next = NULL, -}; - -static __always_inline void __devfs_init_root_inode() -{ - devfs_root_dentry->dir_inode = vfs_alloc_inode(); - devfs_root_dentry->dir_inode->file_ops = &devfs_file_ops; - devfs_root_dentry->dir_inode->inode_ops = &devfs_inode_ops; - - // todo: 增加private inode info - devfs_root_dentry->dir_inode->private_inode_info = NULL; - devfs_root_dentry->dir_inode->sb = &devfs_sb; - devfs_root_dentry->dir_inode->attribute = VFS_IF_DIR; -} -/** - * @brief 初始化devfs的根dentry - */ -static __always_inline void __devfs_init_root_dentry() -{ - devfs_root_dentry = vfs_alloc_dentry(0); - devfs_root_dentry->dir_ops = &devfs_dentry_ops; - - __devfs_init_root_inode(); -} - -/** - * @brief 在devfs中注册设备 - * - * @param device_type 设备主类型 - * @param sub_type 设备子类型 - * @param file_ops 设备的文件操作接口 - * @param ret_private_inode_info_ptr 返回的指向inode私有信息结构体的指针 - * @return int 错误码 - */ -int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops, struct devfs_private_inode_info_t **ret_private_inode_info_ptr) -{ - spin_lock(&devfs_global_lock); - int retval = 0; - // 申请private info结构体 - struct devfs_private_inode_info_t *private_info = (struct devfs_private_inode_info_t *)kzalloc(sizeof(struct devfs_private_inode_info_t), 0); - private_info->f_ops = file_ops; - private_info->type = device_type; - private_info->sub_type = sub_type; - private_info->uuid = __devfs_get_uuid(); - - struct vfs_dir_entry_t *dentry = NULL; // 该指针由对应类型设备的注册函数设置 - - switch (device_type) - { - case DEV_TYPE_CHAR: - retval = __devfs_chardev_register(private_info, &dentry); - break; - - default: - kerror("Unsupported device type [ %d ].", device_type); - retval = -ENOTSUP; - goto failed; - break; - } - if (ret_private_inode_info_ptr != NULL) - *ret_private_inode_info_ptr = private_info; - - spin_unlock(&devfs_global_lock); - return retval; -failed:; - kfree(private_info); - spin_unlock(&devfs_global_lock); - return retval; -} - -/** - * @brief 卸载设备 - * - * @param private_inode_info 待卸载的设备的inode私有信息 - * @param put_private_info 设备被卸载后,执行的函数 - * @return int 错误码 - */ -int devfs_unregister_device(struct devfs_private_inode_info_t *private_inode_info) -{ - int retval = 0; - spin_lock(&devfs_global_lock); - struct vfs_dir_entry_t *base_dentry = NULL; - struct vfs_dir_entry_t *target_dentry = NULL; - - // 找到父目录的dentry - { - - char base_path[64] = {0}; - switch (private_inode_info->type) - { - case DEV_TYPE_CHAR: - strcpy(base_path, "/dev/char"); - break; - default: - retval = -ENOTSUP; - goto out; - break; - } - - base_dentry = vfs_path_walk(base_path, 0); - // bug - if (unlikely(base_dentry == NULL)) - { - BUG_ON(1); - retval = -ENODEV; - goto out; - } - } - - // 遍历子目录,寻找拥有指定inode的dentry(暂时不支持一个inode对应多个dentry的情况) - // todo: 支持链接文件的卸载 - struct List *tmp_list = NULL, *target_list = NULL; - list_for_each_safe(target_list, tmp_list, &base_dentry->subdirs_list) - { - target_dentry = list_entry(target_list, struct vfs_dir_entry_t, child_node_list); - if (target_dentry->dir_inode == private_inode_info->inode) - { - spin_lock(&target_dentry->lockref.lock); - retval = vfs_dentry_put(target_dentry); - if (retval < 0) - { - kerror("Error when try to unregister device"); - spin_unlock(&target_dentry->lockref.lock); - } - else if (retval == 0) // 该设备的所有dentry均被卸载完成,不必继续迭代 - break; - } - } - retval = 0; -out:; - spin_unlock(&devfs_global_lock); - return retval; -} - -/** - * @brief 初始化devfs - * - */ -void devfs_init() -{ - __devfs_init_root_dentry(); - vfs_register_filesystem(&devfs_fs_type); - spin_init(&devfs_global_lock); - vfs_mount_fs(__devfs_mount_path, "DEVFS", NULL); - - __devfs_chardev_init(); -} \ No newline at end of file diff --git a/kernel/src/filesystem/devfs/devfs.h b/kernel/src/filesystem/devfs/devfs.h deleted file mode 100644 index a2c68f5f..00000000 --- a/kernel/src/filesystem/devfs/devfs.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "devfs-types.h" - -/** - * @brief 初始化devfs - * - */ -void devfs_init(); - -/** - * @brief 在devfs中注册设备 - * - * @param device_type 设备主类型 - * @param sub_type 设备子类型 - * @param file_ops 设备的文件操作接口 - * @param ret_private_inode_info_ptr 返回的指向inode私有信息结构体的指针 - * @return int 错误码 - */ -int devfs_register_device(uint16_t device_type, uint16_t sub_type, struct vfs_file_operations_t *file_ops, struct devfs_private_inode_info_t **ret_private_inode_info_ptr); - -/** - * @brief 卸载设备 - * - * @param private_inode_info 待卸载的设备的inode私有信息 - * @param put_private_info 设备被卸载后,执行的函数 - * @return int 错误码 - */ -int devfs_unregister_device(struct devfs_private_inode_info_t * private_inode_info); \ No newline at end of file diff --git a/kernel/src/filesystem/devfs/internal.h b/kernel/src/filesystem/devfs/internal.h deleted file mode 100644 index 015272b7..00000000 --- a/kernel/src/filesystem/devfs/internal.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include "devfs.h" -#include - -extern struct vfs_super_block_operations_t devfs_sb_ops; -extern struct vfs_dir_entry_operations_t devfs_dentry_ops; -extern struct vfs_file_operations_t devfs_file_ops; -extern struct vfs_inode_operations_t devfs_inode_ops; -extern struct vfs_superblock_t devfs_sb; - -/** - * @brief 在devfs中注册字符设备(该函数只应被devfs调用) - * - * @param private_info inode私有信息 - * @param target_dentry 返回的dentry的指针 - * @return int 错误码 - */ -int __devfs_chardev_register(struct devfs_private_inode_info_t *private_info, struct vfs_dir_entry_t **target_dentry); - -/** - * @brief 初始化chardev管理机制 - * - */ -void __devfs_chardev_init(); - -/** - * @brief 在父dentry中寻找子dentry - * - * @param parent_dentry 父dentry结点 - * @param name 子目录项名称 - * @return struct vfs_dir_entry_t* - */ -static inline struct vfs_dir_entry_t *__devfs_find_dentry(struct vfs_dir_entry_t *parent_dentry, const char *name) -{ - struct List *list = &parent_dentry->subdirs_list; - while (list_next(list) != &parent_dentry->subdirs_list) - { - list = list_next(list); - // 获取目标dentry(由于是子目录项,因此是child_node_list) - struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list); - if (strcmp(target_dent->name, name) == 0) - return target_dent; - } - return NULL; -} - -/** - * @brief 在父目录下查找子目录 - * - * @param parent_dentry 父目录 - * @param name 子目录名 - * @return struct vfs_dir_entry_t* 子目录的dentry (找不到则返回NULL) - */ -static inline struct vfs_dir_entry_t *__devfs_find_dir(struct vfs_dir_entry_t *parent_dentry, const char *name) -{ - struct vfs_dir_entry_t *target_dent = __devfs_find_dentry(parent_dentry, name); - if (target_dent->dir_inode->attribute & VFS_IF_DIR) // 名称相符且为目录,则返回dentry - return target_dent; - else - return NULL; // 否则直接返回空 -} - -/** - * @brief 将dentry和inode进行绑定,并填充inode - * - * @param dentry 目标dentry - * @param inode 目标inode - * @param inode_attr inode的属性 - * @param private_inode_data inode私有信息 - */ -static inline void __devfs_fill_inode(struct vfs_dir_entry_t *dentry, struct vfs_index_node_t *inode, uint64_t inode_attr, struct devfs_private_inode_info_t *private_inode_data) -{ - dentry->dir_inode = inode; - dentry->dir_inode->file_ops = private_inode_data->f_ops; - dentry->dir_inode->inode_ops = &devfs_inode_ops; - - dentry->dir_inode->private_inode_info = private_inode_data; - dentry->dir_inode->sb = &devfs_sb; - dentry->dir_inode->attribute = inode_attr; - // 反向绑定inode - private_inode_data->inode = dentry->dir_inode; -} - -/** - * @brief 填充dentry中的内容 - * - * @param dentry 待填充的dentry - * @param name dentry名称 - */ -static inline void __devfs_fill_dentry(struct vfs_dir_entry_t *dentry, const char *name) -{ - strcpy(dentry->name, name); - dentry->name_length = strlen(name); - dentry->dir_ops = &devfs_dentry_ops; -} - -/** - * @brief 将dentry与父dentry进行绑定 - * @param parent 父目录项 - * @param dentry 子目录项 - */ -#define __devfs_dentry_bind_parent(parent_dentry, dentry) ({ \ - (dentry)->parent = (parent_dentry); \ - list_append(&((parent_dentry)->subdirs_list), &((dentry)->child_node_list)); \ -}) diff --git a/kernel/src/filesystem/devfs/mod.rs b/kernel/src/filesystem/devfs/mod.rs index 8b137891..f1f053de 100644 --- a/kernel/src/filesystem/devfs/mod.rs +++ b/kernel/src/filesystem/devfs/mod.rs @@ -1 +1,510 @@ +/// 导出devfs的模块 +pub mod null_dev; +pub mod zero_dev; +use super::vfs::{ + core::{generate_inode_id, ROOT_INODE}, + FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus, +}; +use crate::{ + include::bindings::bindings::{EEXIST, EISDIR, ENOENT, ENOTDIR, ENOTSUP}, + kdebug, kerror, + libs::spinlock::{SpinLock, SpinLockGuard}, + time::TimeSpec, +}; +use alloc::{ + collections::BTreeMap, + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; + +const DEVFS_MAX_NAMELEN: usize = 64; + +/// @brief dev文件系统 +#[derive(Debug)] +pub struct DevFS { + // 文件系统根节点 + root_inode: Arc, +} + +impl FileSystem for DevFS { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn root_inode(&self) -> Arc { + return self.root_inode.clone(); + } + + fn info(&self) -> super::vfs::FsInfo { + return FsInfo { + blk_dev_id: 0, + max_name_len: DEVFS_MAX_NAMELEN, + }; + } +} + +impl DevFS { + pub fn new() -> Arc { + // 初始化root inode + let root: Arc = Arc::new(LockedDevFSInode(SpinLock::new( + // /dev 的权限设置为 读+执行,root 可以读写 + // root 的 parent 是空指针 + DevFSInode::new(FileType::Dir, 0o755 as u32, 0), + ))); + + let devfs: Arc = Arc::new(DevFS { root_inode: root }); + + // 对root inode加锁,并继续完成初始化工作 + let mut root_guard: SpinLockGuard = devfs.root_inode.0.lock(); + root_guard.parent = Arc::downgrade(&devfs.root_inode); + root_guard.self_ref = Arc::downgrade(&devfs.root_inode); + root_guard.fs = Arc::downgrade(&devfs); + // 释放锁 + drop(root_guard); + + // 创建文件夹 + let root: &Arc = &devfs.root_inode; + root.add_dir("char") + .expect("DevFS: Failed to create /dev/char"); + + root.add_dir("block") + .expect("DevFS: Failed to create /dev/block"); + devfs.register_bultinin_device(); + + kdebug!("ls /dev: {:?}", root.list()); + return devfs; + } + + /// @brief 注册系统内部自带的设备 + fn register_bultinin_device(&self) { + use null_dev::LockedNullInode; + use zero_dev::LockedZeroInode; + let dev_root: Arc = self.root_inode.clone(); + dev_root + .add_dev("null", LockedNullInode::new()) + .expect("DevFS: Failed to register /dev/null"); + dev_root + .add_dev("zero", LockedZeroInode::new()) + .expect("DevFS: Failed to register /dev/zero"); + } + + /// @brief 在devfs内注册设备 + /// + /// @param name 设备名称 + /// @param device 设备节点的结构体 + pub fn register_device(&self, name: &str, device: Arc) -> Result<(), i32> { + let dev_root_inode: Arc = self.root_inode.clone(); + match device.metadata().unwrap().file_type { + // 字节设备挂载在 /dev/char + FileType::CharDevice => { + if let Err(_) = dev_root_inode.find("char") { + dev_root_inode.create("char", FileType::Dir, 0o755)?; + } + + let any_char_inode = dev_root_inode.find("char")?; + let dev_char_inode: &LockedDevFSInode = any_char_inode + .as_any_ref() + .downcast_ref::() + .unwrap(); + + dev_char_inode.add_dev(name, device.clone())?; + device.set_fs(dev_char_inode.0.lock().fs.clone()); + } + FileType::BlockDevice => { + if let Err(_) = dev_root_inode.find("block") { + dev_root_inode.create("block", FileType::Dir, 0o755)?; + } + + let any_block_inode = dev_root_inode.find("block")?; + let dev_block_inode: &LockedDevFSInode = any_block_inode + .as_any_ref() + .downcast_ref::() + .unwrap(); + + dev_block_inode.add_dev(name, device.clone())?; + device.set_fs(dev_block_inode.0.lock().fs.clone()); + } + _ => { + return Err(-(ENOTSUP as i32)); + } + } + + return Ok(()); + } + + /// @brief 卸载设备 + pub fn unregister_device(&self, name: &str, device: Arc) -> Result<(), i32> { + let dev_root_inode: Arc = self.root_inode.clone(); + match device.metadata().unwrap().file_type { + // 字节设备挂载在 /dev/char + FileType::CharDevice => { + if let Err(_) = dev_root_inode.find("char") { + return Err(-(ENOENT as i32)); + } + + let any_char_inode = dev_root_inode.find("char")?; + let dev_char_inode = any_char_inode + .as_any_ref() + .downcast_ref::() + .unwrap(); + // TODO: 调用设备的卸载接口(当引入卸载接口之后) + dev_char_inode.remove(name)?; + } + FileType::BlockDevice => { + if let Err(_) = dev_root_inode.find("block") { + return Err(-(ENOENT as i32)); + } + + let any_block_inode = dev_root_inode.find("block")?; + let dev_block_inode = any_block_inode + .as_any_ref() + .downcast_ref::() + .unwrap(); + + dev_block_inode.remove(name)?; + } + _ => { + return Err(-(ENOTSUP as i32)); + } + } + + return Ok(()); + } +} + +/// @brief dev文件i节点(锁) +#[derive(Debug)] +pub struct LockedDevFSInode(SpinLock); + +/// @brief dev文件i节点(无锁) +#[derive(Debug)] +pub struct DevFSInode { + /// 指向父Inode的弱引用 + parent: Weak, + /// 指向自身的弱引用 + self_ref: Weak, + /// 子Inode的B树 + children: BTreeMap>, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + /// INode 元数据 + metadata: Metadata, +} + +impl DevFSInode { + pub fn new(dev_type_: FileType, mode_: u32, data_: usize) -> Self { + return Self::new_with_parent(Weak::default(), dev_type_, mode_, data_); + } + + pub fn new_with_parent( + parent: Weak, + dev_type_: FileType, + mode_: u32, + data_: usize, + ) -> Self { + return DevFSInode { + parent: parent, + self_ref: Weak::default(), + children: BTreeMap::new(), + metadata: Metadata { + dev_id: 1, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: dev_type_, // 文件夹 + mode: mode_, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: data_, + }, + fs: Weak::default(), + }; + } +} + +impl LockedDevFSInode { + pub fn add_dir(&self, name: &str) -> Result<(), i32> { + let guard:SpinLockGuard = self.0.lock(); + + if guard.children.contains_key(name) { + return Err(-(EEXIST as i32)); + } + + match self.do_create_with_data(guard, name, FileType::Dir, 0o755 as u32, 0) { + Ok(inode) => inode, + Err(err) => { + return Err(err); + } + }; + + return Ok(()); + } + + pub fn add_dev(&self, name: &str, dev: Arc) -> Result<(), i32> { + let mut this = self.0.lock(); + + if this.children.contains_key(name) { + return Err(-(EEXIST as i32)); + } + + this.children.insert(name.to_string(), dev); + return Ok(()); + } + + pub fn remove(&self, name: &str) -> Result<(), i32> { + let x = self + .0 + .lock() + .children + .remove(name) + .ok_or(-(ENOENT as i32))?; + + drop(x); + return Ok(()); + } + + fn do_create_with_data(&self, mut guard: SpinLockGuard,_name: &str, + _file_type: FileType, + _mode: u32, + _data: usize,) -> Result, i32>{ + if guard.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 如果有重名的,则返回 + if guard.children.contains_key(_name) { + return Err(-(EEXIST as i32)); + } + + // 创建inode + let result: Arc = Arc::new(LockedDevFSInode(SpinLock::new(DevFSInode { + parent: guard.self_ref.clone(), + self_ref: Weak::default(), + children: BTreeMap::new(), + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: _file_type, + mode: _mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: _data, + }, + fs: guard.fs.clone(), + }))); + + // 初始化inode的自引用的weak指针 + result.0.lock().self_ref = Arc::downgrade(&result); + + // 将子inode插入父inode的B树中 + guard.children.insert(String::from(_name), result.clone()); + return Ok(result); + + } +} + +impl IndexNode for LockedDevFSInode { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn open(&self, _data: &mut super::vfs::FilePrivateData) -> Result<(), i32> { + return Ok(()); + } + + fn close(&self, _data: &mut super::vfs::FilePrivateData) -> Result<(), i32> { + return Ok(()); + } + + fn create_with_data( + &self, + name: &str, + file_type: FileType, + mode: u32, + data: usize, + ) -> Result, i32> { + // 获取当前inode + let guard:SpinLockGuard = self.0.lock(); + // 如果当前inode不是文件夹,则返回 + return self.do_create_with_data(guard, name, file_type, mode, data); + } + + fn find(&self, name: &str) -> Result, i32> { + let inode = self.0.lock(); + + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match name { + "" | "." => { + return Ok(inode.self_ref.upgrade().ok_or(-(ENOENT as i32))?); + } + ".." => { + return Ok(inode.parent.upgrade().ok_or(-(ENOENT as i32))?); + } + name => { + // 在子目录项中查找 + return Ok(inode.children.get(name).ok_or(-(ENOENT as i32))?.clone()); + } + } + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn get_entry_name(&self, ino: super::vfs::InodeId) -> Result { + let inode: SpinLockGuard = self.0.lock(); + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match ino { + 0 => { + return Ok(String::from(".")); + } + 1 => { + return Ok(String::from("..")); + } + ino => { + // 暴力遍历所有的children,判断inode id是否相同 + // TODO: 优化这里,这个地方性能很差! + let mut key: Vec = inode + .children + .keys() + .filter(|k| inode.children.get(*k).unwrap().metadata().unwrap().inode_id == ino) + .cloned() + .collect(); + + match key.len() { + 0=>{return Err(-(ENOENT as i32));} + 1=>{return Ok(key.remove(0));} + _ => panic!("Devfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = inode.metadata.inode_id, to_find=ino) + } + } + } + } + + fn ioctl(&self, _cmd: u32, _data: usize) -> Result { + Err(-(ENOTSUP as i32)) + } + + fn list(&self) -> Result, i32> { + let info = self.metadata()?; + if info.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + let mut keys: Vec = Vec::new(); + keys.push(String::from(".")); + keys.push(String::from("..")); + keys.append(&mut self.0.lock().children.keys().cloned().collect()); + + return Ok(keys); + } + + fn metadata(&self) -> Result { + return Ok(self.0.lock().metadata.clone()); + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn poll(&self) -> Result { + // 加锁 + let inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + return Ok(PollStatus { + flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK, + }); + } + + /// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn read_at( + &self, + _offset: usize, + _len: usize, + _buf: &mut [u8], + _data: &mut super::vfs::file::FilePrivateData, + ) -> Result { + Err(-(ENOTSUP as i32)) + } + + /// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: &mut super::vfs::file::FilePrivateData, + ) -> Result { + Err(-(ENOTSUP as i32)) + } +} + +/// @brief 所有的设备INode都需要额外实现这个trait +pub trait DeviceINode: IndexNode { + fn set_fs(&self, fs: Weak); + // TODO: 增加 unregister 方法 +} + +/// @brief 获取devfs实例的强类型不可变引用 +macro_rules! devfs_exact_ref { + () => {{ + let devfs_inode: Result, i32> = ROOT_INODE().find("dev"); + if let Err(e) = devfs_inode { + kerror!("failed to get DevFS ref. errcode = {e}"); + return Err(-(ENOENT as i32)); + } + + let binding = devfs_inode.unwrap(); + let devfs_inode: &LockedDevFSInode = binding + .as_any_ref() + .downcast_ref::() + .unwrap(); + let binding = devfs_inode.fs(); + binding + } + .as_any_ref() + .downcast_ref::() + .unwrap()}; +} +/// @brief devfs的设备注册函数 +pub fn devfs_register(name: &str, device: Arc) -> Result<(), i32> { + return devfs_exact_ref!().register_device(name, device); +} + +/// @brief devfs的设备卸载函数 +#[allow(dead_code)] +pub fn devfs_unregister(name: &str, device: Arc) -> Result<(), i32> { + return devfs_exact_ref!().unregister_device(name, device); +} diff --git a/kernel/src/filesystem/devfs/null_dev.rs b/kernel/src/filesystem/devfs/null_dev.rs new file mode 100644 index 00000000..83fa2457 --- /dev/null +++ b/kernel/src/filesystem/devfs/null_dev.rs @@ -0,0 +1,146 @@ +use crate::filesystem::vfs::make_rawdev; +use crate::filesystem::vfs::{ + core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus, +}; +use crate::{ + include::bindings::bindings::{EINVAL, ENOTSUP}, + libs::spinlock::SpinLock, + time::TimeSpec, +}; +use alloc::{ + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; +// use uuid::{uuid, Uuid}; +use super::{DevFS, DeviceINode}; + +#[derive(Debug)] +pub struct NullInode { + /// uuid 暂时不知道有什么用(x + // uuid: Uuid, + /// 指向自身的弱引用 + self_ref: Weak, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + /// INode 元数据 + metadata: Metadata, +} + +#[derive(Debug)] +pub struct LockedNullInode(SpinLock); + +impl LockedNullInode { + pub fn new() -> Arc { + let inode = NullInode { + // uuid: Uuid::new_v5(), + self_ref: Weak::default(), + fs: Weak::default(), + metadata: Metadata { + dev_id: 1, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::CharDevice, // 文件夹,block设备,char设备 + mode: 0o666, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: make_rawdev(1, 3), // 这里用来作为device number + }, + }; + + let result = Arc::new(LockedNullInode(SpinLock::new(inode))); + result.0.lock().self_ref = Arc::downgrade(&result); + + return result; + } +} + +impl DeviceINode for LockedNullInode { + fn set_fs(&self, fs: Weak) { + self.0.lock().fs = fs; + } +} + +impl IndexNode for LockedNullInode { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + Err(-(ENOTSUP as i32)) + } + + fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + Err(-(ENOTSUP as i32)) + } + + fn metadata(&self) -> Result { + return Ok(self.0.lock().metadata.clone()); + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn list(&self) -> Result, i32> { + Err(-(ENOTSUP as i32)) + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn poll(&self) -> Result { + return Ok(PollStatus { + flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK, + }); + } + + /// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn read_at( + &self, + _offset: usize, + len: usize, + buf: &mut [u8], + _data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + for i in 0..len { + buf[i] = 0; + } + + return Ok(len); + } + + /// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn write_at( + &self, + _offset: usize, + len: usize, + buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + Ok(len) + } +} diff --git a/kernel/src/filesystem/devfs/zero_dev.rs b/kernel/src/filesystem/devfs/zero_dev.rs new file mode 100644 index 00000000..25762108 --- /dev/null +++ b/kernel/src/filesystem/devfs/zero_dev.rs @@ -0,0 +1,146 @@ +use crate::filesystem::vfs::make_rawdev; +use crate::filesystem::vfs::{ + core::generate_inode_id, FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus, +}; +use crate::{ + include::bindings::bindings::{EINVAL, ENOTSUP}, + libs::spinlock::SpinLock, + time::TimeSpec, +}; +use alloc::{ + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; +// use uuid::{uuid, Uuid}; +use super::{DevFS, DeviceINode}; + +#[derive(Debug)] +pub struct ZeroInode { + /// uuid 暂时不知道有什么用(x + // uuid: Uuid, + /// 指向自身的弱引用 + self_ref: Weak, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + /// INode 元数据 + metadata: Metadata, +} + +#[derive(Debug)] +pub struct LockedZeroInode(SpinLock); + +impl LockedZeroInode { + pub fn new() -> Arc { + let inode = ZeroInode { + // uuid: Uuid::new_v5(), + self_ref: Weak::default(), + fs: Weak::default(), + metadata: Metadata { + dev_id: 1, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::CharDevice, // 文件夹,block设备,char设备 + mode: 0o666, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: make_rawdev(1, 3), // 这里用来作为device number + }, + }; + + let result = Arc::new(LockedZeroInode(SpinLock::new(inode))); + result.0.lock().self_ref = Arc::downgrade(&result); + + return result; + } +} + +impl DeviceINode for LockedZeroInode { + fn set_fs(&self, fs: Weak) { + self.0.lock().fs = fs; + } +} + +impl IndexNode for LockedZeroInode { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + Err(-(ENOTSUP as i32)) + } + + fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + Err(-(ENOTSUP as i32)) + } + + fn metadata(&self) -> Result { + return Ok(self.0.lock().metadata.clone()); + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn list(&self) -> Result, i32> { + Err(-(ENOTSUP as i32)) + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn poll(&self) -> Result { + return Ok(PollStatus { + flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK, + }); + } + + /// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn read_at( + &self, + _offset: usize, + len: usize, + buf: &mut [u8], + _data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + for i in 0..len { + buf[i] = 0; + } + + return Ok(len); + } + + /// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写 + fn write_at( + &self, + _offset: usize, + len: usize, + buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + Ok(len) + } +} diff --git a/kernel/src/filesystem/fat/bpb.rs b/kernel/src/filesystem/fat/bpb.rs new file mode 100644 index 00000000..6a82142b --- /dev/null +++ b/kernel/src/filesystem/fat/bpb.rs @@ -0,0 +1,380 @@ +#![allow(dead_code)] +use alloc::{sync::Arc, vec::Vec}; + +use crate::{ + include::bindings::bindings::EINVAL, + io::{device::LBA_SIZE, disk_info::Partition, SeekFrom}, + kerror, + libs::vec_cursor::VecCursor, +}; + +use super::fs::Cluster; + +/// 对于所有的FAT文件系统都适用的Bios Parameter Block结构体 +#[derive(Debug, Clone, Copy, Default)] +pub struct BiosParameterBlock { + /// 跳转指令 + pub jmp_boot: [u8; 3], + + /// 生产厂商名(表明是哪个操作系统格式化了这个卷) + pub oem_name: [u8; 8], + + /// 每扇区字节数 + pub bytes_per_sector: u16, + + /// 每簇扇区数 + pub sector_per_cluster: u8, + + /// 保留扇区数 + pub rsvd_sec_cnt: u16, + + /// FAT表数量 + pub num_fats: u8, + + /// 根目录下的32字节目录项数量最大值(只对FAT12、FAT16生效) + pub root_entries_cnt: u16, + + /// 当前分区的总扇区数(只对FAT12、FAT16生效) + pub total_sectors_16: u16, + + /// 介质描述符 + pub media: u8, + + /// FAT12/16每FAT扇区数 + pub fat_size_16: u16, + + /// 每磁道扇区数 + pub sector_per_track: u16, + + /// 磁头数 + pub num_heads: u16, + + /// 隐藏扇区数 + pub hidden_sectors: u32, + + /// FAT32的总扇区数 + pub total_sectors_32: u32, + + /// FAT文件系统类型(以及他们的一些私有信息字段) + pub fat_type: FATType, + + /// 引导扇区结束标志0xAA55 + pub trail_sig: u16, +} + +#[derive(Debug, Clone, Copy)] +pub enum FATType { + FAT12(BiosParameterBlockLegacy), + FAT16(BiosParameterBlockLegacy), + FAT32(BiosParameterBlockFAT32), +} + +/// @brief FAT12/FAT16文件系统特有的BPB信息字段 +#[derive(Debug, Clone, Copy, Default)] +pub struct BiosParameterBlockLegacy { + /// int0x13的驱动器号 + pub drive_num: u8, + /// 保留字段 + pub reserved1: u8, + /// 扩展引导标记 + pub boot_sig: u8, + /// 卷号 + /// BS_VolID + pub volume_id: u32, + /// 文件系统类型 + pub filesystem_type: u32, +} + +/// @brief FAT32文件系统特有的BPB信息字段 +#[derive(Debug, Clone, Copy, Default)] +pub struct BiosParameterBlockFAT32 { + /// FAT32每FAT扇区数 + /// BPB_FATSz32 + pub fat_size_32: u32, + + /// 扩展标记 + /// Bits 0-3 -- Zero based number of active FAT(活跃的FAT表的编号) + /// Only valid if mirroring iFAT32s disabled + /// Bits 4-6 -- 保留 + /// Bit 7 -- 0表示在运行时,所有的FAT表都互为镜像 + /// -- 1表示只使用1个FAT表,具体使用的FAT表的编号需要看Bits 0-3 + /// Bits 8-15 -- 保留备用 + /// BPB_ExtFlags + pub ext_flags: u16, + + /// 文件系统版本号。 + /// 高字节表示主版本号,低字节表示次版本号。 + /// BPB_FSVer + pub fs_version: u16, + + /// 根目录的簇号 + /// BPB_RootClus + pub root_cluster: u32, + + /// FsInfo结构体在分区内的偏移量(单位:扇区) + pub fs_info: u16, + + /// 如果这个值非0,那么它表示备份的引导扇区号。 + /// BPB_BkBootSec + pub backup_boot_sec: u16, + + /// 保留备用 + /// BPB_Reserved0 + pub reserved0: [u8; 12], + + /// int0x13的驱动器号 + /// BS_DrvNum + pub drive_num: u8, + + pub reserved1: u8, + + /// 引导标记 + /// BS_BootSig + pub boot_sig: u8, + + /// 卷号 + /// BS_VolID + pub volume_id: u32, + + /// 卷标 + /// BS_VolLab + pub volume_label: [u8; 11], + + /// 文件系统类型 + /// BS_FilSystype + pub filesystem_type: [u8; 8], +} + +impl Default for FATType { + fn default() -> Self { + return FATType::FAT32(BiosParameterBlockFAT32::default()); + } +} + +impl FATType { + /// @brief 获取指定的簇对应的FAT表项在分区内的字节偏移量 + /// + /// @param cluster 要查询的簇 + /// @param fat_start_sector FAT表的起始扇区 + /// @param bytes_per_sec 文件系统每扇区的字节数 + /// + /// @return 指定的簇对应的FAT表项在分区内的字节偏移量 + #[inline] + pub fn get_fat_bytes_offset( + &self, + cluster: Cluster, + fat_start_sector: u64, + bytes_per_sec: u64, + ) -> u64 { + let current_cluster = cluster.cluster_num; + // 要查询的簇,在FAT表中的字节偏移量 + let fat_bytes_offset = match self { + FATType::FAT12(_) => current_cluster + (current_cluster / 2), + FATType::FAT16(_) => current_cluster * 2, + FATType::FAT32(_) => current_cluster * 4, + }; + let fat_sec_number = fat_start_sector + (fat_bytes_offset / bytes_per_sec); + let fat_ent_offset = fat_bytes_offset % bytes_per_sec; + return fat_sec_number * bytes_per_sec + fat_ent_offset; + } +} + +impl BiosParameterBlock { + pub fn new(partition: Arc) -> Result { + let mut v = Vec::with_capacity(LBA_SIZE); + v.resize(LBA_SIZE, 0); + + // 读取分区的引导扇区 + partition + .disk() + .read_at(partition.lba_start as usize, 1, &mut v)?; + + // 获取指针对象 + let mut cursor = VecCursor::new(v); + + let mut bpb = BiosParameterBlock::default(); + + cursor.read_exact(&mut bpb.jmp_boot)?; + cursor.read_exact(&mut bpb.oem_name)?; + bpb.bytes_per_sector = cursor.read_u16()?; + bpb.sector_per_cluster = cursor.read_u8()?; + bpb.rsvd_sec_cnt = cursor.read_u16()?; + bpb.num_fats = cursor.read_u8()?; + bpb.root_entries_cnt = cursor.read_u16()?; + bpb.total_sectors_16 = cursor.read_u16()?; + bpb.media = cursor.read_u8()?; + bpb.fat_size_16 = cursor.read_u16()?; + bpb.sector_per_track = cursor.read_u16()?; + bpb.num_heads = cursor.read_u16()?; + bpb.hidden_sectors = cursor.read_u32()?; + bpb.total_sectors_32 = cursor.read_u32()?; + + let mut bpb32 = BiosParameterBlockFAT32::default(); + bpb32.fat_size_32 = cursor.read_u32()?; + bpb32.ext_flags = cursor.read_u16()?; + bpb32.fs_version = cursor.read_u16()?; + bpb32.root_cluster = cursor.read_u32()?; + bpb32.fs_info = cursor.read_u16()?; + bpb32.backup_boot_sec = cursor.read_u16()?; + + cursor.read_exact(&mut bpb32.reserved0)?; + bpb32.drive_num = cursor.read_u8()?; + bpb32.reserved1 = cursor.read_u8()?; + bpb32.boot_sig = cursor.read_u8()?; + bpb32.volume_id = cursor.read_u32()?; + cursor.read_exact(&mut bpb32.volume_label)?; + cursor.read_exact(&mut bpb32.filesystem_type)?; + + // 跳过启动代码 + cursor.seek(SeekFrom::SeekCurrent(420))?; + // 读取尾部的启动扇区标志 + bpb.trail_sig = cursor.read_u16()?; + + // 验证BPB32的信息是否合法 + bpb.validate(&bpb32)?; + + // 计算根目录项占用的空间(单位:字节) + let root_sectors = ((bpb.root_entries_cnt as u32 * 32) + (bpb.bytes_per_sector as u32 - 1)) + / (bpb.bytes_per_sector as u32); + + // 每FAT扇区数 + let fat_size = if bpb.fat_size_16 != 0 { + bpb.fat_size_16 as u32 + } else { + bpb32.fat_size_32 + }; + + // 当前分区总扇区数 + let total_sectors = if bpb.total_sectors_16 != 0 { + bpb.total_sectors_16 as u32 + } else { + bpb.total_sectors_32 + }; + + // 数据区扇区数 + let data_sectors = total_sectors + - ((bpb.rsvd_sec_cnt as u32) + (bpb.num_fats as u32) * fat_size + root_sectors); + // 总的数据簇数量(向下对齐) + let count_clusters = data_sectors / (bpb.sector_per_cluster as u32); + + // 设置FAT类型 + bpb.fat_type = if count_clusters < 4085 { + FATType::FAT12(BiosParameterBlockLegacy::default()) + } else if count_clusters < 65525 { + FATType::FAT16(BiosParameterBlockLegacy::default()) + } else { + FATType::FAT32(bpb32) + }; + + return Ok(bpb); + } + + /// @brief 验证BPB32的信息是否合法 + pub fn validate(&self, bpb32: &BiosParameterBlockFAT32) -> Result<(), i32> { + // 校验每扇区字节数是否合法 + if self.bytes_per_sector.count_ones() != 1 { + kerror!("Invalid bytes per sector(not a power of 2)"); + return Err(-(EINVAL as i32)); + } else if self.bytes_per_sector < 512 { + kerror!("Invalid bytes per sector (value < 512)"); + return Err(-(EINVAL as i32)); + } else if self.bytes_per_sector > 4096 { + kerror!("Invalid bytes per sector (value > 4096)"); + return Err(-(EINVAL as i32)); + } + + let is_fat32 = self.is_fat32(); + + if self.rsvd_sec_cnt < 1 { + kerror!("Invalid rsvd_sec_cnt value in BPB"); + return Err(-(EINVAL as i32)); + } + + if self.num_fats == 0 { + kerror!("Invalid fats value in BPB"); + return Err(-(EINVAL as i32)); + } + + if is_fat32 && self.root_entries_cnt != 0 { + kerror!("Invalid root_entries value in BPB (should be zero for FAT32)"); + return Err(-(EINVAL as i32)); + } + + if is_fat32 && self.total_sectors_16 != 0 { + kerror!("Invalid total_sectors_16 value in BPB (should be zero for FAT32)"); + return Err(-(EINVAL as i32)); + } + + if (self.total_sectors_16 == 0) && (self.total_sectors_32 == 0) { + kerror!("Invalid BPB (total_sectors_16 or total_sectors_32 should be non-zero)"); + return Err(-(EINVAL as i32)); + } + + if is_fat32 && bpb32.fat_size_32 == 0 { + kerror!("Invalid fat_size_32 value in BPB (should be non-zero for FAT32)"); + return Err(-(EINVAL as i32)); + } + + if bpb32.fs_version != 0 { + kerror!("Unknown FAT FS version"); + return Err(-(EINVAL as i32)); + } + + let root_sectors = ((self.root_entries_cnt as u32 * 32) + + (self.bytes_per_sector as u32 - 1)) + / (self.bytes_per_sector as u32); + + // 每FAT扇区数 + let fat_size = if self.fat_size_16 != 0 { + self.fat_size_16 as u32 + } else { + bpb32.fat_size_32 + }; + + // 当前分区总扇区数 + let total_sectors = if self.total_sectors_16 != 0 { + self.total_sectors_16 as u32 + } else { + self.total_sectors_32 + }; + + let first_data_sector = + (self.rsvd_sec_cnt as u32) + (self.num_fats as u32) * fat_size + root_sectors; + + // 数据区扇区数 + let data_sectors = total_sectors - first_data_sector; + // 总的数据簇数量(向下对齐) + let count_clusters = data_sectors / (self.sector_per_cluster as u32); + + // 总扇区数应当大于第一个数据扇区的扇区号 + if total_sectors <= first_data_sector { + kerror!("Total sectors lesser than first data sector"); + return Err(-(EINVAL as i32)); + } + + // 检查文件系统类型与总的数据簇数量的关系是否合法 + if (is_fat32 && (count_clusters < 65525)) || ((!is_fat32) && (count_clusters >= 65525)) { + kerror!("FAT determination using tot_sec_16 and count_cluster differs"); + return Err(-(EINVAL as i32)); + } + return Ok(()); + } + + /// @brief 判断当前是否为fat32的bpb + fn is_fat32(&self) -> bool { + // fat32的bpb,这个字段是0 + return self.total_sectors_16 == 0; + } + + pub fn get_volume_id(&self) -> u32 { + match self.fat_type { + FATType::FAT12(f) | FATType::FAT16(f) => { + return f.volume_id; + } + + FATType::FAT32(f) => { + return f.volume_id; + } + } + } +} diff --git a/kernel/src/filesystem/fat/entry.rs b/kernel/src/filesystem/fat/entry.rs new file mode 100644 index 00000000..fa9dd7d3 --- /dev/null +++ b/kernel/src/filesystem/fat/entry.rs @@ -0,0 +1,2404 @@ +#![allow(dead_code)] +use core::cmp::min; + +use alloc::{ + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; + +use crate::{ + include::bindings::bindings::{ + EEXIST, EILSEQ, EINVAL, EISDIR, ENAMETOOLONG, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY, EPERM, + EROFS, + }, + io::{device::LBA_SIZE, SeekFrom}, + kwarn, + libs::vec_cursor::VecCursor, +}; + +use super::{ + fs::{Cluster, FATFileSystem, MAX_FILE_SIZE}, + utils::decode_u8_ascii, +}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct FileAttributes { + value: u8, +} + +/// FAT表中,关于每个簇的信息 +#[derive(Debug, Eq, PartialEq)] +pub enum FATEntry { + /// 当前簇未使用 + Unused, + /// 当前簇是坏簇 + Bad, + /// 当前簇是整个FAT簇链的最后一个簇 + EndOfChain, + /// 在整个链中,当前簇的下一个簇的值 + Next(Cluster), +} + +/// FAT目录项的枚举类型 +#[derive(Debug, Clone)] +pub enum FATDirEntry { + File(FATFile), + VolId(FATFile), + Dir(FATDir), + UnInit, +} + +/// FAT文件系统中的文件 +#[derive(Debug, Default, Clone)] +pub struct FATFile { + /// 文件的第一个簇 + pub first_cluster: Cluster, + /// 文件名 + pub file_name: String, + /// 文件对应的短目录项 + pub short_dir_entry: ShortDirEntry, + /// 文件目录项的起始、终止簇。格式:(簇,簇内偏移量) + pub loc: ((Cluster, u64), (Cluster, u64)), +} + +impl FATFile { + /// @brief 获取文件大小 + #[inline] + pub fn size(&self) -> u64 { + return self.short_dir_entry.file_size as u64; + } + + /// @brief 设置当前文件大小(仅仅更改short_dir_entry内的值) + #[inline] + pub fn set_size(&mut self, size: u32) { + self.short_dir_entry.file_size = size; + } + + /// @brief 从文件读取数据。读取的字节数与buf长度相等 + /// + /// @param buf 输出缓冲区 + /// @param offset 起始位置在文件中的偏移量 + /// + /// @return Ok(usize) 成功读取到的字节数 + /// @return Err(i32) 读取时出现错误,返回错误码 + pub fn read(&self, fs: &Arc, buf: &mut [u8], offset: u64) -> Result { + if offset >= self.size() { + return Ok(0); + } + + // 文件内的簇偏移量 + let start_cluster_number: u64 = offset / fs.bytes_per_cluster(); + // 计算对应在分区内的簇号 + let mut current_cluster = if let Some(c) = + fs.get_cluster_by_relative(self.first_cluster, start_cluster_number as usize) + { + c + } else { + return Ok(0); + }; + + let bytes_remain: u64 = self.size() - offset; + + // 计算簇内偏移量 + let mut in_cluster_offset: u64 = offset % fs.bytes_per_cluster(); + let to_read_size: usize = min(buf.len(), bytes_remain as usize); + + let mut start = 0; + let mut read_ok = 0; + + loop { + // 当前簇已经读取完,尝试读取下一个簇 + if in_cluster_offset >= fs.bytes_per_cluster() { + if let Some(FATEntry::Next(c)) = fs.get_fat_entry(current_cluster).ok() { + current_cluster = c; + in_cluster_offset %= fs.bytes_per_cluster(); + } else { + break; + } + } + + // 计算下一次读取,能够读多少字节 + let end_len: usize = min( + to_read_size - read_ok, + min( + (fs.bytes_per_cluster() - in_cluster_offset) as usize, + buf.len() - read_ok, + ), + ); + + // 从磁盘上读取数据 + let offset = fs.cluster_bytes_offset(current_cluster) + in_cluster_offset; + let r = fs.partition.disk().device().read_at( + offset as usize, + end_len, + &mut buf[start..start + end_len], + )?; + + // 更新偏移量计数信息 + read_ok += r; + start += r; + in_cluster_offset += r as u64; + if read_ok == to_read_size { + break; + } + } + // todo: 更新时间信息 + return Ok(read_ok); + } + + /// @brief 向文件写入数据。写入的字节数与buf长度相等 + /// + /// @param buf 输入缓冲区 + /// @param offset 起始位置在文件中的偏移量 + /// + /// @return Ok(usize) 成功写入的字节数 + /// @return Err(i32) 写入时出现错误,返回错误码 + pub fn write( + &mut self, + fs: &Arc, + buf: &[u8], + offset: u64, + ) -> Result { + self.ensure_len(fs, offset, buf.len() as u64)?; + + // 要写入的第一个簇的簇号 + let start_cluster_num = offset / fs.bytes_per_cluster(); + + // 获取要写入的第一个簇 + let mut current_cluster: Cluster = if let Some(c) = + fs.get_cluster_by_relative(self.first_cluster, start_cluster_num as usize) + { + c + } else { + return Ok(0); + }; + + let mut in_cluster_bytes_offset: u64 = offset % fs.bytes_per_cluster(); + + let mut start: usize = 0; + let mut write_ok: usize = 0; + + // 循环写入数据 + loop { + if in_cluster_bytes_offset >= fs.bytes_per_cluster() { + if let Some(FATEntry::Next(c)) = fs.get_fat_entry(current_cluster).ok() { + current_cluster = c; + in_cluster_bytes_offset = in_cluster_bytes_offset % fs.bytes_per_cluster(); + } else { + break; + } + } + + let end_len = min( + (fs.bytes_per_cluster() - in_cluster_bytes_offset) as usize, + buf.len() - write_ok, + ); + + // 计算本次写入位置在磁盘上的偏移量 + let offset = fs.cluster_bytes_offset(current_cluster) + in_cluster_bytes_offset; + // 写入磁盘 + let w: usize = fs.partition.disk().device().write_at( + offset as usize, + end_len, + &buf[start..start + end_len], + )?; + + // 更新偏移量数据 + write_ok += w; + start += w; + in_cluster_bytes_offset += w as u64; + + if write_ok == buf.len() { + break; + } + } + // todo: 更新时间信息 + return Ok(write_ok); + } + + /// @brief 确保文件从指定偏移量开始,仍有长度为len的空间。 + /// 如果文件大小不够,就尝试分配更多的空间给这个文件。 + /// + /// @param fs 当前文件所属的文件系统 + /// @param offset 起始位置在文件内的字节偏移量 + /// @param len 期待的空闲空间长度 + /// + /// @return Ok(()) 经过操作后,offset后面具有长度至少为len的空闲空间 + /// @return Err(i32) 处理过程中出现了异常。 + fn ensure_len(&mut self, fs: &Arc, offset: u64, len: u64) -> Result<(), i32> { + // 文件内本身就还有空余的空间 + if offset + len <= self.size() { + return Ok(()); + } + + // 如果文件大小为0,证明它还没有分配簇,因此分配一个簇给它 + if self.size() == 0 { + // first_cluster应当为0,否则将产生空间泄露的错误 + assert_eq!(self.first_cluster, Cluster::default()); + self.first_cluster = fs.allocate_cluster(None)?; + self.short_dir_entry.set_first_cluster(self.first_cluster); + } + + // 计算文件的最后一个簇中有多少空闲空间 + + let in_cluster_offset = self.size() % fs.bytes_per_cluster(); + let bytes_remain_in_cluster = fs.bytes_per_cluster() - in_cluster_offset; + + // 计算还需要申请多少空间 + let extra_bytes = min((offset + len) - self.size(), MAX_FILE_SIZE - self.size()); + + // 如果还需要更多的簇 + if bytes_remain_in_cluster < extra_bytes { + let clusters_to_allocate = + (extra_bytes - bytes_remain_in_cluster + fs.bytes_per_cluster() - 1) + / fs.bytes_per_cluster(); + let last_cluster = if let Some(c) = fs.get_last_cluster(self.first_cluster) { + c + } else { + kwarn!("FAT: last cluster not found, File = {self:?}"); + return Err(-(EINVAL as i32)); + }; + // 申请簇 + let mut current_cluster: Cluster = last_cluster; + for _ in 0..clusters_to_allocate { + current_cluster = fs.allocate_cluster(Some(current_cluster))?; + } + } + + // 如果文件被扩展,则清空刚刚被扩展的部分的数据 + if offset > self.size() { + // 文件内的簇偏移 + let start_cluster: u64 = self.size() / fs.bytes_per_cluster(); + let start_cluster: Cluster = fs + .get_cluster_by_relative(self.first_cluster, start_cluster as usize) + .unwrap(); + // 计算当前文件末尾在磁盘上的字节偏移量 + let start_offset: u64 = + fs.cluster_bytes_offset(start_cluster) + self.size() % fs.bytes_per_cluster(); + // 扩展之前,最后一个簇内还剩下多少字节的空间 + let bytes_remain: u64 = fs.bytes_per_cluster() - (self.size() % fs.bytes_per_cluster()); + // 计算在扩展之后的最后一个簇内,文件的终止字节 + let cluster_offset_start = offset / fs.bytes_per_cluster(); + // 扩展后,文件的最后 + let end_cluster: Cluster = fs + .get_cluster_by_relative(self.first_cluster, cluster_offset_start as usize) + .unwrap(); + + if start_cluster != end_cluster { + self.zero_range(fs, start_offset, start_offset + bytes_remain)?; + } else { + self.zero_range(fs, start_offset, start_offset + offset - self.size())?; + } + } + // 计算文件的新大小 + let new_size = self.size() + extra_bytes; + self.set_size(new_size as u32); + // 计算短目录项所在的位置,更新短目录项 + let short_entry_offset = fs.cluster_bytes_offset(self.loc.1 .0) + self.loc.1 .1; + // todo: 更新时间信息 + // 把短目录项写入磁盘 + self.short_dir_entry.flush(fs, short_entry_offset)?; + return Ok(()); + } + + /// @brief 把磁盘上[range_start, range_end)范围的数据清零 + /// + /// @param range_start 磁盘上起始位置(单位:字节) + /// @param range_end 磁盘上终止位置(单位:字节) + fn zero_range( + &self, + fs: &Arc, + range_start: u64, + range_end: u64, + ) -> Result<(), i32> { + if range_end <= range_start { + return Ok(()); + } + + let zeroes: Vec = vec![0u8; (range_end - range_start) as usize]; + fs.partition.disk().device().write_at( + range_start as usize, + zeroes.len(), + zeroes.as_slice(), + )?; + return Ok(()); + } + + /// @brief 截断文件的内容,并设置新的文件大小。如果new_size大于当前文件大小,则不做操作。 + /// + /// @param new_size 新的文件大小,如果它大于当前文件大小,则不做操作。 + /// + /// @return Ok(()) 操作成功 + /// @return Err(i32) 在操作时出现错误 + pub fn truncate(&mut self, fs: &Arc, new_size: u64) -> Result<(), i32> { + if new_size >= self.size() { + return Ok(()); + } + + let new_last_cluster = new_size / fs.bytes_per_cluster(); + if let Some(begin_delete) = + fs.get_cluster_by_relative(self.first_cluster, (new_last_cluster + 1) as usize) + { + fs.deallocate_cluster(begin_delete)?; + }; + + self.set_size(new_size as u32); + // 计算短目录项在磁盘内的字节偏移量 + let short_entry_offset = fs.cluster_bytes_offset((self.loc.1).0) + (self.loc.1).1; + self.short_dir_entry.flush(fs, short_entry_offset)?; + return Ok(()); + } +} + +/// FAT文件系统中的文件夹 +#[derive(Debug, Default, Clone)] +pub struct FATDir { + /// 目录的第一个簇 + pub first_cluster: Cluster, + /// 该字段仅对FAT12、FAT16生效 + pub root_offset: Option, + /// 文件夹名称 + pub dir_name: String, + pub short_dir_entry: Option, + /// 文件的起始、终止簇。格式:(簇,簇内偏移量) + pub loc: Option<((Cluster, u64), (Cluster, u64))>, +} + +impl FATDir { + /// @brief 获得用于遍历当前目录的迭代器 + /// + /// @param fs 当前目录所在的文件系统 + pub fn to_iter(&self, fs: Arc) -> FATDirIter { + return FATDirIter { + current_cluster: self.first_cluster, + offset: self.root_offset.unwrap_or(0), + is_root: self.is_root(), + fs: fs, + }; + } + + /// @brief 判断当前目录是否为根目录(仅对FAT12和FAT16生效) + #[inline] + pub fn is_root(&self) -> bool { + return self.root_offset.is_some(); + } + + /// @brief 获取当前目录所占用的大小 + pub fn size(&self, fs: &Arc) -> u64 { + return fs.num_clusters_chain(self.first_cluster) * fs.bytes_per_cluster(); + } + + /// @brief 在目录项中,寻找num_free个连续空闲目录项 + /// + /// @param num_free 需要的空闲目录项数目. + /// @param fs 当前文件夹属于的文件系统 + /// + /// @return Ok(Option<(第一个符合条件的空闲目录项所在的簇,簇内偏移量)) + /// @return Err(错误码) + pub fn find_free_entries( + &self, + num_free: u64, + fs: Arc, + ) -> Result, i32> { + let mut free = 0; + let mut current_cluster: Cluster = self.first_cluster; + let mut offset = self.root_offset.unwrap_or(0); + // 第一个符合条件的空闲目录项 + let mut first_free: Option<(Cluster, u64)> = None; + + loop { + // 如果当前簇没有空间了,并且当前不是FAT12和FAT16的根目录,那么就读取下一个簇。 + if offset >= fs.bytes_per_cluster() && !self.is_root() { + // 成功读取下一个簇 + if let Some(FATEntry::Next(c)) = fs.get_fat_entry(current_cluster).ok() { + current_cluster = c; + // 计算簇内偏移量 + offset = offset % fs.bytes_per_cluster(); + } else { + // 读取失败,当前已经是最后一个簇,退出循环 + break; + } + } + // 如果当前目录是FAT12和FAT16的根目录,且已经读取完,就直接返回。 + if self.is_root() && offset > fs.root_dir_end_bytes_offset().unwrap() { + return Ok(None); + } + + let e_offset = fs.cluster_bytes_offset(current_cluster) + offset; + let entry: FATRawDirEntry = get_raw_dir_entry(&fs, e_offset)?; + + match entry { + FATRawDirEntry::Free | FATRawDirEntry::FreeRest => { + if free == 0 { + first_free = Some((current_cluster, offset)); + } + + free += 1; + if free == num_free { + // kdebug!("first_free = {first_free:?}, current_free = ({current_cluster:?}, {offset})"); + return Ok(first_free); + } + } + + // 遇到一个不空闲的目录项,那么重新开始计算空闲目录项 + _ => { + free = 0; + } + } + offset += FATRawDirEntry::DIR_ENTRY_LEN; + } + + // 剩余的需要获取的目录项 + let remain_entries = num_free - free; + + // 计算需要申请多少个簇 + let clusters_required = + (remain_entries * FATRawDirEntry::DIR_ENTRY_LEN + fs.bytes_per_cluster() - 1) + / fs.bytes_per_cluster(); + let mut first_cluster = Cluster::default(); + let mut prev_cluster = current_cluster; + // kdebug!( + // "clusters_required={clusters_required}, prev_cluster={prev_cluster:?}, free ={free}" + // ); + // 申请簇 + for i in 0..clusters_required { + let c: Cluster = fs.allocate_cluster(Some(prev_cluster))?; + if i == 0 { + first_cluster = c; + } + + prev_cluster = c; + } + + if free > 0 { + // 空闲目录项跨越了簇,返回第一个空闲目录项 + return Ok(first_free); + } else { + // 空闲目录项是在全新的簇开始的 + return Ok(Some((first_cluster, 0))); + } + } + + /// @brief 在当前目录中寻找目录项 + /// + /// @param name 目录项的名字 + /// @param expect_dir 该值为Some时有效。如果期待目标目录项是文件夹,那么值为Some(true), 否则为Some(false). + /// @param short_name_gen 短目录项名称生成器 + /// @param fs 当前目录所属的文件系统 + /// + /// @return Ok(FATDirEntry) 找到期待的目录项 + /// @return Err(i32) 错误码 + pub fn find_entry( + &self, + name: &str, + expect_dir: Option, + mut short_name_gen: Option<&mut ShortNameGenerator>, + fs: Arc, + ) -> Result { + LongDirEntry::validate_long_name(name)?; + // 迭代当前目录下的文件/文件夹 + for e in self.to_iter(fs) { + if e.eq_name(name) { + if expect_dir.is_some() && Some(e.is_dir()) != expect_dir { + if e.is_dir() { + // 期望得到文件,但是是文件夹 + return Err(-(EISDIR as i32)); + } else { + // 期望得到文件夹,但是是文件 + return Err(-(ENOTDIR as i32)); + } + } + // 找到期望的目录项 + return Ok(e); + } + + if let Some(ref mut sng) = short_name_gen { + sng.add_name(&e.short_name_raw()) + } + } + // 找不到文件/文件夹 + return Err(-(ENOENT as i32)); + } + + /// @brief 在当前目录下打开文件,获取FATFile结构体 + pub fn open_file(&self, name: &str, fs: Arc) -> Result { + let f: FATFile = self.find_entry(name, Some(false), None, fs)?.to_file()?; + return Ok(f); + } + + /// @brief 在当前目录下打开文件夹,获取FATDir结构体 + pub fn open_dir(&self, name: &str, fs: Arc) -> Result { + let d: FATDir = self.find_entry(name, Some(true), None, fs)?.to_dir()?; + return Ok(d); + } + + /// @brief 在当前文件夹下创建文件。 + /// + /// @param name 文件名 + /// @param fs 当前文件夹所属的文件系统 + pub fn create_file(&self, name: &str, fs: &Arc) -> Result { + let r: Result = + self.check_existence(name, Some(false), fs.clone()); + // 检查错误码,如果能够表明目录项已经存在,则返回-EEXIST + if r.is_err() { + let err_val = r.unwrap_err(); + if err_val == (-(EISDIR as i32)) || err_val == (-(ENOTDIR as i32)) { + return Err(-(EEXIST as i32)); + } else { + return Err(err_val); + } + } + + match r.unwrap() { + FATDirEntryOrShortName::ShortName(short_name) => { + // 确认名称是一个可行的长文件名 + LongDirEntry::validate_long_name(name)?; + // 创建目录项 + let x: Result = self + .create_dir_entries( + name.trim(), + &short_name, + None, + FileAttributes { + value: FileAttributes::ARCHIVE, + }, + fs.clone(), + ) + .map(|e| e.to_file())?; + return x; + } + + FATDirEntryOrShortName::DirEntry(_) => { + // 已经存在这样的一个目录项了 + return Err(-(EEXIST as i32)); + } + } + } + + pub fn create_dir(&self, name: &str, fs: &Arc) -> Result { + let r: Result = + self.check_existence(name, Some(true), fs.clone()); + // kdebug!("check existence ok"); + // 检查错误码,如果能够表明目录项已经存在,则返回-EEXIST + if r.is_err() { + let err_val = r.unwrap_err(); + if err_val == (-(EISDIR as i32)) || err_val == (-(ENOTDIR as i32)) { + return Err(-(EEXIST as i32)); + } else { + return Err(err_val); + } + } + + match r.unwrap() { + // 文件夹不存在,创建文件夹 + FATDirEntryOrShortName::ShortName(short_name) => { + LongDirEntry::validate_long_name(name)?; + // 目标目录项 + let mut short_entry = ShortDirEntry::default(); + // kdebug!("to allocate cluster"); + let first_cluster: Cluster = fs.allocate_cluster(None)?; + short_entry.set_first_cluster(first_cluster); + + // kdebug!("to create dot"); + // === 接下来在子目录中创建'.'目录项和'..'目录项 + let mut offset = 0; + // '.'目录项 + let mut dot_entry = ShortDirEntry::default(); + dot_entry.name = ShortNameGenerator::new(".").generate().unwrap(); + dot_entry.attributes.value = FileAttributes::DIRECTORY; + dot_entry.set_first_cluster(first_cluster); + + // todo: 设置创建、访问时间 + dot_entry.flush(&fs, fs.cluster_bytes_offset(first_cluster) + offset)?; + + drop(dot_entry); + // 偏移量加上一个目录项的长度 + offset += FATRawDirEntry::DIR_ENTRY_LEN; + + // kdebug!("to create dot dot"); + // '..'目录项 + let mut dot_dot_entry = ShortDirEntry::default(); + dot_dot_entry.name = ShortNameGenerator::new("..").generate().unwrap(); + dot_dot_entry.attributes.value = FileAttributes::DIRECTORY; + dot_dot_entry.set_first_cluster(self.first_cluster); + // todo: 设置创建、访问时间 + + dot_dot_entry.flush(&fs, fs.cluster_bytes_offset(first_cluster) + offset)?; + + // kdebug!("to create dentries"); + // 在当前目录下创建目标目录项 + let res = self + .create_dir_entries( + name.trim(), + &short_name, + Some(short_entry), + FileAttributes { + value: FileAttributes::DIRECTORY, + }, + fs.clone(), + ) + .map(|e| e.to_dir())?; + // kdebug!("create dentries ok"); + return res; + } + FATDirEntryOrShortName::DirEntry(_) => { + // 已经存在这样的一个目录项了 + return Err(-(EEXIST as i32)); + } + } + } + /// @brief 检查目录项在当前文件夹下是否存在 + /// + /// @param name 目录项的名字 + /// @param expect_dir 该值为Some时有效。如果期待目标目录项是文件夹,那么值为Some(true), 否则为Some(false). + /// @param fs 当前目录所属的文件系统 + /// + /// @return Ok(FATDirEntryOrShortName::DirEntry) 找到期待的目录项 + /// @return Ok(FATDirEntryOrShortName::ShortName) 当前文件夹下不存在指定的目录项,因此返回一个可行的短文件名 + /// @return Err(i32) 错误码 + pub fn check_existence( + &self, + name: &str, + expect_dir: Option, + fs: Arc, + ) -> Result { + let mut sng = ShortNameGenerator::new(name); + + loop { + let e: Result = + self.find_entry(name, expect_dir, Some(&mut sng), fs.clone()); + match e { + Ok(e) => { + // 找到,返回目录项 + return Ok(FATDirEntryOrShortName::DirEntry(e)); + } + Err(e) => { + // 如果没找到,则不返回错误 + if e == -(ENOENT as i32) { + } else { + // 其他错误,则返回 + return Err(e); + } + } + } + + // 没找到文件,则生成短文件名 + if let Ok(name) = sng.generate() { + return Ok(FATDirEntryOrShortName::ShortName(name)); + } + + sng.next_iteration(); + } + } + + /// @brief 创建一系列的目录项 + /// + /// @param long_name 长文件名 + /// @param short_name 短文件名 + /// @param short_dentry 可选的生成好的短目录项结构体 + /// @param attrs FAT目录项的属性 + /// @param fs 当前文件夹所属的文件系统 + /// + /// @return Ok(FATDirEntry) FAT目录项的枚举类型(目录项链条的最后一个长目录项) + fn create_dir_entries( + &self, + long_name: &str, + short_name: &[u8; 11], + short_dentry: Option, + attrs: FileAttributes, + fs: Arc, + ) -> Result { + let mut short_dentry: ShortDirEntry = short_dentry.unwrap_or(ShortDirEntry::default()); + short_dentry.name = short_name.clone(); + short_dentry.attributes = attrs; + + // todo: 设置创建时间、修改时间 + + let mut long_name_gen: LongNameEntryGenerator = + LongNameEntryGenerator::new(long_name, short_dentry.checksum()); + let num_entries = long_name_gen.num_entries() as u64; + + // kdebug!("to find free entries"); + let free_entries: Option<(Cluster, u64)> = + self.find_free_entries(num_entries, fs.clone())?; + // 目录项开始位置 + let start_loc: (Cluster, u64) = match free_entries { + Some(c) => c, + None => return Err(-(ENOSPC as i32)), + }; + let offsets: Vec<(Cluster, u64)> = + FATDirEntryOffsetIter::new(fs.clone(), start_loc, num_entries, None).collect(); + + // 迭代长目录项 + for off in &offsets.as_slice()[..offsets.len() - 1] { + // 获取生成的下一个长目录项 + let long_entry: LongDirEntry = long_name_gen.next().unwrap(); + // 获取这个长目录项在磁盘内的字节偏移量 + let bytes_offset = fs.cluster_bytes_offset(off.0) + off.1; + long_entry.flush(fs.clone(), bytes_offset)?; + } + + let start: (Cluster, u64) = offsets[0]; + let end: (Cluster, u64) = *offsets.last().unwrap(); + // 短目录项在磁盘上的字节偏移量 + let offset = fs.cluster_bytes_offset(end.0) + end.1; + short_dentry.flush(&fs, offset)?; + + return Ok(short_dentry.to_dir_entry_with_long_name(long_name.to_string(), (start, end))); + } + + /// @brief 判断当前目录是否为空 + /// + /// @return true 当前目录为空 + /// @return false 当前目录不为空 + pub fn is_empty(&self, fs: Arc) -> bool { + for e in self.to_iter(fs) { + let s = e.short_name(); + if s == "." || s == ".." { + continue; + } else { + return false; + } + } + return true; + } + + /// @brief 从当前文件夹中删除文件或者文件夹。如果目标文件夹不为空,则不能删除,返回-ENOTEMPTY. + /// + /// @param fs 当前FATDir所属的文件系统 + /// @param name 目录项的名字 + /// @param remove_clusters 是否删除与指定的目录项相关联的数据簇 + /// + /// @return Ok() 成功时无返回值 + /// @return Err(i32) 如果目标文件夹不为空,则不能删除,返回-ENOTEMPTY. 或者返回底层传上来的错误 + pub fn remove( + &self, + fs: Arc, + name: &str, + remove_clusters: bool, + ) -> Result<(), i32> { + let e: FATDirEntry = self.find_entry(name, None, None, fs.clone())?; + + // 判断文件夹是否为空,如果空,则不删除,报错。 + if e.is_dir() && !(e.to_dir().unwrap().is_empty(fs.clone())) { + return Err(-(ENOTEMPTY as i32)); + } + + if e.first_cluster().cluster_num >= 2 && remove_clusters { + // 删除与指定的目录项相关联的数据簇 + fs.deallocate_cluster_chain(e.first_cluster())?; + } + + if e.get_dir_range().is_some() { + self.remove_dir_entries(fs, e.get_dir_range().unwrap())?; + } + + return Ok(()); + } + + /// @brief 在当前目录中删除多个目录项 + /// + /// @param fs 当前目录所属的文件系统 + /// @param cluster_range 要删除的目录项的范围(以簇+簇内偏移量的形式表示) + fn remove_dir_entries( + &self, + fs: Arc, + cluster_range: ((Cluster, u64), (Cluster, u64)), + ) -> Result<(), i32> { + // 收集所有的要移除的目录项 + let offsets: Vec<(Cluster, u64)> = + FATDirEntryOffsetIter::new(fs.clone(), cluster_range.0, 15, Some(cluster_range.1)) + .collect(); + // 逐个设置这些目录项为“空闲”状态 + for off in offsets { + let disk_bytes_offset = fs.cluster_bytes_offset(off.0) + off.1; + let mut short_entry = ShortDirEntry::default(); + short_entry.name[0] = 0xe5; + short_entry.flush(&fs, disk_bytes_offset)?; + } + return Ok(()); + } + + /// @brief 根据名字在当前文件夹下寻找目录项 + /// + /// @return Ok(FATDirEntry) 目标目录项 + /// @return Err(i32) 底层传上来的错误码 + pub fn get_dir_entry(&self, fs: Arc, name: &str) -> Result { + if name == "." || name == "/" { + return Ok(FATDirEntry::Dir(self.clone())); + } + + LongDirEntry::validate_long_name(name)?; + return self.find_entry(name, None, None, fs); + } + + /// @brief 在当前目录内,重命名一个目录项 + /// + pub fn rename( + &self, + fs: Arc, + old_name: &str, + new_name: &str, + ) -> Result { + // 判断源目录项是否存在 + let old_dentry: FATDirEntry = if let FATDirEntryOrShortName::DirEntry(dentry) = + self.check_existence(old_name, None, fs.clone())? + { + dentry + } else { + // 如果目标目录项不存在,则返回错误 + return Err(-(ENOENT as i32)); + }; + + let short_name = if let FATDirEntryOrShortName::ShortName(s) = + self.check_existence(new_name, None, fs.clone())? + { + s + } else { + // 如果目标目录项存在,那么就返回错误 + return Err(-(EEXIST as i32)); + }; + + let old_short_dentry: Option = old_dentry.short_dir_entry(); + if let Some(se) = old_short_dentry { + // 删除原来的目录项 + self.remove(fs.clone(), old_dentry.name().as_str(), false)?; + + // 创建新的目录项 + let new_dentry: FATDirEntry = self.create_dir_entries( + new_name, + &short_name, + Some(se), + se.attributes, + fs.clone(), + )?; + + return Ok(new_dentry); + } else { + // 不允许对根目录项进行重命名 + return Err(-(EPERM as i32)); + } + } +} + +impl FileAttributes { + pub const READ_ONLY: u8 = 1 << 0; + pub const HIDDEN: u8 = 1 << 1; + pub const SYSTEM: u8 = 1 << 2; + pub const VOLUME_ID: u8 = 1 << 3; + pub const DIRECTORY: u8 = 1 << 4; + pub const ARCHIVE: u8 = 1 << 5; + pub const LONG_NAME: u8 = FileAttributes::READ_ONLY + | FileAttributes::HIDDEN + | FileAttributes::SYSTEM + | FileAttributes::VOLUME_ID; + + /// @brief 判断属性是否存在 + #[inline] + pub fn contains(&self, attr: u8) -> bool { + return (self.value & attr) != 0; + } + + pub fn new(attr: u8) -> Self { + return Self { value: attr }; + } +} + +/// FAT32的短目录项 +#[derive(Debug, Clone, Copy, Default)] +pub struct ShortDirEntry { + /// short name + name: [u8; 11], + /// 目录项属性 (见 FileAttributes ) + attributes: FileAttributes, + + /// Windows NT系统的保留字段。用来表示短目录项文件名。 + /// EXT|BASE => 8(BASE).3(EXT) + /// BASE:LowerCase(8),UpperCase(0) + /// EXT:LowerCase(16),UpperCase(0) + nt_res: u8, + + /// 文件创建时间的毫秒级时间戳 + crt_time_tenth: u8, + /// 创建时间 + crt_time: u16, + /// 创建日期 + crt_date: u16, + /// 最后一次访问日期 + lst_acc_date: u16, + /// High word of first cluster(0 for FAT12 and FAT16) + fst_clus_hi: u16, + /// 最后写入时间 + wrt_time: u16, + /// 最后写入日期 + wrt_date: u16, + /// Low word of first cluster + fst_clus_lo: u16, + /// 文件大小 + file_size: u32, +} + +/// FAT32的长目录项 +#[derive(Debug, Clone, Copy, Default)] +pub struct LongDirEntry { + /// 长目录项的序号 + ord: u8, + /// 长文件名的第1-5个字符,每个字符占2bytes + name1: [u16; 5], + /// 目录项属性必须为ATTR_LONG_NAME + file_attrs: FileAttributes, + /// Entry Type: 如果为0,则说明这是长目录项的子项 + /// 非零值是保留的。 + dirent_type: u8, + /// 短文件名的校验和 + checksum: u8, + /// 长文件名的第6-11个字符,每个字符占2bytes + name2: [u16; 6], + /// 必须为0 + first_clus_low: u16, + /// 长文件名的12-13个字符,每个字符占2bytes + name3: [u16; 2], +} + +impl LongDirEntry { + /// 长目录项的字符串长度(单位:word) + pub const LONG_NAME_STR_LEN: usize = 13; + + /// @brief 初始化一个新的长目录项 + /// + /// @param ord 顺序 + /// @param name_part 长目录项名称的数组(长度必须为13) + /// @param check_sum 短目录项的校验和 + /// + /// @return Self 初始化好的长目录项对象 + fn new(ord: u8, name_part: &[u16], check_sum: u8) -> Self { + let mut result = LongDirEntry::default(); + result.ord = ord; + result + .insert_name(name_part) + .expect("Name part's len should be equal to 13."); + result.file_attrs.value = FileAttributes::LONG_NAME; + result.dirent_type = 0; + result.checksum = check_sum; + // 该字段需要外层的代码手动赋值 + result.first_clus_low = 0; + return result; + } + + /// @brief 填写长目录项的名称字段。 + /// + /// @param name_part 要被填入当前长目录项的名字(数组长度必须为13) + /// + /// @return Ok(()) + /// @return Err(i32) 错误码 + fn insert_name(&mut self, name_part: &[u16]) -> Result<(), i32> { + if name_part.len() != Self::LONG_NAME_STR_LEN { + return Err(-(EINVAL as i32)); + } + self.name1.copy_from_slice(&name_part[0..5]); + self.name2.copy_from_slice(&name_part[5..11]); + self.name3.copy_from_slice(&name_part[11..13]); + return Ok(()); + } + + /// @brief 将当前长目录项的名称字段,原样地拷贝到一个长度为13的u16数组中。 + /// @param dst 拷贝的目的地,一个[u16]数组,长度必须为13。 + pub fn copy_name_to_slice(&self, dst: &mut [u16]) -> Result<(), i32> { + if dst.len() != Self::LONG_NAME_STR_LEN { + return Err(-(EINVAL as i32)); + } + dst[0..5].copy_from_slice(&self.name1); + dst[5..11].copy_from_slice(&self.name2); + dst[11..13].copy_from_slice(&self.name3); + return Ok(()); + } + + /// @brief 是否为最后一个长目录项 + /// + /// @return true 是最后一个长目录项 + /// @return false 不是最后一个长目录项 + pub fn is_last(&self) -> bool { + return self.ord & 0x40 > 0; + } + + /// @brief 校验字符串是否符合长目录项的命名要求 + /// + /// @return Ok(()) 名称合法 + /// @return Err(i32) 名称不合法,返回错误码 + pub fn validate_long_name(mut name: &str) -> Result<(), i32> { + // 去除首尾多余的空格 + name = name.trim(); + + // 名称不能为0 + if name.len() == 0 { + return Err(-(EINVAL as i32)); + } + + // 名称长度不能大于255 + if name.len() > 255 { + return Err(-(ENAMETOOLONG as i32)); + } + + // 检查是否符合命名要求 + for c in name.chars() { + match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' => {} + '\u{80}'..='\u{ffff}' => {} + '$' | '%' | '\'' | '-' | '_' | '@' | '~' | '`' | '!' | '(' | ')' | '{' | '}' + | '^' | '#' | '&' => {} + '+' | ',' | ';' | '=' | '[' | ']' | '.' | ' ' => {} + _ => { + return Err(-(EILSEQ as i32)); + } + } + } + return Ok(()); + } + + /// @brief 把当前长目录项写入磁盘 + /// + /// @param fs 对应的文件系统 + /// @param disk_bytes_offset 长目录项所在位置对应的在磁盘上的字节偏移量 + /// + /// @return Ok(()) + /// @return Err(i32) 错误码 + pub fn flush(&self, fs: Arc, disk_bytes_offset: u64) -> Result<(), i32> { + // 从磁盘读取数据 + let blk_offset = fs.get_in_block_offset(disk_bytes_offset); + let lba = fs.get_lba_from_offset( + fs.bytes_to_sector(fs.get_in_partition_bytes_offset(disk_bytes_offset)), + ); + let mut v: Vec = Vec::new(); + v.resize(1 * fs.lba_per_sector() * LBA_SIZE, 0); + fs.partition + .disk() + .read_at(lba, 1 * fs.lba_per_sector(), &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + // 切换游标到对应位置 + cursor.seek(SeekFrom::SeekSet(blk_offset as i64))?; + + // 写入数据 + cursor.write_u8(self.ord)?; + for b in &self.name1 { + cursor.write_u16(*b)?; + } + + cursor.write_u8(self.file_attrs.value)?; + cursor.write_u8(self.dirent_type)?; + cursor.write_u8(self.checksum)?; + + for b in &self.name2 { + cursor.write_u16(*b)?; + } + + cursor.write_u16(self.first_clus_low)?; + + for b in &self.name3 { + cursor.write_u16(*b)?; + } + + // 把修改后的长目录项刷入磁盘 + fs.partition + .disk() + .write_at(lba, 1 * fs.lba_per_sector(), cursor.as_slice())?; + fs.partition.disk().sync()?; + + return Ok(()); + } +} + +impl ShortDirEntry { + const PADDING: u8 = ' ' as u8; + + /// @brief 判断当前目录项是否为文件夹 + /// + /// @return true 是文件夹 + /// @return false 不是文件夹 + pub fn is_dir(&self) -> bool { + return (self.attributes.contains(FileAttributes::DIRECTORY)) + && (!self.attributes.contains(FileAttributes::VOLUME_ID)); + } + + /// @brief 判断当前目录项是否为文件 + /// + /// @return true 是文件 + /// @return false 不是文件 + pub fn is_file(&self) -> bool { + return (!self.attributes.contains(FileAttributes::DIRECTORY)) + && (!self.attributes.contains(FileAttributes::VOLUME_ID)); + } + + /// @brief 判断当前目录项是否为卷号 + /// + /// @return true 是卷号 + /// @return false 不是卷号 + pub fn is_volume_id(&self) -> bool { + return (!self.attributes.contains(FileAttributes::DIRECTORY)) + && self.attributes.contains(FileAttributes::VOLUME_ID); + } + + /// @brief 将短目录项的名字转换为String + fn name_to_string(&self) -> String { + // 计算基础名的长度 + let base_len = self.name[..8] + .iter() + .rposition(|x| *x != ShortDirEntry::PADDING) + .map(|len| len + 1) + .unwrap_or(0); + // 计算扩展名的长度 + let ext_len = self.name[8..] + .iter() + .rposition(|x| *x != ShortDirEntry::PADDING) + .map(|len| len + 1) + .unwrap_or(0); + + // 声明存储完整名字的数组(包含“.”) + let mut name = [ShortDirEntry::PADDING; 12]; + // 拷贝基础名 + name[..base_len].copy_from_slice(&self.name[..base_len]); + + // 拷贝扩展名,并计算总的长度 + let total_len = if ext_len > 0 { + name[base_len] = '.' as u8; + name[base_len + 1..base_len + 1 + ext_len].copy_from_slice(&self.name[8..8 + ext_len]); + // 总长度为基础名长度+点号+扩展名长度 + base_len + 1 + ext_len + } else { + base_len + }; + + if name[0] == 0x05 { + name[0] = 0xe5; + } + + let iter = name[..total_len].iter().map(|c| decode_u8_ascii(*c)); + // 返回最终的字符串 + return String::from_iter(iter); + } + + /// @brief 将短目录项结构体,转换为FATDirEntry枚举类型 + /// + /// @param loc 当前文件的起始、终止簇。格式:(簇,簇内偏移量) + /// @return 生成的FATDirENtry枚举类型 + pub fn to_dir_entry(&self, loc: (Cluster, u64)) -> FATDirEntry { + // 当前文件的第一个簇 + let first_cluster = + Cluster::new(((self.fst_clus_hi as u64) << 16) | (self.fst_clus_lo as u64)); + + // 当前是文件或卷号 + if self.is_file() || self.is_volume_id() { + let mut file: FATFile = FATFile::default(); + + file.file_name = self.name_to_string(); + file.first_cluster = first_cluster; + file.short_dir_entry = self.clone(); + file.loc = (loc, loc); + + // 根据当前短目录项的类型的不同,返回对应的枚举类型。 + if self.is_file() { + return FATDirEntry::File(file); + } else { + return FATDirEntry::VolId(file); + } + } else { + // 当前是文件夹 + let mut dir = FATDir::default(); + dir.dir_name = self.name_to_string(); + dir.first_cluster = first_cluster; + dir.root_offset = None; + dir.short_dir_entry = Some(self.clone()); + dir.loc = Some((loc, loc)); + + return FATDirEntry::Dir(dir); + } + } + + /// @brief 将短目录项结构体,转换为FATDirEntry枚举类型. 并且,该短目录项具有对应的长目录项。 + /// 因此,需要传入从长目录项获得的完整的文件名 + /// + /// @param name 从长目录项获取的完整文件名 + /// @param loc 当前文件的起始、终止簇。格式:(簇,簇内偏移量) + /// @return 生成的FATDirENtry枚举类型 + pub fn to_dir_entry_with_long_name( + &self, + name: String, + loc: ((Cluster, u64), (Cluster, u64)), + ) -> FATDirEntry { + // 当前文件的第一个簇 + let first_cluster = + Cluster::new(((self.fst_clus_hi as u64) << 16) | (self.fst_clus_lo as u64)); + + if self.is_file() || self.is_volume_id() { + let mut file = FATFile::default(); + + file.first_cluster = first_cluster; + file.file_name = name; + file.loc = loc; + file.short_dir_entry = self.clone(); + + if self.is_file() { + return FATDirEntry::File(file); + } else { + return FATDirEntry::VolId(file); + } + } else { + let mut dir = FATDir::default(); + + dir.first_cluster = first_cluster; + dir.dir_name = name; + dir.loc = Some(loc); + dir.short_dir_entry = Some(self.clone()); + dir.root_offset = None; + + return FATDirEntry::Dir(dir); + } + } + + /// @brief 计算短目录项的名称的校验和 + fn checksum(&self) -> u8 { + let mut result = 0; + + for c in &self.name { + result = (result << 7) + (result >> 1) + *c; + } + return result; + } + + /// @brief 把当前短目录项写入磁盘 + /// + /// @param fs 对应的文件系统 + /// @param disk_bytes_offset 短目录项所在位置对应的在磁盘上的字节偏移量 + /// + /// @return Ok(()) + /// @return Err(i32) 错误码 + pub fn flush(&self, fs: &Arc, disk_bytes_offset: u64) -> Result<(), i32> { + // 从磁盘读取数据 + let blk_offset = fs.get_in_block_offset(disk_bytes_offset); + let lba = fs.get_lba_from_offset( + fs.bytes_to_sector(fs.get_in_partition_bytes_offset(disk_bytes_offset)), + ); + let mut v: Vec = Vec::new(); + v.resize(1 * fs.lba_per_sector() * LBA_SIZE, 0); + fs.partition + .disk() + .read_at(lba, 1 * fs.lba_per_sector(), &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + // 切换游标到对应位置 + cursor.seek(SeekFrom::SeekSet(blk_offset as i64))?; + cursor.write_exact(&self.name)?; + cursor.write_u8(self.attributes.value)?; + cursor.write_u8(self.nt_res)?; + cursor.write_u8(self.crt_time_tenth)?; + cursor.write_u16(self.crt_time)?; + cursor.write_u16(self.crt_date)?; + cursor.write_u16(self.lst_acc_date)?; + cursor.write_u16(self.fst_clus_hi)?; + cursor.write_u16(self.wrt_time)?; + cursor.write_u16(self.wrt_date)?; + cursor.write_u16(self.fst_clus_lo)?; + cursor.write_u32(self.file_size)?; + + // 把修改后的长目录项刷入磁盘 + fs.partition + .disk() + .write_at(lba, 1 * fs.lba_per_sector(), cursor.as_slice())?; + fs.partition.disk().sync()?; + + return Ok(()); + } + + /// @brief 设置短目录项的“第一个簇”字段的值 + pub fn set_first_cluster(&mut self, cluster: Cluster) { + self.fst_clus_lo = (cluster.cluster_num & 0x0000ffff) as u16; + self.fst_clus_hi = ((cluster.cluster_num & 0xffff0000) >> 16) as u16; + } +} + +/// @brief FAT文件系统标准定义的目录项 +#[derive(Debug, Clone)] +pub enum FATRawDirEntry { + /// 短目录项 + Short(ShortDirEntry), + /// 长目录项 + Long(LongDirEntry), + /// 当前目录项的Name[0]==0xe5, 是空闲目录项 + Free, + /// 当前目录项的Name[0]==0xe5, 是空闲目录项,且在这之后没有被分配过的目录项了。 + FreeRest, +} + +impl FATRawDirEntry { + /// 每个目录项的长度(单位:字节) + pub const DIR_ENTRY_LEN: u64 = 32; + + /// @brief 判断当前目录项是否为这个文件的最后一个目录项 + fn is_last(&self) -> bool { + match self { + &Self::Short(_) => { + return true; + } + &Self::Long(l) => { + return l.is_last(); + } + _ => { + return false; + } + } + } + + /// @brief 判断当前目录项是否为长目录项 + fn is_long(&self) -> bool { + if let Self::Long(_) = self { + return true; + } else { + return false; + } + } + + /// @brief 判断当前目录项是否为短目录项 + fn is_short(&self) -> bool { + if let Self::Short(_) = self { + return true; + } else { + return false; + } + } +} + +/// @brief FAT文件系统的目录项迭代器 +#[derive(Debug)] +pub struct FATDirIter { + /// 当前正在迭代的簇 + current_cluster: Cluster, + /// 当前正在迭代的簇的簇内偏移量 + offset: u64, + /// True for the root directories of FAT12 and FAT16 + is_root: bool, + /// 指向当前文件系统的指针 + fs: Arc, +} + +impl FATDirIter { + /// @brief 迭代当前inode的目录项(获取下一个目录项) + /// + /// @return Ok(Cluster, u64, Option) + /// Cluster: 下一个要读取的簇号 + /// u64: 下一个要读取的簇内偏移量 + /// Option: 读取到的目录项(如果没有读取到,就返回失败) + /// @return Err(错误码) 可能出现了内部错误,或者是磁盘错误等。具体原因看错误码。 + fn get_dir_entry(&mut self) -> Result<(Cluster, u64, Option), i32> { + loop { + // 如果当前簇已经被读完,那么尝试获取下一个簇 + if self.offset >= self.fs.bytes_per_cluster() && !self.is_root { + match self.fs.get_fat_entry(self.current_cluster)? { + FATEntry::Next(c) => { + // 获得下一个簇的信息 + self.current_cluster = c; + self.offset %= self.fs.bytes_per_cluster(); + } + + _ => { + // 没有下一个簇了,返回None + return Ok((self.current_cluster, self.offset, None)); + } + } + } + + // 如果当前是FAT12/FAT16文件系统,并且当前inode是根目录项。 + // 如果offset大于根目录项的最大大小(已经遍历完根目录),那么就返回None + if self.is_root && self.offset > self.fs.root_dir_end_bytes_offset().unwrap() { + return Ok((self.current_cluster, self.offset, None)); + } + + // 获取簇在磁盘内的字节偏移量 + let offset: u64 = self.fs.cluster_bytes_offset(self.current_cluster) + self.offset; + + // 从磁盘读取原始的dentry + let raw_dentry: FATRawDirEntry = get_raw_dir_entry(&self.fs, offset)?; + + // 由于迭代顺序从前往后,因此: + // 如果找到1个短目录项,那么证明有一个完整的entry被找到,因此返回。 + // 如果找到1个长目录项,那么,就依次往下迭代查找,直到找到一个短目录项,然后返回结果。这里找到的所有的目录项,都属于同一个文件/文件夹。 + match raw_dentry { + FATRawDirEntry::Short(s) => { + // 当前找到一个短目录项,更新offset之后,直接返回 + self.offset += FATRawDirEntry::DIR_ENTRY_LEN; + return Ok(( + self.current_cluster, + self.offset, + Some(s.to_dir_entry(( + self.current_cluster, + self.offset - FATRawDirEntry::DIR_ENTRY_LEN, + ))), + )); + } + FATRawDirEntry::Long(_) => { + // 当前找到一个长目录项 + + // 声明一个数组,来容纳所有的entry。(先把最后一个entry放进去) + let mut long_name_entries: Vec = vec![raw_dentry]; + let start_offset: u64 = self.offset; + let start_cluster: Cluster = self.current_cluster; + + self.offset += FATRawDirEntry::DIR_ENTRY_LEN; + + // 由于在FAT文件系统中,文件名最长为255字节,因此,最多有20个长目录项以及1个短目录项。 + // 由于上面已经塞了1个长目录项,因此接下来最多需要迭代20次 + // 循环查找目录项,直到遇到1个短目录项,或者是空闲目录项 + for _ in 0..20 { + // 如果当前簇已经被读完,那么尝试获取下一个簇 + if self.offset >= self.fs.bytes_per_cluster() && !self.is_root { + match self.fs.get_fat_entry(self.current_cluster)? { + FATEntry::Next(c) => { + // 获得下一个簇的信息 + self.current_cluster = c; + self.offset %= self.fs.bytes_per_cluster(); + } + + _ => { + // 没有下一个簇了,退出迭代 + break; + } + } + } + // 如果当前是FAT12/FAT16文件系统,并且当前inode是根目录项。 + // 如果offset大于根目录项的最大大小(已经遍历完根目录),那么就退出迭代 + if self.is_root + && self.offset > self.fs.root_dir_end_bytes_offset().unwrap() + { + break; + } + + // 获取簇在磁盘内的字节偏移量 + let offset: u64 = + self.fs.cluster_bytes_offset(self.current_cluster) + self.offset; + // 从磁盘读取原始的dentry + let raw_dentry: FATRawDirEntry = get_raw_dir_entry(&self.fs, offset)?; + + match raw_dentry { + FATRawDirEntry::Short(_) => { + // 当前遇到1个短目录项,证明当前文件/文件夹的所有dentry都被读取完了,因此在将其加入数组后,退出迭代。 + long_name_entries.push(raw_dentry); + break; + } + FATRawDirEntry::Long(_) => { + // 当前遇到1个长目录项,将其加入数组,然后更新offset,继续迭代。 + long_name_entries.push(raw_dentry); + self.offset += FATRawDirEntry::DIR_ENTRY_LEN; + } + + _ => { + // 遇到了空闲簇,但没遇到短目录项,说明文件系统出错了,退出。 + break; + } + } + } + // kdebug!("collect dentries done. long_name_entries={long_name_entries:?}"); + let dir_entry: Result = FATDirEntry::new( + long_name_entries, + ( + (start_cluster, start_offset), + (self.current_cluster, self.offset), + ), + ); + // kdebug!("dir_entry={:?}", dir_entry); + match dir_entry { + Ok(d) => { + // kdebug!("dir_entry ok"); + self.offset += FATRawDirEntry::DIR_ENTRY_LEN; + return Ok((self.current_cluster, self.offset, Some(d))); + } + + Err(_) => { + // kdebug!("dir_entry err, e={}", e); + self.offset += FATRawDirEntry::DIR_ENTRY_LEN; + } + } + } + FATRawDirEntry::Free => { + // 当前目录项是空的 + self.offset += FATRawDirEntry::DIR_ENTRY_LEN; + } + FATRawDirEntry::FreeRest => { + // 当前目录项是空的,且之后都是空的,因此直接返回 + return Ok((self.current_cluster, self.offset, None)); + } + } + } + } +} + +/// 为DirIter实现迭代器trait +impl Iterator for FATDirIter { + type Item = FATDirEntry; + + fn next(&mut self) -> Option { + match self.get_dir_entry() { + Ok((cluster, offset, result)) => { + self.current_cluster = cluster; + self.offset = offset; + return result; + } + Err(_) => { + return None; + } + } + } +} + +impl FATDirEntry { + /// @brief 构建FATDirEntry枚举类型 + /// + /// @param long_name_entries 长目录项的数组。 + /// 格式:[第20个(或者是最大ord的那个), 19, 18, ..., 1, 短目录项] + /// + /// @return Ok(FATDirEntry) 构建好的FATDirEntry类型的对象 + /// @return Err(i32) 错误码 + pub fn new( + mut long_name_entries: Vec, + loc: ((Cluster, u64), (Cluster, u64)), + ) -> Result { + if long_name_entries.is_empty() { + return Err(-(EINVAL as i32)); + } + + if !long_name_entries[0].is_last() || !long_name_entries.last().unwrap().is_short() { + // 存在孤立的目录项,文件系统出现异常,因此返回错误,表明其只读。 + // TODO: 标记整个FAT文件系统为只读的 + return Err(-(EROFS as i32)); + } + + // 取出短目录项(位于vec的末尾) + let short_dentry: ShortDirEntry = match long_name_entries.pop().unwrap() { + FATRawDirEntry::Short(s) => s, + _ => unreachable!(), + }; + + let mut extractor = LongNameExtractor::new(); + for entry in &long_name_entries { + match entry { + &FATRawDirEntry::Long(l) => { + extractor.process(l)?; + } + + _ => { + return Err(-(EROFS as i32)); + } + } + } + // 检验校验和是否正确 + if extractor.validate_checksum(&short_dentry) { + // 校验和正确,返回一个长目录项 + return Ok(short_dentry.to_dir_entry_with_long_name(extractor.to_string(), loc)); + } else { + // 校验和不相同,认为文件系统出错 + return Err(-(EROFS as i32)); + } + } + + /// @brief 获取短目录项的名字 + pub fn short_name(&self) -> String { + match self { + FATDirEntry::File(f) | FATDirEntry::VolId(f) => { + return f.short_dir_entry.name_to_string(); + } + FATDirEntry::Dir(d) => match d.short_dir_entry { + Some(s) => { + return s.name_to_string(); + } + None => { + return String::from("/"); + } + }, + FATDirEntry::UnInit => unreachable!("FATFS: FATDirEntry uninitialized."), + } + } + + /// @brief 获取短目录项结构体 + pub fn short_dir_entry(&self) -> Option { + match &self { + FATDirEntry::File(f) => { + return Some(f.short_dir_entry); + } + FATDirEntry::Dir(d) => { + return d.short_dir_entry; + } + FATDirEntry::VolId(s) => { + return Some(s.short_dir_entry); + } + FATDirEntry::UnInit => unreachable!("FATFS: FATDirEntry uninitialized."), + } + } + + /// @brief 获取目录项的第一个簇的簇号 + pub fn first_cluster(&self) -> Cluster { + match self { + FATDirEntry::File(f) => { + return f.first_cluster; + } + FATDirEntry::Dir(d) => { + return d.first_cluster; + } + FATDirEntry::VolId(s) => { + return s.first_cluster; + } + FATDirEntry::UnInit => unreachable!("FATFS: FATDirEntry uninitialized."), + } + } + + /// @brief 获取当前目录项所占用的簇的范围 + /// + /// @return (起始簇,簇内偏移量), (终止簇,簇内偏移量) + pub fn get_dir_range(&self) -> Option<((Cluster, u64), (Cluster, u64))> { + match self { + FATDirEntry::File(f) => Some(f.loc), + FATDirEntry::Dir(d) => d.loc, + FATDirEntry::VolId(s) => Some(s.loc), + FATDirEntry::UnInit => unreachable!("FATFS: FATDirEntry uninitialized."), + } + } + + /// @brief 获取原始的短目录项名(FAT标准规定的) + pub fn short_name_raw(&self) -> [u8; 11] { + match self { + FATDirEntry::File(f) => { + return f.short_dir_entry.name; + } + FATDirEntry::Dir(d) => match d.short_dir_entry { + // 存在短目录项,直接返回 + Some(s) => { + return s.name; + } + // 是根目录项 + None => { + let mut s = [0x20u8; 11]; + s[0] = '/' as u8; + return s; + } + }, + FATDirEntry::VolId(s) => { + return s.short_dir_entry.name; + } + + FATDirEntry::UnInit => unreachable!("FATFS: FATDirEntry uninitialized."), + } + } + + /// @brief 获取目录项的名字 + pub fn name(&self) -> String { + match self { + FATDirEntry::File(f) => { + return f.file_name.clone(); + } + FATDirEntry::VolId(s) => { + return s.file_name.clone(); + } + FATDirEntry::Dir(d) => { + return d.dir_name.clone(); + } + FATDirEntry::UnInit => unreachable!("FATFS: FATDirEntry uninitialized."), + } + } + + /// @brief 判断目录项是否为文件 + pub fn is_file(&self) -> bool { + match self { + &FATDirEntry::File(_) | &FATDirEntry::VolId(_) => true, + _ => false, + } + } + + /// @brief 判断目录项是否为文件夹 + pub fn is_dir(&self) -> bool { + match &self { + &FATDirEntry::Dir(_) => true, + _ => false, + } + } + + /// @brief 判断目录项是否为Volume id + pub fn is_vol_id(&self) -> bool { + match self { + &FATDirEntry::VolId(_) => true, + _ => false, + } + } + + /// @brief 判断FAT目录项的名字与给定的是否相等 + /// + /// 由于FAT32对大小写不敏感,因此将字符都转为大写,然后比较 + /// + /// @return bool 相等 => true + /// 不相等 => false + pub fn eq_name(&self, name: &str) -> bool { + // 由于FAT32对大小写不敏感,因此将字符都转为大写,然后比较。 + let binding = self.short_name(); + let short_name = binding.chars().flat_map(|c| c.to_uppercase()); + let binding = self.name(); + let long_name = binding.chars().flat_map(|c| c.to_uppercase()); + let name = name.chars().flat_map(|c| c.to_uppercase()); + + let long_name_matches: bool = long_name.eq(name.clone()); + let short_name_matches: bool = short_name.eq(name); + + return long_name_matches || short_name_matches; + } + + /// @brief 将FATDirEntry转换为FATFile对象 + pub fn to_file(&self) -> Result { + if self.is_file() == false { + return Err(-(EISDIR as i32)); + } + + match &self { + FATDirEntry::File(f) | FATDirEntry::VolId(f) => { + return Ok(f.clone()); + } + _ => unreachable!(), + } + } + + /// @brief 将FATDirEntry转换为FATDir对象 + pub fn to_dir(&self) -> Result { + if self.is_dir() == false { + return Err(-(ENOTDIR as i32)); + } + match &self { + FATDirEntry::Dir(d) => { + return Ok(d.clone()); + } + _ => unreachable!(), + } + } +} + +/// 用于生成短目录项文件名的生成器。 +#[derive(Debug, Default)] +pub struct ShortNameGenerator { + /// 短目录项的名字 + name: [u8; 11], + /// 生成器的标志位(使用impl里面的mask来解析) + flags: u8, + /// 基础名的长度 + basename_len: u8, + /// 对于文件名形如(TE021F~1.TXT)的,短前缀+校验码的短目录项,该字段表示基础名末尾数字的对应位。 + checksum_bitmask: u16, + /// Fletcher-16 Checksum(与填写到ShortDirEntry里面的不一样) + checksum: u16, + /// 对于形如(TEXTFI~1.TXT)的短目录项名称,其中的数字的bitmask(第0位置位则表示这个数字是0) + suffix_bitmask: u16, +} + +impl ShortNameGenerator { + /// 短目录项的名称的长度 + const SHORT_NAME_LEN: usize = 8; + + // ===== flags标志位的含义 ===== + const IS_LOSSY: u8 = (1 << 0); + const IS_EXACT_MATCH: u8 = (1 << 1); + const IS_DOT: u8 = (1 << 2); + const IS_DOTDOT: u8 = (1 << 3); + /// 名称被完全拷贝 + const NAME_FITS: u8 = (1 << 4); + + /// @brief 初始化一个短目录项名称生成器 + pub fn new(mut name: &str) -> Self { + name = name.trim(); + + let mut short_name: [u8; 11] = [0x20u8; 11]; + if name == "." { + short_name[0] = '.' as u8; + } + + if name == ".." { + short_name[0] = '.' as u8; + short_name[1] = '.' as u8; + } + + // @name_fits: 名称是否被完全拷贝 + // @basename_len: 基础名的长度 + // @is_lossy: 是否存在不合法的字符 + let (name_fits, basename_len, is_lossy) = match name.rfind('.') { + Some(index) => { + // 文件名里面有".", 且index为最右边的点号所在的下标(bytes index) + // 拷贝基础名 + let (b_len, fits, b_lossy) = + Self::copy_part(&mut short_name[..Self::SHORT_NAME_LEN], &name[..index]); + + // 拷贝扩展名 + let (_, ext_fits, ext_lossy) = Self::copy_part( + &mut short_name[Self::SHORT_NAME_LEN..Self::SHORT_NAME_LEN + 3], + &name[index + 1..], + ); + + (fits && ext_fits, b_len, b_lossy || ext_lossy) + } + None => { + // 文件名中,不存在"." + let (b_len, fits, b_lossy) = + Self::copy_part(&mut short_name[..Self::SHORT_NAME_LEN], &name); + (fits, b_len, b_lossy) + } + }; + + let mut flags: u8 = 0; + // 设置flags + if is_lossy { + flags |= Self::IS_LOSSY; + } + if name == "." { + flags |= Self::IS_DOT; + } + if name == ".." { + flags |= Self::IS_DOTDOT; + } + + if name_fits { + flags |= Self::NAME_FITS; + } + + return ShortNameGenerator { + name: short_name, + flags: flags, + basename_len: basename_len, + checksum: Self::fletcher_16_checksum(name), + ..Default::default() + }; + } + + /// @brief 拷贝字符串到一个u8数组 + /// + /// @return (u8, bool, bool) + /// return.0: 拷贝了的字符串的长度 + /// return.1: 是否完全拷贝完整个字符串 + /// return.2: 拷贝过程中,是否出现了不合法字符 + fn copy_part(dest: &mut [u8], src: &str) -> (u8, bool, bool) { + let mut dest_len: usize = 0; + let mut lossy_conv = false; + + for c in src.chars() { + // 如果src还有字符,而dest已经满了,那么表示没有完全拷贝完。 + if dest_len == dest.len() { + return (dest_len as u8, false, lossy_conv); + } + + if c == ' ' || c == '.' { + lossy_conv = true; + continue; + } + + let cp: char = match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' => c, + '$' | '%' | '\'' | '-' | '_' | '@' | '~' | '`' | '!' | '(' | ')' | '{' | '}' + | '^' | '#' | '&' => c, + _ => '_', + }; + + // 判断是否存在不符合条件的字符 + lossy_conv = lossy_conv || c != cp; + + // 拷贝字符 + dest[dest_len] = c.to_ascii_uppercase() as u8; + dest_len += 1; + } + + // 返回结果 + return (dest_len as u8, true, lossy_conv); + } + + fn fletcher_16_checksum(name: &str) -> u16 { + let mut sum1: u16 = 0; + let mut sum2: u16 = 0; + for c in name.chars() { + sum1 = (sum1 + (c as u16)) % 0xff; + sum2 = (sum1 + sum2) & 0xff; + } + return (sum2 << 8) | sum1; + } + + /// @brief 更新生成器的状态 + /// 当长目录项不存在的时候,需要调用这个函数来更新生成器的状态 + pub fn add_name(&mut self, name: &[u8; 11]) { + // === 判断名称是否严格的完全匹配 + if name == &self.name { + self.flags |= Self::IS_EXACT_MATCH; + } + + // === 检查是否存在长前缀的格式冲突。对于这样的短目录项名称:(TEXTFI~1.TXT) + // 获取名称前缀 + let prefix_len = min(self.basename_len, 6) as usize; + // 获取后缀的那个数字 + let num_suffix: Option = if name[prefix_len] as char == '~' { + (name[prefix_len + 1] as char).to_digit(10) + } else { + None + }; + + // 判断扩展名是否匹配 + let ext_matches: bool = name[8..] == self.name[8..]; + + if name[..prefix_len] == self.name[..prefix_len] // 基础名前缀相同 + && num_suffix.is_some() // 基础名具有数字后缀 + && ext_matches + // 扩展名相匹配 + { + let num = num_suffix.unwrap(); + self.suffix_bitmask |= 1 << num; + } + + // === 检查是否存在短前缀+校验和的冲突,文件名形如:(TE021F~1.TXT) + let prefix_len = min(self.basename_len, 2) as usize; + let num_suffix: Option = if name[prefix_len + 4] as char == '~' { + (name[prefix_len + 1] as char).to_digit(10) + } else { + None + }; + + if name[..prefix_len] == self.name[..prefix_len] && num_suffix.is_some() && ext_matches { + // 获取短文件名中的校验码字段 + let checksum_result: Result< + Result, + core::str::Utf8Error, + > = core::str::from_utf8(&name[prefix_len..prefix_len + 4]) + .map(|s| u16::from_str_radix(s, 16)); + // 如果校验码相同 + if checksum_result == Ok(Ok(self.checksum)) { + let num = num_suffix.unwrap(); + // 置位checksum_bitmask中,基础名末尾数字的对应位 + self.checksum_bitmask |= 1 << num; + } + } + } + + pub fn generate(&self) -> Result<[u8; 11], i32> { + if self.is_dot() || self.is_dotdot() { + return Ok(self.name); + } + + // 如果当前名字不存在不合法的字符,且名称被完整拷贝,但是exact match为false,可以认为名称没有冲突,直接返回 + if !self.is_lossy() && self.name_fits() && !self.is_exact_match() { + return Ok(self.name); + } + + // 尝试使用长前缀(6字符) + for i in 1..5 { + if self.suffix_bitmask & (1 << i) == 0 { + return Ok(self.build_prefixed_name(i as u32, false)); + } + } + + // 尝试使用短前缀+校验码 + for i in 1..10 { + if self.checksum_bitmask & (1 << i) == 0 { + return Ok(self.build_prefixed_name(i as u32, true)); + } + } + // 由于产生太多的冲突,因此返回错误(“短文件名已经存在”) + return Err(-(EEXIST as i32)); + } + + pub fn next_iteration(&mut self) { + // 在下一次迭代中,尝试一个不同的校验和 + self.checksum = (core::num::Wrapping(self.checksum) + core::num::Wrapping(1)).0; + // 清空bitmask + self.suffix_bitmask = 0; + self.checksum_bitmask = 0; + } + + /// @brief 构造具有前缀的短目录项名称 + /// + /// @param num 这是第几个重名的前缀名 + /// @param with_checksum 前缀名中是否包含校验码 + /// + /// @return 构造好的短目录项名称数组 + fn build_prefixed_name(&self, num: u32, with_checksum: bool) -> [u8; 11] { + let mut buf: [u8; 11] = [0x20u8; 11]; + let prefix_len: usize = if with_checksum { + let prefix_len: usize = min(self.basename_len as usize, 2); + buf[..prefix_len].copy_from_slice(&self.name[..prefix_len]); + buf[prefix_len..prefix_len + 4].copy_from_slice(&Self::u16_to_u8_array(self.checksum)); + prefix_len + 4 + } else { + let prefix_len = min(self.basename_len as usize, 6); + buf[..prefix_len].copy_from_slice(&self.name[..prefix_len]); + prefix_len + }; + + buf[prefix_len] = '~' as u8; + buf[prefix_len + 1] = char::from_digit(num, 10).unwrap() as u8; + buf[8..].copy_from_slice(&self.name[8..]); + return buf; + } + + /// @brief 将一个u16数字转换为十六进制大写字符串对应的ascii数组。 + /// 举例:将x=12345转换为16进制字符串“3039”对应的ascii码数组:[51,48,51,57] + fn u16_to_u8_array(x: u16) -> [u8; 4] { + let c1 = char::from_digit((x as u32 >> 12) & 0xf, 16) + .unwrap() + .to_ascii_uppercase() as u8; + let c2 = char::from_digit((x as u32 >> 8) & 0xf, 16) + .unwrap() + .to_ascii_uppercase() as u8; + let c3 = char::from_digit((x as u32 >> 4) & 0xf, 16) + .unwrap() + .to_ascii_uppercase() as u8; + let c4 = char::from_digit((x as u32 >> 0) & 0xf, 16) + .unwrap() + .to_ascii_uppercase() as u8; + return [c1, c2, c3, c4]; + } + + #[inline] + fn is_lossy(&self) -> bool { + return (self.flags & Self::IS_LOSSY) > 0; + } + + #[inline] + fn is_exact_match(&self) -> bool { + return (self.flags & Self::IS_EXACT_MATCH) > 0; + } + + #[inline] + fn is_dot(&self) -> bool { + return (self.flags & Self::IS_DOT) > 0; + } + + #[inline] + fn is_dotdot(&self) -> bool { + return (self.flags & Self::IS_DOTDOT) > 0; + } + + #[inline] + fn name_fits(&self) -> bool { + return (self.flags & Self::NAME_FITS) > 0; + } +} + +/// 从多个LongName中提取完整文件名字段的提取器 +struct LongNameExtractor { + name: Vec, + checksum: u8, + index: u8, +} + +impl LongNameExtractor { + fn new() -> Self { + return LongNameExtractor { + name: Vec::new(), + checksum: 0, + index: 0, + }; + } + + /// @brief 提取长目录项的名称 + /// @param longname_dentry 长目录项 + /// 请注意,必须倒序输入长目录项对象 + fn process(&mut self, longname_dentry: LongDirEntry) -> Result<(), i32> { + let is_last: bool = longname_dentry.is_last(); + let index: u8 = longname_dentry.ord & 0x1f; + + if index == 0 { + self.name.clear(); + return Err(-(EROFS as i32)); + } + + // 如果是最后一个LongDirEntry,则初始化当前生成器 + if is_last { + self.index = index; + self.checksum = longname_dentry.checksum; + self.name + .resize(index as usize * LongDirEntry::LONG_NAME_STR_LEN, 0); + } else if self.index == 0 + || index != self.index - 1 + || self.checksum != longname_dentry.checksum + { + // 如果当前index为0,或者index不连续,或者是校验和不同,那么认为文件系统损坏,清除生成器的名称字段 + // TODO: 对文件系统的变为只读状态状况的拦截 + self.name.clear(); + return Err(-(EROFS as i32)); + } else { + // 由于dentry倒序输入,因此index是每次减1的 + self.index -= 1; + } + + let pos: usize = ((index - 1) as usize) * LongDirEntry::LONG_NAME_STR_LEN; + // 将当前目录项的值,拷贝到生成器的数组中 + longname_dentry + .copy_name_to_slice(&mut self.name[pos..pos + LongDirEntry::LONG_NAME_STR_LEN])?; + return Ok(()); + } + + /// @brief 返回名称的长度 + #[inline] + fn len(&self) -> usize { + return self.name.len(); + } + + /// @brief 返回抽取得到的名称字符串 + fn to_string(&self) -> String { + let mut s = String::from_utf16_lossy(self.name.as_slice()); + // 计算字符串的长度。如果字符串中有\0,那么就截取字符串的前面部分 + if let Some(len) = s.find('\u{0}') { + s.truncate(len); + } + return s; + } + + /// @brief 判断校验码是否与指定的短目录项的校验码相同 + /// + /// @return bool 相同 => true + /// 不同 => false + fn validate_checksum(&self, short_dentry: &ShortDirEntry) -> bool { + return self.checksum == short_dentry.checksum(); + } +} + +/// @brief 长目录项生成器 +#[derive(Debug)] +struct LongNameEntryGenerator { + name: Vec, + // 短目录项的校验和 + checksum: u8, + // 当前迭代器的索引 + idx: u8, + /// 最后一个目录项的索引 + last_index: u8, +} + +impl LongNameEntryGenerator { + /// @brief 初始化长目录项生成器 + /// + /// @param name 长文件名数组 + /// @param checksum 短目录项的校验和 + pub fn new(name: &str, checksum: u8) -> Self { + let mut name: Vec = name.chars().map(|c| c as u16).collect(); + + let padding_bytes: usize = (13 - (name.len() % 13)) % 13; + // 填充最后一个长目录项的文件名 + for i in 0..padding_bytes { + if i == 0 { + name.push(0); + } else { + name.push(0xffff); + } + } + + // 先从最后一个长目录项开始生成 + let start_index = (name.len() / 13) as u8; + return LongNameEntryGenerator { + name: name, + checksum: checksum, + idx: start_index, + last_index: start_index, + }; + } + + /// @brief 返回要生成的长目录项的总数 + pub fn num_entries(&self) -> u8 { + return self.last_index + 1; + } +} + +impl Iterator for LongNameEntryGenerator { + type Item = LongDirEntry; + + fn next(&mut self) -> Option { + match self.idx { + 0 => { + return None; + } + // 最后一个长目录项 + n if n == self.last_index => { + // 最后一个长目录项的ord需要与0x40相或 + let ord: u8 = n | 0x40; + let start_idx = ((n - 1) * 13) as usize; + self.idx -= 1; + return Some(LongDirEntry::new( + ord, + &self.name.as_slice()[start_idx..start_idx + 13], + self.checksum, + )); + } + n => { + // 其它的长目录项 + let start_idx = ((n - 1) * 13) as usize; + self.idx -= 1; + return Some(LongDirEntry::new( + n, + &self.name.as_slice()[start_idx..start_idx + 13], + self.checksum, + )); + } + } + } +} + +#[derive(Debug)] +pub enum FATDirEntryOrShortName { + DirEntry(FATDirEntry), + ShortName([u8; 11]), +} + +/// @brief 对FAT目录项的迭代器(基于簇和簇内偏移量) +#[derive(Debug)] +struct FATDirEntryOffsetIter { + /// 当前迭代的偏移量(下一次迭代要返回的值) + current_offset: (Cluster, u64), + /// 截止迭代的位置(end_offset所在的位置也会被迭代器返回) + end_offset: Option<(Cluster, u64)>, + /// 属于的文件系统 + fs: Arc, + /// 当前已经迭代了多少次 + index: u64, + /// 总共要迭代多少次 + len: u64, + /// 如果end_offset不为None,该字段表示“是否已经到达了迭代终点” + fin: bool, +} + +impl FATDirEntryOffsetIter { + /// @brief 初始化FAT目录项的迭代器(基于簇和簇内偏移量) + /// + /// @param fs 属于的文件系统 + /// @param start 起始偏移量 + /// @param len 要迭代的次数 + /// @param end_offset 截止迭代的位置(end_offset所在的位置也会被迭代器返回) + /// + /// @return 构建好的迭代器对象 + pub fn new( + fs: Arc, + start: (Cluster, u64), + len: u64, + end_offset: Option<(Cluster, u64)>, + ) -> Self { + return FATDirEntryOffsetIter { + current_offset: start, + end_offset, + fs, + index: 0, + len, + fin: false, + }; + } +} + +impl Iterator for FATDirEntryOffsetIter { + type Item = (Cluster, u64); + + fn next(&mut self) -> Option { + if self.index == self.len || self.fin { + return None; + } + + let r: (Cluster, u64) = self.current_offset; + // 计算新的字节偏移量 + let mut new_offset = r.1 + FATRawDirEntry::DIR_ENTRY_LEN; + let mut new_cluster: Cluster = r.0; + // 越过了当前簇,则获取下一个簇 + if new_offset >= self.fs.bytes_per_cluster() { + new_offset %= self.fs.bytes_per_cluster(); + + match self.fs.get_fat_entry(new_cluster) { + Ok(FATEntry::Next(c)) => { + new_cluster = c; + } + // 没有下一个簇了 + _ => { + self.fin = true; + } + } + } + + if let Some(off) = self.end_offset { + // 判断当前簇是否是要求停止搜索的最后一个位置 + self.fin = off == self.current_offset; + } + // 更新当前迭代的偏移量 + self.current_offset = (new_cluster, new_offset); + self.index += 1; + + return Some(r); + } +} + +/// @brief 根据磁盘内字节偏移量,读取磁盘,并生成一个FATRawDirEntry对象 +pub fn get_raw_dir_entry( + fs: &Arc, + in_disk_bytes_offset: u64, +) -> Result { + // 块内偏移量 + let blk_offset: u64 = fs.get_in_block_offset(in_disk_bytes_offset); + let lba = fs.get_lba_from_offset( + fs.bytes_to_sector(fs.get_in_partition_bytes_offset(in_disk_bytes_offset)), + ); + + // let step1 = fs.get_in_partition_bytes_offset(in_disk_bytes_offset); + // let step2 = fs.bytes_to_sector(step1); + // let lba = fs.get_lba_from_offset(step2); + // kdebug!("step1={step1}, step2={step2}, lba={lba}"); + let mut v: Vec = Vec::new(); + v.resize(1 * LBA_SIZE, 0); + + fs.partition.disk().read_at(lba, 1, &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + // 切换游标到对应位置 + cursor.seek(SeekFrom::SeekSet(blk_offset as i64))?; + + let dir_0 = cursor.read_u8()?; + + match dir_0 { + 0x00 => { + return Ok(FATRawDirEntry::FreeRest); + } + 0xe5 => { + return Ok(FATRawDirEntry::Free); + } + _ => { + cursor.seek(SeekFrom::SeekCurrent(10))?; + let file_attr: FileAttributes = FileAttributes::new(cursor.read_u8()?); + + // 指针回到目录项的开始处 + cursor.seek(SeekFrom::SeekSet(blk_offset as i64))?; + + if file_attr.contains(FileAttributes::LONG_NAME) { + // 当前目录项是一个长目录项 + let mut long_dentry = LongDirEntry::default(); + + long_dentry.ord = cursor.read_u8()?; + cursor.read_u16_into(&mut long_dentry.name1)?; + long_dentry.file_attrs = FileAttributes::new(cursor.read_u8()?); + long_dentry.dirent_type = cursor.read_u8()?; + long_dentry.checksum = cursor.read_u8()?; + + cursor.read_u16_into(&mut long_dentry.name2)?; + long_dentry.first_clus_low = cursor.read_u16()?; + cursor.read_u16_into(&mut long_dentry.name3)?; + + return Ok(FATRawDirEntry::Long(long_dentry)); + } else { + // 当前目录项是一个短目录项 + let mut short_dentry = ShortDirEntry::default(); + cursor.read_exact(&mut short_dentry.name)?; + + short_dentry.attributes = FileAttributes::new(cursor.read_u8()?); + + short_dentry.nt_res = cursor.read_u8()?; + short_dentry.crt_time_tenth = cursor.read_u8()?; + short_dentry.crt_time = cursor.read_u16()?; + short_dentry.crt_date = cursor.read_u16()?; + short_dentry.lst_acc_date = cursor.read_u16()?; + short_dentry.fst_clus_hi = cursor.read_u16()?; + short_dentry.wrt_time = cursor.read_u16()?; + short_dentry.wrt_date = cursor.read_u16()?; + short_dentry.fst_clus_lo = cursor.read_u16()?; + short_dentry.file_size = cursor.read_u32()?; + + return Ok(FATRawDirEntry::Short(short_dentry)); + } + } + } +} diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs new file mode 100644 index 00000000..6637763e --- /dev/null +++ b/kernel/src/filesystem/fat/fs.rs @@ -0,0 +1,1668 @@ +#![allow(dead_code)] +use core::{any::Any, fmt::Debug}; + +use alloc::{ + collections::BTreeMap, + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; + +use crate::{ + filesystem::vfs::{ + core::generate_inode_id, file::FilePrivateData, FileSystem, FileType, IndexNode, InodeId, + Metadata, PollStatus, + }, + include::bindings::bindings::{ + EFAULT, EINVAL, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY, ENOTSUP, EPERM, EROFS, + }, + io::{device::LBA_SIZE, disk_info::Partition, SeekFrom}, + kdebug, kerror, + libs::{ + spinlock::{SpinLock, SpinLockGuard}, + vec_cursor::VecCursor, + }, + time::TimeSpec, +}; + +use super::{ + bpb::{BiosParameterBlock, FATType}, + entry::{FATDir, FATDirEntry, FATDirIter, FATEntry}, + utils::RESERVED_CLUSTERS, +}; + +/// FAT32文件系统的最大的文件大小 +pub const MAX_FILE_SIZE: u64 = 0xffff_ffff; + +/// @brief 表示当前簇和上一个簇的关系的结构体 +/// 定义这样一个结构体的原因是,FAT文件系统的文件中,前后两个簇具有关联关系。 +#[derive(Debug, Clone, Copy, Default)] +pub struct Cluster { + pub cluster_num: u64, + pub parent_cluster: u64, +} + +impl PartialOrd for Cluster { + /// @brief 根据当前簇号比较大小 + fn partial_cmp(&self, other: &Self) -> Option { + return self.cluster_num.partial_cmp(&other.cluster_num); + } +} + +impl PartialEq for Cluster { + /// @brief 根据当前簇号比较是否相等 + fn eq(&self, other: &Self) -> bool { + self.cluster_num == other.cluster_num + } +} + +impl Eq for Cluster {} + +#[derive(Debug)] +pub struct FATFileSystem { + /// 当前文件系统所在的分区 + pub partition: Arc, + /// 当前文件系统的BOPB + pub bpb: BiosParameterBlock, + /// 当前文件系统的第一个数据扇区(相对分区开始位置) + pub first_data_sector: u64, + /// 文件系统信息结构体 + pub fs_info: Arc, + /// 文件系统的根inode + root_inode: Arc, +} + +/// FAT文件系统的Inode +#[derive(Debug)] +pub struct LockedFATInode(SpinLock); + +#[derive(Debug)] +pub struct LockedFATFsInfo(SpinLock); + +impl LockedFATFsInfo { + #[inline] + pub fn new(fs_info: FATFsInfo) -> Self { + return Self(SpinLock::new(fs_info)); + } +} + +#[derive(Debug)] +pub struct FATInode { + /// 指向父Inode的弱引用 + parent: Weak, + /// 指向自身的弱引用 + self_ref: Weak, + /// 子Inode的B树. 该数据结构用作缓存区。其中,它的key表示inode的名称。 + /// 请注意,由于FAT的查询过程对大小写不敏感,因此我们选择让key全部是大写的,方便统一操作。 + children: BTreeMap>, + /// 当前inode的元数据 + metadata: Metadata, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + + /// 根据不同的Inode类型,创建不同的私有字段 + inode_type: FATDirEntry, +} + +impl FATInode { + /// @brief 更新当前inode的元数据 + pub fn update_metadata(&mut self) { + // todo: 更新文件的访问时间等信息 + match &self.inode_type { + FATDirEntry::File(f) | FATDirEntry::VolId(f) => { + self.metadata.size = f.size() as i64; + } + FATDirEntry::Dir(d) => { + self.metadata.size = d.size(&self.fs.upgrade().unwrap().clone()) as i64; + } + FATDirEntry::UnInit => { + kerror!("update_metadata: Uninitialized FATDirEntry: {:?}", self); + return; + } + }; + } + + fn find(&mut self, name: &str) -> Result, i32> { + match &self.inode_type { + FATDirEntry::Dir(d) => { + // 尝试在缓存区查找 + if let Some(entry) = self.children.get(&name.to_uppercase()) { + return Ok(entry.clone()); + } + // 在缓存区找不到 + // 在磁盘查找 + let fat_entry: FATDirEntry = + d.find_entry(name, None, None, self.fs.upgrade().unwrap())?; + // kdebug!("find entry from disk ok, entry={fat_entry:?}"); + // 创建新的inode + let entry_inode: Arc = LockedFATInode::new( + self.fs.upgrade().unwrap(), + self.self_ref.clone(), + fat_entry, + ); + // 加入缓存区, 由于FAT文件系统的大小写不敏感问题,因此存入缓存区的key应当是全大写的 + self.children + .insert(name.to_uppercase(), entry_inode.clone()); + return Ok(entry_inode); + } + FATDirEntry::UnInit => { + panic!( + "Uninitialized FAT Inode, fs = {:?}, inode={self:?}", + self.fs + ) + } + _ => { + return Err(-(ENOTDIR as i32)); + } + } + } +} + +impl LockedFATInode { + pub fn new( + fs: Arc, + parent: Weak, + inode_type: FATDirEntry, + ) -> Arc { + let file_type = if let FATDirEntry::Dir(_) = inode_type { + FileType::Dir + } else { + FileType::File + }; + + let inode: Arc = Arc::new(LockedFATInode(SpinLock::new(FATInode { + parent: parent, + self_ref: Weak::default(), + children: BTreeMap::new(), + fs: Arc::downgrade(&fs), + inode_type: inode_type, + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: fs.bpb.bytes_per_sector as usize, + blocks: if let FATType::FAT32(_) = fs.bpb.fat_type { + fs.bpb.total_sectors_32 as usize + } else { + fs.bpb.total_sectors_16 as usize + }, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: file_type, + mode: 0o777, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: 0, + }, + }))); + + inode.0.lock().self_ref = Arc::downgrade(&inode); + + inode.0.lock().update_metadata(); + + return inode; + } +} + +/// FsInfo结构体(内存中的一份拷贝,当卸载卷或者sync的时候,把它写入磁盘) +#[derive(Debug)] +pub struct FATFsInfo { + /// Lead Signature - must equal 0x41615252 + lead_sig: u32, + /// Value must equal 0x61417272 + struc_sig: u32, + /// 空闲簇数目 + free_count: u32, + /// 第一个空闲簇的位置(不一定准确,仅供加速查找) + next_free: u32, + /// 0xAA550000 + trail_sig: u32, + /// Dirty flag to flush to disk + dirty: bool, + /// FsInfo Structure 在磁盘上的字节偏移量 + /// Not present for FAT12 and FAT16 + offset: Option, +} + +impl FileSystem for FATFileSystem { + fn root_inode(&self) -> Arc { + return self.root_inode.clone(); + } + + fn info(&self) -> crate::filesystem::vfs::FsInfo { + todo!() + } + + /// @brief 本函数用于实现动态转换。 + /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self + fn as_any_ref(&self) -> &dyn Any { + self + } +} + +impl FATFileSystem { + pub fn new(partition: Arc) -> Result, i32> { + let bpb = BiosParameterBlock::new(partition.clone())?; + + // 从磁盘上读取FAT32文件系统的FsInfo结构体 + let fs_info: FATFsInfo = match bpb.fat_type { + FATType::FAT32(bpb32) => { + let fs_info_in_disk_bytes_offset = partition.lba_start * LBA_SIZE as u64 + + bpb32.fs_info as u64 * bpb.bytes_per_sector as u64; + FATFsInfo::new( + partition.clone(), + fs_info_in_disk_bytes_offset, + bpb.bytes_per_sector as usize, + )? + } + _ => FATFsInfo::default(), + }; + + // 根目录项占用的扇区数(向上取整) + let root_dir_sectors: u64 = ((bpb.root_entries_cnt as u64 * 32) + + (bpb.bytes_per_sector as u64 - 1)) + / (bpb.bytes_per_sector as u64); + + // FAT表大小(单位:扇区) + let fat_size = if bpb.fat_size_16 != 0 { + bpb.fat_size_16 as u64 + } else { + match bpb.fat_type { + FATType::FAT32(x) => x.fat_size_32 as u64, + _ => { + kerror!("FAT12 and FAT16 volumes should have non-zero BPB_FATSz16"); + return Err(-(EINVAL as i32)); + } + } + }; + + let first_data_sector = + bpb.rsvd_sec_cnt as u64 + (bpb.num_fats as u64 * fat_size) + root_dir_sectors; + + // 创建文件系统的根节点 + let root_inode: Arc = Arc::new(LockedFATInode(SpinLock::new(FATInode { + parent: Weak::default(), + self_ref: Weak::default(), + children: BTreeMap::new(), + fs: Weak::default(), + inode_type: FATDirEntry::UnInit, + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: bpb.bytes_per_sector as usize, + blocks: if let FATType::FAT32(_) = bpb.fat_type { + bpb.total_sectors_32 as usize + } else { + bpb.total_sectors_16 as usize + }, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::Dir, + mode: 0o777, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: 0, + }, + }))); + + let result: Arc = Arc::new(FATFileSystem { + partition: partition, + bpb, + first_data_sector, + fs_info: Arc::new(LockedFATFsInfo::new(fs_info)), + root_inode: root_inode, + }); + + // 对root inode加锁,并继续完成初始化工作 + let mut root_guard: SpinLockGuard = result.root_inode.0.lock(); + root_guard.inode_type = FATDirEntry::Dir(result.root_dir()); + root_guard.parent = Arc::downgrade(&result.root_inode); + root_guard.self_ref = Arc::downgrade(&result.root_inode); + root_guard.fs = Arc::downgrade(&result); + // 释放锁 + drop(root_guard); + + return Ok(result); + } + + /// @brief 计算每个簇有多少个字节 + #[inline] + pub fn bytes_per_cluster(&self) -> u64 { + return (self.bpb.bytes_per_sector as u64) * (self.bpb.sector_per_cluster as u64); + } + + /// @brief 读取当前簇在FAT表中存储的信息 + /// + /// @param cluster 当前簇 + /// + /// @return Ok(FATEntry) 当前簇在FAT表中,存储的信息。(详情见FATEntry的注释) + /// @return Err(i32) 错误码 + pub fn get_fat_entry(&self, cluster: Cluster) -> Result { + let current_cluster = cluster.cluster_num; + + let fat_type: FATType = self.bpb.fat_type; + // 获取FAT表的起始扇区(相对分区起始扇区的偏移量) + let fat_start_sector = self.fat_start_sector(); + let bytes_per_sec = self.bpb.bytes_per_sector as u64; + + // cluster对应的FAT表项在分区内的字节偏移量 + let fat_bytes_offset = + fat_type.get_fat_bytes_offset(cluster, fat_start_sector, bytes_per_sec); + + // FAT表项所在的LBA地址 + // let fat_ent_lba = self.get_lba_from_offset(self.bytes_to_sector(fat_bytes_offset)); + let fat_ent_lba = self.partition.lba_start + fat_bytes_offset / LBA_SIZE as u64; + + // FAT表项在逻辑块内的字节偏移量 + let blk_offset = self.get_in_block_offset(fat_bytes_offset); + + let mut v = Vec::::new(); + v.resize(self.bpb.bytes_per_sector as usize, 0); + self.partition + .disk() + .read_at(fat_ent_lba as usize, 1 * self.lba_per_sector(), &mut v)?; + + let mut cursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(blk_offset as i64))?; + + let res: FATEntry = match self.bpb.fat_type { + FATType::FAT12(_) => { + let mut entry = cursor.read_u16()?; + // 由于FAT12文件系统的FAT表,每个entry占用1.5字节,因此奇数的簇需要取高12位的值。 + if (current_cluster & 1) > 0 { + entry >>= 4; + } else { + entry &= 0x0fff; + } + + if entry == 0 { + FATEntry::Unused + } else if entry == 0x0ff7 { + FATEntry::Bad + } else if entry >= 0x0ff8 { + FATEntry::EndOfChain + } else { + FATEntry::Next(Cluster { + cluster_num: entry as u64, + parent_cluster: current_cluster, + }) + } + } + FATType::FAT16(_) => { + let entry = cursor.read_u16()?; + + if entry == 0 { + FATEntry::Unused + } else if entry == 0xfff7 { + FATEntry::Bad + } else if entry >= 0xfff8 { + FATEntry::EndOfChain + } else { + FATEntry::Next(Cluster { + cluster_num: entry as u64, + parent_cluster: current_cluster, + }) + } + } + FATType::FAT32(_) => { + let entry = cursor.read_u32()? & 0x0fffffff; + + match entry { + _n if (current_cluster >= 0x0ffffff7 && current_cluster <= 0x0fffffff) => { + // 当前簇号不是一个能被获得的簇(可能是文件系统出错了) + kerror!("FAT32 get fat entry: current cluster number [{}] is not an allocatable cluster number.", current_cluster); + FATEntry::Bad + } + 0 => FATEntry::Unused, + 0x0ffffff7 => FATEntry::Bad, + 0x0ffffff8..=0x0fffffff => FATEntry::EndOfChain, + _n => FATEntry::Next(Cluster { + cluster_num: entry as u64, + parent_cluster: current_cluster, + }), + } + } + }; + return Ok(res); + } + + /// @brief 读取当前簇在FAT表中存储的信息(直接返回读取到的值,而不加处理) + /// + /// @param cluster 当前簇 + /// + /// @return Ok(u64) 当前簇在FAT表中,存储的信息。 + /// @return Err(i32) 错误码 + pub fn get_fat_entry_raw(&self, cluster: Cluster) -> Result { + let current_cluster = cluster.cluster_num; + + let fat_type: FATType = self.bpb.fat_type; + // 获取FAT表的起始扇区(相对分区起始扇区的偏移量) + let fat_start_sector = self.fat_start_sector(); + let bytes_per_sec = self.bpb.bytes_per_sector as u64; + + // cluster对应的FAT表项在分区内的字节偏移量 + let fat_bytes_offset = + fat_type.get_fat_bytes_offset(cluster, fat_start_sector, bytes_per_sec); + + // FAT表项所在的LBA地址 + let fat_ent_lba = self.get_lba_from_offset(self.bytes_to_sector(fat_bytes_offset)); + + // FAT表项在逻辑块内的字节偏移量 + let blk_offset = self.get_in_block_offset(fat_bytes_offset); + + let mut v = Vec::::new(); + v.resize(self.bpb.bytes_per_sector as usize, 0); + self.partition + .disk() + .read_at(fat_ent_lba, 1 * self.lba_per_sector(), &mut v)?; + + let mut cursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(blk_offset as i64))?; + + let res = match self.bpb.fat_type { + FATType::FAT12(_) => { + let mut entry = cursor.read_u16()?; + entry = if (current_cluster & 0x0001) > 0 { + entry >> 4 + } else { + entry & 0x0fff + }; + entry as u64 + } + FATType::FAT16(_) => { + let entry = (cursor.read_u16()?) as u64; + entry + } + FATType::FAT32(_) => { + let entry = cursor.read_u32()? & 0x0fff_ffff; + entry as u64 + } + }; + + return Ok(res); + } + + /// @brief 获取当前文件系统的root inode,在磁盘上的字节偏移量 + pub fn root_dir_bytes_offset(&self) -> u64 { + match self.bpb.fat_type { + FATType::FAT32(s) => { + let first_sec_cluster: u64 = (s.root_cluster as u64 - 2) + * (self.bpb.sector_per_cluster as u64) + + self.first_data_sector; + return (self.get_lba_from_offset(first_sec_cluster) * LBA_SIZE) as u64; + } + _ => { + let root_sec = (self.bpb.rsvd_sec_cnt as u64) + + (self.bpb.num_fats as u64) * (self.bpb.fat_size_16 as u64); + return (self.get_lba_from_offset(root_sec) * LBA_SIZE) as u64; + } + } + } + + /// @brief 获取当前文件系统的根目录项区域的结束位置,在磁盘上的字节偏移量。 + /// 请注意,当前函数只对FAT12/FAT16生效。对于FAT32,返回None + pub fn root_dir_end_bytes_offset(&self) -> Option { + match self.bpb.fat_type { + FATType::FAT12(_) | FATType::FAT16(_) => { + return Some( + self.root_dir_bytes_offset() + (self.bpb.root_entries_cnt as u64) * 32, + ); + } + _ => { + return None; + } + } + } + + /// @brief 获取簇在磁盘内的字节偏移量(相对磁盘起始位置。注意,不是分区内偏移量) + pub fn cluster_bytes_offset(&self, cluster: Cluster) -> u64 { + if cluster.cluster_num >= 2 { + // 指定簇的第一个扇区号 + let first_sec_of_cluster = (cluster.cluster_num - 2) + * (self.bpb.sector_per_cluster as u64) + + self.first_data_sector; + return (self.get_lba_from_offset(first_sec_of_cluster) * LBA_SIZE) as u64; + } else { + return 0; + } + } + + /// @brief 获取一个空闲簇 + /// + /// @param prev_cluster 簇链的前一个簇。本函数将会把新获取的簇,连接到它的后面。 + /// + /// @return Ok(Cluster) 新获取的空闲簇 + /// @return Err(i32) 错误码 + pub fn allocate_cluster(&self, prev_cluster: Option) -> Result { + let end_cluster: Cluster = self.max_cluster_number(); + let start_cluster: Cluster = match self.bpb.fat_type { + FATType::FAT32(_) => { + let next_free: u64 = match self.fs_info.0.lock().next_free() { + Some(x) => x, + None => 0xffffffff, + }; + if next_free < end_cluster.cluster_num { + Cluster::new(next_free) + } else { + Cluster::new(RESERVED_CLUSTERS as u64) + } + } + _ => Cluster::new(RESERVED_CLUSTERS as u64), + }; + + // 寻找一个空的簇 + let free_cluster: Cluster = match self.get_free_cluster(start_cluster, end_cluster) { + Ok(c) => c, + Err(_) if start_cluster.cluster_num > RESERVED_CLUSTERS as u64 => { + self.get_free_cluster(Cluster::new(RESERVED_CLUSTERS as u64), end_cluster)? + } + Err(e) => return Err(e), + }; + + self.set_entry(free_cluster, FATEntry::EndOfChain)?; + // 减少空闲簇计数 + self.fs_info.0.lock().update_free_count_delta(-1); + // 更新搜索空闲簇的参考量 + self.fs_info + .0 + .lock() + .update_next_free((free_cluster.cluster_num + 1) as u32); + + // 如果这个空闲簇不是簇链的第一个簇,那么把当前簇跟前一个簇连上。 + if let Some(prev_cluster) = prev_cluster { + // kdebug!("set entry, prev ={prev_cluster:?}, next = {free_cluster:?}"); + self.set_entry(prev_cluster, FATEntry::Next(free_cluster))?; + } + // 清空新获取的这个簇 + self.zero_cluster(free_cluster)?; + return Ok(free_cluster); + } + + /// @brief 释放簇链上的所有簇 + /// + /// @param start_cluster 簇链的第一个簇 + pub fn deallocate_cluster_chain(&self, start_cluster: Cluster) -> Result<(), i32> { + let clusters: Vec = self.clusters(start_cluster); + for c in clusters { + self.deallocate_cluster(c)?; + } + return Ok(()); + } + + /// @brief 释放簇 + /// + /// @param 要释放的簇 + pub fn deallocate_cluster(&self, cluster: Cluster) -> Result<(), i32> { + let entry: FATEntry = self.get_fat_entry(cluster)?; + // 如果不是坏簇 + if entry != FATEntry::Bad { + self.set_entry(cluster, FATEntry::Unused)?; + self.fs_info.0.lock().update_free_count_delta(1); + // 安全选项:清空被释放的簇 + #[cfg(feature = "secure")] + self.zero_cluster(cluster)?; + return Ok(()); + } else { + // 不能释放坏簇 + kerror!("Bad clusters cannot be freed."); + return Err(-(EFAULT as i32)); + } + } + + /// @brief 获取文件系统的根目录项 + pub fn root_dir(&self) -> FATDir { + match self.bpb.fat_type { + FATType::FAT32(s) => { + return FATDir { + first_cluster: Cluster::new(s.root_cluster as u64), + dir_name: String::from("/"), + root_offset: None, + short_dir_entry: None, + loc: None, + }; + } + _ => FATDir { + first_cluster: Cluster::new(0), + dir_name: String::from("/"), + root_offset: Some(self.root_dir_bytes_offset()), + short_dir_entry: None, + loc: None, + }, + } + } + + /// @brief 获取FAT表的起始扇区(相对分区起始扇区的偏移量) + pub fn fat_start_sector(&self) -> u64 { + let active_fat = self.active_fat(); + let fat_size = self.fat_size(); + return self.bpb.rsvd_sec_cnt as u64 + active_fat * fat_size; + } + + /// @brief 获取当前活动的FAT表 + pub fn active_fat(&self) -> u64 { + if self.mirroring_enabled() { + return 0; + } else { + match self.bpb.fat_type { + FATType::FAT32(bpb32) => { + return (bpb32.ext_flags & 0x0f) as u64; + } + _ => { + return 0; + } + } + } + } + + /// @brief 获取当前文件系统的每个FAT表的大小 + pub fn fat_size(&self) -> u64 { + if self.bpb.fat_size_16 != 0 { + return self.bpb.fat_size_16 as u64; + } else { + match self.bpb.fat_type { + FATType::FAT32(bpb32) => { + return bpb32.fat_size_32 as u64; + } + + _ => { + panic!("FAT12 and FAT16 volumes should have non-zero BPB_FATSz16"); + } + } + } + } + + /// @brief 判断当前文件系统是否启用了FAT表镜像 + pub fn mirroring_enabled(&self) -> bool { + match self.bpb.fat_type { + FATType::FAT32(bpb32) => { + return (bpb32.ext_flags & 0x80) == 0; + } + _ => { + return false; + } + } + } + + /// @brief 根据分区内的扇区偏移量,获得在磁盘上的LBA地址 + #[inline] + pub fn get_lba_from_offset(&self, in_partition_sec_offset: u64) -> usize { + return (self.partition.lba_start + + in_partition_sec_offset * (self.bpb.bytes_per_sector as u64 / LBA_SIZE as u64)) + as usize; + } + + /// @brief 获取每个扇区占用多少个LBA + #[inline] + pub fn lba_per_sector(&self) -> usize { + return self.bpb.bytes_per_sector as usize / LBA_SIZE; + } + + /// @brief 将分区内字节偏移量转换为扇区偏移量 + #[inline] + pub fn bytes_to_sector(&self, in_partition_bytes_offset: u64) -> u64 { + return in_partition_bytes_offset / (self.bpb.bytes_per_sector as u64); + } + + /// @brief 根据磁盘上的字节偏移量,获取对应位置在分区内的字节偏移量 + #[inline] + pub fn get_in_partition_bytes_offset(&self, disk_bytes_offset: u64) -> u64 { + return disk_bytes_offset - (self.partition.lba_start * LBA_SIZE as u64); + } + + /// @brief 根据字节偏移量计算在逻辑块内的字节偏移量 + #[inline] + pub fn get_in_block_offset(&self, bytes_offset: u64) -> u64 { + return bytes_offset % LBA_SIZE as u64; + } + + /// @brief 获取在FAT表中,以start_cluster开头的FAT链的所有簇的信息 + /// + /// @param start_cluster 整个FAT链的起始簇号 + pub fn clusters(&self, start_cluster: Cluster) -> Vec { + return self.cluster_iter(start_cluster).collect(); + } + + /// @brief 获取在FAT表中,以start_cluster开头的FAT链的长度(总计经过多少个簇) + /// + /// @param start_cluster 整个FAT链的起始簇号 + pub fn num_clusters_chain(&self, start_cluster: Cluster) -> u64 { + return self + .cluster_iter(start_cluster) + .fold(0, |size, _cluster| size + 1); + } + /// @brief 获取一个簇迭代器对象 + /// + /// @param start_cluster 整个FAT链的起始簇号 + fn cluster_iter(&self, start_cluster: Cluster) -> ClusterIter { + return ClusterIter { + current_cluster: Some(start_cluster), + fs: self, + }; + } + + /// @brief 获取从start_cluster开始的簇链中,第n个簇的信息。(请注意,下标从0开始) + #[inline] + pub fn get_cluster_by_relative(&self, start_cluster: Cluster, n: usize) -> Option { + return self.cluster_iter(start_cluster).skip(n).next(); + } + + /// @brief 获取整个簇链的最后一个簇 + #[inline] + pub fn get_last_cluster(&self, start_cluster: Cluster) -> Option { + return self.cluster_iter(start_cluster).last(); + } + + /// @brief 判断FAT文件系统的shut bit是否正常。 + /// shut bit 表示文件系统是否正常卸载。如果这一位是1,则表示这个卷是“干净的” + /// 参考资料:https://thestarman.pcministry.com/DOS/DirtyShutdownFlag.html + /// + /// @return Ok(true) 正常 + /// @return Ok(false) 不正常 + /// @return Err(i32) 在判断时发生错误 + pub fn is_shut_bit_ok(&mut self) -> Result { + match self.bpb.fat_type { + FATType::FAT32(_) => { + // 对于FAT32, error bit位于第一个扇区的第8字节。 + let bit = self.get_fat_entry_raw(Cluster::new(1))? & 0x0800_0000; + return Ok(bit > 0); + } + FATType::FAT16(_) => { + let bit = self.get_fat_entry_raw(Cluster::new(1))? & 0x8000; + return Ok(bit > 0); + } + _ => return Ok(true), + } + } + + /// @brief 判断FAT文件系统的hard error bit是否正常。 + /// 如果此位为0,则文件系统驱动程序在上次安装卷时遇到磁盘 I/O 错误,这表明 + /// 卷上的某些扇区可能已损坏。 + /// 参考资料:https://thestarman.pcministry.com/DOS/DirtyShutdownFlag.html + /// + /// @return Ok(true) 正常 + /// @return Ok(false) 不正常 + /// @return Err(i32) 在判断时发生错误 + pub fn is_hard_error_bit_ok(&mut self) -> Result { + match self.bpb.fat_type { + FATType::FAT32(_) => { + let bit = self.get_fat_entry_raw(Cluster::new(1))? & 0x0400_0000; + return Ok(bit > 0); + } + FATType::FAT16(_) => { + let bit = self.get_fat_entry_raw(Cluster::new(1))? & 0x4000; + return Ok(bit > 0); + } + _ => return Ok(true), + } + } + + /// @brief 设置文件系统的shut bit为正常状态 + /// 参考资料:https://thestarman.pcministry.com/DOS/DirtyShutdownFlag.html + /// + /// @return Ok(()) 设置成功 + /// @return Err(i32) 在设置过程中,出现错误 + pub fn set_shut_bit_ok(&mut self) -> Result<(), i32> { + match self.bpb.fat_type { + FATType::FAT32(_) => { + let raw_entry = self.get_fat_entry_raw(Cluster::new(1))? | 0x0800_0000; + self.set_entry(Cluster::new(1), FATEntry::Next(Cluster::new(raw_entry)))?; + + return Ok(()); + } + + FATType::FAT16(_) => { + let raw_entry = self.get_fat_entry_raw(Cluster::new(1))? | 0x8000; + self.set_entry(Cluster::new(1), FATEntry::Next(Cluster::new(raw_entry)))?; + return Ok(()); + } + _ => return Ok(()), + } + } + + /// @brief 设置文件系统的hard error bit为正常状态 + /// 参考资料:https://thestarman.pcministry.com/DOS/DirtyShutdownFlag.html + /// + /// @return Ok(()) 设置成功 + /// @return Err(i32) 在设置过程中,出现错误 + pub fn set_hard_error_bit_ok(&mut self) -> Result<(), i32> { + match self.bpb.fat_type { + FATType::FAT32(_) => { + let raw_entry = self.get_fat_entry_raw(Cluster::new(1))? | 0x0400_0000; + self.set_entry(Cluster::new(1), FATEntry::Next(Cluster::new(raw_entry)))?; + return Ok(()); + } + + FATType::FAT16(_) => { + let raw_entry = self.get_fat_entry_raw(Cluster::new(1))? | 0x4000; + self.set_entry(Cluster::new(1), FATEntry::Next(Cluster::new(raw_entry)))?; + return Ok(()); + } + _ => return Ok(()), + } + } + + /// @brief 执行文件系统卸载前的一些准备工作:设置好对应的标志位,并把缓存中的数据刷入磁盘 + pub fn umount(&mut self) -> Result<(), i32> { + self.fs_info.0.lock().flush(&self.partition)?; + + self.set_shut_bit_ok()?; + + self.set_hard_error_bit_ok()?; + + self.partition.disk().sync()?; + + return Ok(()); + } + + /// @brief 获取文件系统的最大簇号 + pub fn max_cluster_number(&self) -> Cluster { + match self.bpb.fat_type { + FATType::FAT32(s) => { + // FAT32 + + // 数据扇区数量(总扇区数-保留扇区-FAT占用的扇区) + let data_sec: u64 = self.bpb.total_sectors_32 as u64 + - (self.bpb.rsvd_sec_cnt as u64 + + self.bpb.num_fats as u64 * s.fat_size_32 as u64); + + // 数据区的簇数量 + let total_clusters: u64 = data_sec / self.bpb.sector_per_cluster as u64; + + // 返回最大的簇号 + return Cluster::new(total_clusters + RESERVED_CLUSTERS as u64 - 1); + } + + _ => { + // FAT12 / FAT16 + let root_dir_sectors: u64 = (((self.bpb.root_entries_cnt as u64) * 32) + + self.bpb.bytes_per_sector as u64 + - 1) + / self.bpb.bytes_per_sector as u64; + // 数据区扇区数 + let data_sec: u64 = self.bpb.total_sectors_16 as u64 + - (self.bpb.rsvd_sec_cnt as u64 + + (self.bpb.num_fats as u64 * self.bpb.fat_size_16 as u64) + + root_dir_sectors); + let total_clusters = data_sec / self.bpb.sector_per_cluster as u64; + return Cluster::new(total_clusters + RESERVED_CLUSTERS as u64 - 1); + } + } + } + + /// @brief 在文件系统中寻找一个簇号在给定的范围(左闭右开区间)内的空闲簇 + /// + /// @param start_cluster 起始簇号 + /// @param end_cluster 终止簇号(不包含) + /// + /// @return Ok(Cluster) 寻找到的空闲簇 + /// @return Err(i32) 错误码。如果磁盘无剩余空间,或者簇号达到给定的最大值,则返回-ENOSPC. + pub fn get_free_cluster( + &self, + start_cluster: Cluster, + end_cluster: Cluster, + ) -> Result { + let max_cluster: Cluster = self.max_cluster_number(); + let mut cluster: u64 = start_cluster.cluster_num; + + let fat_type: FATType = self.bpb.fat_type; + let fat_start_sector: u64 = self.fat_start_sector(); + let bytes_per_sec: u64 = self.bpb.bytes_per_sector as u64; + + match fat_type { + FATType::FAT12(_) => { + let part_bytes_offset: u64 = + fat_type.get_fat_bytes_offset(start_cluster, fat_start_sector, bytes_per_sec); + let in_block_offset = self.get_in_block_offset(part_bytes_offset); + + let lba = self.get_lba_from_offset(self.bytes_to_sector(part_bytes_offset)); + + // 由于FAT12的FAT表不大于6K,因此直接读取6K + let num_lba = (6 * 1024) / LBA_SIZE; + let mut v: Vec = Vec::new(); + v.resize(num_lba * LBA_SIZE, 0); + self.partition.disk().read_at(lba, num_lba, &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + let mut packed_val: u16 = cursor.read_u16()?; + loop { + let val = if (cluster & 0x1) > 0 { + packed_val >> 4 + } else { + packed_val & 0x0fff + }; + if val == 0 { + return Ok(Cluster::new(cluster as u64)); + } + + cluster += 1; + + // 磁盘无剩余空间,或者簇号达到给定的最大值 + if cluster == end_cluster.cluster_num || cluster == max_cluster.cluster_num { + return Err(-(ENOSPC as i32)); + } + + packed_val = match cluster & 1 { + 0 => cursor.read_u16()?, + _ => { + let next_byte = cursor.read_u8()? as u16; + (packed_val >> 8) | (next_byte << 8) + } + }; + } + } + FATType::FAT16(_) => { + // todo: 优化这里,减少读取磁盘的次数。 + while cluster < end_cluster.cluster_num && cluster < max_cluster.cluster_num { + let part_bytes_offset: u64 = fat_type.get_fat_bytes_offset( + Cluster::new(cluster), + fat_start_sector, + bytes_per_sec, + ); + let in_block_offset = self.get_in_block_offset(part_bytes_offset); + + let lba = self.get_lba_from_offset(self.bytes_to_sector(part_bytes_offset)); + + let mut v: Vec = Vec::new(); + v.resize(self.lba_per_sector() * LBA_SIZE, 0); + self.partition + .disk() + .read_at(lba, self.lba_per_sector(), &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + let val = cursor.read_u16()?; + // 找到空闲簇 + if val == 0 { + return Ok(Cluster::new(val as u64)); + } + cluster += 1; + } + + // 磁盘无剩余空间,或者簇号达到给定的最大值 + return Err(-(ENOSPC as i32)); + } + FATType::FAT32(_) => { + // todo: 优化这里,减少读取磁盘的次数。 + while cluster < end_cluster.cluster_num && cluster < max_cluster.cluster_num { + let part_bytes_offset: u64 = fat_type.get_fat_bytes_offset( + Cluster::new(cluster), + fat_start_sector, + bytes_per_sec, + ); + let in_block_offset = self.get_in_block_offset(part_bytes_offset); + + let lba = self.get_lba_from_offset(self.bytes_to_sector(part_bytes_offset)); + + let mut v: Vec = Vec::new(); + v.resize(self.lba_per_sector() * LBA_SIZE, 0); + self.partition + .disk() + .read_at(lba, self.lba_per_sector(), &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + let val = cursor.read_u32()? & 0x0fffffff; + + if val == 0 { + return Ok(Cluster::new(cluster)); + } + cluster += 1; + } + + // 磁盘无剩余空间,或者簇号达到给定的最大值 + return Err(-(ENOSPC as i32)); + } + } + } + + /// @brief 在FAT表中,设置指定的簇的信息。 + /// + /// @param cluster 目标簇 + /// @param fat_entry 这个簇在FAT表中,存储的信息(下一个簇的簇号) + pub fn set_entry(&self, cluster: Cluster, fat_entry: FATEntry) -> Result<(), i32> { + // fat表项在分区上的字节偏移量 + let fat_part_bytes_offset: u64 = self.bpb.fat_type.get_fat_bytes_offset( + cluster, + self.fat_start_sector(), + self.bpb.bytes_per_sector as u64, + ); + + match self.bpb.fat_type { + FATType::FAT12(_) => { + // 计算要写入的值 + let raw_val: u16 = match fat_entry { + FATEntry::Unused => 0, + FATEntry::Bad => 0xff7, + FATEntry::EndOfChain => 0xfff, + FATEntry::Next(c) => c.cluster_num as u16, + }; + + let in_block_offset = self.get_in_block_offset(fat_part_bytes_offset); + + let lba = self.get_lba_from_offset(self.bytes_to_sector(fat_part_bytes_offset)); + + let mut v: Vec = Vec::new(); + v.resize(LBA_SIZE, 0); + self.partition.disk().read_at(lba, 1, &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + let old_val: u16 = cursor.read_u16()?; + let new_val: u16 = if (cluster.cluster_num & 0x1) > 0 { + (old_val & 0x000f) | (raw_val << 4) + } else { + (old_val & 0xf000) | raw_val + }; + + // 写回数据到磁盘上 + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + cursor.write_u16(new_val)?; + self.partition.disk().write_at(lba, 1, cursor.as_slice())?; + return Ok(()); + } + FATType::FAT16(_) => { + // 计算要写入的值 + let raw_val: u16 = match fat_entry { + FATEntry::Unused => 0, + FATEntry::Bad => 0xfff7, + FATEntry::EndOfChain => 0xfdff, + FATEntry::Next(c) => c.cluster_num as u16, + }; + + let in_block_offset = self.get_in_block_offset(fat_part_bytes_offset); + + let lba = self.get_lba_from_offset(self.bytes_to_sector(fat_part_bytes_offset)); + + let mut v: Vec = Vec::new(); + v.resize(LBA_SIZE, 0); + self.partition.disk().read_at(lba, 1, &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + cursor.write_u16(raw_val)?; + self.partition.disk().write_at(lba, 1, cursor.as_slice())?; + + return Ok(()); + } + FATType::FAT32(_) => { + let fat_size: u64 = self.fat_size(); + let bound: u64 = if self.mirroring_enabled() { + 1 + } else { + self.bpb.num_fats as u64 + }; + // kdebug!("set entry, bound={bound}, fat_size={fat_size}"); + for i in 0..bound { + // 当前操作的FAT表在磁盘上的字节偏移量 + let f_offset: u64 = fat_part_bytes_offset + i * fat_size; + let in_block_offset: u64 = self.get_in_block_offset(f_offset); + let lba = self.get_lba_from_offset(self.bytes_to_sector(f_offset)); + + // kdebug!("set entry, lba={lba}, in_block_offset={in_block_offset}"); + let mut v: Vec = Vec::new(); + v.resize(LBA_SIZE, 0); + self.partition.disk().read_at(lba, 1, &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + // FAT32的高4位保留 + let old_bits = cursor.read_u32()? & 0xf0000000; + + if fat_entry == FATEntry::Unused + && cluster.cluster_num >= 0x0ffffff7 + && cluster.cluster_num <= 0x0fffffff + { + kerror!( + "FAT32: Reserved Cluster {:?} cannot be marked as free", + cluster + ); + return Err(-(EPERM as i32)); + } + + // 计算要写入的值 + let mut raw_val: u32 = match fat_entry { + FATEntry::Unused => 0, + FATEntry::Bad => 0x0FFFFFF7, + FATEntry::EndOfChain => 0x0FFFFFFF, + FATEntry::Next(c) => c.cluster_num as u32, + }; + + // 恢复保留位 + raw_val |= old_bits; + + // kdebug!("sent entry, raw_val={raw_val}"); + + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + cursor.write_u32(raw_val)?; + + self.partition.disk().write_at(lba, 1, cursor.as_slice())?; + } + + return Ok(()); + } + } + } + + /// @brief 清空指定的簇 + /// + /// @param cluster 要被清空的簇 + pub fn zero_cluster(&self, cluster: Cluster) -> Result<(), i32> { + // 准备数据,用于写入 + let zeros: Vec = vec![0u8; self.bytes_per_cluster() as usize]; + let offset: usize = self.cluster_bytes_offset(cluster) as usize; + self.partition + .disk() + .device() + .write_at(offset, zeros.len(), zeros.as_slice())?; + return Ok(()); + } +} + +impl Drop for FATFileSystem { + fn drop(&mut self) { + let r = self.umount(); + if r.is_err() { + kerror!( + "Umount FAT filesystem failed: errno={}, FS detail:{self:?}", + r.unwrap_err() + ); + } + } +} + +impl FATFsInfo { + const LEAD_SIG: u32 = 0x41615252; + const STRUC_SIG: u32 = 0x61417272; + const TRAIL_SIG: u32 = 0xAA550000; + const FS_INFO_SIZE: u64 = 512; + + /// @brief 从磁盘上读取FAT文件系统的FSInfo结构体 + /// + /// @param partition 磁盘分区 + /// @param in_disk_fs_info_offset FSInfo扇区在磁盘内的字节偏移量(单位:字节) + /// @param bytes_per_sec 每扇区字节数 + pub fn new( + partition: Arc, + in_disk_fs_info_offset: u64, + bytes_per_sec: usize, + ) -> Result { + let mut v = Vec::::new(); + v.resize(bytes_per_sec, 0); + + // 计算fs_info扇区在磁盘上的字节偏移量,从磁盘读取数据 + partition + .disk() + .read_at(in_disk_fs_info_offset as usize / LBA_SIZE, 1, &mut v)?; + let mut cursor = VecCursor::new(v); + + let mut fsinfo = FATFsInfo::default(); + + fsinfo.lead_sig = cursor.read_u32()?; + cursor.seek(SeekFrom::SeekCurrent(480))?; + fsinfo.struc_sig = cursor.read_u32()?; + fsinfo.free_count = cursor.read_u32()?; + fsinfo.next_free = cursor.read_u32()?; + + cursor.seek(SeekFrom::SeekCurrent(12))?; + + fsinfo.trail_sig = cursor.read_u32()?; + fsinfo.dirty = false; + fsinfo.offset = Some(in_disk_fs_info_offset); + + if fsinfo.is_valid() { + return Ok(fsinfo); + } else { + kerror!("Error occurred while parsing FATFsInfo."); + return Err(-(EINVAL as i32)); + } + } + + /// @brief 判断是否为正确的FsInfo结构体 + fn is_valid(&self) -> bool { + self.lead_sig == Self::LEAD_SIG + && self.struc_sig == Self::STRUC_SIG + && self.trail_sig == Self::TRAIL_SIG + } + + /// @brief 根据fsinfo的信息,计算当前总的空闲簇数量 + /// + /// @param 当前文件系统的最大簇号 + pub fn count_free_cluster(&self, max_cluster: Cluster) -> Option { + let count_clusters = max_cluster.cluster_num - RESERVED_CLUSTERS as u64 + 1; + // 信息不合理,当前的FsInfo中存储的free count大于计算出来的值 + if self.free_count as u64 > count_clusters { + return None; + } else { + match self.free_count { + // free count字段不可用 + 0xffffffff => return None, + // 返回FsInfo中存储的数据 + n => return Some(n as u64), + } + } + } + + /// @brief 更新FsInfo中的“空闲簇统计信息“为new_count + /// + /// 请注意,除非手动调用`flush()`,否则本函数不会将数据刷入磁盘 + pub fn update_free_count_abs(&mut self, new_count: u32) { + self.free_count = new_count; + } + + /// @brief 更新FsInfo中的“空闲簇统计信息“,把它加上delta. + /// + /// 请注意,除非手动调用`flush()`,否则本函数不会将数据刷入磁盘 + pub fn update_free_count_delta(&mut self, delta: i32) { + self.free_count = (self.free_count as i32 + delta) as u32; + } + + /// @brief 更新FsInfo中的“第一个空闲簇统计信息“为next_free. + /// + /// 请注意,除非手动调用`flush()`,否则本函数不会将数据刷入磁盘 + pub fn update_next_free(&mut self, next_free: u32) { + // 这个值是参考量,不一定要准确,仅供加速查找 + self.next_free = next_free; + } + + /// @brief 获取fs info 记载的第一个空闲簇。(不一定准确,仅供参考) + pub fn next_free(&self) -> Option { + match self.next_free { + 0xffffffff => return None, + 0 | 1 => return None, + n => return Some(n as u64), + }; + } + + /// @brief 把fs info刷入磁盘 + /// + /// @param partition fs info所在的分区 + pub fn flush(&self, partition: &Arc) -> Result<(), i32> { + if let Some(off) = self.offset { + let in_block_offset = off % LBA_SIZE as u64; + + let lba = off as usize / LBA_SIZE; + + let mut v: Vec = Vec::new(); + v.resize(LBA_SIZE, 0); + partition.disk().read_at(lba, 1, &mut v)?; + + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + + cursor.write_u32(self.lead_sig)?; + cursor.seek(SeekFrom::SeekCurrent(480))?; + cursor.write_u32(self.struc_sig)?; + cursor.write_u32(self.free_count)?; + cursor.write_u32(self.next_free)?; + cursor.seek(SeekFrom::SeekCurrent(12))?; + cursor.write_u32(self.trail_sig)?; + + partition.disk().write_at(lba, 1, cursor.as_slice())?; + } + return Ok(()); + } + + /// @brief 读取磁盘上的Fs Info扇区,将里面的内容更新到结构体中 + /// + /// @param partition fs info所在的分区 + pub fn update(&mut self, partition: Arc) -> Result<(), i32> { + if let Some(off) = self.offset { + let in_block_offset = off % LBA_SIZE as u64; + + let lba = off as usize / LBA_SIZE; + + let mut v: Vec = Vec::new(); + v.resize(LBA_SIZE, 0); + partition.disk().read_at(lba, 1, &mut v)?; + let mut cursor: VecCursor = VecCursor::new(v); + cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?; + self.lead_sig = cursor.read_u32()?; + + cursor.seek(SeekFrom::SeekCurrent(480))?; + self.struc_sig = cursor.read_u32()?; + self.free_count = cursor.read_u32()?; + self.next_free = cursor.read_u32()?; + cursor.seek(SeekFrom::SeekCurrent(12))?; + self.trail_sig = cursor.read_u32()?; + } + return Ok(()); + } +} + +impl IndexNode for LockedFATInode { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: &mut FilePrivateData, + ) -> Result { + let mut guard: SpinLockGuard = self.0.lock(); + match &guard.inode_type { + FATDirEntry::File(f) | FATDirEntry::VolId(f) => { + let r = f.read( + &guard.fs.upgrade().unwrap(), + &mut buf[0..len], + offset as u64, + ); + guard.update_metadata(); + return r; + } + FATDirEntry::Dir(_) => { + return Err(-(EISDIR as i32)); + } + FATDirEntry::UnInit => { + kerror!("FATFS: param: Inode_type uninitialized."); + return Err(-(EROFS as i32)); + } + } + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result { + let mut guard: SpinLockGuard = self.0.lock(); + let fs: &Arc = &guard.fs.upgrade().unwrap(); + + match &mut guard.inode_type { + FATDirEntry::File(f) | FATDirEntry::VolId(f) => { + let r = f.write(fs, &buf[0..len], offset as u64); + guard.update_metadata(); + return r; + } + FATDirEntry::Dir(_) => { + return Err(-(EISDIR as i32)); + } + FATDirEntry::UnInit => { + kerror!("FATFS: param: Inode_type uninitialized."); + return Err(-(EROFS as i32)); + } + } + } + + fn poll(&self) -> Result { + // 加锁 + let inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + return Ok(PollStatus { + flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK, + }); + } + + fn create( + &self, + name: &str, + file_type: FileType, + _mode: u32, + ) -> Result, i32> { + // 由于FAT32不支持文件权限的功能,因此忽略mode参数 + + let mut guard: SpinLockGuard = self.0.lock(); + let fs: &Arc = &guard.fs.upgrade().unwrap(); + + match &mut guard.inode_type { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(-(ENOTDIR as i32)); + } + FATDirEntry::Dir(d) => match file_type { + FileType::File => { + d.create_file(name, fs)?; + return Ok(guard.find(name)?); + } + FileType::Dir => { + d.create_dir(name, fs)?; + return Ok(guard.find(name)?); + } + + FileType::SymLink => return Err(-(ENOTSUP as i32)), + _ => return Err(-(EINVAL as i32)), + }, + FATDirEntry::UnInit => { + kerror!("FATFS: param: Inode_type uninitialized."); + return Err(-(EROFS as i32)); + } + } + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + return self; + } + + fn metadata(&self) -> Result { + return Ok(self.0.lock().metadata.clone()); + } + + fn list(&self) -> Result, i32> { + let mut guard: SpinLockGuard = self.0.lock(); + let fatent: &FATDirEntry = &guard.inode_type; + match fatent { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(-(ENOTDIR as i32)); + } + FATDirEntry::Dir(dir) => { + // 获取当前目录下的所有目录项 + let mut ret: Vec = Vec::new(); + let dir_iter: FATDirIter = dir.to_iter(guard.fs.upgrade().unwrap()); + for ent in dir_iter { + ret.push(ent.name()); + + // ====== 生成inode缓存,存入B树 + let name: String = ent.name(); + // kdebug!("name={name}"); + + if guard.children.contains_key(&name.to_uppercase()) == false + && name != "." + && name != ".." + { + // 创建新的inode + let entry_inode: Arc = LockedFATInode::new( + guard.fs.upgrade().unwrap(), + guard.self_ref.clone(), + ent, + ); + // 加入缓存区, 由于FAT文件系统的大小写不敏感问题,因此存入缓存区的key应当是全大写的 + guard + .children + .insert(name.to_uppercase(), entry_inode.clone()); + } + } + return Ok(ret); + } + FATDirEntry::UnInit => { + kerror!("FATFS: param: Inode_type uninitialized."); + return Err(-(EROFS as i32)); + } + } + } + + fn find(&self, name: &str) -> Result, i32> { + let mut guard: SpinLockGuard = self.0.lock(); + let target = guard.find(name)?; + return Ok(target); + } + + fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + return Ok(()); + } + + fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + return Ok(()); + } + + fn unlink(&self, name: &str) -> Result<(), i32> { + let mut guard: SpinLockGuard = self.0.lock(); + let target: Arc = guard.find(name)?; + // 对目标inode上锁,以防更改 + let target_guard: SpinLockGuard = target.0.lock(); + // 先从缓存删除 + guard.children.remove(&name.to_uppercase()); + + let dir = match &guard.inode_type { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(-(ENOTDIR as i32)); + } + FATDirEntry::Dir(d) => d, + FATDirEntry::UnInit => { + kerror!("FATFS: param: Inode_type uninitialized."); + return Err(-(EROFS as i32)); + } + }; + // 检查文件是否存在 + dir.check_existence(name, Some(false), guard.fs.upgrade().unwrap())?; + + // 再从磁盘删除 + let r = dir.remove(guard.fs.upgrade().unwrap().clone(), name, true); + drop(target_guard); + return r; + + } + + fn rmdir(&self, name: &str) -> Result<(), i32> { + let mut guard: SpinLockGuard = self.0.lock(); + let target: Arc = guard.find(name)?; + // 对目标inode上锁,以防更改 + let target_guard: SpinLockGuard = target.0.lock(); + // 先从缓存删除 + guard.children.remove(&name.to_uppercase()); + + let dir = match &guard.inode_type { + FATDirEntry::File(_) | FATDirEntry::VolId(_) => { + return Err(-(ENOTDIR as i32)); + } + FATDirEntry::Dir(d) => d, + FATDirEntry::UnInit => { + kerror!("FATFS: param: Inode_type uninitialized."); + return Err(-(EROFS as i32)); + } + }; + // 检查文件夹是否存在 + dir.check_existence(name, Some(true), guard.fs.upgrade().unwrap())?; + + // 再从磁盘删除 + let r: Result<(), i32> = dir.remove(guard.fs.upgrade().unwrap().clone(), name, true); + if r.is_ok() { + return r; + } else { + let r = r.unwrap_err(); + if r == -(ENOTEMPTY as i32) { + // 如果要删除的是目录,且不为空,则删除动作未发生,重新加入缓存 + guard.children.insert(name.to_uppercase(), target.clone()); + drop(target_guard); + } + return Err(r); + } + } + + fn get_entry_name(&self, ino: InodeId) -> Result { + let guard: SpinLockGuard = self.0.lock(); + if guard.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match ino { + 0 => { + return Ok(String::from(".")); + } + 1 => { + return Ok(String::from("..")); + } + ino => { + // 暴力遍历所有的children,判断inode id是否相同 + // TODO: 优化这里,这个地方性能很差! + let mut key: Vec = guard + .children + .keys() + .filter(|k| guard.children.get(*k).unwrap().metadata().unwrap().inode_id == ino) + .cloned() + .collect(); + + match key.len() { + 0=>{return Err(-(ENOENT as i32));} + 1=>{return Ok(key.remove(0));} + _ => panic!("FatFS get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = guard.metadata.inode_id, to_find=ino) + } + } + } + } +} + +impl Default for FATFsInfo { + fn default() -> Self { + return FATFsInfo { + lead_sig: FATFsInfo::LEAD_SIG, + struc_sig: FATFsInfo::STRUC_SIG, + free_count: 0xFFFFFFFF, + next_free: RESERVED_CLUSTERS, + trail_sig: FATFsInfo::TRAIL_SIG, + dirty: false, + offset: None, + }; + } +} + +impl Cluster { + pub fn new(cluster: u64) -> Self { + return Cluster { + cluster_num: cluster, + parent_cluster: 0, + }; + } +} + +/// @brief 用于迭代FAT表的内容的簇迭代器对象 +#[derive(Debug)] +struct ClusterIter<'a> { + /// 迭代器的next要返回的簇 + current_cluster: Option, + /// 属于的文件系统 + fs: &'a FATFileSystem, +} + +impl<'a> Iterator for ClusterIter<'a> { + type Item = Cluster; + + fn next(&mut self) -> Option { + // 当前要返回的簇 + let ret: Option = self.current_cluster; + + // 获得下一个要返回簇 + let new: Option = match self.current_cluster { + Some(c) => { + let entry: Option = self.fs.get_fat_entry(c).ok(); + match entry { + Some(FATEntry::Next(c)) => Some(c), + _ => None, + } + } + _ => None, + }; + + self.current_cluster = new; + return ret; + } +} diff --git a/kernel/src/filesystem/fat/mod.rs b/kernel/src/filesystem/fat/mod.rs new file mode 100644 index 00000000..8c62156f --- /dev/null +++ b/kernel/src/filesystem/fat/mod.rs @@ -0,0 +1,4 @@ +pub mod bpb; +pub mod entry; +pub mod fs; +pub mod utils; diff --git a/kernel/src/filesystem/fat/utils.rs b/kernel/src/filesystem/fat/utils.rs new file mode 100644 index 00000000..97f5a823 --- /dev/null +++ b/kernel/src/filesystem/fat/utils.rs @@ -0,0 +1,15 @@ +use core::char::REPLACEMENT_CHARACTER; + +/// FAT文件系统保留开头的2个簇 +pub const RESERVED_CLUSTERS: u32 = 2; + +/// @brief 将u8转为ascii字符。 +/// 当转码成功时,返回对应的ascii字符,否则返回Unicode占位符 +pub fn decode_u8_ascii(value: u8) -> char { + if value <= 0x7f { + return value as char; + } else { + // 如果不是ascii字符,则返回Unicode占位符 U+FFFD + return REPLACEMENT_CHARACTER; + } +} diff --git a/kernel/src/filesystem/fat32/Makefile b/kernel/src/filesystem/fat32/Makefile deleted file mode 100644 index 721720d2..00000000 --- a/kernel/src/filesystem/fat32/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - -CFLAGS += -I . - - -kernel_fs_fat32_objs:= $(shell find ./*.c) - - -ECHO: - @echo "$@" - - -$(kernel_fs_fat32_objs): ECHO - $(CC) $(CFLAGS) -c $@ -o $@.o - - -all: $(kernel_fs_fat32_objs) - diff --git a/kernel/src/filesystem/fat32/fat32.c b/kernel/src/filesystem/fat32/fat32.c deleted file mode 100644 index cd25bee0..00000000 --- a/kernel/src/filesystem/fat32/fat32.c +++ /dev/null @@ -1,1416 +0,0 @@ -#include "fat32.h" -#include "fat_ent.h" -#include "internal.h" -#include -#include -#include -#include -#include -#include -#include -#include - -struct vfs_super_block_operations_t fat32_sb_ops; -struct vfs_dir_entry_operations_t fat32_dEntry_ops; -struct vfs_file_operations_t fat32_file_ops; -struct vfs_inode_operations_t fat32_inode_ops; -extern struct blk_gendisk ahci_gendisk0; - -static unsigned int vfat_striptail_len(unsigned int len, const char *name); -static int vfat_find(struct vfs_index_node_t *dir, const char *name, struct fat32_slot_info *slot_info); -static int __fat32_search_long_short(struct vfs_index_node_t *parent_inode, const char *name, int name_len, - struct fat32_slot_info *sinfo); -static int fat32_detach_inode(struct vfs_index_node_t *inode); - -/** - * @brief 注册指定磁盘上的指定分区的fat32文件系统 - * - * @param blk_dev 块设备结构体 - * @param part_num 磁盘分区编号 - * - * @return struct vfs_super_block_t * 文件系统的超级块 - */ -struct vfs_superblock_t *fat32_register_partition(struct block_device *blk_dev, uint8_t part_num) -{ - // 挂载文件系统到vfs - return vfs_mount_fs("/", "FAT32", blk_dev); -} - -/** - * @brief 计算短目录项文件名的校验和 - * - * @param name 短目录项文件名字符串(长度为11) - * @return uint8_t 校验和 - */ -static uint8_t fat32_ChkSum(uint8_t *name) -{ - uint8_t chksum = 0; - for (uint8_t i = 0; i < 11; ++i) - { - chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + *name; - ++name; - } - return chksum; -} - -static int __fat32_search_long_short(struct vfs_index_node_t *parent_inode, const char *name, int name_len, - struct fat32_slot_info *sinfo) -{ - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)parent_inode->private_inode_info; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; - struct block_device *blk = parent_inode->sb->blk_device; - - uint8_t *buf = kzalloc(fsbi->bytes_per_clus, 0); - - // 计算父目录项的起始簇号 - uint32_t cluster = finode->first_clus; - - struct fat32_Directory_t *tmp_dEntry = NULL; - int cnt_long_dir = 0; // 最终结果中,长目录项的数量 - - while (true) - { - - // 计算父目录项的起始LBA扇区号 - uint64_t sector = __fat32_calculate_LBA(fsbi->first_data_sector, fsbi->sec_per_clus, cluster); - // kdebug("fat32_part_info[part_id].bootsector.BPB_SecPerClus=%d",fat32_part_info[part_id].bootsector.BPB_SecPerClus); - // kdebug("sector=%d",sector); - - // 读取父目录项的起始簇数据 - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf); - - tmp_dEntry = (struct fat32_Directory_t *)buf; - - // 查找每个文件的短目录项 - for (int i = 0; i < fsbi->bytes_per_clus; i += 32, ++tmp_dEntry) - { - // 跳过长目录项 - if (tmp_dEntry->DIR_Attr == ATTR_LONG_NAME) - continue; - - // 跳过无效目录项、空闲目录项 - if (tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00 || tmp_dEntry->DIR_Name[0] == 0x05) - continue; - // kdebug("short name [%d] %s\n 33333==[%#02x]", i / 32, tmp_dEntry->DIR_Name, tmp_dEntry->DIR_Name[3]); - // 找到长目录项,位于短目录项之前 - struct fat32_LongDirectory_t *tmp_ldEntry = (struct fat32_LongDirectory_t *)tmp_dEntry - 1; - cnt_long_dir = 0; - int js = 0; - // 遍历每个长目录项 - while (tmp_ldEntry->LDIR_Attr == ATTR_LONG_NAME && tmp_ldEntry->LDIR_Ord != 0xe5) - { - // 比较name1 - for (int x = 0; x < 5; ++x) - { - if (js >= name_len && (tmp_ldEntry->LDIR_Name1[x] == 0xffff)) - continue; - else if (js > name_len || - tmp_ldEntry->LDIR_Name1[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 - goto continue_cmp_fail; - } - - // 比较name2 - for (int x = 0; x < 6; ++x) - { - if (js >= name_len && (tmp_ldEntry->LDIR_Name2[x] == 0xffff)) - continue; - else if (js > name_len || - tmp_ldEntry->LDIR_Name2[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 - goto continue_cmp_fail; - } - - // 比较name3 - for (int x = 0; x < 2; ++x) - { - if (js >= name_len && (tmp_ldEntry->LDIR_Name3[x] == 0xffff)) - continue; - else if (js > name_len || - tmp_ldEntry->LDIR_Name3[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 - goto continue_cmp_fail; - } - - if (js >= name_len) // 找到需要的目录项,返回 - { - // kdebug("found target long name."); - cnt_long_dir = tmp_dEntry - (struct fat32_Directory_t *)tmp_ldEntry; - goto success; - } - - --tmp_ldEntry; // 检索下一个长目录项 - } - - // 不存在长目录项,匹配短目录项的基础名 - js = 0; - for (int x = 0; x < 8; ++x) - { - // kdebug("no long name, comparing short name"); - // kdebug("value = %#02x", tmp_dEntry->DIR_Name[x]); - switch (tmp_dEntry->DIR_Name[x]) - { - case ' ': - if (!(tmp_dEntry->DIR_Attr & ATTR_DIRECTORY)) // 不是文件夹(是文件) - { - if (name[js] == '.') - continue; - else if (tmp_dEntry->DIR_Name[x] == name[js]) - { - ++js; - break; - } - else - goto continue_cmp_fail; - } - else // 是文件夹 - { - if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) // 当前位正确匹配 - { - ++js; - break; // 进行下一位的匹配 - } - else if (js == name_len) - continue; - else - goto continue_cmp_fail; - } - break; - - // 当前位是字母 - case 'A' ... 'Z': - case 'a' ... 'z': - if (tmp_dEntry->DIR_NTRes & LOWERCASE_BASE) // 为兼容windows系统,检测DIR_NTRes字段 - { - if (js < name_len && (tmp_dEntry->DIR_Name[x] + 32 == name[js])) - { - ++js; - break; - } - else - goto continue_cmp_fail; - } - else - { - if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) - { - ++js; - break; - } - else - goto continue_cmp_fail; - } - break; - case '0' ... '9': - if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) - { - ++js; - break; - } - else - goto continue_cmp_fail; - - break; - default: - // ++js; - goto continue_cmp_fail; - break; - } - } - if (js > name_len) - { - // kdebug("js > namelen"); - goto continue_cmp_fail; - } - // 若短目录项为文件,则匹配扩展名 - if (!(tmp_dEntry->DIR_Attr & ATTR_DIRECTORY)) - { - ++js; - for (int x = 8; x < 11; ++x) - { - switch (tmp_dEntry->DIR_Name[x]) - { - // 当前位是字母 - case 'A' ... 'Z': - case 'a' ... 'z': - if (tmp_dEntry->DIR_NTRes & LOWERCASE_EXT) // 为兼容windows系统,检测DIR_NTRes字段 - { - if ((tmp_dEntry->DIR_Name[x] + 32 == name[js])) - { - ++js; - break; - } - else - goto continue_cmp_fail; - } - else - { - if (tmp_dEntry->DIR_Name[x] == name[js]) - { - ++js; - break; - } - else - goto continue_cmp_fail; - } - break; - case '0' ... '9': - case ' ': - if (tmp_dEntry->DIR_Name[x] == name[js]) - { - ++js; - break; - } - else - goto continue_cmp_fail; - - break; - - default: - goto continue_cmp_fail; - break; - } - } - } - if (js > name_len) - { - // kdebug("js > namelen"); - goto continue_cmp_fail; - } - cnt_long_dir = 0; - goto success; - continue_cmp_fail:; - } - - // 当前簇没有发现目标文件名,寻找下一个簇 - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - - if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到目标文件名 - { - kfree(buf); - return -ENOENT; - } - } - if (unlikely(tmp_dEntry == NULL)) - { - BUG_ON(1); - kfree(buf); - return -ENOENT; - } -success:; - - // 填充sinfo - sinfo->buffer = buf; - sinfo->de = tmp_dEntry; - sinfo->i_pos = __fat32_calculate_LBA(fsbi->first_data_sector, fsbi->sec_per_clus, cluster); - sinfo->num_slots = cnt_long_dir + 1; - sinfo->slot_off = tmp_dEntry - (struct fat32_Directory_t *)buf; - // kdebug("successfully found:%s", name); - return 0; -} - -/** - * @brief 在父目录中寻找指定的目录项 - * - * @param parent_inode 父目录项的inode - * @param dest_dentry 搜索目标目录项 - * @return struct vfs_dir_entry_t* 目标目录项 - */ -struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dentry) -{ - int errcode = 0; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; - struct fat32_inode_info_t *finode = NULL; - - struct fat32_slot_info sinfo = {0}; - errcode = vfat_find(parent_inode, dest_dentry->name, &sinfo); - - if (unlikely(errcode != 0)) - return NULL; - -find_lookup_success:; // 找到目标dentry - struct vfs_index_node_t *p = vfs_alloc_inode(); - - p->file_size = sinfo.de->DIR_FileSize; - // 计算文件占用的扇区数, 由于最小存储单位是簇,因此需要按照簇的大小来对齐扇区 - p->blocks = (p->file_size + fsbi->bytes_per_clus - 1) / fsbi->bytes_per_sec; - p->attribute = (sinfo.de->DIR_Attr & ATTR_DIRECTORY) ? VFS_IF_DIR : VFS_IF_FILE; - p->sb = parent_inode->sb; - p->file_ops = &fat32_file_ops; - p->inode_ops = &fat32_inode_ops; - - // 为inode的与文件系统相关的信息结构体分配空间 - p->private_inode_info = (void *)kzalloc(sizeof(fat32_inode_info_t), 0); - finode = (fat32_inode_info_t *)p->private_inode_info; - - finode->first_clus = ((sinfo.de->DIR_FstClusHI << 16) | sinfo.de->DIR_FstClusLO) & 0x0fffffff; - finode->dEntry_location_clus = __fat32_LBA_to_cluster(fsbi->first_data_sector, fsbi->sec_per_clus, sinfo.i_pos); - finode->dEntry_location_clus_offset = sinfo.slot_off; // 计算dentry的偏移量 - // kdebug("finode->dEntry_location_clus=%#018lx", finode->dEntry_location_clus); - // kdebug("finode->dEntry_location_clus_offset=%#018lx", finode->dEntry_location_clus_offset); - finode->create_date = sinfo.de->DIR_CrtDate; - finode->create_time = sinfo.de->DIR_CrtTime; - finode->write_date = sinfo.de->DIR_WrtDate; - finode->write_time = sinfo.de->DIR_WrtTime; - - // 暂时使用fat32的高4bit来标志设备文件 - // todo: 引入devfs后删除这段代码 - if ((sinfo.de->DIR_FstClusHI >> 12) && (p->attribute & VFS_IF_FILE)) - p->attribute |= VFS_IF_DEVICE; - - dest_dentry->dir_inode = p; - dest_dentry->dir_ops = &fat32_dEntry_ops; - list_init(&dest_dentry->child_node_list); - list_init(&dest_dentry->subdirs_list); - - kfree(sinfo.buffer); - return dest_dentry; -} - -/** - * @brief 创建fat32文件系统的超级块 - * - * @param blk 块设备结构体 - * @return struct vfs_superblock_t* 创建好的超级块 - */ -struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk) -{ - // BUG - // 读取文件系统的boot扇区 - uint8_t buf[512] = {0}; - - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, blk->bd_start_LBA, 1, (uint64_t)&buf); - // 分配超级块的空间 - struct vfs_superblock_t *sb_ptr = (struct vfs_superblock_t *)kzalloc(sizeof(struct vfs_superblock_t), 0); - blk->bd_superblock = sb_ptr; - sb_ptr->sb_ops = &fat32_sb_ops; - sb_ptr->dir_ops = &fat32_dEntry_ops; - sb_ptr->private_sb_info = kzalloc(sizeof(fat32_sb_info_t), 0); - sb_ptr->blk_device = blk; - - struct fat32_BootSector_t *fbs = (struct fat32_BootSector_t *)buf; - - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)(sb_ptr->private_sb_info); - - fsbi->starting_sector = blk->bd_start_LBA; - fsbi->sector_count = blk->bd_sectors_num; - fsbi->sec_per_clus = fbs->BPB_SecPerClus; - fsbi->bytes_per_clus = fbs->BPB_SecPerClus * fbs->BPB_BytesPerSec; - fsbi->bytes_per_sec = fbs->BPB_BytesPerSec; - fsbi->first_data_sector = blk->bd_start_LBA + fbs->BPB_RsvdSecCnt + fbs->BPB_FATSz32 * fbs->BPB_NumFATs; - fsbi->FAT1_base_sector = blk->bd_start_LBA + fbs->BPB_RsvdSecCnt; - fsbi->FAT2_base_sector = fsbi->FAT1_base_sector + fbs->BPB_FATSz32; - fsbi->sec_per_FAT = fbs->BPB_FATSz32; - fsbi->NumFATs = fbs->BPB_NumFATs; - fsbi->fsinfo_sector_addr_infat = fbs->BPB_FSInfo; - fsbi->bootsector_bak_sector_addr_infat = fbs->BPB_BkBootSec; - - printk_color(ORANGE, BLACK, - "FAT32 Boot Sector\n\tBPB_FSInfo:%#018lx\n\tBPB_BkBootSec:%#018lx\n\tBPB_TotSec32:%#018lx\n", - fbs->BPB_FSInfo, fbs->BPB_BkBootSec, fbs->BPB_TotSec32); - - // fsinfo扇区的信息 - memset(&fsbi->fsinfo, 0, sizeof(struct fat32_FSInfo_t)); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, - blk->bd_start_LBA + fsbi->fsinfo_sector_addr_infat, 1, (uint64_t)&fsbi->fsinfo); - - printk_color(BLUE, BLACK, "FAT32 FSInfo\n\tFSI_LeadSig:%#018lx\n\tFSI_StrucSig:%#018lx\n\tFSI_Free_Count:%#018lx\n", - fsbi->fsinfo.FSI_LeadSig, fsbi->fsinfo.FSI_StrucSig, fsbi->fsinfo.FSI_Free_Count); - - // 初始化超级块的dir entry - sb_ptr->root = vfs_alloc_dentry(2); - - sb_ptr->root->parent = sb_ptr->root; - sb_ptr->root->dir_ops = &fat32_dEntry_ops; - // 分配2个字节的name - sb_ptr->root->name[0] = '/'; - sb_ptr->root->name_length = 1; - - // 为root目录项分配index node - sb_ptr->root->dir_inode = vfs_alloc_inode(); - sb_ptr->root->dir_inode->inode_ops = &fat32_inode_ops; - sb_ptr->root->dir_inode->file_ops = &fat32_file_ops; - sb_ptr->root->dir_inode->file_size = 0; - // 计算文件占用的扇区数, 由于最小存储单位是簇,因此需要按照簇的大小来对齐扇区 - sb_ptr->root->dir_inode->blocks = - (sb_ptr->root->dir_inode->file_size + fsbi->bytes_per_clus - 1) / fsbi->bytes_per_sec; - sb_ptr->root->dir_inode->attribute = VFS_IF_DIR; - sb_ptr->root->dir_inode->sb = sb_ptr; // 反向绑定对应的超级块 - - // 初始化inode信息 - sb_ptr->root->dir_inode->private_inode_info = kmalloc(sizeof(struct fat32_inode_info_t), 0); - memset(sb_ptr->root->dir_inode->private_inode_info, 0, sizeof(struct fat32_inode_info_t)); - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)sb_ptr->root->dir_inode->private_inode_info; - - finode->first_clus = fbs->BPB_RootClus; - finode->dEntry_location_clus = 0; - finode->dEntry_location_clus_offset = 0; - finode->create_time = 0; - finode->create_date = 0; - finode->write_date = 0; - finode->write_time; - return sb_ptr; -} - -/** - * @brief todo: 写入superblock - * - * @param sb - */ -void fat32_write_superblock(struct vfs_superblock_t *sb) -{ -} - -/** - * @brief 释放superblock的内存空间 - * - * @param sb 要被释放的superblock - */ -void fat32_put_superblock(struct vfs_superblock_t *sb) -{ - kfree(sb->private_sb_info); - kfree(sb->root->dir_inode->private_inode_info); - kfree(sb->root->dir_inode); - kfree(sb->root); - kfree(sb); -} - -/** - * @brief 写入inode到硬盘上 - * - * @param inode - */ -void fat32_write_inode(struct vfs_index_node_t *inode) -{ - fat32_inode_info_t *finode = inode->private_inode_info; - - if (finode->dEntry_location_clus == 0) - { - kerror("FAT32 error: Attempt to write the root inode"); - return; - } - - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)inode->sb->private_sb_info; - - // 计算目标inode对应数据区的LBA地址 - uint64_t fLBA = fsbi->first_data_sector + (finode->dEntry_location_clus - 2) * fsbi->sec_per_clus; - - struct fat32_Directory_t *buf = (struct fat32_Directory_t *)kmalloc(fsbi->bytes_per_clus, 0); - memset(buf, 0, fsbi->bytes_per_clus); - - inode->sb->blk_device->bd_disk->fops->transfer(inode->sb->blk_device->bd_disk, AHCI_CMD_READ_DMA_EXT, fLBA, - fsbi->sec_per_clus, (uint64_t)buf); - // 计算目标dEntry所在的位置 - struct fat32_Directory_t *fdEntry = buf + finode->dEntry_location_clus_offset; - - // 写入fat32文件系统的dir_entry - fdEntry->DIR_FileSize = inode->file_size; - fdEntry->DIR_FstClusLO = finode->first_clus & 0xffff; - fdEntry->DIR_FstClusHI = (finode->first_clus >> 16) | (fdEntry->DIR_FstClusHI & 0xf000); - - // 将dir entry写回磁盘 - inode->sb->blk_device->bd_disk->fops->transfer(inode->sb->blk_device->bd_disk, AHCI_CMD_WRITE_DMA_EXT, fLBA, - fsbi->sec_per_clus, (uint64_t)buf); - kfree(buf); -} - -struct vfs_super_block_operations_t fat32_sb_ops = { - .write_superblock = fat32_write_superblock, - .put_superblock = fat32_put_superblock, - .write_inode = fat32_write_inode, -}; - -// todo: compare -long fat32_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) -{ - return 0; -} -// todo: hash -long fat32_hash(struct vfs_dir_entry_t *dEntry, char *filename) -{ - return 0; -} -// todo: release -long fat32_release(struct vfs_dir_entry_t *dEntry) -{ - return 0; -} -// todo: iput -long fat32_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) -{ - return 0; -} - -/** - * @brief fat32文件系统对于dEntry的操作 - * - */ -struct vfs_dir_entry_operations_t fat32_dEntry_ops = { - .compare = fat32_compare, - .hash = fat32_hash, - .release = fat32_release, - .iput = fat32_iput, -}; - -// todo: open -long fat32_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - return 0; -} - -// todo: close -long fat32_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - return 0; -} - -/** - * @brief 从fat32文件系统读取数据 - * - * @param file_ptr 文件描述符 - * @param buf 输出缓冲区 - * @param count 要读取的字节数 - * @param position 文件指针位置 - * @return long 执行成功:传输的字节数量 执行失败:错误码(小于0) - */ -long fat32_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) -{ - - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)(file_ptr->dEntry->dir_inode->private_inode_info); - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)(file_ptr->dEntry->dir_inode->sb->private_sb_info); - struct block_device *blk = file_ptr->dEntry->dir_inode->sb->blk_device; - - // First cluster num of the file - uint64_t cluster = finode->first_clus; - // kdebug("fsbi->bytes_per_clus=%d fsbi->sec_per_clus=%d finode->first_clus=%d cluster=%d", fsbi->bytes_per_clus, - // fsbi->sec_per_clus, finode->first_clus, cluster); - - // kdebug("fsbi->bytes_per_clus=%d", fsbi->bytes_per_clus); - - // clus offset in file - uint64_t clus_offset_in_file = (*position) / fsbi->bytes_per_clus; - // bytes offset in clus - uint64_t bytes_offset = (*position) % fsbi->bytes_per_clus; - - if (!cluster) - return -EFAULT; - - // find the actual cluster on disk of the specified position - for (int i = 0; i < clus_offset_in_file; ++i) - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - - // 如果需要读取的数据边界大于文件大小 - if (*position + count > file_ptr->dEntry->dir_inode->file_size) - count = file_ptr->dEntry->dir_inode->file_size - *position; - - // 剩余还需要传输的字节数量 - int64_t bytes_remain = count; - - // alloc buffer memory space for ahci transfer - void *tmp_buffer = kmalloc(fsbi->bytes_per_clus, 0); - - int64_t retval = 0; - do - { - - memset(tmp_buffer, 0, fsbi->bytes_per_clus); - uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; - - // 读取一个簇的数据 - int errno = blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, - (uint64_t)tmp_buffer); - if (errno != AHCI_SUCCESS) - { - kerror("FAT32 FS(read) error!"); - retval = -EIO; - break; - } - - int64_t step_trans_len = 0; // 当前循环传输的字节数 - if (bytes_remain > (fsbi->bytes_per_clus - bytes_offset)) - step_trans_len = (fsbi->bytes_per_clus - bytes_offset); - else - step_trans_len = bytes_remain; - - if (((uint64_t)buf) < USER_MAX_LINEAR_ADDR) - copy_to_user(buf, tmp_buffer + bytes_offset, step_trans_len); - else - memcpy(buf, tmp_buffer + bytes_offset, step_trans_len); - - bytes_remain -= step_trans_len; - buf += step_trans_len; - bytes_offset -= bytes_offset; - - *position += step_trans_len; // 更新文件指针 - - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - } while (bytes_remain && (cluster < 0x0ffffff8) && cluster != 0); - - kfree(tmp_buffer); - - if (!bytes_remain) - retval = count; - - return retval; -} - -/** - * @brief 向fat32文件系统写入数据 - * - * @param file_ptr 文件描述符 - * @param buf 输入写入的字节数 - * @param position 文件指针位置 - * @return long 执行成功:传输的字节数量 执行失败:错误码(小于0) - */ -long fat32_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) -{ - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)file_ptr->dEntry->dir_inode->private_inode_info; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)(file_ptr->dEntry->dir_inode->sb->private_sb_info); - struct block_device *blk = file_ptr->dEntry->dir_inode->sb->blk_device; - - // First cluster num of the file - uint32_t cluster = finode->first_clus; - int64_t flags = 0; - - // clus offset in file - uint64_t clus_offset_in_file = (*position) / fsbi->bytes_per_clus; - // bytes offset in clus - uint64_t bytes_offset = (*position) % fsbi->bytes_per_clus; - - if (!cluster) // 起始簇号为0,说明是空文件 - { - // 分配空闲簇 - if (fat32_alloc_clusters(file_ptr->dEntry->dir_inode, &cluster, 1) != 0) - return -ENOSPC; - } - else - { - // 跳转到position所在的簇 - for (uint64_t i = 0; i < clus_offset_in_file; ++i) - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - } - // kdebug("cluster(start)=%d", cluster); - // 没有可用的磁盘空间 - if (!cluster) - return -ENOSPC; - - int64_t bytes_remain = count; - - if (count < 0) // 要写入的字节数小于0 - return -EINVAL; - - uint64_t sector; - int64_t retval = 0; - - void *tmp_buffer = kmalloc(fsbi->bytes_per_clus, 0); - do - { - memset(tmp_buffer, 0, fsbi->bytes_per_clus); - sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; // 计算对应的扇区 - if (!flags) // 当前簇已分配 - { - // kdebug("read existed sec=%ld", sector); - // 读取一个簇的数据 - int errno = blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, - (uint64_t)tmp_buffer); - if (errno != 0) - { - // kerror("FAT32 FS(write) read disk error!"); - retval = -EIO; - break; - } - } - - int64_t step_trans_len = 0; // 当前循环传输的字节数 - if (bytes_remain > (fsbi->bytes_per_clus - bytes_offset)) - step_trans_len = (fsbi->bytes_per_clus - bytes_offset); - else - step_trans_len = bytes_remain; - - // kdebug("step_trans_len=%d, bytes_offset=%d", step_trans_len, bytes_offset); - if (((uint64_t)buf) < USER_MAX_LINEAR_ADDR) - copy_from_user(tmp_buffer + bytes_offset, buf, step_trans_len); - else - memcpy(tmp_buffer + bytes_offset, buf, step_trans_len); - - // 写入数据到对应的簇 - int errno = blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sector, fsbi->sec_per_clus, - (uint64_t)tmp_buffer); - if (errno != AHCI_SUCCESS) - { - kerror("FAT32 FS(write) write disk error!"); - retval = -EIO; - break; - } - - bytes_remain -= step_trans_len; - buf += step_trans_len; - bytes_offset -= bytes_offset; - - *position += step_trans_len; // 更新文件指针 - // kdebug("step_trans_len=%d", step_trans_len); - - int next_clus = 0; - if (bytes_remain) - next_clus = fat32_read_FAT_entry(blk, fsbi, cluster); - else - break; - if (next_clus >= 0x0ffffff8) // 已经到达了最后一个簇,需要分配新簇 - { - if (fat32_alloc_clusters(file_ptr->dEntry->dir_inode, &next_clus, 1) != 0) - { - // 没有空闲簇 - kfree(tmp_buffer); - return -ENOSPC; - } - - cluster = next_clus; // 切换当前簇 - flags = 1; // 标记当前簇是新分配的簇 - } - - } while (bytes_remain); - - // 文件大小有增长 - if (*position > (file_ptr->dEntry->dir_inode->file_size)) - { - file_ptr->dEntry->dir_inode->file_size = *position; - file_ptr->dEntry->dir_inode->sb->sb_ops->write_inode(file_ptr->dEntry->dir_inode); - // kdebug("new file size=%ld", *position); - } - - kfree(tmp_buffer); - if (!bytes_remain) - retval = count; - // kdebug("retval=%lld", retval); - return retval; -} - -/** - * @brief 调整文件的当前访问位置 - * - * @param file_ptr vfs文件指针 - * @param offset 调整的偏移量 - * @param whence 调整方法 - * @return long 更新后的指针位置 - */ -long fat32_lseek(struct vfs_file_t *file_ptr, long offset, long whence) -{ - struct vfs_index_node_t *inode = file_ptr->dEntry->dir_inode; - - long pos = 0; - switch (whence) - { - case SEEK_SET: // 相对于文件头 - pos = offset; - break; - case SEEK_CUR: // 相对于当前位置 - pos = file_ptr->position + offset; - break; - case SEEK_END: // 相对于文件末尾 - pos = file_ptr->dEntry->dir_inode->file_size + offset; - break; - - default: - return -EINVAL; - break; - } - - if (pos < 0 || pos > file_ptr->dEntry->dir_inode->file_size) - return -EOVERFLOW; - file_ptr->position = pos; - - // kdebug("fat32 lseek -> position=%d", file_ptr->position); - return pos; -} -// todo: ioctl -long fat32_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) -{ - return 0; -} - -/** - * @brief fat32文件系统,关于文件的操作 - * - */ -struct vfs_file_operations_t fat32_file_ops = { - .open = fat32_open, - .close = fat32_close, - .read = fat32_read, - .write = fat32_write, - .lseek = fat32_lseek, - .ioctl = fat32_ioctl, - .readdir = fat32_readdir, -}; - -/** - * @brief 创建新的文件 - * @param parent_inode 父目录的inode结构体 - * @param dest_dEntry 新文件的dentry - * @param mode 创建模式 - */ -long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode) -{ - // 文件系统超级块信息 - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; - // 父目录项的inode的私有信息 - struct fat32_inode_info_t *parent_inode_info = (struct fat32_inode_info_t *)parent_inode->private_inode_info; - - int64_t retval = 0; - - // ======== 检验名称的合法性 - retval = fat32_check_name_available(dest_dEntry->name, dest_dEntry->name_length, 0); - - if (retval != 0) - return retval; - - if (dest_dEntry->dir_inode != NULL) - return -EEXIST; - - struct vfs_index_node_t *inode = vfs_alloc_inode(); - dest_dEntry->dir_inode = inode; - dest_dEntry->dir_ops = &fat32_dEntry_ops; - - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)kzalloc(sizeof(struct fat32_inode_info_t), 0); - inode->attribute = VFS_IF_FILE; - inode->file_ops = &fat32_file_ops; - inode->file_size = 0; - inode->sb = parent_inode->sb; - inode->inode_ops = &fat32_inode_ops; - inode->private_inode_info = (void *)finode; - inode->blocks = fsbi->sec_per_clus; - - struct block_device *blk = inode->sb->blk_device; - - // 计算总共需要多少个目录项 - uint32_t cnt_longname = (dest_dEntry->name_length + 25) / 26; - // 默认都是创建长目录项来存储 - if (cnt_longname == 0) - cnt_longname = 1; - - // 空闲dentry所在的扇区号 - uint32_t tmp_dentry_sector = 0; - // 空闲dentry所在的缓冲区的基地址 - uint64_t tmp_dentry_clus_buf_addr = 0; - uint64_t tmp_parent_dentry_clus = 0; - // 寻找空闲目录项 - struct fat32_Directory_t *empty_fat32_dentry = fat32_find_empty_dentry( - parent_inode, cnt_longname + 1, 0, &tmp_dentry_sector, &tmp_parent_dentry_clus, &tmp_dentry_clus_buf_addr); - // kdebug("found empty dentry, cnt_longname=%ld", cnt_longname); - - finode->first_clus = 0; - finode->dEntry_location_clus = tmp_parent_dentry_clus; - finode->dEntry_location_clus_offset = empty_fat32_dentry - (struct fat32_Directory_t *)tmp_dentry_clus_buf_addr; - - // ====== 为新的文件分配一个簇 ======= - uint32_t new_dir_clus; - if (fat32_alloc_clusters(inode, &new_dir_clus, 1) != 0) - { - retval = -ENOSPC; - goto fail; - } - // kdebug("new dir clus=%ld", new_dir_clus); - // kdebug("dest_dEntry->name=%s", dest_dEntry->name); - - // ====== 填写短目录项 - fat32_fill_shortname(dest_dEntry, empty_fat32_dentry, new_dir_clus); - // kdebug("dest_dEntry->name=%s",dest_dEntry->name); - - // 计算校验和 - uint8_t short_dentry_ChkSum = fat32_ChkSum(empty_fat32_dentry->DIR_Name); - - // kdebug("dest_dEntry->name=%s", dest_dEntry->name); - // ======== 填写长目录项 - fat32_fill_longname(dest_dEntry, (struct fat32_LongDirectory_t *)(empty_fat32_dentry - 1), short_dentry_ChkSum, - cnt_longname); - - // ====== 将目录项写回磁盘 - // kdebug("tmp_dentry_sector=%ld", tmp_dentry_sector); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, tmp_dentry_sector, fsbi->sec_per_clus, - tmp_dentry_clus_buf_addr); - - // 注意:parent字段需要在调用函数的地方进行设置 - - // 释放在find empty dentry中动态申请的缓冲区 - kfree((void *)tmp_dentry_clus_buf_addr); - return 0; -fail:; - // 释放在find empty dentry中动态申请的缓冲区 - kfree((void *)tmp_dentry_clus_buf_addr); - dest_dEntry->dir_inode = NULL; - dest_dEntry->dir_ops = NULL; - kfree(finode); - kfree(inode); - return retval; -} - -/** - * @brief 创建文件夹 - * @param inode 父目录的inode - * @param dEntry 新的文件夹的dentry - * @param mode 创建文件夹的mode - * @return long 错误码 - */ -int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dEntry, int mode) -{ - int64_t retval = 0; - - // 文件系统超级块信息 - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; - // 父目录项的inode私有信息 - struct fat32_inode_info_t *parent_inode_info = (struct fat32_inode_info_t *)parent_inode->private_inode_info; - // ======== 检验名称的合法性 - retval = fat32_check_name_available(dEntry->name, dEntry->name_length, 0); - if (retval != 0) - return retval; - // ====== 找一块连续的区域放置新的目录项 ===== - - // 计算总共需要多少个目录项 - uint32_t cnt_longname = (dEntry->name_length + 25) / 26; - // 默认都是创建长目录项来存储 - if (cnt_longname == 0) - cnt_longname = 1; - - // 空闲dentry所在的扇区号 - uint32_t tmp_dentry_sector = 0; - // 空闲dentry所在的缓冲区的基地址 - uint64_t tmp_dentry_clus_buf_addr = 0; - uint64_t tmp_parent_dentry_clus = 0; - // 寻找空闲目录项 - struct fat32_Directory_t *empty_fat32_dentry = fat32_find_empty_dentry( - parent_inode, cnt_longname + 1, 0, &tmp_dentry_sector, &tmp_parent_dentry_clus, &tmp_dentry_clus_buf_addr); - - // ====== 初始化inode ======= - struct vfs_index_node_t *inode = vfs_alloc_inode(); - inode->attribute = VFS_IF_DIR; - inode->blocks = fsbi->sec_per_clus; - inode->file_ops = &fat32_file_ops; - inode->file_size = 0; - inode->inode_ops = &fat32_inode_ops; - inode->sb = parent_inode->sb; - - struct block_device *blk = inode->sb->blk_device; - - // ===== 初始化inode的文件系统私有信息 ==== - - inode->private_inode_info = (fat32_inode_info_t *)kmalloc(sizeof(fat32_inode_info_t), 0); - memset(inode->private_inode_info, 0, sizeof(fat32_inode_info_t)); - fat32_inode_info_t *p = (fat32_inode_info_t *)inode->private_inode_info; - p->first_clus = 0; - p->dEntry_location_clus = tmp_parent_dentry_clus; - p->dEntry_location_clus_offset = empty_fat32_dentry - (struct fat32_Directory_t *)tmp_dentry_clus_buf_addr; - // kdebug(" p->dEntry_location_clus_offset=%d", p->dEntry_location_clus_offset); - // todo: 填写完全fat32_inode_info的信息 - - // 初始化dentry信息 - dEntry->dir_ops = &fat32_dEntry_ops; - dEntry->dir_inode = inode; - - // ====== 为新的文件夹分配一个簇 ======= - uint32_t new_dir_clus; - if (fat32_alloc_clusters(inode, &new_dir_clus, 1) != 0) - { - retval = -ENOSPC; - goto fail; - } - - // kdebug("new dir clus=%ld", new_dir_clus); - - // ====== 填写短目录项 - fat32_fill_shortname(dEntry, empty_fat32_dentry, new_dir_clus); - - // 计算校验和 - uint8_t short_dentry_ChkSum = fat32_ChkSum(empty_fat32_dentry->DIR_Name); - - // ======== 填写长目录项 - fat32_fill_longname(dEntry, (struct fat32_LongDirectory_t *)(empty_fat32_dentry - 1), short_dentry_ChkSum, - cnt_longname); - - // ====== 将目录项写回磁盘 - // kdebug("tmp_dentry_sector=%ld", tmp_dentry_sector); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, tmp_dentry_sector, fsbi->sec_per_clus, - tmp_dentry_clus_buf_addr); - // ====== 初始化新的文件夹的目录项 ===== - { - // kdebug("to create dot and dot dot."); - void *buf = kmalloc(fsbi->bytes_per_clus, 0); - struct fat32_Directory_t *new_dir_dentries = (struct fat32_Directory_t *)buf; - memset((void *)new_dir_dentries, 0, fsbi->bytes_per_clus); - - // 新增 . 目录项 - new_dir_dentries->DIR_Attr = ATTR_DIRECTORY; - new_dir_dentries->DIR_FileSize = 0; - new_dir_dentries->DIR_Name[0] = '.'; - for (int i = 1; i < 11; ++i) - new_dir_dentries->DIR_Name[i] = 0x20; - - new_dir_dentries->DIR_FstClusHI = empty_fat32_dentry->DIR_FstClusHI; - new_dir_dentries->DIR_FstClusLO = empty_fat32_dentry->DIR_FstClusLO; - - // 新增 .. 目录项 - ++new_dir_dentries; - new_dir_dentries->DIR_Attr = ATTR_DIRECTORY; - new_dir_dentries->DIR_FileSize = 0; - new_dir_dentries->DIR_Name[0] = '.'; - new_dir_dentries->DIR_Name[1] = '.'; - for (int i = 2; i < 11; ++i) - new_dir_dentries->DIR_Name[i] = 0x20; - new_dir_dentries->DIR_FstClusHI = (unsigned short)(parent_inode_info->first_clus >> 16) & 0x0fff; - new_dir_dentries->DIR_FstClusLO = (unsigned short)(parent_inode_info->first_clus) & 0xffff; - - // 写入磁盘 - - uint64_t sector = fsbi->first_data_sector + (new_dir_clus - 2) * fsbi->sec_per_clus; - // kdebug("add dot and dot dot: sector=%ld", sector); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf); - } - - // 注意:parent字段需要在调用函数的地方进行设置 - // 注意:需要将当前dentry加入父目录的subdirs_list - - // 释放在find empty dentry中动态申请的缓冲区 - kfree((void *)tmp_dentry_clus_buf_addr); - - return 0; -fail:; - // 释放在find empty dentry中动态申请的缓冲区 - kfree((void *)tmp_dentry_clus_buf_addr); - return retval; -} - -// todo: rmdir -int64_t fat32_rmdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry) -{ - return 0; -} - -// todo: rename -int64_t fat32_rename(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, - struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry) -{ - return 0; -} - -// todo: getAttr -int64_t fat32_getAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) -{ - return 0; -} - -// todo: setAttr -int64_t fat32_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) -{ - return 0; -} - -/** - * @brief 从fat32中卸载inode - * - * @param inode 要被卸载的inode - * @return int 错误码 - */ -static int fat32_detach_inode(struct vfs_index_node_t *inode) -{ - // todo: 当引入哈希表管理inode之后,这个函数负责将inode从哈希表中删除 - // 参考Linux的fat_detach - return 0; -} - -/** - * @brief 取消inode和dentry之间的链接关系(删除文件) - * - * @param inode 要被取消关联关系的目录项的【父目录项】 - * @param dentry 要被取消关联关系的子目录项 - */ -int64_t fat32_unlink(struct vfs_index_node_t *dir, struct vfs_dir_entry_t *dentry) -{ - int retval = 0; - struct vfs_superblock_t *sb = dir->sb; - struct vfs_index_node_t *inode_to_remove = dentry->dir_inode; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)sb->private_sb_info; - struct fat32_slot_info sinfo = {0}; - // todo: 对fat32的超级块加锁 - - retval = vfat_find(dir, dentry->name, &sinfo); - - if (unlikely(retval != 0)) - goto out; - - // 从fat表删除目录项 - retval = fat32_remove_entries(dir, &sinfo); - if (unlikely(retval != 0)) - goto out; - retval = fat32_detach_inode(dentry->dir_inode); - if (unlikely(retval != 0)) - goto out; -out:; - if (sinfo.buffer != NULL) - kfree(sinfo.buffer); - // todo: 对fat32的超级块放锁 - return retval; -} - -/** - * @brief 读取文件夹(在指定目录中找出有效目录项) - * - * @param file_ptr 文件结构体指针 - * @param dirent 返回的dirent - * @param filler 填充dirent的函数 - * @return uint64_t dirent的总大小 - */ -int64_t fat32_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler) -{ - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)file_ptr->dEntry->dir_inode->private_inode_info; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)file_ptr->dEntry->dir_inode->sb->private_sb_info; - struct block_device *blk = file_ptr->dEntry->dir_inode->sb->blk_device; - - unsigned char *buf = (unsigned char *)kzalloc(fsbi->bytes_per_clus, 0); - uint32_t cluster = finode->first_clus; - - // 当前文件指针所在位置的簇号(文件内偏移量) - int clus_num = file_ptr->position / fsbi->bytes_per_clus; - - // 循环读取fat entry,直到读取到文件当前位置的所在簇号 - for (int i = 0; i < clus_num; ++i) - { - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - if (cluster > 0x0ffffff7) // 文件结尾 - { - kerror("file position out of range! (cluster not exists)"); - return NULL; - } - } - - uint64_t dentry_type = 0; // 传递给filler的dentry类型数据 - - char *dir_name = NULL; - int name_len = 0; - // ==== 此时已经将文件夹的目录项起始簇的簇号读取到cluster变量中 === - while (cluster <= 0x0ffffff7) // cluster在循环末尾更新(如果当前簇已经没有短目录项的话) - { - // 计算文件夹当前位置所在簇的起始扇区号 - uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; - // 读取文件夹目录项当前位置起始扇区的数据 - - if (AHCI_SUCCESS != blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, - fsbi->sec_per_clus, (uint64_t)buf)) - { - // 读取失败 - kerror("Failed to read the file's first sector."); - kfree(buf); - return NULL; - } - - struct fat32_Directory_t *dentry = NULL; - struct fat32_LongDirectory_t *long_dentry = NULL; - - // 找到当前短目录项 - dentry = (struct fat32_Directory_t *)(buf + file_ptr->position % fsbi->bytes_per_clus); - - name_len = 0; - // 逐个查找短目录项 - for (int i = file_ptr->position % fsbi->bytes_per_clus; i < fsbi->bytes_per_clus; - i += 32, file_ptr->position += 32, ++dentry) - { - // 若是长目录项则跳过 - if (dentry->DIR_Attr == ATTR_LONG_NAME) - continue; - // 跳过无效表项、空闲表项 - if (dentry->DIR_Name[0] == 0xe5 || dentry->DIR_Name[0] == 0x00 || dentry->DIR_Name[0] == 0x05) - continue; - - // 找到短目录项 - // 该短目录项对应的第一个长目录项 - long_dentry = (struct fat32_LongDirectory_t *)(dentry - 1); - - // 如果长目录项有效,则读取长目录项 - if (long_dentry->LDIR_Attr == ATTR_LONG_NAME && long_dentry->LDIR_Ord != 0xe5 && - long_dentry->LDIR_Ord != 0x00 && long_dentry->LDIR_Ord != 0x05) - { - int count_long_dentry = 0; - // 统计长目录项的个数 - while (long_dentry->LDIR_Attr == ATTR_LONG_NAME && long_dentry->LDIR_Ord != 0xe5 && - long_dentry->LDIR_Ord != 0x00 && long_dentry->LDIR_Ord != 0x05) - { - ++count_long_dentry; - if (long_dentry->LDIR_Ord & 0x40) // 最后一个长目录项 - break; - --long_dentry; - } - // 为目录名分配空间 - dir_name = (char *)kmalloc(count_long_dentry * 26 + 1, 0); - memset(dir_name, 0, count_long_dentry * 26 + 1); - - // 重新将长目录项指针指向第一个长目录项 - long_dentry = (struct fat32_LongDirectory_t *)(dentry - 1); - name_len = 0; - // 逐个存储文件名 - for (int j = 0; j < count_long_dentry; ++j, --long_dentry) - { - // 存储name1 - for (int k = 0; k < 5; ++k) - { - if (long_dentry->LDIR_Name1[k] != 0xffff && long_dentry->LDIR_Name1[k] != 0x0000) - dir_name[name_len++] = (char)long_dentry->LDIR_Name1[k]; - } - - // 存储name2 - for (int k = 0; k < 6; ++k) - { - if (long_dentry->LDIR_Name2[k] != 0xffff && long_dentry->LDIR_Name2[k] != 0x0000) - dir_name[name_len++] = (char)long_dentry->LDIR_Name2[k]; - } - - // 存储name3 - for (int k = 0; k < 2; ++k) - { - if (long_dentry->LDIR_Name3[k] != 0xffff && long_dentry->LDIR_Name3[k] != 0x0000) - dir_name[name_len++] = (char)long_dentry->LDIR_Name3[k]; - } - } - - // 读取目录项成功,返回 - dentry_type = dentry->DIR_Attr; - goto find_dir_success; - } - else // 不存在长目录项 - { - dir_name = (char *)kmalloc(15, 0); - memset(dir_name, 0, 15); - - name_len = 0; - int total_len = 0; - // 读取基础名 - for (int j = 0; j < 8; ++j, ++total_len) - { - if (dentry->DIR_Name[j] == ' ') - break; - - if (dentry->DIR_NTRes & LOWERCASE_BASE) // 如果标记了文件名小写,则转换为小写字符 - dir_name[name_len++] = dentry->DIR_Name[j] + 32; - else - dir_name[name_len++] = dentry->DIR_Name[j]; - } - - // 如果当前短目录项为文件夹,则直接返回,不需要读取扩展名 - if (dentry->DIR_Attr & ATTR_DIRECTORY) - { - dentry_type = dentry->DIR_Attr; - goto find_dir_success; - } - - // 是文件,增加 . - dir_name[name_len++] = '.'; - - // 读取扩展名 - // 读取基础名 - for (int j = 0; j < 3; ++j, ++total_len) - { - if (dentry->DIR_Name[j] == ' ') - break; - - if (dentry->DIR_NTRes & LOWERCASE_BASE) // 如果标记了文件名小写,则转换为小写字符 - dir_name[name_len++] = dentry->DIR_Name[j] + 32; - else - dir_name[name_len++] = dentry->DIR_Name[j]; - } - - if (total_len == 8) // 没有扩展名 - dir_name[--name_len] = '\0'; - - dentry_type = dentry->DIR_Attr; - goto find_dir_success; - } - } - - // 当前簇不存在目录项 - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - } - - kfree(buf); - // 在上面的循环中读取到目录项结尾了,仍没有找到 - return NULL; - -find_dir_success:; - // 将文件夹位置坐标加32(即指向下一个目录项) - file_ptr->position += 32; - // todo: 计算ino_t - if (dentry_type & ATTR_DIRECTORY) - dentry_type = VFS_IF_DIR; - else - dentry_type = VFS_IF_FILE; - - return filler(dirent, 0, dir_name, name_len, dentry_type, 0); -} - -struct vfs_inode_operations_t fat32_inode_ops = { - .create = fat32_create, - .mkdir = fat32_mkdir, - .rmdir = fat32_rmdir, - .lookup = fat32_lookup, - .rename = fat32_rename, - .getAttr = fat32_getAttr, - .setAttr = fat32_setAttr, - .unlink = fat32_unlink, - -}; - -/** - * @brief 给定字符串长度,计算去除字符串尾部的'.'后,剩余部分的长度 - * - * @param len 字符串长度(不包括\0) - * @param name 名称字符串 - * @return unsigned int 去除'.'后的 - */ -static unsigned int vfat_striptail_len(unsigned int len, const char *name) -{ - while (len && name[len - 1] == '.') - --len; - return len; -} - -/** - * @brief 在指定inode的长目录项中搜索目标子目录项 - * - * @param dir 父目录项inode - * @param name 要查找的子目录项的名称 - * @param len 子目录项名称长度 - * @param slot_info 返回的对应的子目录项的短目录项。 - * @return int 错误码 - */ -static int fat_search_long(struct vfs_index_node_t *dir, const char *name, int len, struct fat32_slot_info *slot_info) -{ - int retval = 0; - retval = __fat32_search_long_short(dir, name, len, slot_info); - return retval; -} -/** - * @brief 在fat32中,根据父inode,寻找给定名称的子inode - * - * @param dir 父目录项的inode - * @param name 子目录项名称 - * @param slot_info 找到的slot的信息 - * @return int 错误码 - */ -static int vfat_find(struct vfs_index_node_t *dir, const char *name, struct fat32_slot_info *slot_info) -{ - uint32_t len = vfat_striptail_len(strnlen(name, PAGE_4K_SIZE - 1), name); - - if (len == 0) - return -ENOENT; - - return fat_search_long(dir, name, len, slot_info); -} - -struct vfs_filesystem_type_t fat32_fs_type = { - .name = "FAT32", - .fs_flags = 0, - .read_superblock = fat32_read_superblock, - .next = NULL, -}; -void fat32_init() -{ - - kinfo("Initializing FAT32..."); - - // 在VFS中注册fat32文件系统 - vfs_register_filesystem(&fat32_fs_type); - // 挂载根文件系统 - fat32_register_partition(ahci_gendisk0.partition + 0, 0); -} \ No newline at end of file diff --git a/kernel/src/filesystem/fat32/fat32.h b/kernel/src/filesystem/fat32/fat32.h deleted file mode 100644 index a67ee779..00000000 --- a/kernel/src/filesystem/fat32/fat32.h +++ /dev/null @@ -1,221 +0,0 @@ -/** - * @file fat32.h - * @author fslongjin (longjin@RinGoTek.cn) - * @brief fat32文件系统 - * @version 0.1 - * @date 2022-04-19 - * - * @copyright Copyright (c) 2022 - * - */ - -#pragma once - -#include -#include - -#define FAT32_MAX_PARTITION_NUM 128 // 系统支持的最大的fat32分区数量 - -#define FAT32_DELETED_FLAG 0xe5 // 如果短目录项的name[0]为这个值,那么意味着这个短目录项是空闲的 - -/** - * @brief fat32文件系统引导扇区结构体 - * - */ -struct fat32_BootSector_t -{ - uint8_t BS_jmpBoot[3]; // 跳转指令 - uint8_t BS_OEMName[8]; // 生产厂商名 - uint16_t BPB_BytesPerSec; // 每扇区字节数 - uint8_t BPB_SecPerClus; // 每簇扇区数 - uint16_t BPB_RsvdSecCnt; // 保留扇区数 - uint8_t BPB_NumFATs; // FAT表数量 - uint16_t BPB_RootEntCnt; // 根目录文件数最大值 - uint16_t BPB_TotSec16; // 16位扇区总数 - uint8_t BPB_Media; // 介质描述符 - uint16_t BPB_FATSz16; // FAT12/16每FAT扇区数 - uint16_t BPB_SecPerTrk; // 每磁道扇区数 - uint16_t BPB_NumHeads; // 磁头数 - uint32_t BPB_HiddSec; // 隐藏扇区数 - uint32_t BPB_TotSec32; // 32位扇区总数 - - uint32_t BPB_FATSz32; // FAT32每FAT扇区数 - uint16_t BPB_ExtFlags; // 扩展标志 - uint16_t BPB_FSVer; // 文件系统版本号 - uint32_t BPB_RootClus; // 根目录起始簇号 - uint16_t BPB_FSInfo; // FS info结构体的扇区号 - uint16_t BPB_BkBootSec; // 引导扇区的备份扇区号 - uint8_t BPB_Reserved0[12]; - - uint8_t BS_DrvNum; // int0x13的驱动器号 - uint8_t BS_Reserved1; - uint8_t BS_BootSig; // 扩展引导标记 - uint32_t BS_VolID; // 卷序列号 - uint8_t BS_VolLab[11]; // 卷标 - uint8_t BS_FilSysType[8]; // 文件系统类型 - - uint8_t BootCode[420]; // 引导代码、数据 - - uint16_t BS_TrailSig; // 结束标志0xAA55 -} __attribute__((packed)); - -/** - * @brief fat32文件系统的FSInfo扇区结构体 - * - */ -struct fat32_FSInfo_t -{ - uint32_t FSI_LeadSig; // FS info扇区标志符 数值为0x41615252 - uint8_t FSI_Reserved1[480]; // 保留使用,全部置为0 - uint32_t FSI_StrucSig; // 另一个标志符,数值为0x61417272 - uint32_t FSI_Free_Count; // 上一次记录的空闲簇数量,这是一个参考值 - uint32_t FSI_Nxt_Free; // 空闲簇的起始搜索位置,这是为驱动程序提供的参考值 - uint8_t FSI_Reserved2[12]; // 保留使用,全部置为0 - uint32_t FSI_TrailSig; // 结束标志,数值为0xaa550000 -} __attribute__((packed)); - -#define ATTR_READ_ONLY (1 << 0) -#define ATTR_HIDDEN (1 << 1) -#define ATTR_SYSTEM (1 << 2) -#define ATTR_VOLUME_ID (1 << 3) -#define ATTR_DIRECTORY (1 << 4) -#define ATTR_ARCHIVE (1 << 5) -#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID) - -/** - * @brief fat32文件系统短目录项,大小为32bytes - * - */ -struct fat32_Directory_t -{ - unsigned char DIR_Name[11]; - unsigned char DIR_Attr; // 目录项属性 - unsigned char DIR_NTRes; // EXT|BASE => 8(BASE).3(EXT) - // BASE:LowerCase(8),UpperCase(0) - // EXT:LowerCase(16),UpperCase(0) - unsigned char DIR_CrtTimeTenth; // 文件创建的毫秒级时间戳 - unsigned short DIR_CrtTime; // 文件创建时间 - unsigned short DIR_CrtDate; // 文件创建日期 - unsigned short DIR_LastAccDate; // 文件的最后访问日期 - unsigned short DIR_FstClusHI; // 起始簇号(高16bit) - unsigned short DIR_WrtTime; // 最后写入时间 - unsigned short DIR_WrtDate; // 最后写入日期 - unsigned short DIR_FstClusLO; // 起始簇号(低16bit) - unsigned int DIR_FileSize; // 文件大小 -} __attribute__((packed)); - -#define LOWERCASE_BASE (8) -#define LOWERCASE_EXT (16) - -/** - * @brief fat32文件系统长目录项,大小为32bytes - * - */ -struct fat32_LongDirectory_t -{ - unsigned char LDIR_Ord; // 长目录项的序号 - unsigned short LDIR_Name1[5]; // 长文件名的第1-5个字符,每个字符占2bytes - unsigned char LDIR_Attr; // 目录项属性必须为ATTR_LONG_NAME - unsigned char LDIR_Type; // 如果为0,则说明这是长目录项的子项 - unsigned char LDIR_Chksum; // 短文件名的校验和 - unsigned short LDIR_Name2[6]; // 长文件名的第6-11个字符,每个字符占2bytes - unsigned short LDIR_FstClusLO; // 必须为0 - unsigned short LDIR_Name3[2]; // 长文件名的12-13个字符,每个字符占2bytes -} __attribute__((packed)); - -/** - * @brief fat32文件系统的超级块信息结构体 - * - */ -struct fat32_partition_info_t -{ - uint16_t partition_id; // 全局fat32分区id - // todo: 增加mutex,使得对fat32文件系统的访问是互斥的 - - struct fat32_BootSector_t bootsector; - struct fat32_FSInfo_t fsinfo; - uint64_t fsinfo_sector_addr_infat; - uint64_t bootsector_bak_sector_addr_infat; - - uint64_t starting_sector; - uint64_t sector_count; - - uint64_t sec_per_clus; // 每簇扇区数 - uint64_t bytes_per_sec; // 每扇区字节数 - uint64_t bytes_per_clus; // 每簇字节数 - - uint64_t first_data_sector; // 数据区起始扇区号 - uint64_t FAT1_base_sector; // FAT1表的起始簇号 - uint64_t FAT2_base_sector; // FAT2表的起始簇号 - uint64_t sec_per_FAT; // 每FAT表扇区数 - uint64_t NumFATs; // FAT表数 -}; - -typedef struct fat32_partition_info_t fat32_sb_info_t; - -struct fat32_inode_info_t -{ - uint32_t first_clus; // 文件的起始簇号 - uint64_t dEntry_location_clus; // fat entry的起始簇号 dEntry struct in cluster (0 is root, 1 is invalid) - uint64_t dEntry_location_clus_offset; // fat entry在起始簇中的偏移量(是第几个entry) dEntry struct offset in cluster - - uint16_t create_date; - uint16_t create_time; - uint16_t write_time; - uint16_t write_date; -}; - -typedef struct fat32_inode_info_t fat32_inode_info_t; - -/** - * @brief FAT32目录项插槽信息 - * 一个插槽指的是 一个长目录项/短目录项 - */ -struct fat32_slot_info -{ - off_t i_pos; // on-disk position of directory entry(扇区号) - off_t slot_off; // offset for slot or (de) start - int num_slots; // number of slots +1(de) in filename - struct fat32_Directory_t * de; - - // todo: 加入block io层后,在这里引入buffer_head - void *buffer; // 记得释放这个buffer!!! -}; - -/** - * @brief 注册指定磁盘上的指定分区的fat32文件系统 - * - * @param blk_dev 块设备结构体 - * @param part_num 磁盘分区编号 - * - * @return struct vfs_super_block_t * 文件系统的超级块 - */ -struct vfs_superblock_t *fat32_register_partition(struct block_device *blk_dev, uint8_t part_num); - -/** - * @brief 创建fat32文件系统的超级块 - * - * @param blk 块设备结构体 - * @return struct vfs_superblock_t* 创建好的超级块 - */ -struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk); - -/** - * @brief 创建新的文件 - * @param parent_inode 父目录的inode结构体 - * @param dest_dEntry 新文件的dentry - * @param mode 创建模式 - */ -long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode); - -void fat32_init(); - -/** - * @brief 读取文件夹(在指定目录中找出有效目录项) - * - * @param file_ptr 文件结构体指针 - * @param dirent 返回的dirent - * @param filler 填充dirent的函数 - * @return int64_t - */ -int64_t fat32_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler); \ No newline at end of file diff --git a/kernel/src/filesystem/fat32/fat_ent.c b/kernel/src/filesystem/fat32/fat_ent.c deleted file mode 100644 index b0a50dbf..00000000 --- a/kernel/src/filesystem/fat32/fat_ent.c +++ /dev/null @@ -1,481 +0,0 @@ -#include "fat_ent.h" -#include "internal.h" -#include -#include -#include - -static const char unavailable_character_in_short_name[] = {0x22, 0x2a, 0x2b, 0x2c, 0x2e, 0x2f, 0x3a, 0x3b, - 0x3c, 0x3d, 0x3e, 0x3f, 0x5b, 0x5c, 0x5d, 0x7c}; -/** - * @brief 请求分配指定数量的簇 - * - * @param inode 要分配簇的inode - * @param clusters 返回的被分配的簇的簇号结构体 - * @param num_clusters 要分配的簇的数量 - * @return int 错误码 - */ -int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int32_t num_clusters) -{ - int retval = 0; - - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)inode->sb->private_sb_info; - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)inode->private_inode_info; - struct block_device *blk = inode->sb->blk_device; - uint64_t sec_per_fat = fsbi->sec_per_FAT; - - // 申请1扇区的缓冲区 - uint32_t *buf = (uint32_t *)kzalloc(fsbi->bytes_per_sec, 0); - int ent_per_sec = (fsbi->bytes_per_sec >> 2); - int clus_idx = 0; - for (int i = 0; i < sec_per_fat; ++i) - { - if (clus_idx >= num_clusters) - goto done; - memset(buf, 0, fsbi->bytes_per_sec); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + i, 1, (uint64_t)buf); - // 依次检查簇是否空闲 - for (int j = 0; j < ent_per_sec; ++j) - { - if (clus_idx >= num_clusters) - goto done; - // 找到空闲簇 - if ((buf[j] & 0x0fffffff) == 0) - { - // kdebug("clus[%d] = %d", clus_idx, i * ent_per_sec + j); - clusters[clus_idx] = i * ent_per_sec + j; - ++clus_idx; - } - } - } - // 空间不足 - retval = -ENOSPC; - -done:; - kfree(buf); - if (retval == 0) // 成功 - { - int cluster, idx; - if (finode->first_clus == 0) - { - // 空文件 - finode->first_clus = clusters[0]; - cluster = finode->first_clus; - // 写入inode到磁盘 - inode->sb->sb_ops->write_inode(inode); - idx = 1; - } - else - { - // 跳转到文件当前的最后一个簇 - idx = 0; - int tmp_clus = finode->first_clus; - cluster = tmp_clus; - while (true) - { - tmp_clus = fat32_read_FAT_entry(blk, fsbi, cluster); - if (tmp_clus <= 0x0ffffff7) - cluster = tmp_clus; - else - break; - } - } - - // 写入fat表 - for (int i = idx; i < num_clusters; ++i) - { - // kdebug("write cluster i=%d : cluster=%d, value= %d", i, cluster, clusters[i]); - fat32_write_FAT_entry(blk, fsbi, cluster, clusters[i]); - cluster = clusters[i]; - } - fat32_write_FAT_entry(blk, fsbi, cluster, 0x0ffffff8); - - return 0; - } - else // 出现错误 - { - kwarn("err in alloc clusters"); - if (clus_idx < num_clusters) - fat32_free_clusters(inode, clusters[0]); - return retval; - } - - return 0; -} - -/** - * @brief 释放从属于inode的,从cluster开始的所有簇 - * - * @param inode 指定的文件的inode - * @param cluster 指定簇 - * @return int 错误码 - */ -int fat32_free_clusters(struct vfs_index_node_t *inode, int32_t cluster) -{ - // todo: 释放簇 - return 0; -} - -/** - * @brief 读取指定簇的FAT表项 - * - * @param blk 块设备结构体 - * @param fsbi fat32超级块私有信息结构体 - * @param cluster 指定簇 - * @return uint32_t 下一个簇的簇号 - */ -uint32_t fat32_read_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, uint32_t cluster) -{ - // 计算每个扇区内含有的FAT表项数 - // FAT每项4bytes - uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂 - - uint32_t buf[256]; - memset(buf, 0, fsbi->bytes_per_sec); - - // 读取一个sector的数据, - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, - fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)&buf); - - // 返回下一个fat表项的值(也就是下一个cluster) - return buf[cluster & (fat_ent_per_sec - 1)] & 0x0fffffff; -} - -/** - * @brief 写入指定簇的FAT表项 - * - * @param blk 块设备结构体 - * @param fsbi fat32超级块私有信息结构体 - * @param cluster 指定簇 - * @param value 要写入该fat表项的值 - * @return uint32_t errcode - */ -int fat32_write_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value) -{ - // 计算每个扇区内含有的FAT表项数 - // FAT每项4bytes - uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂 - uint32_t *buf = kzalloc(fsbi->bytes_per_sec, 0); - - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, - fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)buf); - - buf[cluster & (fat_ent_per_sec - 1)] = (buf[cluster & (fat_ent_per_sec - 1)] & 0xf0000000) | (value & 0x0fffffff); - // 向FAT1和FAT2写入数据 - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, - fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)buf); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, - fsbi->FAT2_base_sector + (cluster / fat_ent_per_sec), 1, (uint64_t)buf); - - kfree(buf); - return 0; -} - -/** - * @brief 在父亲inode的目录项簇中,寻找连续num个空的目录项 - * - * @param parent_inode 父inode - * @param num 请求的目录项数量 - * @param mode 操作模式 - * @param res_sector 返回信息:缓冲区对应的扇区号 - * @param res_cluster 返回信息:缓冲区对应的簇号 - * @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存!!!!) - * @return struct fat32_Directory_t* - * 符合要求的entry的指针(指向地址高处的空目录项,也就是说,有连续num个≤这个指针的空目录项) - */ -struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode, - uint32_t *res_sector, uint64_t *res_cluster, - uint64_t *res_data_buf_base) -{ - // kdebug("find empty_dentry"); - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)parent_inode->private_inode_info; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; - - uint8_t *buf = kzalloc(fsbi->bytes_per_clus, 0); - - struct block_device *blk = parent_inode->sb->blk_device; - - // 计算父目录项的起始簇号 - uint32_t cluster = finode->first_clus; - - struct fat32_Directory_t *tmp_dEntry = NULL; - // 指向最终的有用的dentry的指针 - struct fat32_Directory_t *result_dEntry = NULL; - - while (true) - { - // 计算父目录项的起始LBA扇区号 - uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; - - // 读取父目录项的起始簇数据 - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf); - tmp_dEntry = (struct fat32_Directory_t *)buf; - // 计数连续的空目录项 - uint32_t count_continuity = 0; - - // 查找连续num个空闲目录项 - for (int i = 0; (i < fsbi->bytes_per_clus) && count_continuity < num; i += 32, ++tmp_dEntry) - { - if (!(tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00 || - tmp_dEntry->DIR_Name[0] == 0x05)) - { - count_continuity = 0; - continue; - } - - if (count_continuity == 0) - result_dEntry = tmp_dEntry; - ++count_continuity; - } - - // 成功查找到符合要求的目录项 - if (count_continuity == num) - { - result_dEntry += (num - 1); - *res_sector = sector; - *res_data_buf_base = (uint64_t)buf; - *res_cluster = cluster; - - return result_dEntry; - } - - // 当前簇没有发现符合条件的空闲目录项,寻找下一个簇 - uint64_t old_cluster = cluster; - cluster = fat32_read_FAT_entry(blk, fsbi, cluster); - if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到符合要求的空目录项 - { - - // 新增一个簇 - - if (fat32_alloc_clusters(parent_inode, &cluster, 1) != 0) - { - kerror("Cannot allocate a new cluster!"); - while (1) - pause(); - } - - // 将这个新的簇清空 - sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; - void *tmp_buf = kzalloc(fsbi->bytes_per_clus, 0); - blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sector, fsbi->sec_per_clus, - (uint64_t)tmp_buf); - kfree(tmp_buf); - } - } -} - -/** - * @brief 检查文件名是否合法 - * - * @param name 文件名 - * @param namelen 文件名长度 - * @param reserved 保留字段 - * @return int 合法:0, 其他:错误码 - */ -int fat32_check_name_available(const char *name, int namelen, int8_t reserved) -{ - if (namelen > 255 || namelen <= 0) - return -ENAMETOOLONG; - // 首个字符不能是空格或者'.' - if (name[0] == 0x20 || name[0] == '.') - return -EINVAL; - - return 0; -} - -/** - * @brief 检查字符在短目录项中是否合法 - * - * @param c 给定字符 - * @param index 字符在文件名中处于第几位 - * @return true 合法 - * @return false 不合法 - */ -bool fat32_check_char_available_in_short_name(const char c, int index) -{ - // todo: 严格按照fat规范完善合法性检查功能 - if (index == 0) - { - if (c < 0x20) - { - if (c != 0x05) - return false; - return true; - } - } - - for (int i = 0; i < sizeof(unavailable_character_in_short_name) / sizeof(char); ++i) - { - if (c == unavailable_character_in_short_name[i]) - return false; - } - return true; -} - -/** - * @brief 填充短目录项的函数 - * - * @param dEntry 目标dentry - * @param target 目标dentry对应的短目录项 - * @param cluster 短目录项对应的文件/文件夹起始簇 - */ -void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory_t *target, uint32_t cluster) -{ - memset(target, 0, sizeof(struct fat32_Directory_t)); - { - int tmp_index = 0; - // kdebug("dEntry->name_length=%d", dEntry->name_length); - for (tmp_index = 0; tmp_index < min(8, dEntry->name_length); ++tmp_index) - { - if (dEntry->name[tmp_index] == '.') - break; - if (fat32_check_char_available_in_short_name(dEntry->name[tmp_index], tmp_index)) - target->DIR_Name[tmp_index] = dEntry->name[tmp_index]; - else - target->DIR_Name[tmp_index] = 0x20; - } - - // 不满的部分使用0x20填充 - while (tmp_index < 8) - { - // kdebug("tmp index = %d", tmp_index); - target->DIR_Name[tmp_index] = 0x20; - ++tmp_index; - } - if (dEntry->dir_inode->attribute & VFS_IF_DIR) - { - while (tmp_index < 11) - { - // kdebug("tmp index = %d", tmp_index); - target->DIR_Name[tmp_index] = 0x20; - ++tmp_index; - } - } - else - { - for (int j = 8; j < 11; ++j) - { - target->DIR_Name[j] = 'a'; - } - } - } - - struct vfs_index_node_t *inode = dEntry->dir_inode; - target->DIR_Attr = 0; - if (inode->attribute & VFS_IF_DIR) - target->DIR_Attr |= ATTR_DIRECTORY; - - target->DIR_FileSize = dEntry->dir_inode->file_size; - target->DIR_FstClusHI = (uint16_t)((cluster >> 16) & 0x0fff); - target->DIR_FstClusLO = (uint16_t)(cluster & 0xffff); - - // todo: 填写短目录项中的时间信息 -} - -/** - * @brief 填充长目录项的函数 - * - * @param dEntry 目标dentry - * @param target 起始长目录项 - * @param checksum 短目录项的校验和 - * @param cnt_longname 总的长目录项的个数 - */ -void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirectory_t *target, uint8_t checksum, - uint32_t cnt_longname) -{ - uint32_t current_name_index = 0; - struct fat32_LongDirectory_t *Ldentry = (struct fat32_LongDirectory_t *)(target + 1); - // kdebug("filling long name, name=%s, namelen=%d", dEntry->name, dEntry->name_length); - int name_length = dEntry->name_length + 1; - for (int i = 1; i <= cnt_longname; ++i) - { - --Ldentry; - - Ldentry->LDIR_Ord = i; - - for (int j = 0; j < 5; ++j, ++current_name_index) - { - if (current_name_index < name_length) - Ldentry->LDIR_Name1[j] = dEntry->name[current_name_index]; - else - Ldentry->LDIR_Name1[j] = 0xffff; - } - for (int j = 0; j < 6; ++j, ++current_name_index) - { - if (current_name_index < name_length) - Ldentry->LDIR_Name2[j] = dEntry->name[current_name_index]; - else - Ldentry->LDIR_Name2[j] = 0xffff; - } - for (int j = 0; j < 2; ++j, ++current_name_index) - { - if (current_name_index < name_length) - Ldentry->LDIR_Name3[j] = dEntry->name[current_name_index]; - else - Ldentry->LDIR_Name3[j] = 0xffff; - } - Ldentry->LDIR_Attr = ATTR_LONG_NAME; - Ldentry->LDIR_FstClusLO = 0; - Ldentry->LDIR_Type = 0; - Ldentry->LDIR_Chksum = checksum; - } - - // 最后一个长目录项的ord要|=0x40 - Ldentry->LDIR_Ord |= 0x40; -} - -/** - * @brief 删除目录项 - * - * @param dir 父目录的inode - * @param sinfo 待删除的dentry的插槽信息 - * @return int 错误码 - */ -int fat32_remove_entries(struct vfs_index_node_t *dir, struct fat32_slot_info *sinfo) -{ - int retval = 0; - struct vfs_superblock_t *sb = dir->sb; - struct fat32_Directory_t *de = sinfo->de; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)sb->private_sb_info; - int cnt_dentries = sinfo->num_slots; - - // 获取文件数据区的起始簇号 - int data_cluster = ((((uint32_t)de->DIR_FstClusHI) << 16) | ((uint32_t)de->DIR_FstClusLO)) & 0x0fffffff; - // kdebug("data_cluster=%d, cnt_dentries=%d, offset=%d", data_cluster, cnt_dentries, sinfo->slot_off); - // kdebug("fsbi->first_data_sector=%d, sec per clus=%d, i_pos=%d", fsbi->first_data_sector, fsbi->sec_per_clus, - // sinfo->i_pos); - // === 第一阶段,先删除短目录项 - while (cnt_dentries > 0) - { - de->DIR_Name[0] = FAT32_DELETED_FLAG; - --cnt_dentries; - --de; - } - - // === 第二阶段:将对目录项的更改写入磁盘 - - sb->blk_device->bd_disk->fops->transfer(sb->blk_device->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sinfo->i_pos, - fsbi->sec_per_clus, (uint64_t)sinfo->buffer); - - // === 第三阶段:清除文件的数据区 - uint32_t next_clus; - int js = 0; - // kdebug("data_cluster=%#018lx", data_cluster); - while (data_cluster < 0x0ffffff8 && data_cluster >= 2) - { - // 读取下一个表项 - next_clus = fat32_read_FAT_entry(sb->blk_device, fsbi, data_cluster); - // kdebug("data_cluster=%#018lx, next_clus=%#018lx", data_cluster, next_clus); - // 清除当前表项 - retval = fat32_write_FAT_entry(sb->blk_device, fsbi, data_cluster, 0); - if (unlikely(retval != 0)) - { - kerror("fat32_remove_entries: Failed to mark fat entry as unused for cluster:%d", data_cluster); - goto out; - } - ++js; - data_cluster = next_clus; - } -out:; - // kdebug("Successfully remove %d clusters.", js); - return retval; -} \ No newline at end of file diff --git a/kernel/src/filesystem/fat32/fat_ent.h b/kernel/src/filesystem/fat32/fat_ent.h deleted file mode 100644 index 0867565b..00000000 --- a/kernel/src/filesystem/fat32/fat_ent.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include "fat32.h" -#include -#include - -/** - * @brief 请求分配指定数量的簇 - * - * @param inode 要分配簇的inode - * @param clusters 返回的被分配的簇的簇号结构体 - * @param num_clusters 要分配的簇的数量 - * @return int 错误码 - */ -int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int32_t num_clusters); - -/** - * @brief 释放从属于inode的,从cluster开始的所有簇 - * - * @param inode 指定的文件的inode - * @param cluster 指定簇 - * @return int 错误码 - */ -int fat32_free_clusters(struct vfs_index_node_t *inode, int32_t cluster); - -/** - * @brief 读取指定簇的FAT表项 - * - * @param blk 块设备结构体 - * @param fsbi fat32超级块私有信息结构体 - * @param cluster 指定簇 - * @return uint32_t 下一个簇的簇号 - */ -uint32_t fat32_read_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, uint32_t cluster); - -/** - * @brief 写入指定簇的FAT表项 - * - * @param blk 块设备结构体 - * @param fsbi fat32超级块私有信息结构体 - * @param cluster 指定簇 - * @param value 要写入该fat表项的值 - * @return uint32_t errcode - */ -int fat32_write_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value); - -/** - * @brief 在父亲inode的目录项簇中,寻找连续num个空的目录项 - * - * @param parent_inode 父inode - * @param num 请求的目录项数量 - * @param mode 操作模式 - * @param res_sector 返回信息:缓冲区对应的扇区号 - * @param res_cluster 返回信息:缓冲区对应的簇号 - * @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存!!!!) - * @return struct fat32_Directory_t* 符合要求的entry的指针(指向地址高处的空目录项,也就是说,有连续num个≤这个指针的空目录项) - */ -struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode, uint32_t *res_sector, uint64_t *res_cluster, uint64_t *res_data_buf_base); - -/** - * @brief 检查文件名是否合法 - * - * @param name 文件名 - * @param namelen 文件名长度 - * @param reserved 保留字段 - * @return int 合法:0, 其他:错误码 - */ -int fat32_check_name_available(const char *name, int namelen, int8_t reserved); - -/** - * @brief 检查字符在短目录项中是否合法 - * - * @param c 给定字符 - * @param index 字符在文件名中处于第几位 - * @return true 合法 - * @return false 不合法 - */ -bool fat32_check_char_available_in_short_name(const char c, int index); - -/** - * @brief 填充短目录项的函数 - * - * @param dEntry 目标dentry - * @param target 目标dentry对应的短目录项 - * @param cluster 短目录项对应的文件/文件夹起始簇 - */ -void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory_t *target, uint32_t cluster); - -/** - * @brief 填充长目录项的函数 - * - * @param dEntry 目标dentry - * @param target 起始长目录项 - * @param checksum 短目录项的校验和 - * @param cnt_longname 总的长目录项的个数 - */ -void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirectory_t *target, uint8_t checksum, uint32_t cnt_longname); - -int fat32_remove_entries(struct vfs_index_node_t *dir, struct fat32_slot_info *sinfo); \ No newline at end of file diff --git a/kernel/src/filesystem/fat32/internal.h b/kernel/src/filesystem/fat32/internal.h deleted file mode 100644 index 26b5be95..00000000 --- a/kernel/src/filesystem/fat32/internal.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - -/** - * @brief 根据簇号计算该簇的起始扇区号(LBA地址) - * - * @param first_data_sector 数据区的其实扇区号 - * @param sec_per_clus 每个簇的扇区数量 - * @param cluster 簇号 - * @return uint32_t LBA地址 - */ -static inline uint32_t __fat32_calculate_LBA(uint32_t first_data_sector, uint32_t sec_per_clus, uint32_t cluster) -{ - return first_data_sector + (cluster - 2) * sec_per_clus; -} - -/** - * @brief 计算LBA地址所在的簇 - * - * @param first_data_sector 数据区的其实扇区号 - * @param sec_per_clus 每个簇的扇区数量 - * @param LBA LBA地址 - * @return uint32_t 所在的簇 - */ -static inline uint32_t __fat32_LBA_to_cluster(uint32_t first_data_sector, uint32_t sec_per_clus, uint32_t LBA) -{ - return ((LBA - first_data_sector) / sec_per_clus) + 2; -} \ No newline at end of file diff --git a/kernel/src/filesystem/fat32/mod.rs b/kernel/src/filesystem/fat32/mod.rs deleted file mode 100644 index 8b137891..00000000 --- a/kernel/src/filesystem/fat32/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/kernel/src/filesystem/mbr.rs b/kernel/src/filesystem/mbr.rs new file mode 100644 index 00000000..f6f7dbb2 --- /dev/null +++ b/kernel/src/filesystem/mbr.rs @@ -0,0 +1,65 @@ +#![allow(dead_code)] +use core::default::Default; + +/// @brief MBR硬盘分区表项的结构 +#[repr(packed)] +#[derive(Debug, Clone, Copy)] +pub struct MbrDiskPartitionTableEntry { + pub flags: u8, // 引导标志符,标记此分区为活动分区 + pub starting_head: u8, // 起始磁头号 + pub starting_sector_cylinder: u16, // sector : 低6, cylinder : 高10; 起始扇区号 + 起始柱面号 + pub part_type: u8, // 分区类型ID + pub ending_head: u8, // 结束磁头号 + pub ending_sector_cylingder: u16, // ending_sector : 低6, ending_cylinder : 高10; 结束扇区号 + 结束柱面号 + pub starting_lba: u32, // 起始逻辑扇区 + pub total_sectors: u32, // 分区占用的磁盘扇区数 +} + +impl MbrDiskPartitionTableEntry { + pub fn starting_sector(&self) -> u16 { + return self.starting_sector_cylinder & ((1 << 6) - 1) as u16; + } + pub fn starting_cylinder(&self) -> u16 { + return (self.starting_sector_cylinder >> 6) & ((1 << 10) - 1) as u16; + } + pub fn ending_sector(&self) -> u16 { + return self.ending_sector_cylingder & ((1 << 6) - 1) as u16; + } + pub fn ending_cylinder(&self) -> u16 { + return (self.ending_sector_cylingder >> 6) & ((1 << 10) - 1) as u16; + } +} + +/// @brief MBR磁盘分区表结构体 +#[repr(packed)] +#[derive(Debug, Clone, Copy)] +pub struct MbrDiskPartionTable { + pub reserved: [u8; 446], + pub dpte: [MbrDiskPartitionTableEntry; 4], // 磁盘分区表项 + pub bs_trailsig: u16, +} + +impl Default for MbrDiskPartitionTableEntry { + fn default() -> Self { + MbrDiskPartitionTableEntry { + flags: 0, + starting_head: 0, + starting_sector_cylinder: 0, + part_type: 0, + ending_head: 0, + ending_sector_cylingder: 0, + starting_lba: 0, + total_sectors: 0, + } + } +} + +impl Default for MbrDiskPartionTable { + fn default() -> Self { + MbrDiskPartionTable { + reserved: [0; 446], + dpte: [Default::default(); 4], + bs_trailsig: Default::default(), + } + } +} diff --git a/kernel/src/filesystem/mod.rs b/kernel/src/filesystem/mod.rs index 3ac26c88..e0de780b 100644 --- a/kernel/src/filesystem/mod.rs +++ b/kernel/src/filesystem/mod.rs @@ -1,5 +1,6 @@ pub mod devfs; -pub mod fat32; +pub mod fat; +pub mod mbr; pub mod procfs; -pub mod rootfs; +pub mod ramfs; pub mod vfs; diff --git a/kernel/src/filesystem/procfs/Makefile b/kernel/src/filesystem/procfs/Makefile deleted file mode 100644 index 1236dd66..00000000 --- a/kernel/src/filesystem/procfs/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - -CFLAGS += -I . - - -kernel_fs_procfs_objs:= $(shell find ./*.c) - - -ECHO: - @echo "$@" - - -$(kernel_fs_procfs_objs): ECHO - $(CC) $(CFLAGS) -c $@ -o $@.o - - -all: $(kernel_fs_procfs_objs) - diff --git a/kernel/src/filesystem/procfs/mod.rs b/kernel/src/filesystem/procfs/mod.rs index 8b137891..c0c2be40 100644 --- a/kernel/src/filesystem/procfs/mod.rs +++ b/kernel/src/filesystem/procfs/mod.rs @@ -1 +1,706 @@ +use core::intrinsics::size_of; +use alloc::{ + borrow::ToOwned, + collections::BTreeMap, + format, + string::{String, ToString}, + sync::{Arc, Weak}, + vec::Vec, +}; + +use crate::{ + filesystem::vfs::{ + core::{generate_inode_id, ROOT_INODE}, + FileType, + }, + include::bindings::bindings::{ + pid_t, process_find_pcb_by_pid, EEXIST, EINVAL, EISDIR, ENOBUFS, ENOENT, ENOTDIR, + ENOTEMPTY, ENOTSUP, EPERM, ESRCH, + }, + kerror, + libs::spinlock::{SpinLock, SpinLockGuard}, + time::TimeSpec, +}; + +use super::vfs::{ + file::FilePrivateData, FileSystem, FsInfo, IndexNode, InodeId, Metadata, PollStatus, +}; + +/// @brief 进程文件类型 +/// @usage 用于定义进程文件夹下的各类文件类型 +#[derive(Debug)] +#[repr(u8)] +pub enum ProcFileType { + ///展示进程状态信息 + ProcStatus = 0, + //todo: 其他文件类型 + ///默认文件类型 + Default, +} + +impl From for ProcFileType { + fn from(value: u8) -> Self { + match value { + 0 => ProcFileType::ProcStatus, + _ => ProcFileType::Default, + } + } +} +/// @brief 节点私有信息结构体 +/// @usage 用于传入各类文件所需的信息 +#[derive(Debug)] +pub struct InodeInfo { + ///进程的pid + pid: i64, + ///文件类型 + ftype: ProcFileType, + //其他需要传入的信息在此定义 +} + +/// @brief procfs的inode名称的最大长度 +const PROCFS_MAX_NAMELEN: usize = 64; + +/// @brief procfs文件系统的Inode结构体 +#[derive(Debug)] +pub struct LockedProcFSInode(SpinLock); + +/// @brief procfs文件系统结构体 +#[derive(Debug)] +pub struct ProcFS { + /// procfs的root inode + root_inode: Arc, +} + +#[derive(Debug, Clone)] +pub struct ProcfsFilePrivateData { + data: Vec, +} + +impl ProcfsFilePrivateData { + pub fn new() -> Self { + return ProcfsFilePrivateData { data: Vec::new() }; + } +} + +/// @brief procfs文件系统的Inode结构体(不包含锁) +#[derive(Debug)] +pub struct ProcFSInode { + /// 指向父Inode的弱引用 + parent: Weak, + /// 指向自身的弱引用 + self_ref: Weak, + /// 子Inode的B树 + children: BTreeMap>, + /// 当前inode的数据部分 + data: Vec, + /// 当前inode的元数据 + metadata: Metadata, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, + /// 储存私有信息 + fdata: InodeInfo, +} + +/// 对ProcFSInode实现获取各类文件信息的函数 +impl ProcFSInode { + /// @brief 去除Vec中所有的\0,并在结尾添加\0 + #[inline] + fn trim_string(&self, data: &mut Vec) { + data.drain_filter(|x: &mut u8| *x == 0); + data.push(0); + } + // todo:其他数据获取函数实现 + + /// @brief 打开status文件 + /// + fn open_status(&self, pdata: &mut ProcfsFilePrivateData) -> Result { + // 获取该pid对应的pcb结构体 + let pid: &i64 = &self.fdata.pid; + let pcb = unsafe { process_find_pcb_by_pid(*pid).as_mut() }; + let pcb = if pcb.is_none() { + kerror!( + "ProcFS: Cannot find pcb for pid {} when opening its 'status' file.", + pid + ); + return Err(-(ESRCH as i32)); + } else { + pcb.unwrap() + }; + // 传入数据 + let pdata: &mut Vec = &mut pdata.data; + // !!!!!由于目前有bug,不能获取到pcb的name,因此暂时用'Unknown'代替 + let tmp_name: Vec = "Unknown".as_bytes().to_vec(); + // kdebug!("pcb.name={:?}", pcb.name); + // let mut tmp_name: Vec = Vec::with_capacity(pcb.name.len()); + // for val in pcb.name.iter() { + // tmp_name.push(*val as u8); + // } + + pdata.append( + &mut format!( + "Name:\t{}", + String::from_utf8(tmp_name).unwrap_or("NULL".to_string()) + ) + .as_bytes() + .to_owned(), + ); + pdata.append(&mut format!("\nstate:\t{}", pcb.state).as_bytes().to_owned()); + pdata.append(&mut format!("\npid:\t{}", pcb.pid).as_bytes().to_owned()); + pdata.append( + &mut format!("\nPpid:\t{}", unsafe { *pcb.parent_pcb }.pid) + .as_bytes() + .to_owned(), + ); + pdata.append(&mut format!("\ncpu_id:\t{}", pcb.cpu_id).as_bytes().to_owned()); + pdata.append( + &mut format!("\npriority:\t{}", pcb.priority) + .as_bytes() + .to_owned(), + ); + pdata.append( + &mut format!("\npreempt:\t{}", pcb.preempt_count) + .as_bytes() + .to_owned(), + ); + pdata.append( + &mut format!("\nvrtime:\t{}", pcb.virtual_runtime) + .as_bytes() + .to_owned(), + ); + + // 当前进程运行过程中占用内存的峰值 + let hiwater_vm: u64 = + unsafe { *(*pcb.mm).vmas }.vm_end - unsafe { *(*pcb.mm).vmas }.vm_start; + // 进程数据段的大小 + let text: u64 = unsafe { *pcb.mm }.code_addr_end - unsafe { *pcb.mm }.code_addr_start; + // 进程代码的大小 + let data: u64 = unsafe { *pcb.mm }.data_addr_end - unsafe { *pcb.mm }.data_addr_start; + + pdata.append( + &mut format!("\nVmPeak:\t{} kB", hiwater_vm) + .as_bytes() + .to_owned(), + ); + pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned()); + pdata.append(&mut format!("\nVmExe:\t{} kB\n", text).as_bytes().to_owned()); + + // 去除多余的\0 + self.trim_string(pdata); + + return Ok((pdata.len() * size_of::()) as i64); + } + + /// status文件读取函数 + fn read_status( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _pdata: &mut ProcfsFilePrivateData, + ) -> Result { + let start = _pdata.data.len().min(offset); + let end = _pdata.data.len().min(offset + len); + + // buffer空间不足 + if buf.len() < (end - start) { + return Err(-(ENOBUFS as i32)); + } + + // 拷贝数据 + let src = &_pdata.data[start..end]; + buf[0..src.len()].copy_from_slice(src); + return Ok(src.len()); + } +} + +impl FileSystem for ProcFS { + fn root_inode(&self) -> Arc { + return self.root_inode.clone(); + } + + fn info(&self) -> FsInfo { + return FsInfo { + blk_dev_id: 0, + max_name_len: PROCFS_MAX_NAMELEN, + }; + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } +} + +impl ProcFS { + pub fn new() -> Arc { + // 初始化root inode + let root: Arc = + Arc::new(LockedProcFSInode(SpinLock::new(ProcFSInode { + parent: Weak::default(), + self_ref: Weak::default(), + children: BTreeMap::new(), + data: Vec::new(), + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::Dir, + mode: 0o777, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: 0, + }, + fs: Weak::default(), + fdata: InodeInfo { + pid: 0, + ftype: ProcFileType::Default, + }, + }))); + + let result: Arc = Arc::new(ProcFS { root_inode: root }); + + // 对root inode加锁,并继续完成初始化工作 + let mut root_guard: SpinLockGuard = result.root_inode.0.lock(); + root_guard.parent = Arc::downgrade(&result.root_inode); + root_guard.self_ref = Arc::downgrade(&result.root_inode); + root_guard.fs = Arc::downgrade(&result); + // 释放锁 + drop(root_guard); + + return result; + } + + /// @brief 进程注册函数 + /// @usage 在进程中调用并创建进程对应文件 + pub fn register_pid(&self, pid: i64) -> Result<(), i32> { + // 获取当前inode + let proc: Arc = self.root_inode(); + // 创建对应进程文件夹 + let _pf: Arc = proc.create(&pid.to_string(), FileType::Dir, 0o777)?; + // 创建相关文件 + // status文件 + let binding: Arc = _pf.create("status", FileType::File, 0o777)?; + let _sf: &LockedProcFSInode = binding + .as_any_ref() + .downcast_ref::() + .unwrap(); + _sf.0.lock().fdata.pid = pid; + _sf.0.lock().fdata.ftype = ProcFileType::ProcStatus; + + //todo: 创建其他文件 + + return Ok(()); + } + + /// @brief 解除进程注册 + /// + pub fn unregister_pid(&self, pid: i64) -> Result<(), i32> { + // 获取当前inode + let proc: Arc = self.root_inode(); + // 获取进程文件夹 + let pid_dir: Arc = proc.find(&format!("{}", pid))?; + // 删除进程文件夹下文件 + pid_dir.unlink("status")?; + + // 查看进程文件是否还存在 + // let pf= pid_dir.find("status").expect("Cannot find status"); + + // 删除进程文件夹 + proc.unlink(&format!("{}", pid))?; + + return Ok(()); + } +} + +impl IndexNode for LockedProcFSInode { + fn open(&self, data: &mut FilePrivateData) -> Result<(), i32> { + // 加锁 + let mut inode: SpinLockGuard = self.0.lock(); + + // 如果inode类型为文件夹,则直接返回成功 + if let FileType::Dir = inode.metadata.file_type { + return Ok(()); + } + let mut private_data = ProcfsFilePrivateData::new(); + // 根据文件类型获取相应数据 + let file_size = match inode.fdata.ftype { + ProcFileType::ProcStatus => inode.open_status(&mut private_data)?, + _ => { + todo!() + } + }; + *data = FilePrivateData::Procfs(private_data); + // 更新metadata里面的文件大小数值 + inode.metadata.size = file_size; + + return Ok(()); + } + + fn close(&self, data: &mut FilePrivateData) -> Result<(), i32> { + let guard: SpinLockGuard = self.0.lock(); + // 如果inode类型为文件夹,则直接返回成功 + if let FileType::Dir = guard.metadata.file_type { + return Ok(()); + } + // 获取数据信息 + let private_data = match data { + FilePrivateData::Procfs(p) => p, + _ => { + panic!("ProcFS: FilePrivateData mismatch!"); + } + }; + // 释放资源 + drop(private_data); + return Ok(()); + } + + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + // 加锁 + let inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + // 获取数据信息 + let private_data = match data { + FilePrivateData::Procfs(p) => p, + _ => { + panic!("ProcFS: FilePrivateData mismatch!"); + } + }; + + // 根据文件类型读取相应数据 + match inode.fdata.ftype { + ProcFileType::ProcStatus => return inode.read_status(offset, len, buf, private_data), + ProcFileType::Default => (), + }; + + // 默认读取 + let start = inode.data.len().min(offset); + let end = inode.data.len().min(offset + len); + + // buffer空间不足 + if buf.len() < (end - start) { + return Err(-(ENOBUFS as i32)); + } + + // 拷贝数据 + let src = &inode.data[start..end]; + buf[0..src.len()].copy_from_slice(src); + return Ok(src.len()); + } + + fn write_at( + &self, + _offset: usize, + _len: usize, + _buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result { + return Err(-(ENOTSUP as i32)); + } + + fn poll(&self) -> Result { + // 加锁 + let inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + return Ok(PollStatus { + flags: PollStatus::READ_MASK, + }); + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn metadata(&self) -> Result { + let inode = self.0.lock(); + let metadata = inode.metadata.clone(); + + return Ok(metadata); + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn resize(&self, len: usize) -> Result<(), i32> { + let mut inode = self.0.lock(); + if inode.metadata.file_type == FileType::File { + inode.data.resize(len, 0); + return Ok(()); + } else { + return Err(-(EINVAL as i32)); + } + } + + fn create_with_data( + &self, + name: &str, + file_type: FileType, + mode: u32, + data: usize, + ) -> Result, i32> { + // 获取当前inode + let mut inode = self.0.lock(); + // 如果当前inode不是文件夹,则返回 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + // 如果有重名的,则返回 + if inode.children.contains_key(name) { + return Err(-(EEXIST as i32)); + } + + // 创建inode + let result: Arc = + Arc::new(LockedProcFSInode(SpinLock::new(ProcFSInode { + parent: inode.self_ref.clone(), + self_ref: Weak::default(), + children: BTreeMap::new(), + data: Vec::new(), + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: file_type, + mode: mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: data, + }, + fs: inode.fs.clone(), + fdata: InodeInfo { + pid: 0, + ftype: ProcFileType::Default, + }, + }))); + + // 初始化inode的自引用的weak指针 + result.0.lock().self_ref = Arc::downgrade(&result); + + // 将子inode插入父inode的B树中 + inode.children.insert(String::from(name), result.clone()); + + return Ok(result); + } + + fn link(&self, name: &str, other: &Arc) -> Result<(), i32> { + let other: &LockedProcFSInode = other + .downcast_ref::() + .ok_or(-(EPERM as i32))?; + let mut inode: SpinLockGuard = self.0.lock(); + let mut other_locked: SpinLockGuard = other.0.lock(); + + // 如果当前inode不是文件夹,那么报错 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 如果另一个inode是文件夹,那么也报错 + if other_locked.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + // 如果当前文件夹下已经有同名文件,也报错。 + if inode.children.contains_key(name) { + return Err(-(EEXIST as i32)); + } + + inode + .children + .insert(String::from(name), other_locked.self_ref.upgrade().unwrap()); + + // 增加硬链接计数 + other_locked.metadata.nlinks += 1; + return Ok(()); + } + + fn unlink(&self, name: &str) -> Result<(), i32> { + let mut inode: SpinLockGuard = self.0.lock(); + // 如果当前inode不是目录,那么也没有子目录/文件的概念了,因此要求当前inode的类型是目录 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + // 不允许删除当前文件夹,也不允许删除上一个目录 + if name == "." || name == ".." { + return Err(-(ENOTEMPTY as i32)); + } + + // 获得要删除的文件的inode + let to_delete = inode.children.get(name).ok_or(-(ENOENT as i32))?; + // 减少硬链接计数 + to_delete.0.lock().metadata.nlinks -= 1; + // 在当前目录中删除这个子目录项 + inode.children.remove(name); + return Ok(()); + } + + fn move_( + &self, + _old_name: &str, + _target: &Arc, + _new_name: &str, + ) -> Result<(), i32> { + return Err(-(ENOTSUP as i32)); + } + + fn find(&self, name: &str) -> Result, i32> { + let inode = self.0.lock(); + + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match name { + "" | "." => { + return Ok(inode.self_ref.upgrade().ok_or(-(ENOENT as i32))?); + } + + ".." => { + return Ok(inode.parent.upgrade().ok_or(-(ENOENT as i32))?); + } + name => { + // 在子目录项中查找 + return Ok(inode.children.get(name).ok_or(-(ENOENT as i32))?.clone()); + } + } + } + + fn get_entry_name(&self, ino: InodeId) -> Result { + let inode: SpinLockGuard = self.0.lock(); + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match ino { + 0 => { + return Ok(String::from(".")); + } + 1 => { + return Ok(String::from("..")); + } + ino => { + // 暴力遍历所有的children,判断inode id是否相同 + // TODO: 优化这里,这个地方性能很差! + let mut key: Vec = inode + .children + .keys() + .filter(|k| inode.children.get(*k).unwrap().0.lock().metadata.inode_id == ino) + .cloned() + .collect(); + + match key.len() { + 0=>{return Err(-(ENOENT as i32));} + 1=>{return Ok(key.remove(0));} + _ => panic!("Procfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = inode.metadata.inode_id, to_find=ino) + } + } + } + } + + fn list(&self) -> Result, i32> { + let info = self.metadata()?; + if info.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + let mut keys: Vec = Vec::new(); + keys.push(String::from(".")); + keys.push(String::from("..")); + keys.append(&mut self.0.lock().children.keys().cloned().collect()); + + return Ok(keys); + } +} + +#[no_mangle] +pub extern "C" fn rs_procfs_register_pid(pid: pid_t) -> u64 { + let r = procfs_register_pid(pid); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 向procfs注册进程 +pub fn procfs_register_pid(pid: pid_t) -> Result<(), i32> { + let procfs_inode = ROOT_INODE().find("proc")?; + + let procfs_inode = procfs_inode + .downcast_ref::() + .expect("Failed to find procfs' root inode"); + let fs = procfs_inode.fs(); + let procfs: &ProcFS = fs.as_any_ref().downcast_ref::().unwrap(); + + // 调用注册函数 + procfs.register_pid(pid)?; + + return Ok(()); +} + +#[no_mangle] +pub extern "C" fn rs_procfs_unregister_pid(pid: pid_t) -> u64 { + let r = procfs_unregister_pid(pid); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 在ProcFS中,解除进程的注册 +pub fn procfs_unregister_pid(pid: pid_t) -> Result<(), i32> { + // 获取procfs实例 + let procfs_inode: Arc = ROOT_INODE().find("proc")?; + + let procfs_inode: &LockedProcFSInode = procfs_inode + .downcast_ref::() + .expect("Failed to find procfs' root inode"); + let fs: Arc = procfs_inode.fs(); + let procfs: &ProcFS = fs.as_any_ref().downcast_ref::().unwrap(); + + // 调用解除注册函数 + return procfs.unregister_pid(pid); +} diff --git a/kernel/src/filesystem/procfs/procfs.c b/kernel/src/filesystem/procfs/procfs.c deleted file mode 100644 index 6f4d7191..00000000 --- a/kernel/src/filesystem/procfs/procfs.c +++ /dev/null @@ -1,505 +0,0 @@ -#include "procfs.h" - -//定义文件类型 -#define PROC_STATUS 1 - -//定义buffer大小 -#define FDATA_RBUF_SIZE 1024 - -struct vfs_super_block_operations_t procfs_sb_ops; -struct vfs_dir_entry_operations_t procfs_dentry_ops; -struct vfs_file_operations_t procfs_file_ops; -struct vfs_inode_operations_t procfs_inode_ops; - -struct vfs_superblock_t procfs_sb = {0}; -struct vfs_dir_entry_t *procfs_root_dentry; // 根结点的dentry -static spinlock_t procfs_global_lock; // procfs的全局锁 -const char __procfs_mount_path[] = "/proc"; // 挂在路径 - -static int64_t proc_create_file(const char *path, mode_t type, long pid); -static int __check_name_available(const char *name, int namelen, int8_t reserved); -static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available); - -/** - * @brief 文件的私有信息结构 - * - */ -struct procfs_file_private_data -{ - int readlen; - char *rbuffer; - int writelen; - char *wbuffer; -}; - -/** - * @brief 创建procfs的super block - * - * @param blk 未使用(procfs为伪文件系统,不需要物理设备) - * @return struct vfs_superblock_t* - */ -struct vfs_superblock_t *procfs_read_superblock(struct block_device *blk) -{ - procfs_sb.blk_device = NULL; - procfs_sb.root = procfs_root_dentry; - procfs_sb.sb_ops = &procfs_sb_ops; - procfs_sb.dir_ops = &procfs_dentry_ops; - procfs_sb.private_sb_info = NULL; - kdebug("procfs read superblock done"); - return &procfs_sb; -} - -static void procfs_write_superblock(struct vfs_superblock_t *sb) -{ - return; -} -static void procfs_put_superblock(struct vfs_superblock_t *sb) -{ - return; -} -static void procfs_write_inode(struct vfs_index_node_t *inode) -{ - return; -} -struct vfs_super_block_operations_t procfs_sb_ops = { - .write_superblock = &procfs_write_superblock, - .put_superblock = &procfs_put_superblock, - .write_inode = &procfs_write_inode, -}; - -static long procfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) -{ - return 0; -} -static long procfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) -{ - return 0; -} -static long procfs_release(struct vfs_dir_entry_t *dEntry) -{ - return 0; -} -static long procfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) -{ - return 0; -} -struct vfs_dir_entry_operations_t procfs_dentry_ops = { - .compare = &procfs_compare, - .hash = &procfs_hash, - .release = &procfs_release, - .iput = &procfs_iput, -}; - -void data_puts(struct procfs_file_private_data *fdata, const char *s) -{ - int len = strlen(s); - if(fdata->readlen+len > FDATA_RBUF_SIZE) - { - kerror("out of buffer"); - return; - } - strncpy(fdata->rbuffer + fdata->readlen, s, len); - fdata->readlen += len; -} - -static long procfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - if (inode->attribute & VFS_IF_DIR) - { - return 0; - } - - struct procfs_inode_info_t *finode = inode->private_inode_info; - if (finode == NULL) - { - return 0; - } - // kdebug("finode=%#018lx", finode); - struct procfs_file_private_data *fdata = kzalloc(sizeof(struct procfs_file_private_data), 0); - struct process_control_block *pcb_t = process_find_pcb_by_pid(finode->pid); - //判断文件类型 - int mode = finode->type; - fdata->rbuffer = kzalloc(FDATA_RBUF_SIZE, 0); - int len = 0; - switch (mode) - { - case 1: - data_puts(fdata, "Name:\t"); - data_puts(fdata, pcb_t->name); - data_puts(fdata, "\nstate:\t"); - data_puts(fdata, ltoa(pcb_t->state)); - data_puts(fdata, "\npid:\t"); - data_puts(fdata, ltoa(pcb_t->pid)); - data_puts(fdata, "\nPpid:\t"); - data_puts(fdata, ltoa(pcb_t->parent_pcb->pid)); - data_puts(fdata, "\ncpu_id:\t"); - data_puts(fdata, ltoa(pcb_t->cpu_id)); - data_puts(fdata, "\npriority:\t"); - data_puts(fdata, ltoa(pcb_t->priority)); - data_puts(fdata, "\npreempt:\t"); - data_puts(fdata, ltoa(pcb_t->preempt_count)); - data_puts(fdata, "\nvrtime:\t"); - data_puts(fdata, ltoa(pcb_t->virtual_runtime)); - - // data_puts(fdata,"\n"); - - uint64_t hiwater_vm, text, data; - hiwater_vm = pcb_t->mm->vmas->vm_end - pcb_t->mm->vmas->vm_start; - text = pcb_t->mm->code_addr_end - pcb_t->mm->code_addr_start; - data = pcb_t->mm->data_addr_end - pcb_t->mm->data_addr_start; - - data_puts(fdata, "\nVmPeak:"); - data_puts(fdata, ltoa(hiwater_vm)); - data_puts(fdata, " kB"); - data_puts(fdata, "\nVmData:"); - data_puts(fdata, ltoa(data)); - data_puts(fdata, " kB"); - data_puts(fdata, "\nVmExe:"); - data_puts(fdata, ltoa(text)); - data_puts(fdata, " kB\n"); - - break; - - default: - break; - } - - inode->file_size = fdata->readlen; - file_ptr->private_data = fdata; - return 0; -} -static long procfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - return 0; -} -static long procfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) -{ - // 获取私有信息 - struct procfs_file_private_data *priv = (struct procfs_file_private_data *)file_ptr->private_data; - // kdebug("priv=%#018lx", priv); - if (!priv->rbuffer) - return -EINVAL; - - return simple_procfs_read(buf, count, position, priv->rbuffer, priv->readlen); -} - -/** - * @brief 检查读取并将数据从内核拷贝到用户 - * - * @param to: 要读取的用户空间缓冲区 - * @param count: 要读取的最大字节数 - * @param position: 缓冲区中的当前位置 - * @param from: 要读取的缓冲区 - * @param available: 读取的缓冲区大小 - * - * @return long 读取字节数 - */ -static long simple_procfs_read(void *to, int64_t count, long *position, void *from, int64_t available) -{ - long pos = *position; - // kdebug("pos:%ld",pos); - // kdebug("count:%ld",count); - // kdebug("available:%ld",available); - int64_t ret = 0; - - if (pos < 0) - return -EINVAL; - if (pos >= available || !count) - return 0; - if (count > available - pos) - count = available - pos; - // kdebug("count:%d",count); - ret = copy_to_user(to, from + pos, count); - - *position = pos + ret; - return ret; -} - -static long procfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) -{ - return 0; -} -/** - * @brief 调整文件的访问位置 - * - * @param file_ptr 文件描述符号 - * @param offset 偏移量 - * @param whence 调整模式 - * @return uint64_t 调整结束后的文件访问位置 - */ -static long procfs_lseek(struct vfs_file_t *file_ptr, long offset, long whence) -{ - struct vfs_index_node_t *inode = file_ptr->dEntry->dir_inode; - - long pos = 0; - switch (whence) - { - case SEEK_SET: // 相对于文件头 - pos = offset; - break; - case SEEK_CUR: // 相对于当前位置 - pos = file_ptr->position + offset; - break; - case SEEK_END: // 相对于文件末尾 - pos = file_ptr->dEntry->dir_inode->file_size + offset; - break; - - default: - return -EINVAL; - break; - } - - if (pos < 0 || pos > file_ptr->dEntry->dir_inode->file_size) - return -EOVERFLOW; - file_ptr->position = pos; - - return pos; -} -static long procfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) -{ - return 0; -} - -/** - * @brief 读取该目录下的目录项 - * - * @param file_ptr 文件结构体的指针 - * @param dirent 返回的dirent - * @param filler 填充dirent的函数 - * - * @return long 错误码 - */ -static long procfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler) -{ - struct vfs_dir_entry_t *dentry = file_ptr->dEntry; - struct List *list = &dentry->subdirs_list; - // 先切换到position处 - for (int i = 0; i <= file_ptr->position; ++i) - { - list = list_next(list); - if (list == &dentry->subdirs_list) // 找完了 - goto failed; - } - - // 若存在目录项,则增加偏移量 - ++file_ptr->position; - // 获取目标dentry(由于是子目录项,因此是child_node_list) - struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list); - - char *name = (char *)kzalloc(target_dent->name_length + 1, 0); - strncpy(name, target_dent->name, target_dent->name_length); - uint32_t dentry_type; - if (target_dent->dir_inode->attribute & VFS_IF_DIR) - dentry_type = VFS_IF_DIR; - else - dentry_type = VFS_IF_FILE; - - return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1); -failed:; - return 0; -} - -struct vfs_file_operations_t procfs_file_ops = { - .open = &procfs_open, - .close = &procfs_close, - .read = &procfs_read, - .write = &procfs_write, - .lseek = &procfs_lseek, - .ioctl = &procfs_ioctl, - .readdir = &procfs_readdir, -}; - -/** - * @brief 检查文件名是否合法 - * - * @param name 文件名 - * @param namelen 文件名长度 - * @param reserved 保留字段 - * @return int 合法:0, 其他:错误码 - */ -static int __check_name_available(const char *name, int namelen, int8_t reserved) -{ - if (namelen > 255 || namelen <= 0) - return -ENAMETOOLONG; - // 首个字符不能是空格或者'.' - if (name[0] == 0x20 || name[0] == '.') - return -EINVAL; - - return 0; -}; - -/** - * @brief 在procfs中创建文件 - * - * @param parent_inode 父目录的inode - * @param dest_dEntry 目标dentry - * @param mode 创建模式 - * @return long 错误码 - */ -static long procfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode) -{ - int64_t retval = 0; - - //检验名称和法性 - retval = __check_name_available(dest_dEntry->name, dest_dEntry->name_length, 0); - if (retval != 0) - return retval; - if (dest_dEntry->dir_inode != NULL) - return -EEXIST; - - struct vfs_index_node_t *inode = vfs_alloc_inode(); - dest_dEntry->dir_inode = inode; - dest_dEntry->dir_ops = &procfs_dentry_ops; - - inode->attribute = VFS_IF_FILE; - inode->file_ops = &procfs_file_ops; - inode->file_size = 0; - inode->sb = parent_inode->sb; - inode->inode_ops = &procfs_inode_ops; - // kdebug("finode:%#018lx",inode->private_inode_info); - inode->blocks = 0; - - return 0; -} -static struct vfs_dir_entry_t *procfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry) -{ - return NULL; -} - -/** - * @brief 在procfs中创建文件夹(作用是完善子文件夹的inode信息) - * - * @param inode 父目录的inode - * @param dEntry 目标dentry - * @param mode 创建模式 - * @return long 错误码 - */ -static long procfs_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dEntry, int mode) -{ - int64_t retval = 0; - - //检验名称和法性 - retval = __check_name_available(dEntry->name, dEntry->name_length, 0); - if (retval != 0) - return retval; - - struct vfs_index_node_t *inode = vfs_alloc_inode(); - dEntry->dir_inode = inode; - dEntry->dir_ops = &procfs_dentry_ops; - - //结点信息初始化 - struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0); - finode->pid = 0; - finode->type = 0; - - inode->attribute = VFS_IF_DIR; - inode->file_ops = &procfs_file_ops; - inode->file_size = 0; - inode->sb = parent_inode->sb; - inode->inode_ops = &procfs_inode_ops; - inode->private_inode_info = (void *)finode; - // kdebug("inode->private_inode_info=%#018lx", inode->private_inode_info); - inode->blocks = 0; - - return 0; -} -struct vfs_inode_operations_t procfs_inode_ops = { - .create = &procfs_create, - .lookup = &procfs_lookup, - .mkdir = &procfs_mkdir, -}; - -struct vfs_filesystem_type_t procfs_fs_type = { - .name = "procfs", - .fs_flags = 0, - .read_superblock = procfs_read_superblock, - .next = NULL, -}; - -static __always_inline void __procfs_init_root_inode() -{ - procfs_root_dentry->dir_inode = vfs_alloc_inode(); - procfs_root_dentry->dir_inode->file_ops = &procfs_file_ops; - procfs_root_dentry->dir_inode->inode_ops = &procfs_inode_ops; - - procfs_root_dentry->dir_inode->private_inode_info = NULL; - procfs_root_dentry->dir_inode->sb = &procfs_sb; - procfs_root_dentry->dir_inode->attribute = VFS_IF_DIR; -} -/** - * @brief 初始化procfs的根dentry - */ -static __always_inline void __procfs_init_root_dentry() -{ - procfs_root_dentry = vfs_alloc_dentry(0); - procfs_root_dentry->dir_ops = &procfs_dentry_ops; - - __procfs_init_root_inode(); -} - -/** - * @brief 创建进程对应文件夹 - * - * @param pid 进程号 - * @return int64_t 错误码 - */ -int64_t procfs_register_pid(long pid) -{ - int retval = 0; - - //创建文件夹 - char tmp[70] = {0}; - int len = strlen(ltoa(pid)); - // kdebug("len:%d",len); - strcpy(tmp, "/proc/"); - strcpy(tmp + 6, ltoa(pid)); - // kdebug("tmp:%s",tmp); - retval = vfs_mkdir(tmp, 0, false); - - // kdebug("aaaaaaaaaaaaaaa"); - //创建各相关文件 - strcpy(tmp + 6 + len, "/status"); - // kdebug("tmp:%s",tmp); - retval = proc_create_file(tmp, PROC_STATUS, pid); - - return retval; -} - -/** - * @brief 创建文件 - * - * @param path 文件夹路径 - * @param type 文件类型 - * @param pid pid - * @return int64_t 错误码 - */ -static int64_t proc_create_file(const char *path, mode_t type, long pid) -{ - kdebug("procfs: Creating: %s", path); - int ret = do_open(path, O_CREAT, false); - // kdebug("ret:%d", ret); - struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0); - // kdebug("dentry=%#018lx", dentry); - - //结点信息配置 - struct procfs_inode_info_t *finode = (struct procfs_inode_info_t *)kzalloc(sizeof(struct procfs_inode_info_t), 0); - finode->pid = pid; - // kdebug("pid:%d",finode->pid); - finode->type = type; - dentry->dir_inode->private_inode_info = (void *)finode; - ret = vfs_close(ret); - - return ret; -} - -/** - * @brief 初始化procfs - * - */ -void procfs_init() -{ - __procfs_init_root_dentry(); - vfs_register_filesystem(&procfs_fs_type); - spin_init(&procfs_global_lock); - vfs_mount_fs(__procfs_mount_path, "procfs", NULL); -} diff --git a/kernel/src/filesystem/procfs/procfs.h b/kernel/src/filesystem/procfs/procfs.h deleted file mode 100644 index 4bd403ad..00000000 --- a/kernel/src/filesystem/procfs/procfs.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @brief 初始化procfs - * - */ -void procfs_init(); - -/** - * @brief proc文件系统的超级块信息结构体 - * - */ -struct procfs_sb_info_t -{ - struct lockref lockref; //该lockref包含自旋锁以及引用计数 -}; - -/** - * @brief procfs文件系统的结点私有信息 - * - */ -struct procfs_inode_info_t -{ - long pid; - int type; -}; - -/** - * @brief 创建进程对应文件 - * - * @param pid 进程号 - * @return int64_t 错误码 - */ -int64_t procfs_register_pid(long pid); diff --git a/kernel/src/filesystem/ramfs/mod.rs b/kernel/src/filesystem/ramfs/mod.rs new file mode 100644 index 00000000..de4010e2 --- /dev/null +++ b/kernel/src/filesystem/ramfs/mod.rs @@ -0,0 +1,444 @@ +use core::any::Any; + +use alloc::{ + collections::BTreeMap, + string::String, + sync::{Arc, Weak}, + vec::Vec, +}; + +use crate::{ + filesystem::vfs::{core::generate_inode_id, FileType}, + include::bindings::bindings::{ + EEXIST, EINVAL, EISDIR, ENOBUFS, ENOENT, ENOTDIR, ENOTEMPTY, EPERM, + }, + libs::spinlock::{SpinLock, SpinLockGuard}, + time::TimeSpec, +}; + +use super::vfs::{ + file::FilePrivateData, FileSystem, FsInfo, IndexNode, InodeId, Metadata, PollStatus, +}; + +/// RamFS的inode名称的最大长度 +const RAMFS_MAX_NAMELEN: usize = 64; + +/// @brief 内存文件系统的Inode结构体 +#[derive(Debug)] +struct LockedRamFSInode(SpinLock); + +/// @brief 内存文件系统结构体 +#[derive(Debug)] +pub struct RamFS { + /// RamFS的root inode + root_inode: Arc, +} + +/// @brief 内存文件系统的Inode结构体(不包含锁) +#[derive(Debug)] +pub struct RamFSInode { + // parent变量目前只在find函数中使用到 + // 所以只有当inode是文件夹的时候,parent才会生效 + // 对于文件来说,parent就没什么作用了 + // 关于parent的说明: 目录不允许有硬链接 + /// 指向父Inode的弱引用 + parent: Weak, + /// 指向自身的弱引用 + self_ref: Weak, + /// 子Inode的B树 + children: BTreeMap>, + /// 当前inode的数据部分 + data: Vec, + /// 当前inode的元数据 + metadata: Metadata, + /// 指向inode所在的文件系统对象的指针 + fs: Weak, +} + +impl FileSystem for RamFS { + fn root_inode(&self) -> Arc { + return self.root_inode.clone(); + } + + fn info(&self) -> FsInfo { + return FsInfo { + blk_dev_id: 0, + max_name_len: RAMFS_MAX_NAMELEN, + }; + } + + /// @brief 本函数用于实现动态转换。 + /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self + fn as_any_ref(&self) -> &dyn Any { + self + } +} + +impl RamFS { + pub fn new() -> Arc { + // 初始化root inode + let root: Arc = Arc::new(LockedRamFSInode(SpinLock::new(RamFSInode { + parent: Weak::default(), + self_ref: Weak::default(), + children: BTreeMap::new(), + data: Vec::new(), + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: FileType::Dir, + mode: 0o777, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: 0, + }, + fs: Weak::default(), + }))); + + let result: Arc = Arc::new(RamFS { root_inode: root }); + + // 对root inode加锁,并继续完成初始化工作 + let mut root_guard: SpinLockGuard = result.root_inode.0.lock(); + root_guard.parent = Arc::downgrade(&result.root_inode); + root_guard.self_ref = Arc::downgrade(&result.root_inode); + root_guard.fs = Arc::downgrade(&result); + // 释放锁 + drop(root_guard); + + return result; + } +} + +impl IndexNode for LockedRamFSInode { + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + // 加锁 + let inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + let start = inode.data.len().min(offset); + let end = inode.data.len().min(offset + len); + + // buffer空间不足 + if buf.len() < (end - start) { + return Err(-(ENOBUFS as i32)); + } + + // 拷贝数据 + let src = &inode.data[start..end]; + buf[0..src.len()].copy_from_slice(src); + return Ok(src.len()); + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result { + if buf.len() < len { + return Err(-(EINVAL as i32)); + } + + // 加锁 + let mut inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + let data: &mut Vec = &mut inode.data; + + // 如果文件大小比原来的大,那就resize这个数组 + if offset + len > data.len() { + data.resize(offset + len, 0); + } + + let target = &mut data[offset..offset + len]; + target.copy_from_slice(&buf[0..len]); + return Ok(len); + } + + fn poll(&self) -> Result { + // 加锁 + let inode: SpinLockGuard = self.0.lock(); + + // 检查当前inode是否为一个文件夹,如果是的话,就返回错误 + if inode.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + return Ok(PollStatus { + flags: PollStatus::READ_MASK | PollStatus::WRITE_MASK, + }); + } + + fn fs(&self) -> Arc { + return self.0.lock().fs.upgrade().unwrap(); + } + + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn metadata(&self) -> Result { + let inode = self.0.lock(); + let mut metadata = inode.metadata.clone(); + metadata.size = inode.data.len() as i64; + + return Ok(metadata); + } + + fn set_metadata(&self, metadata: &Metadata) -> Result<(), i32> { + let mut inode = self.0.lock(); + inode.metadata.atime = metadata.atime; + inode.metadata.mtime = metadata.mtime; + inode.metadata.ctime = metadata.ctime; + inode.metadata.mode = metadata.mode; + inode.metadata.uid = metadata.uid; + inode.metadata.gid = metadata.gid; + + return Ok(()); + } + + fn resize(&self, len: usize) -> Result<(), i32> { + let mut inode = self.0.lock(); + if inode.metadata.file_type == FileType::File { + inode.data.resize(len, 0); + return Ok(()); + } else { + return Err(-(EINVAL as i32)); + } + } + + fn create_with_data( + &self, + name: &str, + file_type: FileType, + mode: u32, + data: usize, + ) -> Result, i32> { + // 获取当前inode + let mut inode = self.0.lock(); + // 如果当前inode不是文件夹,则返回 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + // 如果有重名的,则返回 + if inode.children.contains_key(name) { + return Err(-(EEXIST as i32)); + } + + // 创建inode + let result: Arc = Arc::new(LockedRamFSInode(SpinLock::new(RamFSInode { + parent: inode.self_ref.clone(), + self_ref: Weak::default(), + children: BTreeMap::new(), + data: Vec::new(), + metadata: Metadata { + dev_id: 0, + inode_id: generate_inode_id(), + size: 0, + blk_size: 0, + blocks: 0, + atime: TimeSpec::default(), + mtime: TimeSpec::default(), + ctime: TimeSpec::default(), + file_type: file_type, + mode: mode, + nlinks: 1, + uid: 0, + gid: 0, + raw_dev: data, + }, + fs: inode.fs.clone(), + }))); + + // 初始化inode的自引用的weak指针 + result.0.lock().self_ref = Arc::downgrade(&result); + + // 将子inode插入父inode的B树中 + inode.children.insert(String::from(name), result.clone()); + + return Ok(result); + } + + fn link(&self, name: &str, other: &Arc) -> Result<(), i32> { + let other: &LockedRamFSInode = other + .downcast_ref::() + .ok_or(-(EPERM as i32))?; + let mut inode: SpinLockGuard = self.0.lock(); + let mut other_locked: SpinLockGuard = other.0.lock(); + + // 如果当前inode不是文件夹,那么报错 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 如果另一个inode是文件夹,那么也报错 + if other_locked.metadata.file_type == FileType::Dir { + return Err(-(EISDIR as i32)); + } + + // 如果当前文件夹下已经有同名文件,也报错。 + if inode.children.contains_key(name) { + return Err(-(EEXIST as i32)); + } + + inode + .children + .insert(String::from(name), other_locked.self_ref.upgrade().unwrap()); + + // 增加硬链接计数 + other_locked.metadata.nlinks += 1; + return Ok(()); + } + + fn unlink(&self, name: &str) -> Result<(), i32> { + let mut inode: SpinLockGuard = self.0.lock(); + // 如果当前inode不是目录,那么也没有子目录/文件的概念了,因此要求当前inode的类型是目录 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + // 不允许删除当前文件夹,也不允许删除上一个目录 + if name == "." || name == ".." { + return Err(-(ENOTEMPTY as i32)); + } + + // 获得要删除的文件的inode + let to_delete = inode.children.get(name).ok_or(-(ENOENT as i32))?; + if to_delete.0.lock().metadata.file_type == FileType::Dir { + return Err(-(EPERM as i32)); + } + // 减少硬链接计数 + to_delete.0.lock().metadata.nlinks -= 1; + // 在当前目录中删除这个子目录项 + inode.children.remove(name); + return Ok(()); + } + + fn rmdir(&self, name: &str) -> Result<(), i32> { + let mut inode: SpinLockGuard = self.0.lock(); + // 如果当前inode不是目录,那么也没有子目录/文件的概念了,因此要求当前inode的类型是目录 + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + // 获得要删除的文件夹的inode + let to_delete = inode.children.get(name).ok_or(-(ENOENT as i32))?; + if to_delete.0.lock().metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + to_delete.0.lock().metadata.nlinks -= 1; + // 在当前目录中删除这个子目录项 + inode.children.remove(name); + return Ok(()); + } + + fn move_( + &self, + old_name: &str, + target: &Arc, + new_name: &str, + ) -> Result<(), i32> { + let old_inode: Arc = self.find(old_name)?; + + // 在新的目录下创建一个硬链接 + target.link(new_name, &old_inode)?; + // 取消现有的目录下的这个硬链接 + if let Err(err) = self.unlink(old_name) { + // 如果取消失败,那就取消新的目录下的硬链接 + target.unlink(new_name)?; + return Err(err); + } + return Ok(()); + } + + fn find(&self, name: &str) -> Result, i32> { + let inode = self.0.lock(); + + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match name { + "" | "." => { + return Ok(inode.self_ref.upgrade().ok_or(-(ENOENT as i32))?); + } + + ".." => { + return Ok(inode.parent.upgrade().ok_or(-(ENOENT as i32))?); + } + name => { + // 在子目录项中查找 + return Ok(inode.children.get(name).ok_or(-(ENOENT as i32))?.clone()); + } + } + } + + fn get_entry_name(&self, ino: InodeId) -> Result { + let inode: SpinLockGuard = self.0.lock(); + if inode.metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + match ino { + 0 => { + return Ok(String::from(".")); + } + 1 => { + return Ok(String::from("..")); + } + ino => { + // 暴力遍历所有的children,判断inode id是否相同 + // TODO: 优化这里,这个地方性能很差! + let mut key: Vec = inode + .children + .keys() + .filter(|k| inode.children.get(*k).unwrap().0.lock().metadata.inode_id == ino) + .cloned() + .collect(); + + match key.len() { + 0=>{return Err(-(ENOENT as i32));} + 1=>{return Ok(key.remove(0));} + _ => panic!("Ramfs get_entry_name: key.len()={key_len}>1, current inode_id={inode_id}, to find={to_find}", key_len=key.len(), inode_id = inode.metadata.inode_id, to_find=ino) + } + } + } + } + + fn list(&self) -> Result, i32> { + let info = self.metadata()?; + if info.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + let mut keys: Vec = Vec::new(); + keys.push(String::from(".")); + keys.push(String::from("..")); + keys.append(&mut self.0.lock().children.keys().cloned().collect()); + + return Ok(keys); + } +} diff --git a/kernel/src/filesystem/rootfs/Makefile b/kernel/src/filesystem/rootfs/Makefile deleted file mode 100644 index 2228ba3a..00000000 --- a/kernel/src/filesystem/rootfs/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - -CFLAGS += -I . - - -kernel_fs_rootfs_objs:= $(shell find ./*.c) - - -ECHO: - @echo "$@" - - -$(kernel_fs_rootfs_objs): ECHO - $(CC) $(CFLAGS) -c $@ -o $@.o - - -all: $(kernel_fs_rootfs_objs) - diff --git a/kernel/src/filesystem/rootfs/mod.rs b/kernel/src/filesystem/rootfs/mod.rs deleted file mode 100644 index 8b137891..00000000 --- a/kernel/src/filesystem/rootfs/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/kernel/src/filesystem/rootfs/rootfs.c b/kernel/src/filesystem/rootfs/rootfs.c deleted file mode 100644 index 5eb9c911..00000000 --- a/kernel/src/filesystem/rootfs/rootfs.c +++ /dev/null @@ -1,228 +0,0 @@ -#include "rootfs.h" -#include -#include -#include - -static struct vfs_superblock_t rootfs_sb = {0}; -extern struct vfs_superblock_t *vfs_root_sb; - -/** - * @brief 释放dentry本身所占的内存 - * - * @param dentry - */ -static inline void __release_dentry(struct vfs_dir_entry_t *dentry) -{ - kfree(dentry->name); - kfree(dentry); -} - -struct vfs_super_block_operations_t rootfs_sb_ops = { - .put_superblock = NULL, - .write_inode = NULL, - .write_superblock = NULL, -}; - -static struct vfs_dir_entry_t *rootfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry) -{ - return NULL; -} -struct vfs_inode_operations_t rootfs_inode_ops = { - .create = NULL, - .getAttr = NULL, - .lookup = NULL, - .lookup = &rootfs_lookup, - .mkdir = NULL, - .rename = NULL, - .rmdir = NULL, - .setAttr = NULL, -}; - -static long rootfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - return 0; -} -static long rootfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) { return 0; } -static long rootfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; } -static long rootfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) { return 0; } -static long rootfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) { return 0; } -static long rootfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; } - -static long rootfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler) -{ - // 循环读取目录下的目录项 - struct vfs_dir_entry_t *dentry = file_ptr->dEntry; - struct List *list = &dentry->subdirs_list; - // 先切换到position处 - for (int i = 0; i <= file_ptr->position; ++i) - { - list = list_next(list); - if (list == &dentry->subdirs_list) // 找完了 - goto failed; - } - - // 存在目录项 - // 增加偏移量 - ++file_ptr->position; - // 获取目标dentry(由于是子目录项,因此是child_node_list) - struct vfs_dir_entry_t *target_dent = container_of(list, struct vfs_dir_entry_t, child_node_list); - // kdebug("target name=%s, namelen=%d", target_dent->name, target_dent->name_length); - - char *name = (char *)kzalloc(target_dent->name_length + 1, 0); - strncpy(name, target_dent->name, target_dent->name_length); - - uint32_t dentry_type = target_dent->dir_inode->attribute; - - return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1); -failed:; - return 0; -} - -static long rootfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) { return 0; } - -static long rootfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) { return 0; } - -static long rootfs_release(struct vfs_dir_entry_t *dEntry) { return 0; } - -static long rootfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) { return 0; } - -struct vfs_dir_entry_operations_t rootfs_dentry_ops = - { - .compare = &rootfs_compare, - .hash = &rootfs_hash, - .release = &rootfs_release, - .iput = &rootfs_iput, -}; - -struct vfs_file_operations_t rootfs_file_ops = { - .open = &rootfs_open, - .close = &rootfs_close, - .read = &rootfs_read, - .write = &rootfs_write, - .lseek = &rootfs_lseek, - .ioctl = &rootfs_ioctl, - .readdir = &rootfs_readdir, -}; - -/** - * @brief 为在rootfs下创建目录(仅仅是形式上的目录,为了支持文件系统挂载) - * - * @param name 目录名称 - * @return int - */ -static int rootfs_add_dir(const char *name) -{ - { - // 检查名称重复 - struct List *list = &rootfs_sb.root->subdirs_list; - while (list_next(list) != &rootfs_sb.root->subdirs_list) - { - list = list_next(list); - struct vfs_dir_entry_t *tmp = container_of(list, struct vfs_dir_entry_t, child_node_list); - if (strcmp(tmp->name, name) == 0) - return -EEXIST; - } - } - - struct vfs_dir_entry_t *dentry = vfs_alloc_dentry(strlen(name) + 1); - strcpy(dentry->name, name); - dentry->name_length = strlen(name); - dentry->parent = rootfs_sb.root; - list_append(&rootfs_sb.root->subdirs_list, &dentry->child_node_list); - return 0; -} - -void rootfs_init() -{ - // 初始化超级块 - rootfs_sb.blk_device = NULL; - rootfs_sb.private_sb_info = NULL; - rootfs_sb.sb_ops = &rootfs_sb_ops; - rootfs_sb.dir_ops = &rootfs_dentry_ops; - - // 初始化dentry - rootfs_sb.root = vfs_alloc_dentry(sizeof("/")); - struct vfs_dir_entry_t *dentry = rootfs_sb.root; - strncpy(dentry->name, "/", 2); - dentry->name_length = 1; - dentry->parent = dentry; - - // 初始化root inode - dentry->dir_inode = vfs_alloc_inode(); - dentry->dir_inode->sb = &rootfs_sb; - dentry->dir_inode->inode_ops = &rootfs_inode_ops; - dentry->dir_inode->file_ops = &rootfs_file_ops; - dentry->dir_inode->attribute = VFS_IF_DIR; - - // 直接将vfs的根superblock设置为rootfs的超级块 - vfs_root_sb = &rootfs_sb; - - // 创建/dev等目录的dentry(以便文件系统的mount) - if (rootfs_add_dir("dev") != 0) - kerror("create dir 'dev' in rootfs failed"); - - // 创建/procfs目录的dentry - if (rootfs_add_dir("proc") != 0) - kerror("create dir 'proc' in rootfs failed"); -} - -/** - * @brief 当新的根文件系统被挂载后,将原有的挂载在rootfs下的文件系统,迁移到新的根文件系统上 - * - */ -static void rootfs_migrate() -{ - kdebug("Migrating rootfs's dentries..."); - struct List *list = &rootfs_sb.root->subdirs_list; - if (unlikely(list_empty(list))) - return; - list = list_next(list); - while (list != &rootfs_sb.root->subdirs_list) - { - - struct vfs_dir_entry_t *tmp = container_of(list, struct vfs_dir_entry_t, child_node_list); - if (tmp->dir_inode != NULL) - { - list = list_next(list); // 获取下一个列表结点(不然的话下面的几行代码就覆盖掉了正确的值了) - - tmp->parent = vfs_root_sb->root; - list_init(&tmp->child_node_list); - list_append(&vfs_root_sb->root->subdirs_list, &tmp->child_node_list); - } - else - { - list = list_next(list); // 不迁移空的dentry,直接释放他们 - list_del(&tmp->child_node_list); - __release_dentry(tmp); - } - } -} - -/** - * @brief 当磁盘文件系统被成功挂载后,释放rootfs所占的空间 - * - */ -void rootfs_umount() -{ - // 将原有的“dev”文件夹等进行迁移 - rootfs_migrate(); - kinfo("Umounting rootfs..."); - - // 遍历mount链表,删除所有父目录是rootfs的dentry - struct mountpoint *mp = NULL; - while (1) - { - mp = mount_find_mnt_list_by_parent(rootfs_sb.root); - if (mp == NULL) - break; - - // 释放dentry(由于没有创建inode,因此不需要释放) - __release_dentry(mp->dentry); - // 释放mountpoint结构体 - mount_release_mountpoint(mp); - } - - // 释放root dentry及其inode - kfree(rootfs_sb.root->dir_inode); - __release_dentry(rootfs_sb.root); -} \ No newline at end of file diff --git a/kernel/src/filesystem/rootfs/rootfs.h b/kernel/src/filesystem/rootfs/rootfs.h deleted file mode 100644 index f9cadee3..00000000 --- a/kernel/src/filesystem/rootfs/rootfs.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -void rootfs_init(); - -/** - * @brief 当磁盘文件系统被成功挂载后,释放rootfs所占的空间 - * - */ -void rootfs_umount(); \ No newline at end of file diff --git a/kernel/src/filesystem/vfs/Makefile b/kernel/src/filesystem/vfs/Makefile deleted file mode 100644 index ff78a304..00000000 --- a/kernel/src/filesystem/vfs/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - -CFLAGS += -I . - - -kernel_fs_vfs_objs:= $(shell find ./*.c) - - -ECHO: - @echo "$@" - - -$(kernel_fs_vfs_objs): ECHO - $(CC) $(CFLAGS) -c $@ -o $@.o - - -all: $(kernel_fs_vfs_objs) - diff --git a/kernel/src/filesystem/vfs/VFS.c b/kernel/src/filesystem/vfs/VFS.c deleted file mode 100644 index dfa817aa..00000000 --- a/kernel/src/filesystem/vfs/VFS.c +++ /dev/null @@ -1,898 +0,0 @@ -#include "VFS.h" -#include "internal.h" -#include "mount.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// 为filesystem_type_t结构体实例化一个链表头 -static struct vfs_filesystem_type_t vfs_fs = {"filesystem", 0}; -struct vfs_superblock_t *vfs_root_sb = NULL; - -struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size); - -/** - * @brief 挂载文件系统 - * - * @param path 要挂载到的路径 - * @param name 文件系统名 - * @param blk 块设备结构体 - * @return struct vfs_superblock_t* 挂载后,文件系统的超级块 - */ -struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk) -{ - - // 判断挂载点是否存在 - struct vfs_dir_entry_t *target_dentry = NULL; - - target_dentry = vfs_path_walk(path, 0); - if (target_dentry == NULL) - return NULL; - - struct vfs_filesystem_type_t *p = NULL; - for (p = &vfs_fs; p; p = p->next) - { - if (!strcmp(p->name, name)) // 存在符合的文件系统 - { - struct vfs_superblock_t *sb = p->read_superblock(blk); - if (strcmp(path, "/") == 0) // 如果挂载到的是'/'挂载点,则让其成为最顶层的文件系统 - { - vfs_root_sb = sb; - } - else - { - kdebug("to mount %s", name); - // 调用mount机制,挂载文件系统 - struct vfs_dir_entry_t *new_dentry = sb->root; - // 注意,umount的时候需要释放这些内存 - new_dentry->name = kzalloc(target_dentry->name_length + 1, 0); - new_dentry->name_length = target_dentry->name_length; - - do_mount(target_dentry, new_dentry); - } - return sb; - } - } - - kdebug("unsupported fs: %s", name); - return NULL; -} - -/** - * @brief 在VFS中注册文件系统 - * - * @param fs 文件系统类型结构体 - * @return uint64_t - */ -uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs) -{ - struct vfs_filesystem_type_t *p = NULL; - for (p = &vfs_fs; p; p = p->next) - { - if (!strcmp(p->name, fs->name)) // 已经注册相同名称的文件系统 - return -EEXIST; - } - - fs->next = vfs_fs.next; - vfs_fs.next = fs; - return 0; -} - -uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs) -{ - struct vfs_filesystem_type_t *p = &vfs_fs; - while (p->next) - { - if (p->next == fs) - { - p->next = p->next->next; - fs->next = NULL; - return 0; - } - else - p = p->next; - } - return -EINVAL; -} - -/** - * @brief 在dentry的sub_dir_list中搜索指定名称的dentry - * - * @param dentry 目录项结构体dentry - * @param name 待搜索的dentry名称 - * @return struct vfs_dir_entry_t* 目标dentry (无结果则返回NULL) - */ -static struct vfs_dir_entry_t *vfs_search_dentry_list(struct vfs_dir_entry_t *dentry, const char *name) -{ - if (list_empty(&dentry->subdirs_list)) - return NULL; - - struct List *ptr = &dentry->subdirs_list; - struct vfs_dir_entry_t *d_ptr = NULL; - do - { - ptr = list_next(ptr); - d_ptr = container_of(ptr, struct vfs_dir_entry_t, child_node_list); - if (strcmp(name, d_ptr->name) == 0) - return d_ptr; - } while (list_next(ptr) != (&dentry->subdirs_list)); - - return NULL; -} - -/** - * @brief 按照路径查找文件 - * - * @param path 路径 - * @param flags 1:返回父目录项, 0:返回结果目录项 - * @return struct vfs_dir_entry_t* 目录项 - */ -struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags) -{ - - struct vfs_dir_entry_t *parent = vfs_root_sb->root; - // 去除路径前的斜杠 - while (*path == '/') - ++path; - - if ((!*path) || (*path == '\0')) - return parent; - - struct vfs_dir_entry_t *dentry = NULL; - // kdebug("path before walk:%s", path); - while (true) - { - // 提取出下一级待搜索的目录名或文件名,并保存在dEntry_name中 - const char *tmp_path = path; - while ((*path && *path != '\0') && (*path != '/')) - ++path; - int tmp_path_len = path - tmp_path; - // 搜索是否有dentry缓存 - { - char *tmpname = kzalloc(tmp_path_len + 1, 0); - strncpy(tmpname, tmp_path, tmp_path_len); - tmpname[tmp_path_len] = '\0'; - // kdebug("tmpname=%s", tmpname); - dentry = vfs_search_dentry_list(parent, tmpname); - - kfree(tmpname); - } - - // 如果没有找到dentry缓存,则申请新的dentry - if (dentry == NULL) - { - dentry = vfs_alloc_dentry(tmp_path_len + 1); - - memcpy(dentry->name, (void *)tmp_path, tmp_path_len); - dentry->name[tmp_path_len] = '\0'; - // kdebug("tmp_path_len=%d, dentry->name=%s", tmp_path_len, dentry->name); - dentry->name_length = tmp_path_len; - - if (parent->dir_inode->inode_ops->lookup(parent->dir_inode, dentry) == NULL) - { - // 搜索失败 - // kwarn("cannot find the file/dir : %s", dentry->name); - kfree(dentry->name); - kfree(dentry); - return NULL; - } - // 找到子目录项 - dentry->parent = parent; - - list_add(&parent->subdirs_list, &dentry->child_node_list); - } - - while (*path == '/') - ++path; - - if ((!*path) || (*path == '\0')) // 已经到达末尾 - { - if (flags & 1) // 返回父目录 - { - return parent; - } - - return dentry; - } - - parent = dentry; - } -} - -/** - * @brief 填充dentry - * - * @return dirent的总大小 - */ -int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset) -{ - struct dirent *dent = (struct dirent *)buf; - - // 如果尝试访问内核空间,则返回错误 - if (!(verify_area((uint64_t)buf, sizeof(struct dirent) + namelen))) - return -EFAULT; - - // ====== 填充dirent结构体 ===== - memset(buf, 0, sizeof(struct dirent) + namelen); - - memcpy(dent->d_name, name, namelen); - dent->d_name[namelen] = '\0'; - // 暂时不显示目录下的记录数 - dent->d_reclen = 0; - dent->d_ino = d_ino; - dent->d_off = offset; - dent->d_type = type; - - // 返回dirent的总大小 - return sizeof(struct dirent) + namelen; -} - -/** - * @brief 创建文件夹 - * - * @param path 文件夹路径 - * @param mode 创建模式 - * @param from_userland 该创建请求是否来自用户态 - * @return int64_t 错误码 - */ -int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland) -{ - uint32_t pathlen; - int retval = 0; - if (from_userland) - pathlen = strnlen_user(path, PAGE_4K_SIZE - 1); - else - pathlen = strnlen(path, PAGE_4K_SIZE - 1); - - if (pathlen == 0) - return -ENOENT; - - int last_slash = -1; - - // 查找最后一个'/',忽略路径末尾的'/' - for (int i = pathlen - 2; i >= 0; --i) - { - if (path[i] == '/') - { - last_slash = i; - break; - } - } - - // 路径格式不合法(必须使用绝对路径) - if (last_slash < 0) - return -ENOTDIR; - - char *buf = (char *)kzalloc(last_slash + 2, 0); - - // 拷贝字符串(不包含要被创建的部分) - if (from_userland) - strncpy_from_user(buf, path, last_slash); - else - strncpy(buf, path, last_slash); - buf[last_slash + 1] = '\0'; - - // 查找父目录 - struct vfs_dir_entry_t *parent_dir = vfs_path_walk(buf, 0); - - if (parent_dir == NULL) - { - kwarn("parent dir is NULL."); - kfree(buf); - return -ENOENT; - } - kfree(buf); - - // 检查父目录中是否已经有相同的目录项 - if (vfs_path_walk((const char *)path, 0) != NULL) - { - // 目录中已有对应的文件夹 - kwarn("Dir '%s' aleardy exists.", path); - return -EEXIST; - } - spin_lock(&parent_dir->lockref.lock); - struct vfs_dir_entry_t *subdir_dentry = vfs_alloc_dentry(pathlen - last_slash); - - if (path[pathlen - 1] == '/') - subdir_dentry->name_length = pathlen - last_slash - 2; - else - subdir_dentry->name_length = pathlen - last_slash - 1; - - for (int i = last_slash + 1, cnt = 0; i < pathlen && cnt < subdir_dentry->name_length; ++i, ++cnt) - subdir_dentry->name[cnt] = path[i]; - // 设置subdir的dentry的父路径 - subdir_dentry->parent = parent_dir; - - // kdebug("to mkdir, parent name=%s", parent_dir->name); - spin_lock(&parent_dir->dir_inode->lockref.lock); - retval = parent_dir->dir_inode->inode_ops->mkdir(parent_dir->dir_inode, subdir_dentry, 0); - spin_unlock(&parent_dir->dir_inode->lockref.lock); - - if (retval != 0) - { - if (vfs_dentry_put(parent_dir) != 0) // 释放dentry - spin_unlock(&parent_dir->lockref.lock); - return retval; - } - - // 获取append前一个dentry并加锁 - struct List *target_list = &parent_dir->subdirs_list; - // kdebug("target_list=%#018lx target_list->prev=%#018lx",target_list,target_list->prev); - if (list_empty(target_list) == false) - { - struct vfs_dir_entry_t *prev_dentry = list_entry(target_list->prev, struct vfs_dir_entry_t, child_node_list); - // kdebug("prev_dentry%#018lx",prev_dentry); - spin_lock(&prev_dentry->lockref.lock); - list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list); - // kdebug("retval = %d", retval); - spin_unlock(&prev_dentry->lockref.lock); - } - else - { - list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list); - goto out; - } - -out:; - spin_unlock(&parent_dir->lockref.lock); - return retval; -} - -/** - * @brief 创建文件夹 - * - * @param path(r8) 路径 - * @param mode(r9) 模式 - * @return uint64_t - */ -uint64_t sys_mkdir(struct pt_regs *regs) -{ - const char *path = (const char *)regs->r8; - // kdebug("path = %s", path); - mode_t mode = (mode_t)regs->r9; - - if (user_mode(regs)) - return vfs_mkdir(path, mode, true); - else - return vfs_mkdir(path, mode, false); -} - -/** - * @brief 打开文件 - * - * @param filename 文件路径 - * @param flags 标志位 - * @param from_user 是否由用户态调用,1为是,0为否 - * @return uint64_t 错误码 - */ -uint64_t do_open(const char *filename, int flags, bool from_user) -{ - long path_len = 0; - if (from_user) - path_len = strnlen_user(filename, PAGE_4K_SIZE) + 1; - else - path_len = strnlen(filename, PAGE_4K_SIZE) + 1; - - if (path_len <= 0) // 地址空间错误 - return -EFAULT; - else if (path_len >= PAGE_4K_SIZE) // 名称过长 - return -ENAMETOOLONG; - - // 为待拷贝文件路径字符串分配内存空间 - char *path = (char *)kzalloc(path_len, 0); - if (path == NULL) - return -ENOMEM; - - if (from_user) - strncpy_from_user(path, filename, path_len); - else - strncpy(path, filename, path_len); - - // 去除末尾的 '/' - if (path_len >= 2 && path[path_len - 2] == '/') - { - path[path_len - 2] = '\0'; - --path_len; - } - - // 寻找文件 - struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0); - if (dentry == NULL && flags & O_CREAT) - { - // 先找到倒数第二级目录 - int tmp_index = -1; - for (int i = path_len - 1; i >= 0; --i) - { - if (path[i] == '/') - { - tmp_index = i; - break; - } - } - - struct vfs_dir_entry_t *parent_dentry = NULL; - // kdebug("tmp_index=%d", tmp_index); - if (tmp_index > 0) - { - - path[tmp_index] = '\0'; - parent_dentry = vfs_path_walk(path, 0); - if (parent_dentry == NULL) - { - kfree(path); - return -ENOENT; - } - } - else - { - parent_dentry = vfs_root_sb->root; - } - // 创建新的文件 - dentry = vfs_alloc_dentry(path_len - tmp_index); - - dentry->name_length = path_len - tmp_index - 2; - - // kdebug("to create new file:%s namelen=%d", dentry->name, dentry->name_length); - strncpy(dentry->name, path + tmp_index + 1, dentry->name_length); - dentry->parent = parent_dentry; - - // 对父目录项加锁 - spin_lock(&parent_dentry->lockref.lock); - spin_lock(&parent_dentry->dir_inode->lockref.lock); - // 创建子目录项 - uint64_t retval = parent_dentry->dir_inode->inode_ops->create(parent_dentry->dir_inode, dentry, 0); - spin_unlock(&parent_dentry->dir_inode->lockref.lock); // 解锁inode - - if (retval != 0) - { - if (vfs_dentry_put(dentry) != 0) // 释放dentry - BUG_ON(1); - BUG_ON(1); - kfree(path); - spin_unlock(&parent_dentry->lockref.lock); - return retval; - } - - // ==== 将子目录项添加到链表 ==== - struct vfs_dir_entry_t *next_dentry = NULL; - // 若list非空,则对前一个dentry加锁 - if (!list_empty(&parent_dentry->subdirs_list)) - { - next_dentry = list_entry(list_next(&parent_dentry->subdirs_list), struct vfs_dir_entry_t, child_node_list); - spin_lock(&next_dentry->lockref.lock); - } - list_add(&parent_dentry->subdirs_list, &dentry->child_node_list); - if (next_dentry != NULL) - spin_unlock(&next_dentry->lockref.lock); - - // 新建文件结束,对父目录项解锁 - spin_unlock(&parent_dentry->lockref.lock); - // kdebug("created."); - } - - kfree(path); - if (dentry == NULL) - { - return -ENOENT; - } - spin_lock(&dentry->lockref.lock); - // 要求打开文件夹而目标不是文件夹 - if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_IF_DIR)) - { - spin_unlock(&dentry->lockref.lock); - return -ENOTDIR; - } - // 创建文件描述符 - struct vfs_file_t *file_ptr = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0); - - int errcode = -1; - - file_ptr->dEntry = dentry; - file_ptr->mode = flags; - - file_ptr->file_ops = dentry->dir_inode->file_ops; - - // 如果文件系统实现了打开文件的函数 - if (file_ptr->file_ops && file_ptr->file_ops->open) - errcode = file_ptr->file_ops->open(dentry->dir_inode, file_ptr); - - if (errcode != 0) - { - kfree(file_ptr); - spin_unlock(&dentry->lockref.lock); - return -EFAULT; - } - - if (file_ptr->mode & O_TRUNC) // 清空文件 - file_ptr->dEntry->dir_inode->file_size = 0; - - if (file_ptr->mode & O_APPEND) - file_ptr->position = file_ptr->dEntry->dir_inode->file_size; - else - file_ptr->position = 0; - - int fd_num = process_fd_alloc(file_ptr); - - // 指针数组没有空位了 - if (fd_num == -1) - { - kfree(file_ptr); - spin_unlock(&dentry->lockref.lock); - return -ENFILE; - } - spin_unlock(&dentry->lockref.lock); - return fd_num; -} - -uint64_t sys_open(struct pt_regs *regs) -{ - char *filename = (char *)(regs->r8); - int flags = (int)(regs->r9); - return do_open(filename, flags, true); -} - -/** - * @brief 关闭文件 - * - * @param fd_num 文件描述符 - * @return uint64_t 错误码 - */ -uint64_t vfs_close(int fd_num) -{ - // 校验文件描述符范围 - if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) - return -EBADF; - // 文件描述符不存在 - if (current_pcb->fds[fd_num] == NULL) - return -EBADF; - struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; - uint64_t ret; - // If there is a valid close function - if (file_ptr->file_ops && file_ptr->file_ops->close) - ret = file_ptr->file_ops->close(file_ptr->dEntry->dir_inode, file_ptr); - - kfree(file_ptr); - current_pcb->fds[fd_num] = NULL; - return 0; -} -/** - * @brief 动态分配dentry以及路径字符串名称 - * - * @param name_size 名称字符串大小(字节)(注意考虑字符串最后需要有一个‘\0’作为结尾) - * @return struct vfs_dir_entry_t* 创建好的dentry - */ -struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size) -{ - if (unlikely(name_size > VFS_MAX_PATHLEN)) - return NULL; - struct vfs_dir_entry_t *dentry = (struct vfs_dir_entry_t *)kzalloc(sizeof(struct vfs_dir_entry_t), 0); - if (unlikely(dentry == NULL)) - return NULL; - if (name_size != 0) - dentry->name = (char *)kzalloc(name_size, 0); - - // 初始化lockref - spin_init(&dentry->lockref.lock); - dentry->lockref.count = 1; - // 初始化链表 - list_init(&dentry->child_node_list); - list_init(&dentry->subdirs_list); - return dentry; -} - -/** - * @brief 判断是否可以删除指定的dentry - * - * 1、我们不能删除一个只读的dentry - * 2、我们应当对这个dentry的inode拥有写、执行权限(暂时还没有实现权限) - * 3、如果dentry指向的是文件夹,而isdir为false,则不能删除 - * 3、如果dentry指向的是文件,而isdir为true,则不能删除 - * @param dentry 将要被删除的dentry - * @param isdir 是否要删除文件夹 - * @return int 错误码 - */ -int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir) -{ - // 当dentry没有inode的时候,认为是bug - BUG_ON(dentry->dir_inode == NULL); - - // todo: 进行权限检查 - - if (isdir) // 要删除文件夹 - { - if (!D_ISDIR(dentry)) - return -ENOTDIR; - else if (IS_ROOT(dentry)) - return -EBUSY; - } - else if (D_ISDIR(dentry)) // 要删除文件但是当前是文件夹 - return -EISDIR; - - return 0; -} - -/** - * @brief 删除文件夹 - * - * @param path 文件夹路径 - * @param from_userland 请求是否来自用户态 - * @return int64_t 错误码 - */ -int64_t vfs_rmdir(const char *path, bool from_userland) -{ - uint32_t pathlen; - int retval = 0; - if (from_userland) - pathlen = strnlen_user(path, PAGE_4K_SIZE - 1); - else - pathlen = strnlen(path, PAGE_4K_SIZE - 1); - - if (pathlen == 0) - return -ENOENT; - - int last_slash = -1; - - // 去除末尾的'/' - for (int i = pathlen - 1; i >= 0; --i) - { - if (path[i] != '/') - { - last_slash = i + 1; - break; - } - } - - // 路径格式不合法 - if (last_slash < 0) - return -ENOTDIR; - else if (path[0] != '/') - return -EINVAL; - - char *buf = (char *)kzalloc(last_slash + 2, 0); - - // 拷贝字符串(不包含要被创建的部分) - if (from_userland) - strncpy_from_user(buf, path, last_slash); - else - strncpy(buf, path, last_slash); - buf[last_slash + 1] = '\0'; - - struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0); - - kfree(buf); - - if (dentry == NULL) - { - retval = -ENOENT; - goto out0; - } - - // todo: 检查文件夹是否为空 - - spin_lock(&dentry->lockref.lock); - retval = vfs_may_delete(dentry, true); - if (retval != 0) - goto out1; - // todo: 对dentry和inode加锁 - retval = -EBUSY; - if (is_local_mountpoint(dentry)) - goto out1; - // todo: - retval = dentry->dir_inode->inode_ops->rmdir(dentry->dir_inode, dentry); - if (retval != 0) - { - BUG_ON(1); - goto out1; - } - - dentry->dir_inode->attribute |= VFS_IF_DEAD; // 将当前inode标记为dead - dont_mount(dentry); // 将当前dentry标记为不可被挂载 - detach_mounts(dentry); // 清理同样挂载在该路径的所有挂载点的挂载树 - - // 释放dentry - retval = vfs_dentry_put(dentry); - - if (retval != 0) - goto out1; - goto out0; -out2:; - spin_unlock(&dentry->dir_inode->lockref.lock); -out1:; - spin_unlock(&dentry->lockref.lock); -out0:; - return retval; -} - -/** - * @brief unlink a filesystem object - * - * 调用者必须持有parent_inode->lockref.lock - * - * @param mnt_userns 暂时未使用 用户命名空间. 请置为NULL - * @param parent_inode 父目录项的inode - * @param dentry 要被删除的目录项 - * @param delegated_inode 暂未使用,请置为NULL - * @return int - */ -int vfs_unlink(struct user_namespace *mnt_userns, struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dentry, - struct vfs_index_node_t **delegated_inode) -{ - // 暂时不支持用户命名空间,因此发出警告 - if (unlikely(mnt_userns != NULL)) - { - WARN_ON(1); - return -EINVAL; - } - - int retval = 0; - struct vfs_index_node_t *target = dentry->dir_inode; - - retval = vfs_may_delete(dentry, false); - if (unlikely(retval != 0)) - return retval; - - // 没有unlink方法,则不允许删除 - if (!parent_inode->inode_ops->unlink) - return -EPERM; - - // 对inode加锁 - spin_lock(&target->lockref.lock); - - if (is_local_mountpoint(dentry)) - retval = -EBUSY; - else - { - retval = parent_inode->inode_ops->unlink(parent_inode, dentry); - if (retval == 0) - { - dont_mount(dentry); - detach_mounts(dentry); - } - } - - spin_unlock(&target->lockref.lock); - -out:; - return retval; -} -/** - * @brief 取消dentry和inode之间的链接 - * - * @param dfd 进程相对路径基准目录的文件描述符(fcntl.h) - * @param pathname 路径 - * @param from_userland 请求是否来自用户态 - * @return int 错误码 - */ -int do_unlink_at(int dfd, const char *pathname, bool from_userland) -{ - // 暂时不支持相对路径,只支持绝对路径 - if (dfd & AT_FDCWD) - { - kwarn("Not support: AT_FDCWD"); - return -EINVAL; - } - - uint32_t pathlen; - int retval = 0; - if (from_userland) - pathlen = strnlen_user(pathname, PAGE_4K_SIZE - 1); - else - pathlen = strnlen(pathname, PAGE_4K_SIZE - 1); - - if (pathlen == 0) - return -ENOENT; - - int last_slash = -1; - - // 去除末尾的'/' - for (int i = pathlen - 1; i >= 0; --i) - { - if (pathname[i] != '/') - { - last_slash = i + 1; - break; - } - } - - // 路径格式不合法 - if (last_slash < 0) - return -ENOTDIR; - else if (pathname[0] != '/') - return -EINVAL; - - char *buf = (char *)kzalloc(last_slash + 1, 0); - - // 拷贝字符串 - if (from_userland) - strncpy_from_user(buf, pathname, last_slash); - else - strncpy(buf, pathname, last_slash); - buf[last_slash] = '\0'; - - struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0); - kfree(buf); - - if (dentry == NULL || dentry->parent == NULL) - { - retval = -ENOENT; - goto out; - } - - struct vfs_index_node_t *p_inode = dentry->parent->dir_inode; - // 对父inode加锁 - spin_lock(&p_inode->lockref.lock); - spin_lock(&dentry->lockref.lock); - retval = vfs_unlink(NULL, dentry->parent->dir_inode, dentry, NULL); - if (unlikely(retval != 0)) - { - // kdebug("retval=%d", retval); - spin_unlock(&dentry->lockref.lock); - spin_unlock(&p_inode->lockref.lock); - goto out; - } - // kdebug("vfs_dentry_put=%d", retval); - spin_unlock(&dentry->lockref.lock); - spin_unlock(&p_inode->lockref.lock); - - if (IS_ERR_VALUE(retval)) - kwarn("In do_unlink_at: dentry put failed; retval=%d", retval); - else - retval = 0; -out:; - return retval; -} - -/** - * @brief 删除文件夹、取消文件的链接、删除文件的系统调用 - * - * @param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h) - * @param regs->r9 路径名称字符串 - * @param regs->r10 flag 预留的标志位,暂时未使用,请置为0。 - * @return uint64_t 错误码 - */ -uint64_t sys_unlink_at(struct pt_regs *regs) -{ - int dfd = regs->r8; - const char *pathname = (const char *)regs->r9; - int flag = regs->r10; - bool from_user = SYSCALL_FROM_USER(regs) ? true : false; - if ((flag & (~AT_REMOVEDIR)) != 0) - return -EINVAL; - if (flag & AT_REMOVEDIR) - return vfs_rmdir(pathname, from_user); - // kdebug("to do_unlink_at, path=%s", pathname); - return do_unlink_at(dfd, pathname, from_user); -} - -/** - * @brief 分配inode并将引用计数初始化为1 - * - * @return struct vfs_index_node_t * 分配得到的inode - */ -struct vfs_index_node_t *vfs_alloc_inode() -{ - struct vfs_index_node_t *inode = kzalloc(sizeof(struct vfs_index_node_t), 0); - spin_init(&inode->lockref.lock); - inode->lockref.count = 1; // 初始化引用计数为1 - return inode; -} - -/** - * @brief 初始化vfs - * - * @return int 错误码 - */ -int vfs_init() -{ - mount_init(); - rootfs_init(); - return 0; -} \ No newline at end of file diff --git a/kernel/src/filesystem/vfs/VFS.h b/kernel/src/filesystem/vfs/VFS.h index 218737ab..4675d9b2 100644 --- a/kernel/src/filesystem/vfs/VFS.h +++ b/kernel/src/filesystem/vfs/VFS.h @@ -16,10 +16,9 @@ #include #include #include +#include #include -extern struct vfs_superblock_t *vfs_root_sb; - #define VFS_DPT_MBR 0 // MBR分区表 #define VFS_DPT_GPT 1 // GPT分区表 @@ -193,102 +192,9 @@ struct vfs_file_operations_t long (*readdir)(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler); // 读取文件夹 }; -/** - * @brief 在VFS中注册文件系统 - * - * @param fs 文件系统类型结构体 - * @return uint64_t - */ -uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs); -uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs); - -/** - * @brief 挂载文件系统 - * - * @param path 要挂载到的路径 - * @param name 文件系统名 - * @param blk 块设备结构体 - * @return struct vfs_superblock_t* 挂载后,文件系统的超级块 - */ -struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk); - -/** - * @brief 按照路径查找文件 - * - * @param path 路径 - * @param flags 1:返回父目录项, 0:返回结果目录项 - * @return struct vfs_dir_entry_t* 目录项 - */ -struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags); - -/** - * @brief 填充dentry - * - */ -int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset); - /** * @brief 初始化vfs * * @return int 错误码 */ -int vfs_init(); - -/** - * @brief 动态分配dentry以及路径字符串名称 - * - * @param name_size 名称字符串大小(字节)(注意考虑字符串最后需要有一个‘\0’作为结尾) - * @return struct vfs_dir_entry_t* 创建好的dentry - */ -struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size); - -/** - * @brief 分配inode并将引用计数初始化为1 - * - * @return struct vfs_index_node_t * 分配得到的inode - */ -struct vfs_index_node_t *vfs_alloc_inode(); - -uint64_t do_open(const char *filename, int flags, bool from_user); - -/** - * @brief 关闭文件 - * - * @param fd_num 文件描述符 - * @return uint64_t 错误码 - */ -uint64_t vfs_close(int fd_num); - -/** - * @brief 创建文件夹 - * - * @param path 文件夹路径 - * @param mode 创建模式 - * @param from_userland 该创建请求是否来自用户态 - * @return int64_t 错误码 - */ -int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland); - -/** - * @brief 删除文件夹 - * - * @param path 文件夹路径 - * @param from_userland 请求是否来自用户态 - * @return int64_t 错误码 - */ -int64_t vfs_rmdir(const char *path, bool from_userland); - -/** - * @brief 释放dentry,并视情况自动释放inode。 在调用该函数前,需要将dentry加锁。 - * - * @param dentry 目标dentry - * - * @return 错误码 - * 注意,当dentry指向文件时,如果返回值为正数,则表示在释放了该dentry后,该dentry指向的inode的引用计数。 - */ -int vfs_dentry_put(struct vfs_dir_entry_t *dentry); - -int vfs_unlink(struct user_namespace *mnt_userns, struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dentry, - struct vfs_index_node_t **delegated_inode); - -int do_unlink_at(int dfd, const char *pathname, bool name); \ No newline at end of file +extern int vfs_init(); diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/core.rs new file mode 100644 index 00000000..2f4f7c24 --- /dev/null +++ b/kernel/src/filesystem/vfs/core.rs @@ -0,0 +1,392 @@ +use core::{ + hint::spin_loop, + ptr::null_mut, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use alloc::{boxed::Box, format, string::ToString, sync::Arc}; + +use crate::{ + arch::asm::current::current_pcb, + driver::disk::ahci::{self}, + filesystem::{ + devfs::DevFS, + fat::fs::FATFileSystem, + procfs::ProcFS, + ramfs::RamFS, + vfs::{file::File, mount::MountFS, FileSystem, FileType}, + }, + include::bindings::bindings::{EBADF, ENAMETOOLONG, ENOENT, ENOTDIR, EPERM, PAGE_4K_SIZE}, + io::SeekFrom, + kerror, kinfo, +}; + +use super::{file::FileMode, utils::rsplit_path, IndexNode, InodeId}; + +/// @brief 原子地生成新的Inode号。 +/// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的 +/// 特殊的两个inode号: +/// [0]: 对应'.'目录项 +/// [1]: 对应'..'目录项 +pub fn generate_inode_id() -> InodeId { + static INO: AtomicUsize = AtomicUsize::new(1); + return INO.fetch_add(1, Ordering::SeqCst); +} + +static mut __ROOT_INODE: *mut Arc = null_mut(); + +/// @brief 获取全局的根节点 +#[inline(always)] +#[allow(non_snake_case)] +pub fn ROOT_INODE() -> Arc { + unsafe { + return __ROOT_INODE.as_ref().unwrap().clone(); + } +} + +#[no_mangle] +pub extern "C" fn vfs_init() -> i32 { + // 使用Ramfs作为默认的根文件系统 + let ramfs = RamFS::new(); + let mount_fs = MountFS::new(ramfs, None); + let root_inode = Box::leak(Box::new(mount_fs.root_inode())); + + unsafe { + __ROOT_INODE = root_inode; + } + + // 创建文件夹 + root_inode + .create("proc", FileType::Dir, 0o777) + .expect("Failed to create /proc"); + root_inode + .create("dev", FileType::Dir, 0o777) + .expect("Failed to create /dev"); + + // // 创建procfs实例 + let procfs: Arc = ProcFS::new(); + + // procfs挂载 + let _t = root_inode + .find("proc") + .expect("Cannot find /proc") + .mount(procfs) + .expect("Failed to mount procfs."); + kinfo!("ProcFS mounted."); + + // 创建 devfs 实例 + let devfs: Arc = DevFS::new(); + // devfs 挂载 + let _t = root_inode + .find("dev") + .expect("Cannot find /dev") + .mount(devfs) + .expect("Failed to mount devfs"); + kinfo!("DevFS mounted."); + + let root_inode = ROOT_INODE().list().expect("VFS init failed"); + if root_inode.len() > 0 { + kinfo!("Successfully initialized VFS!"); + } + return 0; +} + +/// @brief 真正执行伪文件系统迁移的过程 +/// +/// @param mountpoint_name 在根目录下的挂载点的名称 +/// @param inode 原本的挂载点的inode +fn do_migrate( + new_root_inode: Arc, + mountpoint_name: &str, + fs: &MountFS, +) -> Result<(), i32> { + let r = new_root_inode.find(mountpoint_name); + let mountpoint = if r.is_err() { + new_root_inode + .create(mountpoint_name, FileType::Dir, 0o777) + .expect(format!("Failed to create '/{mountpoint_name}'").as_str()) + } else { + r.unwrap() + }; + // 迁移挂载点 + mountpoint + .mount(fs.inner_filesystem()) + .expect(format!("Failed to migrate {mountpoint_name}").as_str()); + + return Ok(()); +} + +/// @brief 迁移伪文件系统的inode +/// 请注意,为了避免删掉了伪文件系统内的信息,因此没有在原root inode那里调用unlink. +fn migrate_virtual_filesystem(new_fs: Arc) -> Result<(), i32> { + kinfo!("VFS: Migrating filesystems..."); + + // ==== 在这里获取要被迁移的文件系统的inode === + let binding = ROOT_INODE().find("proc").expect("ProcFS not mounted!").fs(); + let proc: &MountFS = binding.as_any_ref().downcast_ref::().unwrap(); + let binding = ROOT_INODE().find("dev").expect("DevFS not mounted!").fs(); + let dev: &MountFS = binding.as_any_ref().downcast_ref::().unwrap(); + + let new_fs = MountFS::new(new_fs, None); + // 获取新的根文件系统的根节点的引用 + let new_root_inode = Box::leak(Box::new(new_fs.root_inode())); + + // 把上述文件系统,迁移到新的文件系统下 + do_migrate(new_root_inode.clone(), "proc", proc)?; + do_migrate(new_root_inode.clone(), "dev", dev)?; + + unsafe { + // drop旧的Root inode + let old_root_inode: Box> = Box::from_raw(__ROOT_INODE); + __ROOT_INODE = null_mut(); + drop(old_root_inode); + + // 设置全局的新的ROOT Inode + __ROOT_INODE = new_root_inode; + } + + kinfo!("VFS: Migrate filesystems done!"); + + return Ok(()); +} + +#[no_mangle] +pub extern "C" fn mount_root_fs() -> i32 { + kinfo!("Try to mount FAT32 as root fs..."); + let partiton: Arc = + ahci::get_disks_by_name("ahci_disk_0".to_string()) + .unwrap() + .0 + .lock() + .partitions[0] + .clone(); + + let fatfs: Result, i32> = FATFileSystem::new(partiton); + if fatfs.is_err() { + kerror!( + "Failed to initialize fatfs, code={:?}", + fatfs.as_ref().err() + ); + loop { + spin_loop(); + } + } + let fatfs: Arc = fatfs.unwrap(); + let r = migrate_virtual_filesystem(fatfs); + if r.is_err() { + kerror!("Failed to migrate virtual filesystem to FAT32!"); + loop { + spin_loop(); + } + } + kinfo!("Successfully migrate rootfs to FAT32!"); + + return 0; +} + +/// @brief 为当前进程打开一个文件 +pub fn do_open(path: &str, mode: FileMode) -> Result { + // 文件名过长 + if path.len() > PAGE_4K_SIZE as usize { + return Err(-(ENAMETOOLONG as i32)); + } + + let inode: Result, i32> = ROOT_INODE().lookup(path); + + let inode: Arc = if inode.is_err() { + let errno = inode.unwrap_err(); + // 文件不存在,且需要创建 + if mode.contains(FileMode::O_CREAT) + && !mode.contains(FileMode::O_DIRECTORY) + && errno == -(ENOENT as i32) + { + let (filename, parent_path) = rsplit_path(path); + // 查找父目录 + let parent_inode: Arc = + ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; + // 创建文件 + let inode: Arc = parent_inode.create(filename, FileType::File, 0o777)?; + inode + } else { + // 不需要创建文件,因此返回错误码 + return Err(errno); + } + } else { + inode.unwrap() + }; + + let file_type: FileType = inode.metadata()?.file_type; + // 如果要打开的是文件夹,而目标不是文件夹 + if mode.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件 + if mode.contains(FileMode::O_TRUNC) + && (mode.contains(FileMode::O_RDWR) || mode.contains(FileMode::O_WRONLY)) + && file_type == FileType::File + { + inode.truncate(0)?; + } + + // 创建文件对象 + let mut file: File = File::new(inode, mode)?; + + // 打开模式为“追加” + if mode.contains(FileMode::O_APPEND) { + file.lseek(SeekFrom::SeekEnd(0))?; + } + + // 把文件对象存入pcb + return current_pcb().alloc_fd(file); +} + +/// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。 +/// +/// @param fd 文件描述符编号 +/// @param buf 输出缓冲区。 +/// +/// @return Ok(usize) 成功读取的数据的字节数 +/// @return Err(i32) 读取失败,返回posix错误码 +pub fn do_read(fd: i32, buf: &mut [u8]) -> Result { + let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd); + if file.is_none() { + return Err(-(EBADF as i32)); + } + let file: &mut File = file.unwrap(); + + return file.read(buf.len(), buf); +} + +/// @brief 根据文件描述符,向文件写入数据。尝试写入的数据长度与buf的长度相同。 +/// +/// @param fd 文件描述符编号 +/// @param buf 输入缓冲区。 +/// +/// @return Ok(usize) 成功写入的数据的字节数 +/// @return Err(i32) 写入失败,返回posix错误码 +pub fn do_write(fd: i32, buf: &[u8]) -> Result { + let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd); + if file.is_none() { + return Err(-(EBADF as i32)); + } + let file: &mut File = file.unwrap(); + + return file.write(buf.len(), buf); +} + +/// @brief 调整文件操作指针的位置 +/// +/// @param fd 文件描述符编号 +/// @param seek 调整的方式 +/// +/// @return Ok(usize) 调整后,文件访问指针相对于文件头部的偏移量 +/// @return Err(i32) 调整失败,返回posix错误码 +pub fn do_lseek(fd: i32, seek: SeekFrom) -> Result { + let file: Option<&mut File> = current_pcb().get_file_mut_by_fd(fd); + if file.is_none() { + return Err(-(EBADF as i32)); + } + let file: &mut File = file.unwrap(); + return file.lseek(seek); +} + +/// @brief 创建文件/文件夹 +pub fn do_mkdir(path: &str, _mode: FileMode) -> Result { + // 文件名过长 + if path.len() > PAGE_4K_SIZE as usize { + return Err(-(ENAMETOOLONG as i32)); + } + + let inode: Result, i32> = ROOT_INODE().lookup(path); + + if inode.is_err() { + let errno = inode.unwrap_err(); + // 文件不存在,且需要创建 + if errno == -(ENOENT as i32) { + let (filename, parent_path) = rsplit_path(path); + // 查找父目录 + let parent_inode: Arc = + ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; + // 创建文件夹 + let _create_inode: Arc = + parent_inode.create(filename, FileType::Dir, 0o777)?; + } else { + // 不需要创建文件,因此返回错误码 + return Err(errno); + } + } + + return Ok(0); +} + +/// @breif 删除文件夹 +pub fn do_remove_dir(path: &str) -> Result { + // 文件名过长 + if path.len() > PAGE_4K_SIZE as usize { + return Err(-(ENAMETOOLONG as i32)); + } + + let inode: Result, i32> = ROOT_INODE().lookup(path); + + if inode.is_err() { + let errno = inode.unwrap_err(); + // 文件不存在 + if errno == -(ENOENT as i32) { + return Err(-(ENOENT as i32)); + } + } + + let (filename, parent_path) = rsplit_path(path); + // 查找父目录 + let parent_inode: Arc = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; + + if parent_inode.metadata()?.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + let target_inode: Arc = parent_inode.find(filename)?; + if target_inode.metadata()?.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 删除文件夹 + parent_inode.rmdir(filename)?; + + return Ok(0); +} + +/// @brief 删除文件 +pub fn do_unlink_at(path: &str, _mode: FileMode) -> Result { + // 文件名过长 + if path.len() > PAGE_4K_SIZE as usize { + return Err(-(ENAMETOOLONG as i32)); + } + + let inode: Result, i32> = ROOT_INODE().lookup(path); + + if inode.is_err() { + let errno = inode.clone().unwrap_err(); + // 文件不存在,且需要创建 + if errno == -(ENOENT as i32) { + return Err(-(ENOENT as i32)); + } + } + // 禁止在目录上unlink + if inode.unwrap().metadata()?.file_type == FileType::Dir { + return Err(-(EPERM as i32)); + } + + let (filename, parent_path) = rsplit_path(path); + // 查找父目录 + let parent_inode: Arc = ROOT_INODE().lookup(parent_path.unwrap_or("/"))?; + + if parent_inode.metadata()?.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 删除文件 + parent_inode.unlink(filename)?; + + return Ok(0); +} diff --git a/kernel/src/filesystem/vfs/dcache.c b/kernel/src/filesystem/vfs/dcache.c deleted file mode 100644 index d146b25f..00000000 --- a/kernel/src/filesystem/vfs/dcache.c +++ /dev/null @@ -1,134 +0,0 @@ -#include "internal.h" -#include -#include - -/** - * @brief 释放dentry,并视情况自动释放inode. 在调用该函数前,需要将dentry加锁。 - * - * @param dentry 目标dentry - * - * @return 错误码 - * 注意,当dentry指向文件时,如果返回值为正数,则表示在释放了该dentry后,该dentry指向的inode的引用计数。 - */ -int vfs_dentry_put(struct vfs_dir_entry_t *dentry) -{ - int retval = 0; - uint64_t in_value = 0; - struct kfifo_t fifo = {0}; - const struct vfs_dir_entry_t *start_dentry = dentry; - - // 引用计数大于1时,尝试释放dentry的话,抛出错误信息 - if (unlikely(dentry->lockref.count > 1)) - { - BUG_ON(1); - retval = -EBUSY; - goto out; - } - - if (D_ISDIR(dentry)) - { - - // 创建一个用来存放指向dentry的指针的fifo队列 - // 暂时假设队列大小为1024个元素 - // todo: 实现队列的自动扩容功能 - retval = kfifo_alloc(&fifo, 1024 * sizeof(uint64_t), 0); - - if (retval != 0) - goto failed; - - // 将根dentry加入队列 - in_value = (uint64_t)dentry; - kfifo_in(&fifo, &in_value, sizeof(uint64_t)); - list_del(&dentry->child_node_list); // 从父dentry中删除 - - while (!kfifo_empty(&fifo)) - { - // 取出队列中的下一个元素 - kfifo_out(&fifo, &dentry, sizeof(uint64_t)); - BUG_ON(dentry == NULL); - struct List *list = &dentry->subdirs_list; - if (!list_empty(list)) - { - // 将当前dentry下的所有dentry加入队列 - do - { - list = list_next(list); - in_value = (uint64_t)container_of(list, struct vfs_dir_entry_t, child_node_list); - if (in_value != NULL) - kfifo_in(&fifo, &in_value, sizeof(uint64_t)); - - } while (list_next(list) != (&dentry->subdirs_list)); - } - if (unlikely(dentry != start_dentry)) - spin_lock(&dentry->lockref.lock); - if (dentry->lockref.count > 1) - { - if (unlikely(dentry != start_dentry)) - spin_unlock(&dentry->lockref.lock); - continue; - } - // 释放inode - spin_lock(&dentry->dir_inode->lockref.lock); - retval = vfs_free_inode(dentry->dir_inode); - if (retval > 0) // 还有其他的dentry引用着这个inode - { - spin_unlock(&dentry->dir_inode->lockref.lock); - retval = 0; - } - - // 若当前dentry是否为挂载点,则umount - if (is_local_mountpoint(dentry)) - do_umount(dentry); - if (dentry->dir_ops->release != NULL) - dentry->dir_ops->release(dentry); - kfree(dentry); - } - kfifo_free_alloc(&fifo); - retval = 0; - goto out; - } - else // 是文件或设备 - { - kdebug("to put dentry: file: %s", dentry->name); - list_del(&dentry->child_node_list); // 从父dentry中删除 - // 释放inode - spin_lock(&dentry->dir_inode->lockref.lock); - retval = vfs_free_inode(dentry->dir_inode); - kdebug("retval=%d", retval); - if (retval > 0) // 还有其他的dentry引用着这个inode - spin_unlock(&dentry->dir_inode->lockref.lock); - - if (dentry->dir_ops->release != NULL) - dentry->dir_ops->release(dentry); - kfree(dentry); - goto out; - } -failed:; - if (fifo.buffer != NULL) - kfifo_free_alloc(&fifo); - kerror("dentry_put failed."); -out:; - // 在这里不用释放dentry的锁,因为dentry已经被释放掉了 - return retval; -} - -/** - * @brief 释放inode(要求已经对inode进行加锁后调用该函数) - * - * @param inode 待释放的inode - * @return int 错误码 - * 当inode还有其他的使用者时,返回inode的使用者数量 - */ -int vfs_free_inode(struct vfs_index_node_t *inode) -{ - --inode->lockref.count; - BUG_ON(inode->lockref.count < 0); - if (inode->lockref.count == 0) - { - kfree(inode->private_inode_info); - kfree(inode); - return 0; - } - else // 如果inode没有被释放 - return inode->lockref.count; -} \ No newline at end of file diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs new file mode 100644 index 00000000..bf7fc602 --- /dev/null +++ b/kernel/src/filesystem/vfs/file.rs @@ -0,0 +1,330 @@ +use core::mem::MaybeUninit; + +use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec}; + +use crate::{ + arch::asm::current::current_pcb, + filesystem::procfs::ProcfsFilePrivateData, + include::bindings::bindings::{ + process_control_block, EINVAL, ENOBUFS, EOVERFLOW, EPERM, ESPIPE, + }, + io::SeekFrom, + kerror, +}; + +use super::{Dirent, FileType, IndexNode, Metadata}; + +/// 文件私有信息的枚举类型 +#[derive(Debug, Clone)] +pub enum FilePrivateData { + // procfs文件私有信息 + Procfs(ProcfsFilePrivateData), + // 不需要文件私有信息 + Unused, +} + +impl Default for FilePrivateData { + fn default() -> Self { + return Self::Unused; + } +} + +bitflags! { + /// @brief 文件打开模式 + /// 其中,低2bit组合而成的数字的值,用于表示访问权限。其他的bit,才支持通过按位或的方式来表示参数 + /// + /// 与Linux 5.19.10的uapi/asm-generic/fcntl.h相同 + /// https://opengrok.ringotek.cn/xref/linux-5.19.10/tools/include/uapi/asm-generic/fcntl.h#19 + pub struct FileMode: u32{ + /* File access modes for `open' and `fcntl'. */ + /// Open Read-only + const O_RDONLY = 0; + /// Open Write-only + const O_WRONLY = 1; + /// Open read/write + const O_RDWR = 2; + /// Mask for file access modes + const O_ACCMODE = 00000003; + + /* Bits OR'd into the second argument to open. */ + /// Create file if it does not exist + const O_CREAT = 00000100; + /// Fail if file already exists + const O_EXCL = 00000200; + /// Do not assign controlling terminal + const O_NOCTTY = 00000400; + /// 文件存在且是普通文件,并以O_RDWR或O_WRONLY打开,则它会被清空 + const O_TRUNC = 00001000; + /// 文件指针会被移动到文件末尾 + const O_APPEND = 00002000; + /// 非阻塞式IO模式 + const O_NONBLOCK = 00004000; + /// used to be O_SYNC, see below + const O_DSYNC = 00010000; + /// fcntl, for BSD compatibility + const FASYNC = 00020000; + /* direct disk access hint */ + const O_DIRECT = 00040000; + const O_LARGEFILE = 00100000; + /// 打开的必须是一个目录 + const O_DIRECTORY = 00200000; + /// Do not follow symbolic links + const O_NOFOLLOW = 00400000; + const O_NOATIME = 01000000; + /// set close_on_exec + const O_CLOEXEC = 02000000; + } +} + +/// @brief 抽象文件结构体 +#[derive(Debug, Clone)] +pub struct File { + inode: Arc, + /// 对于文件,表示字节偏移量;对于文件夹,表示当前操作的子目录项偏移量 + offset: usize, + /// 文件的打开模式 + mode: FileMode, + /// 文件类型 + file_type: FileType, + /// readdir时候用的,暂存的本次循环中,所有子目录项的名字的数组 + readdir_subdirs_name: Vec, + pub private_data: FilePrivateData, +} + +impl File { + /// @brief 创建一个新的文件对象 + /// + /// @param inode 文件对象对应的inode + /// @param mode 文件的打开模式 + pub fn new(inode: Arc, mode: FileMode) -> Result { + let file_type: FileType = inode.metadata()?.file_type; + let mut f = File { + inode, + offset: 0, + mode, + file_type, + readdir_subdirs_name: Vec::new(), + private_data: FilePrivateData::default(), + }; + // kdebug!("inode:{:?}",f.inode); + f.inode.open(&mut f.private_data)?; + return Ok(f); + } + + /// @brief 从文件中读取指定的字节数到buffer中 + /// + /// @param len 要读取的字节数 + /// @param buf 目标buffer + /// + /// @return Ok(usize) 成功读取的字节数 + /// @return Err(i32) 错误码 + pub fn read(&mut self, len: usize, buf: &mut [u8]) -> Result { + // 先检查本文件在权限等规则下,是否可读取。 + self.readable()?; + + if buf.len() < len { + return Err(-(ENOBUFS as i32)); + } + + let len = self + .inode + .read_at(self.offset, len, buf, &mut self.private_data)?; + self.offset += len; + return Ok(len); + } + + /// @brief 从buffer向文件写入指定的字节数的数据 + /// + /// @param len 要写入的字节数 + /// @param buf 源数据buffer + /// + /// @return Ok(usize) 成功写入的字节数 + /// @return Err(i32) 错误码 + pub fn write(&mut self, len: usize, buf: &[u8]) -> Result { + // 先检查本文件在权限等规则下,是否可写入。 + self.writeable()?; + if buf.len() < len { + return Err(-(ENOBUFS as i32)); + } + let len = self + .inode + .write_at(self.offset, len, buf, &mut FilePrivateData::Unused)?; + self.offset += len; + return Ok(len); + } + + /// @brief 获取文件的元数据 + pub fn metadata(&self) -> Result { + return self.inode.metadata(); + } + + /// @brief 根据inode号获取子目录项的名字 + pub fn get_entry_name(&self, ino: usize) -> Result { + return self.inode.get_entry_name(ino); + } + + /// @brief 调整文件操作指针的位置 + /// + /// @param origin 调整的起始位置 + pub fn lseek(&mut self, origin: SeekFrom) -> Result { + if self.inode.metadata().unwrap().file_type == FileType::Pipe { + return Err(-(ESPIPE as i32)); + } + let pos: i64; + match origin { + SeekFrom::SeekSet(offset) => { + pos = offset; + } + SeekFrom::SeekCurrent(offset) => { + pos = self.offset as i64 + offset; + } + SeekFrom::SeekEnd(offset) => { + let metadata = self.metadata()?; + pos = metadata.size + offset; + } + SeekFrom::Invalid => { + return Err(-(EINVAL as i32)); + } + } + + if pos < 0 || pos > self.metadata()?.size { + return Err(-(EOVERFLOW as i32)); + } + self.offset = pos as usize; + return Ok(self.offset); + } + + /// @brief 判断当前文件是否可读 + #[inline] + pub fn readable(&self) -> Result<(), i32> { + // 暂时认为只要不是write only, 就可读 + if self.mode == FileMode::O_WRONLY { + return Err(-(EPERM as i32)); + } + + return Ok(()); + } + + /// @brief 判断当前文件是否可写 + #[inline] + pub fn writeable(&self) -> Result<(), i32> { + // 暂时认为只要不是read only, 就可写 + if self.mode == FileMode::O_RDONLY { + return Err(-(EPERM as i32)); + } + + return Ok(()); + } + + /// @biref 充填dirent结构体 + /// @return 返回dirent结构体的大小 + pub fn readdir(&mut self, dirent: &mut Dirent) -> Result { + let inode: &Arc = &self.inode; + + // 如果偏移量为0 + if self.offset == 0 { + self.readdir_subdirs_name = inode.list()?; + self.readdir_subdirs_name.sort(); + } + + // kdebug!("sub_entries={sub_entries:?}"); + if self.readdir_subdirs_name.is_empty() { + self.offset = 0; + return Ok(0); + } + let name: String = self.readdir_subdirs_name.remove(0); + let sub_inode: Arc = match inode.find(&name) { + Ok(i) => i, + Err(e) => { + kerror!("Readdir error: Failed to find sub inode, file={self:?}"); + return Err(e); + } + }; + + let name_bytes: &[u8] = name.as_bytes(); + + self.offset += 1; + dirent.d_ino = sub_inode.metadata().unwrap().inode_id as u64; + dirent.d_off = 0; + dirent.d_reclen = 0; + dirent.d_type = sub_inode.metadata().unwrap().file_type.get_file_type_num() as u8; + // 根据posix的规定,dirent中的d_name是一个不定长的数组,因此需要unsafe来拷贝数据 + unsafe { + let ptr = &mut dirent.d_name as *mut u8; + let buf: &mut [u8] = + ::core::slice::from_raw_parts_mut::<'static, u8>(ptr, name_bytes.len()); + buf.copy_from_slice(name_bytes); + } + + // 计算dirent结构体的大小 + return Ok((name_bytes.len() + ::core::mem::size_of::() + - ::core::mem::size_of_val(&dirent.d_name)) as u64); + } + pub fn inode(&self) -> Arc { + return self.inode.clone(); + } +} + +impl Drop for File { + fn drop(&mut self) { + let r: Result<(), i32> = self.inode.close(&mut self.private_data); + // 打印错误信息 + if r.is_err() { + kerror!( + "pid: {} failed to close file: {:?}, errno={}", + current_pcb().pid, + self, + r.unwrap_err() + ); + } + } +} + +/// @brief pcb里面的文件描述符数组 +#[derive(Debug, Clone)] +pub struct FileDescriptorVec { + /// 当前进程打开的文件描述符 + pub fds: [Option>; FileDescriptorVec::PROCESS_MAX_FD], +} + +impl FileDescriptorVec { + pub const PROCESS_MAX_FD: usize = 32; + + pub fn new() -> Box { + // 先声明一个未初始化的数组 + let mut data: [MaybeUninit>>; FileDescriptorVec::PROCESS_MAX_FD] = + unsafe { MaybeUninit::uninit().assume_init() }; + + // 逐个把每个元素初始化为None + for i in 0..FileDescriptorVec::PROCESS_MAX_FD { + data[i] = MaybeUninit::new(None); + } + // 由于一切都初始化完毕,因此将未初始化的类型强制转换为已经初始化的类型 + let data: [Option>; FileDescriptorVec::PROCESS_MAX_FD] = unsafe { + core::mem::transmute::<_, [Option>; FileDescriptorVec::PROCESS_MAX_FD]>(data) + }; + + // 初始化文件描述符数组结构体 + return Box::new(FileDescriptorVec { fds: data }); + } + + /// @brief 从pcb的fds字段,获取文件描述符数组的可变引用 + #[inline] + pub fn from_pcb(pcb: &'static process_control_block) -> Option<&'static mut FileDescriptorVec> { + return unsafe { (pcb.fds as usize as *mut FileDescriptorVec).as_mut() }; + } + + /// @brief 判断文件描述符序号是否合法 + /// + /// @return true 合法 + /// + /// @return false 不合法 + #[inline] + pub fn validate_fd(fd: i32) -> bool { + if fd < 0 || fd as usize > FileDescriptorVec::PROCESS_MAX_FD { + return false; + } else { + return true; + } + } +} diff --git a/kernel/src/filesystem/vfs/internal.h b/kernel/src/filesystem/vfs/internal.h deleted file mode 100644 index 500f50a6..00000000 --- a/kernel/src/filesystem/vfs/internal.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once -#include "VFS.h" -#include "mount.h" - -/** - * @brief 判断是否可以删除指定的dentry - * - * 1、我们不能删除一个只读的dentry - * 2、我们应当对这个dentry拥有写、执行权限(暂时还没有实现权限) - * 3、如果dentry指向的是文件夹,而isdir为false,则不能删除 - * 3、如果dentry指向的是文件,而isdir为true,则不能删除 - * @param dentry 将要被删除的dentry - * @param isdir 是否要删除文件夹 - * @return int 错误码 - */ -int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir); - -#define D_ISDIR(dentry) ((dentry)->dir_inode->attribute & VFS_IF_DIR) - -// 判断是否为根目录 -#define IS_ROOT(x) ((x) == (x)->parent) - -/** - * @brief 判断当前dentry是否为挂载点 - * - * @param dentry - */ -static inline bool is_local_mountpoint(struct vfs_dir_entry_t *dentry) -{ - if (D_MOUNTED(dentry)) - return true; - else - return false; -} - - - -/** - * @brief 释放inode(要求已经对inode进行加锁后调用该函数) - * - * @param inode 待释放的inode - * @return int 错误码 - * 当inode还有其他的使用者时,返回inode的使用者数量 - */ -int vfs_free_inode(struct vfs_index_node_t * inode); \ No newline at end of file diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 8b137891..f792f5fb 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -1 +1,517 @@ +#![allow(dead_code)] +pub mod core; +pub mod file; +pub mod mount; +mod syscall; +mod utils; + +use ::core::{any::Any, fmt::Debug}; + +use alloc::{string::String, sync::Arc, vec::Vec}; + +use crate::{ + include::bindings::bindings::{ENOTDIR, ENOTSUP}, + time::TimeSpec, +}; + +pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS}; + +/// vfs容许的最大的路径名称长度 +pub const MAX_PATHLEN: u32 = 1024; + +/// 定义inode号的类型为usize +pub type InodeId = usize; + +/// 文件的类型 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FileType { + /// 文件 + File, + /// 文件夹 + Dir, + /// 块设备 + BlockDevice, + /// 字符设备 + CharDevice, + /// 管道文件 + Pipe, + /// 符号链接 + SymLink, +} + +/* these are defined by POSIX and also present in glibc's dirent.h */ +/// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html +pub const DT_UNKNOWN: u16 = 0; +/// 命名管道,或者FIFO +pub const DT_FIFO: u16 = 1; +// 字符设备 +pub const DT_CHR: u16 = 2; +// 目录 +pub const DT_DIR: u16 = 4; +// 块设备 +pub const DT_BLK: u16 = 6; +// 常规文件 +pub const DT_REG: u16 = 8; +// 符号链接 +pub const DT_LNK: u16 = 10; +// 是一个socket +pub const DT_SOCK: u16 = 12; +// 这个是抄Linux的,还不知道含义 +pub const DT_WHT: u16 = 14; +pub const DT_MAX: u16 = 16; + +impl FileType { + pub fn get_file_type_num(&self) -> u16 { + return match self { + FileType::File => DT_REG, + FileType::Dir => DT_DIR, + FileType::BlockDevice => DT_BLK, + FileType::CharDevice => DT_CHR, + FileType::Pipe => DT_FIFO, + FileType::SymLink => DT_LNK, + }; + } +} + +/// @brief inode的状态(由poll方法返回) +#[derive(Debug, Default, PartialEq)] +pub struct PollStatus { + pub flags: u8, +} + +impl PollStatus { + pub const WRITE_MASK: u8 = (1u8 << 0); + pub const READ_MASK: u8 = (1u8 << 1); + pub const ERR_MASK: u8 = (1u8 << 2); +} + +pub trait IndexNode: Any + Sync + Send + Debug { + /// @brief 打开文件 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn open(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 关闭文件 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn close(&self, _data: &mut FilePrivateData) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 在inode的指定偏移量开始,读取指定大小的数据 + /// + /// @param offset 起始位置在Inode中的偏移量 + /// @param len 要读取的字节数 + /// @param buf 缓冲区. 请注意,必须满足@buf.len()>=@len + /// @param _data 各文件系统系统所需私有信息 + /// + /// @return 成功:Ok(读取的字节数) + /// 失败:Err(Posix错误码) + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + _data: &mut FilePrivateData, + ) -> Result; + + /// @brief 在inode的指定偏移量开始,写入指定大小的数据(从buf的第0byte开始写入) + /// + /// @param offset 起始位置在Inode中的偏移量 + /// @param len 要写入的字节数 + /// @param buf 缓冲区. 请注意,必须满足@buf.len()>=@len + /// @param _data 各文件系统系统所需私有信息 + /// + /// @return 成功:Ok(写入的字节数) + /// 失败:Err(Posix错误码) + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result; + + /// @brief 获取当前inode的状态。 + /// + /// @return PollStatus结构体 + fn poll(&self) -> Result; + + /// @brief 获取inode的元数据 + /// + /// @return 成功:Ok(inode的元数据) + /// 失败:Err(错误码) + fn metadata(&self) -> Result { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 设置inode的元数据 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn set_metadata(&self, _metadata: &Metadata) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 重新设置文件的大小 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn resize(&self, _len: usize) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 在当前目录下创建一个新的inode + /// + /// @param name 目录项的名字 + /// @param file_type 文件类型 + /// @param mode 权限 + /// + /// @return 创建成功:返回Ok(新的inode的Arc指针) + /// @return 创建失败:返回Err(错误码) + fn create( + &self, + name: &str, + file_type: FileType, + mode: u32, + ) -> Result, i32> { + // 若文件系统没有实现此方法,则默认调用其create_with_data方法。如果仍未实现,则会得到一个Err(-ENOTSUP)的返回值 + return self.create_with_data(name, file_type, mode, 0); + } + + /// @brief 在当前目录下创建一个新的inode,并传入一个简单的data字段,方便进行初始化。 + /// + /// @param name 目录项的名字 + /// @param file_type 文件类型 + /// @param mode 权限 + /// @param data 用于初始化该inode的数据。(为0则表示忽略此字段)对于不同的文件系统来说,代表的含义可能不同。 + /// + /// @return 创建成功:返回Ok(新的inode的Arc指针) + /// @return 创建失败:返回Err(错误码) + fn create_with_data( + &self, + _name: &str, + _file_type: FileType, + _mode: u32, + _data: usize, + ) -> Result, i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 在当前目录下,创建一个名为Name的硬链接,指向另一个IndexNode + /// + /// @param name 硬链接的名称 + /// @param other 要被指向的IndexNode的Arc指针 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn link(&self, _name: &str, _other: &Arc) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 在当前目录下,删除一个名为Name的硬链接 + /// + /// @param name 硬链接的名称 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn unlink(&self, _name: &str) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 删除文件夹 + /// + /// @param name 文件夹名称 + /// + /// @return 成功 Ok(()) + /// @return 失败 Err(错误码) + fn rmdir(&self, _name: &str) ->Result<(), i32>{ + return Err(-(ENOTSUP as i32)); + } + + /// @brief 将指定名称的子目录项的文件内容,移动到target这个目录下。如果_old_name所指向的inode与_target的相同,那么则直接执行重命名的操作。 + /// + /// @param old_name 旧的名字 + /// + /// @param target 移动到指定的inode + /// + /// @param new_name 新的文件名 + /// + /// @return 成功: Ok() + /// 失败: Err(错误码) + fn move_( + &self, + _old_name: &str, + _target: &Arc, + _new_name: &str, + ) -> Result<(), i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 寻找一个名为Name的inode + /// + /// @param name 要寻找的inode的名称 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn find(&self, _name: &str) -> Result, i32> { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 根据inode号,获取子目录项的名字 + /// + /// @param ino inode号 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn get_entry_name(&self, _ino: InodeId) -> Result { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 根据inode号,获取子目录项的名字和元数据 + /// + /// @param ino inode号 + /// + /// @return 成功:Ok(String, Metadata) + /// 失败:Err(错误码) + fn get_entry_name_and_metadata(&self, ino: InodeId) -> Result<(String, Metadata), i32> { + // 如果有条件,请在文件系统中使用高效的方式实现本接口,而不是依赖这个低效率的默认实现。 + let name = self.get_entry_name(ino)?; + let entry = self.find(&name)?; + return Ok((name, entry.metadata()?)); + } + + /// @brief io control接口 + /// + /// @param cmd 命令 + /// @param data 数据 + /// + /// @return 成功:Ok() + /// 失败:Err(错误码) + fn ioctl(&self, _cmd: u32, _data: usize) -> Result { + // 若文件系统没有实现此方法,则返回“不支持” + return Err(-(ENOTSUP as i32)); + } + + /// @brief 获取inode所在的文件系统的指针 + fn fs(&self) -> Arc; + + /// @brief 本函数用于实现动态转换。 + /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self + fn as_any_ref(&self) -> &dyn Any; + + /// @brief 列出当前inode下的所有目录项的名字 + fn list(&self) -> Result, i32>; + + /// @brief 在当前Inode下,挂载一个新的文件系统 + /// 请注意!该函数只能被MountFS实现,其他文件系统不应实现这个函数 + fn mount(&self, _fs: Arc) -> Result, i32> { + return Err(-(ENOTSUP as i32)); + } + + /// @brief 截断当前inode到指定的长度。如果当前文件长度小于len,则不操作。 + /// + /// @param len 要被截断到的目标长度 + fn truncate(&self, _len: usize) -> Result<(), i32> { + return Err(-(ENOTSUP as i32)); + } +} + +impl dyn IndexNode { + /// @brief 将当前Inode转换为一个具体的结构体(类型由T指定) + /// 如果类型正确,则返回Some,否则返回None + pub fn downcast_ref(&self) -> Option<&T> { + return self.as_any_ref().downcast_ref::(); + } + + /// @brief 查找文件(不考虑符号链接) + /// + /// @param path 文件路径 + /// + /// @return Ok(Arc) 要寻找的目录项的inode + /// @return Err(i32) 错误码 + pub fn lookup(&self, path: &str) -> Result, i32> { + return self.lookup_follow_symlink(path, 0); + } + + /// @brief 查找文件(考虑符号链接) + /// + /// @param path 文件路径 + /// @param max_follow_times 最大经过的符号链接的大小 + /// + /// @return Ok(Arc) 要寻找的目录项的inode + /// @return Err(i32) 错误码 + pub fn lookup_follow_symlink( + &self, + path: &str, + max_follow_times: usize, + ) -> Result, i32> { + if self.metadata()?.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 处理绝对路径 + // result: 上一个被找到的inode + // rest_path: 还没有查找的路径 + let (mut result, mut rest_path) = if let Some(rest) = path.strip_prefix('/') { + (ROOT_INODE().clone(), String::from(rest)) + } else { + // 是相对路径 + (self.find(".")?, String::from(path)) + }; + + // 逐级查找文件 + while !rest_path.is_empty() { + // 当前这一级不是文件夹 + if result.metadata()?.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + let name; + + // 寻找“/” + match rest_path.find('/') { + Some(pos) => { + // 找到了,设置下一个要查找的名字 + name = String::from(&rest_path[0..pos]); + // 剩余的路径字符串 + rest_path = String::from(&rest_path[pos + 1..]); + } + None => { + name = rest_path; + rest_path = String::new(); + } + } + + // 遇到连续多个"/"的情况 + if name.is_empty() { + continue; + } + + let inode = result.find(&name)?; + + // 处理符号链接的问题 + if inode.metadata()?.file_type == FileType::SymLink && max_follow_times > 0 { + let mut content = [0u8; 256]; + // 读取符号链接 + let len = inode.read_at(0, 256, &mut content, &mut FilePrivateData::Unused)?; + + // 将读到的数据转换为utf8字符串(先转为str,再转为String) + let link_path = String::from( + ::core::str::from_utf8(&content[..len]).map_err(|_| -(ENOTDIR as i32))?, + ); + + let new_path = link_path + "/" + &rest_path; + // 继续查找符号链接 + return result.lookup_follow_symlink(&new_path, max_follow_times - 1); + } else { + result = inode; + } + } + + return Ok(result); + } +} + +/// IndexNode的元数据 +/// +/// 对应Posix2008中的sys/stat.h中的定义 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Metadata { + /// 当前inode所在的文件系统的设备号 + pub dev_id: usize, + + /// inode号 + pub inode_id: InodeId, + + /// Inode的大小 + /// 文件:文件大小(单位:字节) + /// 目录:目录项中的文件、文件夹数量 + pub size: i64, + + /// Inode所在的文件系统中,每个块的大小 + pub blk_size: usize, + + /// Inode所占的块的数目 + pub blocks: usize, + + /// inode最后一次被访问的时间 + pub atime: TimeSpec, + + /// inode最后一次修改的时间 + pub mtime: TimeSpec, + + /// inode的创建时间 + pub ctime: TimeSpec, + + /// 文件类型 + pub file_type: FileType, + + /// 权限 + pub mode: u32, + + /// 硬链接的数量 + pub nlinks: usize, + + /// User ID + pub uid: usize, + + /// Group ID + pub gid: usize, + + /// 文件指向的设备的id(对于设备文件系统来说) + pub raw_dev: usize, +} + +/// @brief 所有文件系统都应该实现的trait +pub trait FileSystem: Any + Sync + Send + Debug { + /// @brief 获取当前文件系统的root inode的指针 + fn root_inode(&self) -> Arc; + + /// @brief 获取当前文件系统的信息 + fn info(&self) -> FsInfo; + + /// @brief 本函数用于实现动态转换。 + /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self + fn as_any_ref(&self) -> &dyn Any; +} + +#[derive(Debug)] +pub struct FsInfo { + /// 文件系统所在的块设备的id + pub blk_dev_id: usize, + /// 文件名的最大长度 + pub max_name_len: usize, +} + +/// @brief 整合主设备号+次设备号 +pub fn make_rawdev(major: usize, minor: usize) -> usize { + ((major & 0xffffff) << 8) | (minor & 0xff) +} + +/// @brief +#[repr(C)] +#[derive(Debug)] +pub struct Dirent { + d_ino: u64, // 文件序列号 + d_off: i64, // dir偏移量 + d_reclen: u16, // 目录下的记录数 + d_type: u8, // entry的类型 + d_name: u8, // 文件entry的名字(是一个零长数组), 本字段仅用于占位 +} diff --git a/kernel/src/filesystem/vfs/mount.c b/kernel/src/filesystem/vfs/mount.c deleted file mode 100644 index 4b3f00b1..00000000 --- a/kernel/src/filesystem/vfs/mount.c +++ /dev/null @@ -1,99 +0,0 @@ -#include "mount.h" -#include "VFS.h" -#include -#include - -static struct List mnt_list_head; // 挂载点链表头 - -/** - * @brief 初始化mount机制 - * - * @return int 错误码 - */ -int mount_init() -{ - list_init(&mnt_list_head); - return 0; -} - -/** - * @brief 将new_dentry挂载 - * - * @param old_dentry 挂载点的dentry - * @param new_dentry 待挂载的新的dentry(需使用vfs_alloc_dentry来分配) - * @return int 错误码 - */ -int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_dentry) -{ - struct mountpoint *mp = (struct mountpoint *)kzalloc(sizeof(struct mountpoint), 0); - list_init(&mp->mnt_list); - mp->dentry = old_dentry; - mp->parent_dentry = old_dentry->parent; - - // 拷贝名称 - strncpy(new_dentry->name, old_dentry->name, old_dentry->name_length); - kdebug("new_dentry->name=%s, old_dentry->name=%s, old_dentry->name_length=%d", new_dentry->name, old_dentry->name, old_dentry->name_length); - - new_dentry->d_flags |= VFS_DF_MOUNTED; // 标记新的dentry是一个挂载点 - - list_init(&new_dentry->child_node_list); - list_init(&new_dentry->subdirs_list); - new_dentry->parent = old_dentry->parent; - - // 将新的dentry的list结点替换掉父dentry的列表中的old_dentry的list结点 - list_replace(&old_dentry->child_node_list, &new_dentry->child_node_list); - - // 后挂载的dentry在链表的末尾(umount恢复的时候需要依赖这个性质) - list_append(&mnt_list_head, &mp->mnt_list); - - return 0; -} - -/** - * @brief 取消某个文件系统的挂载 - * - * @param dentry 对应文件系统的根dentry - * @return int 错误码 - */ -int do_umount(struct vfs_dir_entry_t *dentry) -{ - // todo: 实现umount(主要是结点的恢复问题) - - return 0; -} - -/** - * @brief 根据mountpoint的父目录dentry查找第一个符合条件的mountpoint结构体 - * - * @param dentry 父dentry - * @return struct mountpoint* 第一个符合条件的mountpoint结构体的指针 - */ -struct mountpoint *mount_find_mnt_list_by_parent(struct vfs_dir_entry_t *dentry) -{ - struct List *list = &mnt_list_head; - struct mountpoint *ret = NULL; - if (list_empty(list)) - return NULL; - - while (list_next(list) != &mnt_list_head) - { - list = list_next(list); - struct mountpoint *tmp = container_of(list, struct mountpoint, mnt_list); - if (dentry == tmp->parent_dentry) - return tmp; - } - - return NULL; -} - -/** - * @brief 将挂载点结构体从链表中删除并释放 - * - * @param mp mountpoint结构体 - * @return int 错误码 - */ -int mount_release_mountpoint(struct mountpoint *mp) -{ - list_del(&mp->mnt_list); - return kfree(mp); -} \ No newline at end of file diff --git a/kernel/src/filesystem/vfs/mount.h b/kernel/src/filesystem/vfs/mount.h deleted file mode 100644 index 9b1212e9..00000000 --- a/kernel/src/filesystem/vfs/mount.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include -#include "VFS.h" -/** - * @brief 挂载点结构体(用来表示dentry被挂载其他文件系统之后,原先存在的数据) - * - */ -struct mountpoint -{ - struct List mnt_list; // 挂载点串在一起的链表 - struct vfs_dir_entry_t *dentry; // 被挂载前,当前目录项的dentry - struct vfs_dir_entry_t *parent_dentry; // 被挂载前,父目录项的dentry -}; - -/** - * @brief 初始化mount机制 - * - * @return int 错误码 - */ -int mount_init(); - -/** - * @brief 将new_dentry挂载 - * - * @param old_dentry 挂载点的dentry - * @param new_dentry 待挂载的新的dentry(需使用vfs_alloc_dentry来分配) - * @return int 错误码 - */ -int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_dentry); - -/** - * @brief 取消某个文件系统的挂载 - * - * @param dentry 对应文件系统的根dentry - * @return int 错误码 - */ -int do_umount(struct vfs_dir_entry_t *dentry); - -// 判断dentry是否是一个挂载点 -#define D_MOUNTED(x) ((x)->d_flags & VFS_DF_MOUNTED) - -/** - * @brief 将给定的dentry标记为“不可挂载” - * - * @param dentry 目标dentry - */ -static inline void dont_mount(struct vfs_dir_entry_t *dentry) -{ - // todo: 对dentry加锁 - dentry->d_flags |= VFS_DF_CANNOT_MOUNT; -} - -static inline void detach_mounts(struct vfs_dir_entry_t *dentry) -{ - if (!D_MOUNTED(dentry)) - return; // 如果当前文件夹不是一个挂载点,则直接返回 - - // todo:如果当前文件夹是一个挂载点,则对同样挂载在当前文件夹下的dentry进行清理。以免造成内存泄露 - // 可参考 linux5.17或以上的detach_mounts()函数 -} - -/** - * @brief 根据mountpoint的父目录dentry查找第一个符合条件的mountpoint结构体 - * - * @param dentry 父dentry - * @return struct mountpoint* 第一个符合条件的mountpoint结构体的指针 - */ -struct mountpoint *mount_find_mnt_list_by_parent(struct vfs_dir_entry_t *dentry); - -/** - * @brief 释放挂载点结构体 - * - * @param mp mountpoint结构体 - * @return int 错误码 - */ -int mount_release_mountpoint(struct mountpoint* mp); \ No newline at end of file diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs new file mode 100644 index 00000000..0d12d220 --- /dev/null +++ b/kernel/src/filesystem/vfs/mount.rs @@ -0,0 +1,365 @@ +use core::any::Any; + +use alloc::{ + collections::BTreeMap, + sync::{Arc, Weak}, +}; + +use crate::{ + include::bindings::bindings::{EBUSY, ENOTDIR}, + libs::spinlock::SpinLock, kdebug, +}; + +use super::{FilePrivateData, FileSystem, FileType, IndexNode, InodeId}; + +/// @brief 挂载文件系统 +/// 挂载文件系统的时候,套了MountFS这一层,以实现文件系统的递归挂载 +#[derive(Debug)] +pub struct MountFS { + // MountFS内部的文件系统 + inner_filesystem: Arc, + /// 用来存储InodeID->挂载点的MountFS的B树 + mountpoints: SpinLock>>, + /// 当前文件系统挂载到的那个挂载点的Inode + self_mountpoint: Option>, + /// 指向当前MountFS的弱引用 + self_ref: Weak, +} + +/// @brief MountFS的Index Node 注意,这个IndexNode只是一个中间层。它的目的是将具体文件系统的Inode与挂载机制连接在一起。 +#[derive(Debug)] +pub struct MountFSInode { + /// 当前挂载点对应到具体的文件系统的Inode + inner_inode: Arc, + /// 当前Inode对应的MountFS + mount_fs: Arc, + /// 指向自身的弱引用 + self_ref: Weak, +} + +impl MountFS { + pub fn new( + inner_fs: Arc, + self_mountpoint: Option>, + ) -> Arc { + return MountFS { + inner_filesystem: inner_fs, + mountpoints: SpinLock::new(BTreeMap::new()), + self_mountpoint: self_mountpoint, + self_ref: Weak::default(), + } + .wrap(); + } + + /// @brief 用Arc指针包裹MountFS对象。 + /// 本函数的主要功能为,初始化MountFS对象中的自引用Weak指针 + /// 本函数只应在构造器中被调用 + fn wrap(self) -> Arc { + // 创建Arc指针 + let mount_fs: Arc = Arc::new(self); + // 创建weak指针 + let weak: Weak = Arc::downgrade(&mount_fs); + + // 将Arc指针转为Raw指针并对其内部的self_ref字段赋值 + let ptr: *mut MountFS = Arc::into_raw(mount_fs) as *mut Self; + unsafe { + (*ptr).self_ref = weak; + // 返回初始化好的MountFS对象 + return Arc::from_raw(ptr); + } + } + + /// @brief 获取挂载点的文件系统的root inode + pub fn mountpoint_root_inode(&self) -> Arc { + return MountFSInode { + inner_inode: self.inner_filesystem.root_inode(), + mount_fs: self.self_ref.upgrade().unwrap(), + self_ref: Weak::default(), + } + .wrap(); + } + + pub fn inner_filesystem(&self) -> Arc { + return self.inner_filesystem.clone(); + } +} + +impl MountFSInode { + /// @brief 用Arc指针包裹MountFSInode对象。 + /// 本函数的主要功能为,初始化MountFSInode对象中的自引用Weak指针 + /// 本函数只应在构造器中被调用 + fn wrap(self) -> Arc { + // 创建Arc指针 + let inode: Arc = Arc::new(self); + // 创建Weak指针 + let weak: Weak = Arc::downgrade(&inode); + // 将Arc指针转为Raw指针并对其内部的self_ref字段赋值 + let ptr: *mut MountFSInode = Arc::into_raw(inode) as *mut Self; + unsafe { + (*ptr).self_ref = weak; + + // 返回初始化好的MountFSInode对象 + return Arc::from_raw(ptr); + } + } + + /// @brief 判断当前inode是否为它所在的文件系统的root inode + fn is_mountpoint_root(&self) -> Result { + return Ok(self.inner_inode.fs().root_inode().metadata()?.inode_id + == self.inner_inode.metadata()?.inode_id); + } + + /// @brief 在挂载树上进行inode替换。 + /// 如果当前inode是父MountFS内的一个挂载点,那么,本函数将会返回挂载到这个挂载点下的文件系统的root inode. + /// 如果当前inode在父MountFS内,但不是挂载点,那么说明在这里不需要进行inode替换,因此直接返回当前inode。 + /// + /// @return Arc + fn overlaid_inode(&self) -> Arc { + let inode_id = self.metadata().unwrap().inode_id; + + if let Some(sub_mountfs) = self.mount_fs.mountpoints.lock().get(&inode_id) { + return sub_mountfs.mountpoint_root_inode(); + } else { + return self.self_ref.upgrade().unwrap(); + } + } +} + +impl IndexNode for MountFSInode { + fn open(&self, data: &mut FilePrivateData) -> Result<(), i32> { + return self.inner_inode.open(data); + } + + fn close(&self, data: &mut FilePrivateData) -> Result<(), i32> { + return self.inner_inode.close(data); + } + + fn create_with_data( + &self, + name: &str, + file_type: FileType, + mode: u32, + data: usize, + ) -> Result, i32> { + return self + .inner_inode + .create_with_data(name, file_type, mode, data); + } + + fn truncate(&self, len: usize) -> Result<(), i32> { + return self.inner_inode.truncate(len); + } + + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + data: &mut FilePrivateData, + ) -> Result { + return self + .inner_inode + .read_at(offset, len, buf, data); + } + + fn write_at( + &self, + offset: usize, + len: usize, + buf: &[u8], + _data: &mut FilePrivateData, + ) -> Result { + return self + .inner_inode + .write_at(offset, len, buf, &mut FilePrivateData::Unused); + } + + #[inline] + fn poll(&self) -> Result { + return self.inner_inode.poll(); + } + + #[inline] + fn fs(&self) -> Arc { + return self.mount_fs.clone(); + } + + #[inline] + fn as_any_ref(&self) -> &dyn core::any::Any { + return self.inner_inode.as_any_ref(); + } + + #[inline] + fn metadata(&self) -> Result { + return self.inner_inode.metadata(); + } + + #[inline] + fn set_metadata(&self, metadata: &super::Metadata) -> Result<(), i32> { + return self.inner_inode.set_metadata(metadata); + } + + #[inline] + fn resize(&self, len: usize) -> Result<(), i32> { + return self.inner_inode.resize(len); + } + + #[inline] + fn create( + &self, + name: &str, + file_type: FileType, + mode: u32, + ) -> Result, i32> { + return Ok(MountFSInode { + inner_inode: self.inner_inode.create(name, file_type, mode)?, + mount_fs: self.mount_fs.clone(), + self_ref: Weak::default(), + } + .wrap()); + } + + fn link(&self, name: &str, other: &Arc) -> Result<(), i32> { + return self.inner_inode.link(name, other); + } + + /// @brief 在挂载文件系统中删除文件/文件夹 + #[inline] + fn unlink(&self, name: &str) -> Result<(), i32> { + let inode_id = self.inner_inode.find(name)?.metadata()?.inode_id; + + // 先检查这个inode是否为一个挂载点,如果当前inode是一个挂载点,那么就不能删除这个inode + if self.mount_fs.mountpoints.lock().contains_key(&inode_id) { + return Err(-(EBUSY as i32)); + } + // 调用内层的inode的方法来删除这个inode + return self.inner_inode.unlink(name); + } + + #[inline] + fn rmdir(&self, name: &str) ->Result<(), i32> { + let inode_id = self.inner_inode.find(name)?.metadata()?.inode_id; + kdebug!("rmdir {name}"); + // 先检查这个inode是否为一个挂载点,如果当前inode是一个挂载点,那么就不能删除这个inode + if self.mount_fs.mountpoints.lock().contains_key(&inode_id) { + return Err(-(EBUSY as i32)); + } + // 调用内层的rmdir的方法来删除这个inode + let r = self.inner_inode.rmdir(name); + kdebug!("r={r:?}"); + return r; + } + + #[inline] + fn move_( + &self, + old_name: &str, + target: &Arc, + new_name: &str, + ) -> Result<(), i32> { + return self.inner_inode.move_(old_name, target, new_name); + } + + fn find(&self, name: &str) -> Result, i32> { + match name { + // 查找的是当前目录 + "" | "." => return Ok(self.self_ref.upgrade().unwrap()), + // 往父级查找 + ".." => { + if self.is_mountpoint_root()? { + // 当前inode是它所在的文件系统的root inode + match &self.mount_fs.self_mountpoint { + Some(inode) => { + return inode.find(name); + } + None => { + return Ok(self.self_ref.upgrade().unwrap()); + } + } + } else { + // 向上查找时,不会跨过文件系统的边界,因此直接调用当前inode所在的文件系统的find方法进行查找 + return Ok(MountFSInode { + inner_inode: self.inner_inode.find(name)?, + mount_fs: self.mount_fs.clone(), + self_ref: Weak::default(), + } + .wrap()); + } + } + // 在当前目录下查找 + _ => { + // 直接调用当前inode所在的文件系统的find方法进行查找 + // 由于向下查找可能会跨越文件系统的边界,因此需要尝试替换inode + return Ok(MountFSInode { + inner_inode: self.inner_inode.find(name)?, + mount_fs: self.mount_fs.clone(), + self_ref: Weak::default(), + } + .wrap() + .overlaid_inode()); + } + } + } + + #[inline] + fn get_entry_name(&self, ino: InodeId) -> Result { + return self.inner_inode.get_entry_name(ino); + } + + #[inline] + fn get_entry_name_and_metadata( + &self, + ino: InodeId, + ) -> Result<(alloc::string::String, super::Metadata), i32> { + return self.inner_inode.get_entry_name_and_metadata(ino); + } + + #[inline] + fn ioctl(&self, cmd: u32, data: usize) -> Result { + return self.inner_inode.ioctl(cmd, data); + } + + #[inline] + fn list(&self) -> Result, i32> { + return self.inner_inode.list(); + } + + /// @brief 在当前inode下,挂载一个文件系统 + /// + /// @return Ok(Arc) 挂载成功,返回指向MountFS的指针 + fn mount(&self, fs: Arc) -> Result, i32> { + let metadata = self.inner_inode.metadata()?; + if metadata.file_type != FileType::Dir { + return Err(-(ENOTDIR as i32)); + } + + // 为新的挂载点创建挂载文件系统 + let new_mount_fs: Arc = MountFS::new(fs, Some(self.self_ref.upgrade().unwrap())); + // 将新的挂载点-挂载文件系统添加到父级的挂载树 + self.mount_fs + .mountpoints + .lock() + .insert(metadata.inode_id, new_mount_fs.clone()); + return Ok(new_mount_fs); + } +} + +impl FileSystem for MountFS { + fn root_inode(&self) -> Arc { + match &self.self_mountpoint { + Some(inode) => return inode.mount_fs.root_inode(), + // 当前文件系统是rootfs + None => self.mountpoint_root_inode(), + } + } + + fn info(&self) -> super::FsInfo { + return self.inner_filesystem.info(); + } + + /// @brief 本函数用于实现动态转换。 + /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self + fn as_any_ref(&self) -> &dyn Any { + self + } +} diff --git a/kernel/src/filesystem/vfs/syscall.rs b/kernel/src/filesystem/vfs/syscall.rs new file mode 100644 index 00000000..85c81875 --- /dev/null +++ b/kernel/src/filesystem/vfs/syscall.rs @@ -0,0 +1,352 @@ +use core::ffi::{c_char, CStr}; + +use alloc::{ + boxed::Box, + string::{String, ToString}, +}; + +use crate::{ + arch::asm::{current::current_pcb, ptrace::user_mode}, + include::bindings::bindings::{ + pt_regs, verify_area, AT_REMOVEDIR, EBADF, EFAULT, EINVAL, ENAMETOOLONG, ENOENT, ENOTDIR, + EPERM, PAGE_2M_SIZE, PAGE_4K_SIZE, PROC_MAX_FD_NUM, SEEK_CUR, SEEK_END, SEEK_MAX, SEEK_SET, + }, + io::SeekFrom, + kdebug, kerror, +}; + +use super::{ + core::{do_lseek, do_mkdir, do_open, do_read, do_remove_dir, do_unlink_at, do_write}, + file::{File, FileMode}, + Dirent, FileType, ROOT_INODE, +}; + +/// @brief 打开文件 +/// +/// @param regs->r8 path 文件路径 +/// @param regs->r9 o_flags 打开文件的标志位 +/// +/// @return u64 文件描述符编号,或者是错误码 +#[no_mangle] +pub extern "C" fn sys_open(regs: &pt_regs) -> u64 { + let path: &CStr = unsafe { CStr::from_ptr(regs.r8 as usize as *const c_char) }; + let path: Result<&str, core::str::Utf8Error> = path.to_str(); + if path.is_err() { + return (-(EINVAL as i32)) as u64; + } + let path: &str = path.unwrap(); + let flags = regs.r9; + + let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32); + let r: Result = do_open(path, open_flags); + + if r.is_ok() { + return r.unwrap() as u64; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 关闭文件的系统调用函数 +/// +/// @param regs->r8 fd:文件描述符编号 +#[no_mangle] +pub extern "C" fn sys_close(regs: &pt_regs) -> u64 { + let fd = regs.r8 as i32; + let r: Result<(), i32> = current_pcb().drop_fd(fd); + + if r.is_ok() { + return 0; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 读取文件的系统调用函数 +/// +/// @param regs->r8 文件描述符编号 +/// @param regs->r9 输出缓冲区 +/// @param regs->r10 要读取的长度 +#[no_mangle] +pub extern "C" fn sys_read(regs: &pt_regs) -> u64 { + let fd = regs.r8 as i32; + let buf_vaddr = regs.r9 as usize; + let len = regs.r10 as usize; + + // 判断缓冲区是否来自用户态,进行权限校验 + if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } { + // 来自用户态,而buffer在内核态,这样的操作不被允许 + return (-(EPERM as i32)) as u64; + } + + let buf: &mut [u8] = + unsafe { core::slice::from_raw_parts_mut::<'static, u8>(buf_vaddr as *mut u8, len) }; + + let r: Result = do_read(fd, buf); + + if r.is_ok() { + return r.unwrap() as u64; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 向文件写入数据的系统调用函数 +/// +/// @param regs->r8 文件描述符编号 +/// @param regs->r9 输入缓冲区 +/// @param regs->r10 要写入的长度 +#[no_mangle] +pub extern "C" fn sys_write(regs: &pt_regs) -> u64 { + let fd = regs.r8 as i32; + let buf_vaddr = regs.r9 as usize; + let len = regs.r10 as usize; + + // 判断缓冲区是否来自用户态,进行权限校验 + if user_mode(regs) && unsafe { !verify_area(buf_vaddr as u64, len as u64) } { + // 来自用户态,而buffer在内核态,这样的操作不被允许 + return (-(EPERM as i32)) as u64; + } + + let buf: &[u8] = + unsafe { core::slice::from_raw_parts::<'static, u8>(buf_vaddr as *mut u8, len) }; + + let r: Result = do_write(fd, buf); + + if r.is_ok() { + return r.unwrap() as u64; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 调整文件访问指针位置的系统调用函数 +/// +/// @param regs->r8 文件描述符编号 +/// @param regs->r9 调整偏移量 +/// @param regs->r10 调整的模式 +#[no_mangle] +pub extern "C" fn sys_lseek(regs: &pt_regs) -> u64 { + let fd = regs.r8 as i32; + let offset = regs.r9 as i64; + let whence = regs.r10 as u32; + + let w: SeekFrom = match whence { + SEEK_SET => SeekFrom::SeekSet(offset), + SEEK_CUR => SeekFrom::SeekCurrent(offset), + SEEK_END => SeekFrom::SeekEnd(offset), + SEEK_MAX => SeekFrom::SeekEnd(0), + _ => return (-(EINVAL as i32)) as u64, + }; + + let r: Result = do_lseek(fd, w); + if r.is_ok() { + return r.unwrap() as u64; + } else { + return r.unwrap_err() as u64; + } +} + +/// @brief 切换工作目录 +/// +/// @param dest_path 目标路径 +/// +/// @return 返回码 描述 +/// 0 | 成功 +/// +/// EACCESS | 权限不足 +/// +/// ELOOP | 解析path时遇到路径循环 +/// +/// ENAMETOOLONG | 路径名过长 +/// +/// ENOENT | 目标文件或目录不存在 +/// +/// ENODIR | 检索期间发现非目录项 +/// +/// ENOMEM | 系统内存不足 +/// +/// EFAULT | 错误的地址 +/// +/// ENAMETOOLONG | 路径过长 +#[no_mangle] +pub extern "C" fn sys_chdir(regs: &pt_regs) -> u64 { + if regs.r8 == 0 { + return -(EFAULT as i32) as u64; + } + let ptr = regs.r8 as usize as *const c_char; + // 权限校验 + if ptr.is_null() + || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) }) + { + return -(EINVAL as i32) as u64; + } + + let dest_path: &CStr = unsafe { CStr::from_ptr(ptr) }; + let dest_path: Result<&str, core::str::Utf8Error> = dest_path.to_str(); + + if dest_path.is_err() { + return (-(EINVAL as i32)) as u64; + } + + let dest_path: &str = dest_path.unwrap(); + + kdebug!("chdir: dest_path={dest_path}"); + if dest_path.len() == 0 { + return (-(EINVAL as i32)) as u64; + } else if dest_path.len() >= PAGE_4K_SIZE as usize { + return (-(ENAMETOOLONG as i32)) as u64; + } + + let path = Box::new(dest_path.clone()); + let inode = match ROOT_INODE().lookup(&path) { + Err(e) => { + kerror!("Change Directory Failed, Error = {}", e); + return (-(ENOENT as i32)) as u64; + } + Ok(i) => i, + }; + + match inode.metadata() { + Err(e) => { + kerror!("INode Get MetaData Failed, Error = {}", e); + return (-(ENOENT as i32)) as u64; + } + Ok(i) => { + if let FileType::Dir = i.file_type { + return 0; + } else { + return (-(ENOTDIR as i32)) as u64; + } + } + } +} + +/// @brief 获取目录中的数据 +/// +/// @param fd 文件描述符号 +/// @return uint64_t dirent的总大小 +#[no_mangle] +pub extern "C" fn sys_getdents(regs: &pt_regs) -> u64 { + let fd = regs.r8 as i32; + let count = regs.r10 as i64; + let dirent = match unsafe { (regs.r9 as usize as *mut Dirent).as_mut() } { + None => { + return 0; + } + Some(dirent) => dirent, + }; + + if fd < 0 || fd as u32 > PROC_MAX_FD_NUM { + return (-(EBADF as i32)) as u64; + } + + if count < 0 { + return (-(EINVAL as i32)) as u64; + } + + // 获取fd + let file: &mut File = match current_pcb().get_file_mut_by_fd(fd) { + None => { + return (-(EBADF as i32)) as u64; + } + Some(file) => file, + }; + // kdebug!("file={file:?}"); + + return match file.readdir(dirent) { + Err(_) => 0, + Ok(len) => len, + }; +} + +/// @brief 创建文件夹 +/// +/// @param path(r8) 路径 / mode(r9) 模式 +/// +/// @return uint64_t 负数错误码 / 0表示成功 +#[no_mangle] +pub extern "C" fn sys_mkdir(regs: &pt_regs) -> u64 { + let ptr = regs.r8 as usize as *const c_char; + if ptr.is_null() + || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) }) + { + return -(EINVAL as i32) as u64; + } + let path: &CStr = unsafe { CStr::from_ptr(ptr) }; + let path: Result<&str, core::str::Utf8Error> = path.to_str(); + let mode = regs.r9; + + if path.is_err() { + return (-(EINVAL as i32)) as u64; + } + + let path = &path.unwrap().to_string(); + if path.trim() == "" { + return (-(EINVAL as i32)) as u64; + } + + return match do_mkdir(&path, FileMode::from_bits_truncate(mode as u32)) { + Err(err) => { + kerror!("Failed in do_mkdir, Error Code = {}", err); + err as u64 + } + Ok(_) => 0, + }; +} + +///@brief 删除文件夹、取消文件的链接、删除文件的系统调用 +/// +///@param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h) +/// +///@param regs->r9 路径名称字符串 +/// +///@param regs->r10 flag 预留的标志位,暂时未使用,请置为0。 +/// +///@return uint64_t 错误码 +#[no_mangle] +pub extern "C" fn sys_unlink_at(regs: &pt_regs) -> u64 { + let _dfd = regs.r8; + let ptr = regs.r9 as usize as *const c_char; + if ptr.is_null() + || (user_mode(regs) && unsafe { !verify_area(ptr as u64, PAGE_2M_SIZE as u64) }) + { + return -(EINVAL as i32) as u64; + } + let path: &CStr = unsafe { CStr::from_ptr(ptr) }; + let path: Result<&str, core::str::Utf8Error> = path.to_str(); + let flag = regs.r10; + if path.is_err() { + return (-(EINVAL as i32)) as u64; + } + + let path = &path.unwrap().to_string(); + // kdebug!("sys_unlink_at={path:?}"); + if (flag & (!(AT_REMOVEDIR as u64))) != 0_u64 { + return (-(EINVAL as i32)) as u64; + } + + if (flag & (AT_REMOVEDIR as u64)) > 0 { + // kdebug!("rmdir"); + match do_remove_dir(&path) { + Err(err) => { + kerror!("Failed to Remove Directory, Error Code = {}", err); + return err as u64; + } + Ok(_) => { + return 0; + } + } + } + + // kdebug!("rm"); + match do_unlink_at(&path, FileMode::from_bits_truncate(flag as u32)) { + Err(err) => { + kerror!("Failed to Remove Directory, Error Code = {}", err); + return err as u64; + } + Ok(_) => { + return 0; + } + } +} diff --git a/kernel/src/filesystem/vfs/utils.rs b/kernel/src/filesystem/vfs/utils.rs new file mode 100644 index 00000000..dd9db916 --- /dev/null +++ b/kernel/src/filesystem/vfs/utils.rs @@ -0,0 +1,21 @@ +/// @brief 切分路径字符串,返回最左侧那一级的目录名和剩余的部分。 +/// +/// 举例:对于 /123/456/789/ 本函数返回的第一个值为123, 第二个值为456/789 +pub fn split_path(path: &str) -> (&str, Option<&str>) { + let mut path_split: core::str::SplitN<&str> = path.trim_matches('/').splitn(2, "/"); + let comp = path_split.next().unwrap_or(""); + let rest_opt = path_split.next(); + + return (comp, rest_opt); +} + +/// @brief 切分路径字符串,返回最右侧那一级的目录名和剩余的部分。 +/// +/// 举例:对于 /123/456/789/ 本函数返回的第一个值为789, 第二个值为123/456 +pub fn rsplit_path(path: &str) -> (&str, Option<&str>) { + let mut path_split: core::str::RSplitN<&str> = path.trim_matches('/').rsplitn(2, "/"); + let comp = path_split.next().unwrap_or(""); + let rest_opt = path_split.next(); + + return (comp, rest_opt); +} diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 52d9e9f2..4b8c42db 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -25,9 +25,13 @@ #include #include #include +#include #include #include +#include #include +#include +#include #include #include #include diff --git a/kernel/src/io/block/block_io_scheduler.c b/kernel/src/io/block/block_io_scheduler.c deleted file mode 100644 index a5df8780..00000000 --- a/kernel/src/io/block/block_io_scheduler.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include -#include -#include -/** - * @brief 初始化io调度器 - */ -void block_io_scheduler_init() -{ - // 使用rust中的函数进行初始化 - block_io_scheduler_init_rust(); - struct process_control_block *pcb = kthread_run(&block_io_scheduler_address_requests, NULL, "block_io_scheduler", NULL); - if (smp_get_total_cpu() > 1) - sched_migrate_process(pcb, 1); -} \ No newline at end of file diff --git a/kernel/src/io/block/block_io_scheduler.h b/kernel/src/io/block/block_io_scheduler.h deleted file mode 100644 index 4db658a9..00000000 --- a/kernel/src/io/block/block_io_scheduler.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -extern void block_io_scheduler_address_requests(); -extern void block_io_scheduler_init_rust(); - -/** - * @brief 初始化io调度器 - */ -void block_io_scheduler_init(); diff --git a/kernel/src/io/block/block_io_scheduler.rs b/kernel/src/io/block/block_io_scheduler.rs deleted file mode 100644 index 1e3019b1..00000000 --- a/kernel/src/io/block/block_io_scheduler.rs +++ /dev/null @@ -1,304 +0,0 @@ -use core::{ptr::null_mut, sync::atomic::compiler_fence}; - -use alloc::{boxed::Box, vec::Vec}; - -use crate::{ - arch::mm::barrier::mfence, - include::bindings::bindings::{ - ahci_check_complete, ahci_query_disk, ahci_request_packet_t, block_device_request_packet, - complete, completion, completion_alloc, wait_for_completion, - }, - kBUG, - libs::spinlock::RawSpinlock, -}; -#[derive(Debug)] -/// achi请求包 -pub struct AhciRequestPacket { - pub ahci_ctrl_num: u8, - pub port_num: u8, - pub slot: i8, -} - -impl AhciRequestPacket { - pub fn new() -> Self { - return AhciRequestPacket { - ..Default::default() - }; - } -} - -impl Default for AhciRequestPacket { - fn default() -> Self { - AhciRequestPacket { - ahci_ctrl_num: 0, - port_num: Default::default(), - slot: -1, - } - } -} -#[derive(Debug)] - -/// io请求包 -pub struct BlockDeviceRequestPacket { - pub cmd: u8, - pub lba_start: u64, - pub count: u32, - pub buffer_vaddr: u64, - pub device_type: u8, // 0: ahci - pub end_handler: ::core::option::Option< - unsafe extern "C" fn(num: ::core::ffi::c_ulong, arg: ::core::ffi::c_ulong), - >, - pub private_ahci_request_packet: T, - pub status: *mut completion, -} -impl BlockDeviceRequestPacket { - pub fn new( - ahci_request_packet: AhciRequestPacket, - ) -> BlockDeviceRequestPacket { - let cmpl: *mut completion = unsafe { completion_alloc() }; - - return BlockDeviceRequestPacket { - cmd: Default::default(), - lba_start: Default::default(), - count: Default::default(), - buffer_vaddr: Default::default(), - device_type: Default::default(), - end_handler: Default::default(), - private_ahci_request_packet: ahci_request_packet, - status: cmpl, - }; - } -} - -struct RequestQueue { - lock: RawSpinlock, - waiting_queue: Vec>, - processing_queue: Vec>, -} - -impl RequestQueue { - pub fn new() -> RequestQueue { - RequestQueue { - lock: RawSpinlock::INIT, - waiting_queue: Vec::new(), - processing_queue: Vec::new(), - } - } - - /// @brief 将请求包插入等待队列中 - pub fn push_waiting_queue( - &mut self, - ahci_request_packet: BlockDeviceRequestPacket, - ) { - self.waiting_queue.push(ahci_request_packet); - } - - /// @brief 将请求包从正在执行队列中弹出 - pub fn pop_waiting_queue(&mut self) -> Option> { - let mut res: Option> = None; - if self.waiting_queue.len() == 0 { - return res; - } - res = Some(self.waiting_queue.remove(0)); - return res; - } - - /// @brief 将请求包插入正在执行队列中 - pub fn push_processing_queue( - &mut self, - ahci_request_packet: BlockDeviceRequestPacket, - ) { - self.processing_queue.push(ahci_request_packet); - } - - /// @brief 将请求包从正在执行队列中弹出 - pub fn pop_processing_queue(&mut self) -> Option> { - let mut res: Option> = None; - if self.processing_queue.len() == 0 { - return res; - } - res = Some(self.processing_queue.remove(0)); - return res; - } - - /// @brief 将已完成请求包从执行队列中弹出 - pub fn pop_finished_packets(&mut self) { - if self.processing_queue.len() != 0 { - compiler_fence(core::sync::atomic::Ordering::SeqCst); - //将状态设置为完成 - mfence(); - // 过滤器,过滤已完成的请求包 - let filter = |packet: &mut BlockDeviceRequestPacket| { - //判断请求是否完成 - let res = unsafe { - ahci_check_complete( - packet.private_ahci_request_packet.port_num, - packet.private_ahci_request_packet.ahci_ctrl_num, - packet.private_ahci_request_packet.slot, - null_mut(), - ) - }; - // 完成则complete请求包 - if res == 0 { - unsafe { - compiler_fence(core::sync::atomic::Ordering::SeqCst); - complete(packet.status); - compiler_fence(core::sync::atomic::Ordering::SeqCst); - } - return true; - } - return false; - }; - self.processing_queue.drain_filter(filter); - mfence(); - compiler_fence(core::sync::atomic::Ordering::SeqCst); - } - } -} - -pub struct SchedulerIO { - io_queue: Vec<&'static mut RequestQueue>, -} - -impl SchedulerIO { - pub fn new() -> SchedulerIO { - return SchedulerIO { - io_queue: Default::default(), - }; - } -} -// io调度器全局指针 -pub static mut IO_SCHEDULER_PTR: *mut SchedulerIO = null_mut(); - -#[inline] -pub fn __get_io_scheduler() -> &'static mut SchedulerIO { - return unsafe { IO_SCHEDULER_PTR.as_mut().unwrap() }; -} - -/// @brief 初始化io调度器 -#[no_mangle] -pub unsafe extern "C" fn block_io_scheduler_init_rust() { - if IO_SCHEDULER_PTR.is_null() { - IO_SCHEDULER_PTR = Box::leak(Box::new(SchedulerIO::new())); - create_io_queue(); - } else { - kBUG!("Try to init IO Scheduler twice."); - panic!("Try to init IO Scheduler twice."); - } -} - -/// @brief 初始化io请求队列 -#[no_mangle] -pub extern "C" fn create_io_queue() { - let io_scheduler = __get_io_scheduler(); - io_scheduler - .io_queue - .push(Box::leak(Box::new(RequestQueue::new()))); -} - -#[no_mangle] -/// @brief 处理请求 (守护线程运行) -pub extern "C" fn block_io_scheduler_address_requests() { - let io_scheduler = __get_io_scheduler(); - - compiler_fence(core::sync::atomic::Ordering::SeqCst); - //FIXME 暂时只考虑了一个io队列的情况 - loop { - compiler_fence(core::sync::atomic::Ordering::SeqCst); - - //请不要修改下面三个循环的顺序 - let size = io_scheduler.io_queue[0].waiting_queue.len(); - for i in 0..16 { - // 正在运行队列大小限制为16 - if i >= size || io_scheduler.io_queue[0].processing_queue.len() == 16 { - break; - } - compiler_fence(core::sync::atomic::Ordering::SeqCst); - // if !io_scheduler.io_queue[0].lock.is_locked() { - io_scheduler.io_queue[0].lock.lock(); - let mut packet = io_scheduler.io_queue[0].pop_waiting_queue().unwrap(); - //将rust中的请求包转成c中的请求包 - let mut ahci_packet: ahci_request_packet_t = convert_c_ahci_request(&packet); - let mut ret_slot: i8 = -1; - //分发请求包 - unsafe { - compiler_fence(core::sync::atomic::Ordering::SeqCst); - ahci_query_disk(&mut ahci_packet, &mut ret_slot); - compiler_fence(core::sync::atomic::Ordering::SeqCst); - } - //获取请求运行的插槽 - packet.private_ahci_request_packet.slot = ret_slot; - io_scheduler.io_queue[0].push_processing_queue(packet); - io_scheduler.io_queue[0].lock.unlock(); - // } - - compiler_fence(core::sync::atomic::Ordering::SeqCst); - } - compiler_fence(core::sync::atomic::Ordering::SeqCst); - - //检查是否有完成的请求包 - io_scheduler.io_queue[0].lock.lock(); - io_scheduler.io_queue[0].pop_finished_packets(); - io_scheduler.io_queue[0].lock.unlock(); - mfence(); - compiler_fence(core::sync::atomic::Ordering::SeqCst); - } -} - -pub fn convert_c_ahci_request( - pakcet: &BlockDeviceRequestPacket, -) -> ahci_request_packet_t { - let ahci_packet: ahci_request_packet_t = ahci_request_packet_t { - ahci_ctrl_num: pakcet.private_ahci_request_packet.ahci_ctrl_num, - port_num: pakcet.private_ahci_request_packet.port_num, - blk_pak: block_device_request_packet { - LBA_start: pakcet.lba_start, - cmd: pakcet.cmd, - buffer_vaddr: pakcet.buffer_vaddr, - count: pakcet.count, - device_type: pakcet.device_type, - end_handler: pakcet.end_handler, - }, - }; - return ahci_packet; -} - -/// @brief 将c中的ahci_request_packet_t转换成rust中的BlockDeviceRequestPacket -pub fn create_ahci_request( - ahci_request_packet: &ahci_request_packet_t, -) -> BlockDeviceRequestPacket { - let cmpl: *mut completion = unsafe { completion_alloc() }; - let ahci_packet = AhciRequestPacket { - ahci_ctrl_num: ahci_request_packet.ahci_ctrl_num, - port_num: ahci_request_packet.port_num, - slot: -1, - }; - let packet = BlockDeviceRequestPacket { - private_ahci_request_packet: ahci_packet, - buffer_vaddr: ahci_request_packet.blk_pak.buffer_vaddr, - cmd: ahci_request_packet.blk_pak.cmd, - count: ahci_request_packet.blk_pak.count, - device_type: ahci_request_packet.blk_pak.device_type, - end_handler: ahci_request_packet.blk_pak.end_handler, - lba_start: ahci_request_packet.blk_pak.LBA_start, - status: cmpl, - }; - - return packet; -} - -#[no_mangle] -/// @brief 将ahci的io请求插入等待队列中 -pub extern "C" fn ahci_push_request(ahci_request_packet: &ahci_request_packet_t) { - let packet = create_ahci_request(ahci_request_packet); - let io_scheduler = __get_io_scheduler(); - let status = packet.status; - io_scheduler.io_queue[0].lock.lock(); - io_scheduler.io_queue[0].push_waiting_queue(packet); - io_scheduler.io_queue[0].lock.unlock(); - compiler_fence(core::sync::atomic::Ordering::SeqCst); - unsafe { - wait_for_completion(status); - } - compiler_fence(core::sync::atomic::Ordering::SeqCst); -} diff --git a/kernel/src/io/block/mod.rs b/kernel/src/io/block/mod.rs index a4fe0724..6915db41 100644 --- a/kernel/src/io/block/mod.rs +++ b/kernel/src/io/block/mod.rs @@ -1 +1 @@ -pub mod block_io_scheduler; +// pub mod block_io_scheduler; diff --git a/kernel/src/io/device.rs b/kernel/src/io/device.rs new file mode 100644 index 00000000..2e593207 --- /dev/null +++ b/kernel/src/io/device.rs @@ -0,0 +1,323 @@ +/// 引入Module +use crate::include::bindings::bindings::E2BIG; +use alloc::{sync::Arc, vec::Vec}; +use core::{any::Any, fmt::Debug}; + +use super::disk_info::Partition; + +/// 该文件定义了 Device 和 BlockDevice 的接口 +/// Notice 设备错误码使用 Posix 规定的 int32_t 的错误码表示,而不是自己定义错误enum + +// 使用方法: +// 假设 blk_dev 是块设备 +// ::read_at() 调用的是Device的函数 +// ::read_at() 调用的是BlockDevice的函数 + +/// 定义类型 +pub type BlockId = usize; + +/// 定义常量 +const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12. +/// 在DragonOS中,我们认为磁盘的每个LBA大小均为512字节。(注意,文件系统的1个扇区可能事实上是多个LBA) +pub const LBA_SIZE: usize = 512; + +/// @brief 设备应该实现的操作 +/// @usage Device::read_at() +pub trait Device: Any + Send + Sync + Debug { + /// Notice buffer对应设备按字节划分,使用u8类型 + /// Notice offset应该从0开始计数 + + /// @brief: 从设备的第offset个字节开始,读取len个byte,存放到buf中 + /// @parameter offset: 起始字节偏移量 + /// @parameter len: 读取字节的数量 + /// @parameter buf: 目标数组 + /// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度 + fn read_at(&self, offset: usize, len: usize, buf: &mut [u8]) -> Result; + + /// @brief: 从设备的第offset个字节开始,把buf数组的len个byte,写入到设备中 + /// @parameter offset: 起始字节偏移量 + /// @parameter len: 读取字节的数量 + /// @parameter buf: 目标数组 + /// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度 + fn write_at(&self, offset: usize, len: usize, buf: &[u8]) -> Result; + + /// @brief: 同步信息,把所有的dirty数据写回设备 - 待实现 + fn sync(&self) -> Result<(), i32>; + + // TODO: 待实现 open, close +} + +/// @brief 块设备应该实现的操作 +pub trait BlockDevice: Any + Send + Sync + Debug { + /// @brief: 在块设备中,从第lba_id_start个块开始,读取count个块数据,存放到buf中 + /// + /// @parameter lba_id_start: 起始块 + /// @parameter count: 读取块的数量 + /// @parameter buf: 目标数组 + /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节; + /// 否则返回Err(错误码),其中错误码为负数; + /// 如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度) + fn read_at(&self, lba_id_start: BlockId, count: usize, buf: &mut [u8]) -> Result; + + /// @brief: 在块设备中,从第lba_id_start个块开始,把buf中的count个块数据,存放到设备中 + /// @parameter lba_id_start: 起始块 + /// @parameter count: 写入块的数量 + /// @parameter buf: 目标数组 + /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节; + /// 否则返回Err(错误码),其中错误码为负数; + /// 如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度) + fn write_at(&self, lba_id_start: BlockId, count: usize, buf: &[u8]) -> Result; + + /// @brief: 同步磁盘信息,把所有的dirty数据写回硬盘 - 待实现 + fn sync(&self) -> Result<(), i32>; + + /// @breif: 每个块设备都必须固定自己块大小,而且该块大小必须是2的幂次 + /// @return: 返回一个固定量,硬编码(编程的时候固定的常量). + fn blk_size_log2(&self) -> u8; + + // TODO: 待实现 open, close + + /// @brief 本函数用于实现动态转换。 + /// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self + fn as_any_ref(&self) -> &dyn Any; + + /// @brief 本函数用于将BlockDevice转换为Device。 + /// 由于实现了BlockDevice的结构体,本身也实现了Device Trait, 因此转换是可能的。 + /// 思路:在BlockDevice的结构体中新增一个self_ref变量,返回self_ref.upgrade()即可。 + fn device(&self) -> Arc; + + /// @brief 返回块设备的块大小(单位:字节) + fn block_size(&self) -> usize; + + /// @brief 返回当前磁盘上的所有分区的Arc指针数组 + fn partitions(&self) -> Vec>; +} + +/// 对于所有<块设备>自动实现 Device Trait 的 read_at 和 write_at 函数 +impl Device for T { + // 读取设备操作,读取设备内部 [offset, offset + buf.len) 区间内的字符,存放到 buf 中 + fn read_at(&self, offset: usize, len: usize, buf: &mut [u8]) -> Result { + if len > buf.len() { + return Err(-(E2BIG as i32)); + } + + let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2()); + let multi = iter.multiblock; + + // 枚举每一个range + for range in iter { + let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节 + let buf_end = range.origin_end() - offset; + let buf_slice = &mut buf[buf_begin..buf_end]; + let count: usize = (range.lba_end - range.lba_start).try_into().unwrap(); + let full = multi && range.is_multi() || !multi && range.is_full(); + + if full { + // 调用 BlockDevice::read_at() 直接把引用传进去,不是把整个数组move进去 + BlockDevice::read_at(self, range.lba_start, count, buf_slice)?; + } else { + // 判断块的长度不能超过最大值 + if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT { + return Err(-(E2BIG as i32)); + } + + let mut temp = Vec::new(); + temp.resize(1usize << self.blk_size_log2(), 0); + BlockDevice::read_at(self, range.lba_start, 1, &mut temp[..])?; + // 把数据从临时buffer复制到目标buffer + buf_slice.copy_from_slice(&temp[range.begin..range.end]); + } + } + return Ok(len); + } + + /// 写入设备操作,把 buf 的数据写入到设备内部 [offset, offset + len) 区间内 + fn write_at(&self, offset: usize, len: usize, buf: &[u8]) -> Result { + // assert!(len <= buf.len()); + if len > buf.len() { + return Err(-(E2BIG as i32)); + } + + let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2()); + let multi = iter.multiblock; + + for range in iter { + let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节 + let buf_end = range.origin_end() - offset; + let buf_slice = &buf[buf_begin..buf_end]; + let count: usize = (range.lba_end - range.lba_start).try_into().unwrap(); + let full = multi && range.is_multi() || !multi && range.is_full(); + + if full { + BlockDevice::write_at(self, range.lba_start, count, buf_slice)?; + } else { + if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT { + return Err(-(E2BIG as i32)); + } + + let mut temp = Vec::new(); + temp.resize(1usize << self.blk_size_log2(), 0); + // 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全 + BlockDevice::read_at(self, range.lba_start, 1, &mut temp[..])?; + // 把数据从临时buffer复制到目标buffer + temp[range.begin..range.end].copy_from_slice(&buf_slice); + BlockDevice::write_at(self, range.lba_start, 1, &temp[..])?; + } + } + return Ok(len); + } + + /// 数据同步 + fn sync(&self) -> Result<(), i32> { + BlockDevice::sync(self) + } +} + +/// @brief 块设备的迭代器 +/// @usage 某次操作读/写块设备的[L,R]范围内的字节, +/// 那么可以使用此结构体进行迭代遍历,每次调用next()返回一个BlockRange +pub struct BlockIter { + pub begin: usize, // 迭代器的起始位置 -> 块设备的地址 (单位是字节) + pub end: usize, + pub blk_size_log2: u8, + pub multiblock: bool, // 是否启用连续整块同时遍历 +} + +/// @brief Range搭配迭代器BlockIter使用,[L,R]区间被分割成多个小的Range +/// Range要么是整块,要么是一块的某一部分 +/// 细节: range = [begin, end) 左闭右开 +pub struct BlockRange { + pub lba_start: usize, // 起始块的lba_id + pub lba_end: usize, // 终止块的lba_id + pub begin: usize, // 起始位置在块内的偏移量, 如果BlockIter启用Multiblock,则是多个块的偏移量 + pub end: usize, // 结束位置在块内的偏移量,单位是字节 + pub blk_size_log2: u8, +} + +impl BlockIter { + #[allow(dead_code)] + pub fn new(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter { + return BlockIter { + begin: start_addr, + end: end_addr, + blk_size_log2: blk_size_log2, + multiblock: false, + }; + } + pub fn new_multiblock(start_addr: usize, end_addr: usize, blk_size_log2: u8) -> BlockIter { + return BlockIter { + begin: start_addr, + end: end_addr, + blk_size_log2: blk_size_log2, + multiblock: true, + }; + } + + /// 获取下一个整块或者不完整的块 + pub fn next_block(&mut self) -> BlockRange { + let blk_size_log2 = self.blk_size_log2; + let blk_size = 1usize << self.blk_size_log2; + let lba_id = self.begin / blk_size; + let begin = self.begin % blk_size; + let end = if lba_id == self.end / blk_size { + self.end % blk_size + } else { + blk_size + }; + + self.begin += end - begin; + + return BlockRange { + lba_start: lba_id, + lba_end: lba_id + 1, + begin: begin, + end: end, + blk_size_log2: blk_size_log2, + }; + } + + /// 如果能返回多个连续的整块,则返回;否则调用next_block()返回不完整的块 + pub fn next_multiblock(&mut self) -> BlockRange { + let blk_size_log2 = self.blk_size_log2; + let blk_size = 1usize << self.blk_size_log2; + let lba_start = self.begin / blk_size; + let lba_end = self.end / blk_size; + + // 如果不是整块,先返回非整块的小部分 + if __bytes_to_lba(self.begin, blk_size) + != __bytes_to_lba(self.begin + blk_size - 1, blk_size) + || lba_start == lba_end + { + return self.next_block(); + } + + let begin = self.begin % blk_size; // 因为是多个整块,这里必然是0 + let end = __lba_to_bytes(lba_end, blk_size) - self.begin; + + self.begin += end - begin; + + return BlockRange { + lba_start: lba_start, + lba_end: lba_end, + begin: begin, + end: end, + blk_size_log2: blk_size_log2, + }; + } +} + +/// BlockIter 函数实现 +impl Iterator for BlockIter { + type Item = BlockRange; + + fn next(&mut self) -> Option<::Item> { + if self.begin >= self.end { + return None; + } + if self.multiblock { + return Some(self.next_multiblock()); + } else { + return Some(self.next_block()); + } + } +} + +/// BlockRange 函数实现 +impl BlockRange { + #[allow(dead_code)] + pub fn is_empty(&self) -> bool { + return self.end == self.begin; + } + pub fn len(&self) -> usize { + return self.end - self.begin; + } + /// 判断是不是整块 + pub fn is_full(&self) -> bool { + return self.len() == (1usize << self.blk_size_log2); + } + /// 判断是不是多个整块连在一起 + pub fn is_multi(&self) -> bool { + return self.len() >= (1usize << self.blk_size_log2) + && (self.len() % (1usize << self.blk_size_log2) == 0); + } + /// 获取 BlockRange 在块设备内部的起始位置 (单位是字节) + pub fn origin_begin(&self) -> usize { + return (self.lba_start << self.blk_size_log2) + self.begin; + } + /// 获取 BlockRange 在块设备内部的结尾位置 (单位是字节) + pub fn origin_end(&self) -> usize { + return (self.lba_start << self.blk_size_log2) + self.end; + } +} + +/// 从字节地址转换到lba id +#[inline] +pub fn __bytes_to_lba(addr: usize, blk_size: usize) -> BlockId { + return addr / blk_size; +} + +/// 从lba id转换到字节地址, 返回lba_id的最左侧字节 +#[inline] +pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId { + return lba_id * blk_size; +} diff --git a/kernel/src/io/disk_info.rs b/kernel/src/io/disk_info.rs new file mode 100644 index 00000000..6301f744 --- /dev/null +++ b/kernel/src/io/disk_info.rs @@ -0,0 +1,49 @@ +#![allow(dead_code)] +use super::device::BlockDevice; + +use alloc::sync::{Arc, Weak}; + +pub type SectorT = u64; + +pub const BLK_TYPE_AHCI: u64 = 0; +pub const DISK_NAME_LEN: usize = 32; // 磁盘名称的最大长度 +pub const BLK_GF_AHCI: u16 = 1 << 0; // 定义blk_gendisk中的标志位 + +/// @brief: 磁盘的分区信息 - (保留了c版本的数据信息) +#[derive(Debug)] +pub struct Partition { + pub start_sector: SectorT, // 该分区的起始扇区 + pub lba_start: u64, // 起始LBA号 + pub sectors_num: u64, // 该分区的扇区数 + disk: Weak, // 当前分区所属的磁盘 + pub partno: u16, // 在磁盘上的分区号 + + // struct block_device_request_queue *bd_queue; // 请求队列 + // struct vfs_superblock_t *bd_superblock; // 执行超级块的指针 +} + +/// @brief: 分区信息 - 成员函数 +impl Partition { + /// @brief: 为 disk new 一个分区结构体 + pub fn new( + start_sector: SectorT, + lba_start: u64, + sectors_num: u64, + disk: Weak, + partno: u16, + ) -> Arc { + return Arc::new(Partition { + start_sector, + lba_start, + sectors_num, + disk, + partno, + }); + } + + /// @brief 获取当前分区所属的磁盘的Arc指针 + #[inline] + pub fn disk(&self) -> Arc { + return self.disk.upgrade().unwrap(); + } +} diff --git a/kernel/src/io/mod.rs b/kernel/src/io/mod.rs index a863eaad..003fb3a6 100644 --- a/kernel/src/io/mod.rs +++ b/kernel/src/io/mod.rs @@ -1 +1,12 @@ pub mod block; +pub mod device; +pub mod disk_info; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum SeekFrom { + SeekSet(i64), + SeekCurrent(i64), + SeekEnd(i64), + Invalid, +} diff --git a/kernel/src/ipc/Makefile b/kernel/src/ipc/Makefile index 2be17c47..73b26f87 100644 --- a/kernel/src/ipc/Makefile +++ b/kernel/src/ipc/Makefile @@ -1,10 +1,10 @@ -all: pipe.o +all: CFLAGS += -I . -pipe.o: pipe.c - $(CC) $(CFLAGS) -c pipe.c -o pipe.o +# pipe.o: pipe.c +# $(CC) $(CFLAGS) -c pipe.c -o pipe.o clean: echo "Done." \ No newline at end of file diff --git a/kernel/src/ipc/pipe.c b/kernel/src/ipc/pipe.c deleted file mode 100644 index 8a8a207a..00000000 --- a/kernel/src/ipc/pipe.c +++ /dev/null @@ -1,176 +0,0 @@ -#include "pipe.h" -#include -#include -#include -#include -#include -#include -#include - -struct pipe_data_t -{ - volatile unsigned int valid_cnt; - unsigned int read_pos; - unsigned int write_pos; - wait_queue_node_t read_wait_queue; - wait_queue_node_t write_wait_queue; - spinlock_t lock; -} __attribute__((packed)); - -// 由于kmalloc分配的内存是按照2^n对齐的,因此我们需要这样来确定pipe的buffer大小以消除内部碎片 -// 我们设定pipe的总大小为1024字节 -#define PIPE_BUFF_SIZE (1024 - sizeof(struct pipe_data_t)) - -struct pipe_t -{ - struct pipe_data_t data; - char buf[PIPE_BUFF_SIZE]; -}; - -long pipe_read(struct vfs_file_t *file_ptr, char *buf, - int64_t count, long *position) -{ - int i = 0; - struct pipe_t *pipe_ptr = NULL; - - kdebug("pipe_read into!\n"); - pipe_ptr = (struct pipe_t *)file_ptr->private_data; - spin_lock(&pipe_ptr->data.lock); - while (pipe_ptr->data.valid_cnt == 0) - { - /* pipe 空 */ - kdebug("pipe_read empty!\n"); - wait_queue_wakeup(&pipe_ptr->data.write_wait_queue, PROC_UNINTERRUPTIBLE); - wait_queue_sleep_on_unlock(&pipe_ptr->data.read_wait_queue, (void *)&pipe_ptr->data.lock); - spin_lock(&pipe_ptr->data.lock); - } - for (i = 0; i < pipe_ptr->data.valid_cnt; i++) - { - if (i == count) - { - break; - } - copy_to_user(buf + i, &pipe_ptr->buf[pipe_ptr->data.read_pos], sizeof(char)); - pipe_ptr->data.read_pos = (pipe_ptr->data.read_pos + 1) % PIPE_BUFF_SIZE; - } - pipe_ptr->data.valid_cnt = pipe_ptr->data.valid_cnt - i; - spin_unlock(&pipe_ptr->data.lock); - wait_queue_wakeup(&pipe_ptr->data.write_wait_queue, PROC_UNINTERRUPTIBLE); - kdebug("pipe_read end!\n"); - - return i; -} -long pipe_write(struct vfs_file_t *file_ptr, char *buf, - int64_t count, long *position) -{ - int i = 0; - struct pipe_t *pipe_ptr = NULL; - - kdebug("pipe_write into!\n"); - pipe_ptr = (struct pipe_t *)file_ptr->private_data; - spin_lock(&pipe_ptr->data.lock); - while (pipe_ptr->data.valid_cnt + count >= PIPE_BUFF_SIZE) - { - /* pipe 满 */ - kdebug("pipe_write pipe full!\n"); - wait_queue_wakeup(&pipe_ptr->data.read_wait_queue, PROC_UNINTERRUPTIBLE); - wait_queue_sleep_on_unlock(&pipe_ptr->data.write_wait_queue, (void *)&pipe_ptr->data.lock); - spin_lock(&pipe_ptr->data.lock); - } - for (i = pipe_ptr->data.valid_cnt; i < PIPE_BUFF_SIZE; i++) - { - if (i - pipe_ptr->data.valid_cnt == count) - { - break; - } - copy_from_user(&pipe_ptr->buf[pipe_ptr->data.write_pos], buf + i, sizeof(char)); - pipe_ptr->data.write_pos = (pipe_ptr->data.write_pos + 1) % PIPE_BUFF_SIZE; - } - pipe_ptr->data.valid_cnt += count; - spin_unlock(&pipe_ptr->data.lock); - wait_queue_wakeup(&pipe_ptr->data.read_wait_queue, PROC_UNINTERRUPTIBLE); - kdebug("pipe_write out!\n"); - - return count; -} - -long pipe_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) -{ - return 0; -} - -struct vfs_file_operations_t g_pipe_file_ops = { - .open = NULL, - .close = pipe_close, - .read = pipe_read, - .write = pipe_write, - .lseek = NULL, - .ioctl = NULL, - .readdir = NULL, -}; - -static struct pipe_t *pipe_alloc() -{ - struct pipe_t *pipe_ptr = NULL; - - pipe_ptr = (struct pipe_t *)kzalloc(sizeof(struct pipe_t), 0); - spin_init(&pipe_ptr->data.lock); - pipe_ptr->data.read_pos = 0; - pipe_ptr->data.write_pos = 0; - pipe_ptr->data.valid_cnt = 0; - memset(pipe_ptr->buf, 0, PIPE_BUFF_SIZE); - wait_queue_init(&pipe_ptr->data.read_wait_queue, NULL); - wait_queue_init(&pipe_ptr->data.write_wait_queue, NULL); - - return pipe_ptr; -} - -/** - * @brief 创建管道 - * - * @param fd(r8) 文件句柄指针 - * @param num(r9) 文件句柄个数 - * @return uint64_t - */ -uint64_t sys_pipe(struct pt_regs *regs) -{ - int *fd = NULL; - struct pipe_t *pipe_ptr = NULL; - struct vfs_file_t *read_file = NULL; - struct vfs_file_t *write_file = NULL; - - fd = (int *)regs->r8; - kdebug("pipe creat into!\n"); - /* step1 申请pipe结构体、初始化 */ - pipe_ptr = pipe_alloc(); - /* step2 申请2个fd文件句柄,1个作为读端、1个作为写端 */ - read_file = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0); - fd[0] = process_fd_alloc(read_file); - if (fd[0] == -1) - { - kdebug("pipe alloc read fd fail!\n"); - kfree(pipe_ptr); - kfree(read_file); - return -1; - } - write_file = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0); - fd[1] = process_fd_alloc(write_file); - if (fd[1] == -1) - { - kdebug("pipe alloc write fd fail!\n"); - kfree(pipe_ptr); - kfree(read_file); - kfree(write_file); - return -1; - } - /* step3 绑定pipe和file */ - read_file->private_data = (void *)pipe_ptr; - read_file->file_ops = &g_pipe_file_ops; - read_file->mode = VFS_FILE_MODE_READ; - write_file->private_data = (void *)pipe_ptr; - write_file->file_ops = &g_pipe_file_ops; - write_file->mode = VFS_FILE_MODE_WRITE; - kdebug("pipe creat end!\n"); - - return 0; -} diff --git a/kernel/src/ipc/pipe.h b/kernel/src/ipc/pipe.h deleted file mode 100644 index fc4e81c8..00000000 --- a/kernel/src/ipc/pipe.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __PIPE_H__ -#define __PIPE_H__ - -#endif \ No newline at end of file diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 56b3cdaa..5f49db1a 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -16,26 +16,29 @@ use core::panic::PanicInfo; #[path = "arch/x86_64/mod.rs"] #[macro_use] mod arch; - -mod driver; -mod filesystem; -#[macro_use] -mod include; -mod ipc; #[macro_use] mod libs; +#[macro_use] +mod include; +mod driver; // 如果driver依赖了libs,应该在libs后面导出 mod exception; -pub mod io; +mod filesystem; +mod io; +mod ipc; mod mm; mod process; mod sched; mod smp; mod time; +#[macro_use] extern crate alloc; #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate bitflags; + use mm::allocator::KernelAllocator; // <3> diff --git a/kernel/src/libs/kfifo.c b/kernel/src/libs/kfifo.c index 18d08470..30be88d7 100644 --- a/kernel/src/libs/kfifo.c +++ b/kernel/src/libs/kfifo.c @@ -10,7 +10,7 @@ * @param fifo 队列结构体 * @param size 缓冲区大小 * @param reserved 暂时保留,请置为0 - * @return int 错误码:成功->0 + * @return int 错误码: NOMEM; 成功->0 */ int kfifo_alloc(struct kfifo_t *fifo, uint32_t size, uint64_t reserved) { diff --git a/kernel/src/libs/lockref.c b/kernel/src/libs/lockref.c index 6491d7a0..cdbe52a8 100644 --- a/kernel/src/libs/lockref.c +++ b/kernel/src/libs/lockref.c @@ -52,16 +52,20 @@ void lockref_inc(struct lockref *lock_ref) * @brief 原子地将引用计数加1.如果原来的count≤0,则操作失败。 * * @param lock_ref 指向要被操作的lockref变量的指针 - * @return int 操作成功=>true + * @return bool 操作成功=>true * 操作失败=>false */ bool lockref_inc_not_zero(struct lockref *lock_ref) { - CMPXCHG_LOOP(lock_ref, - if (old.count <= 0) return false; - ++new.count; - , - return true;) + CMPXCHG_LOOP( + lock_ref, + { + if (old.count <= 0) + return false; + ++new.count; + }, + { return true; }) + bool retval; spin_lock(&lock_ref->lock); retval = false; @@ -86,11 +90,14 @@ bool lockref_inc_not_zero(struct lockref *lock_ref) */ int lockref_dec(struct lockref *lock_ref) { - CMPXCHG_LOOP(lock_ref, - if (old.count <= 0) break; - --new.count; - , - return new.count;); + CMPXCHG_LOOP( + lock_ref, + { + if (old.count <= 0) + break; + --new.count; + }, + { return new.count; }) // 如果xchg时,处于已加锁的状态或者检测到old.count <= 0,则采取加锁处理 int retval = -1; @@ -117,11 +124,14 @@ int lockref_dec(struct lockref *lock_ref) */ int lockref_dec_return(struct lockref *lock_ref) { - CMPXCHG_LOOP(lock_ref, - if (old.count <= 0) return -1; - --new.count; - , - return new.count;); + CMPXCHG_LOOP( + lock_ref, + { + if (old.count <= 0) + return -1; + --new.count; + }, + { return new.count; }) return -1; } @@ -138,11 +148,14 @@ int lockref_dec_return(struct lockref *lock_ref) */ bool lockref_dec_not_zero(struct lockref *lock_ref) { - CMPXCHG_LOOP(lock_ref, - if (old.count <= 1) return false; - --new.count; - , - return true;) + CMPXCHG_LOOP( + lock_ref, + { + if (old.count <= 1) + return false; + --new.count; + }, + { return true; }) bool retval = false; spin_lock(&lock_ref->lock); @@ -167,11 +180,14 @@ bool lockref_dec_not_zero(struct lockref *lock_ref) */ bool lockref_dec_or_lock_not_zero(struct lockref *lock_ref) { - CMPXCHG_LOOP(lock_ref, - if (old.count <= 1) break; - --new.count; - , - return true;); + CMPXCHG_LOOP( + lock_ref, + { + if (old.count <= 1) + break; + --new.count; + }, + { return true; }); bool retval = false; spin_lock(&lock_ref->lock); @@ -205,11 +221,14 @@ void lockref_mark_dead(struct lockref *lock_ref) */ bool lockref_inc_not_dead(struct lockref *lock_ref) { - CMPXCHG_LOOP(lock_ref, - if (old.count < 0) return false; - ++new.count; - , - return true;) + CMPXCHG_LOOP( + lock_ref, + { + if (old.count < 0) + return false; + ++new.count; + }, + { return true; }) bool retval = false; // 快捷路径操作失败,尝试加锁 diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index 95c01163..3098f653 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -7,6 +7,9 @@ pub mod atomic; pub mod list; pub mod lockref; pub mod mutex; +pub mod vec_cursor; +#[macro_use] +pub mod volatile_io; pub mod rwlock; pub mod semaphore; pub mod wait_queue; diff --git a/kernel/src/libs/vec_cursor.rs b/kernel/src/libs/vec_cursor.rs new file mode 100644 index 00000000..67259a19 --- /dev/null +++ b/kernel/src/libs/vec_cursor.rs @@ -0,0 +1,251 @@ +#![allow(dead_code)] + +use core::mem::size_of; + +use alloc::vec::Vec; + +use crate::{ + include::bindings::bindings::{E2BIG, EINVAL, EOVERFLOW}, + io::SeekFrom, +}; + +/// @brief 本模块用于为数组提供游标的功能,以简化其操作。 +#[derive(Debug)] +pub struct VecCursor { + /// 游标管理的数据 + data: Vec, + /// 游标的位置 + pos: usize, +} + +impl VecCursor { + /// @brief 新建一个游标 + pub fn new(data: Vec) -> Self { + return Self { data: data, pos: 0 }; + } + + /// @brief 创建一个全0的cursor + pub fn zerod(length: usize) -> Self { + let mut result = VecCursor { + data: Vec::new(), + pos: 0, + }; + result.data.resize(length, 0); + return result; + } + + /// @brief 获取游标管理的数据的可变引用 + pub fn get_mut(&mut self) -> &mut Vec { + return &mut self.data; + } + + /// @brief 获取游标管理的数据的不可变引用 + pub fn get_ref(&self) -> &Vec { + return &self.data; + } + + /// @brief 读取一个u8的数据(小端对齐) + pub fn read_u8(&mut self) -> Result { + if self.pos >= self.data.len() { + return Err(-(E2BIG as i32)); + } + self.pos += 1; + return Ok(self.data[self.pos - 1]); + } + + /// @brief 读取一个u16的数据(小端对齐) + pub fn read_u16(&mut self) -> Result { + if self.pos + 2 > self.data.len() { + return Err(-(E2BIG as i32)); + } + let mut res = 0u16; + res |= (self.data[self.pos] as u16) & 0xff; + self.pos += 1; + res |= ((self.data[self.pos] as u16) & 0xff) << 8; + self.pos += 1; + + return Ok(res); + } + + /// @brief 读取一个u32的数据(小端对齐) + pub fn read_u32(&mut self) -> Result { + if self.pos + 4 > self.data.len() { + return Err(-(E2BIG as i32)); + } + let mut res = 0u32; + for i in 0..4 { + res |= ((self.data[self.pos] as u32) & 0xff) << (8 * i); + self.pos += 1; + } + + return Ok(res); + } + + /// @brief 读取一个u64的数据(小端对齐) + pub fn read_u64(&mut self) -> Result { + if self.pos + 8 > self.data.len() { + return Err(-(E2BIG as i32)); + } + let mut res = 0u64; + for i in 0..8 { + res |= ((self.data[self.pos] as u64) & 0xff) << (8 * i); + self.pos += 1; + } + + return Ok(res); + } + + /// @brief 精确读取与buf同样大小的数据。 + /// + /// @param buf 要读取到的目标缓冲区 + /// + /// @return Ok(()) 成功读取 + /// @retunr Err(-E2BIG) 没有这么多数据,读取失败 + pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), i32> { + if self.pos + buf.len() > self.data.len() { + return Err(-(E2BIG as i32)); + } + buf.copy_from_slice(&self.data[self.pos..self.pos + buf.len()]); + self.pos += buf.len(); + return Ok(()); + } + + /// @brief 小端对齐,读取数据到u16数组. + /// + /// @param buf 目标u16数组 + pub fn read_u16_into(&mut self, buf: &mut [u16]) -> Result<(), i32> { + if self.pos + buf.len() * size_of::() > self.data.len() * size_of::() { + return Err(-(E2BIG as i32)); + } + + for i in 0..buf.len() { + buf[i] = self.read_u16()?; + } + + return Ok(()); + } + + /// @brief 调整游标的位置 + /// + /// @param 调整的相对值 + /// + /// @return Ok(新的游标位置) 调整成功,返回新的游标位置 + /// @return Err(-EOVERFLOW) 调整失败,游标超出正确的范围。(失败时游标位置不变) + pub fn seek(&mut self, origin: SeekFrom) -> Result { + let pos: i64; + match origin { + SeekFrom::SeekSet(offset) => { + pos = offset; + } + SeekFrom::SeekCurrent(offset) => { + pos = self.pos as i64 + offset; + } + SeekFrom::SeekEnd(offset) => { + // 请注意,此处的offset应小于等于0,否则肯定是不合法的 + pos = self.data.len() as i64 + offset; + } + SeekFrom::Invalid => { + return Err(-(EINVAL as i32)); + } + } + + if pos < 0 || pos > self.data.len() as i64 { + return Err(-(EOVERFLOW as i32)); + } + self.pos = pos as usize; + return Ok(self.pos); + } + + /// @brief 写入一个u8的数据(小端对齐) + pub fn write_u8(&mut self, value: u8) -> Result { + if self.pos >= self.data.len() { + return Err(-(E2BIG as i32)); + } + + self.data[self.pos] = value; + self.pos += 1; + + return Ok(value); + } + + /// @brief 写入一个u16的数据(小端对齐) + pub fn write_u16(&mut self, value: u16) -> Result { + if self.pos + 2 > self.data.len() { + return Err(-(E2BIG as i32)); + } + + self.data[self.pos] = (value & 0xff) as u8; + self.pos += 1; + self.data[self.pos] = ((value >> 8) & 0xff) as u8; + self.pos += 1; + + return Ok(value); + } + + /// @brief 写入一个u32的数据(小端对齐) + pub fn write_u32(&mut self, value: u32) -> Result { + if self.pos + 4 > self.data.len() { + return Err(-(E2BIG as i32)); + } + + for i in 0..4 { + self.data[self.pos] = ((value >> (i * 8)) & 0xff) as u8; + self.pos += 1; + } + + return Ok(value); + } + + /// @brief 写入一个u64的数据(小端对齐) + pub fn write_u64(&mut self, value: u64) -> Result { + if self.pos + 8 > self.data.len() { + return Err(-(E2BIG as i32)); + } + + for i in 0..8 { + self.data[self.pos] = ((value >> (i * 8)) & 0xff) as u8; + self.pos += 1; + } + + return Ok(value); + } + + /// @brief 精确写入与buf同样大小的数据。 + /// + /// @param buf 要写入到的目标缓冲区 + /// + /// @return Ok(()) 成功写入 + /// @retunr Err(-E2BIG) 没有这么多数据,写入失败 + pub fn write_exact(&mut self, buf: &[u8]) -> Result<(), i32> { + if self.pos + buf.len() > self.data.len() { + return Err(-(E2BIG as i32)); + } + + self.data[self.pos..self.pos + buf.len()].copy_from_slice(&buf[..]); + self.pos += buf.len(); + + return Ok(()); + } + + /// @brief 获取当前的数据切片 + pub fn as_slice(&self) -> &[u8] { + return &self.data[..]; + } + + /// @brief 获取可变数据切片 + pub fn as_mut_slice(&mut self) -> &mut [u8] { + return &mut self.data[..]; + } + + /// @brief 获取当前游标的位置 + #[inline] + pub fn pos(&self) -> usize { + return self.pos; + } + + /// @brief 获取缓冲区数据的大小 + #[inline] + pub fn len(&self) -> usize { + return self.data.len(); + } +} diff --git a/kernel/src/libs/volatile_io.rs b/kernel/src/libs/volatile_io.rs new file mode 100644 index 00000000..8f0254e7 --- /dev/null +++ b/kernel/src/libs/volatile_io.rs @@ -0,0 +1,37 @@ +macro_rules! volatile_read { + ($data: expr) => { + unsafe { core::ptr::read_volatile(core::ptr::addr_of!($data)) } + }; +} + +macro_rules! volatile_write { + ($data: expr, $value: expr) => { + unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($data), $value) } + }; +} + +/// @brief: 用于volatile设置某些bits +/// @param val: 设置这些位 +/// @param flag: true表示设置这些位为1; false表示设置这些位为0; +macro_rules! volatile_set_bit { + ($data: expr, $val: expr, $flag: expr) => { + volatile_write!( + $data, + match $flag { + true => core::ptr::read_volatile(core::ptr::addr_of!($data)) | $val, + false => core::ptr::read_volatile(core::ptr::addr_of!($data)) & (!$val), + } + ) + }; +} + +/// @param data: volatile变量 +/// @param bits: 置1的位才有效,表示写这些位 +/// @param val: 要写的值 +/// 比如: 写 x 的 2至8bit, 为 10, 可以这么写 volatile_write_bit(x, (1<<8)-(1<<2), 10<<2); +macro_rules! volatile_write_bit { + ($data: expr, $bits: expr, $val: expr) => { + volatile_set_bit!($data, $bits, false); + volatile_set_bit!($data, ($val) & ($bits), true); + }; +} diff --git a/kernel/src/main.c b/kernel/src/main.c index c3659b54..5e3e3fb5 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -20,9 +20,6 @@ #include #include -#include -#include -#include #include "driver/acpi/acpi.h" #include "driver/disk/ahci/ahci.h" @@ -52,8 +49,7 @@ void reload_gdt() gdtp.size = bsp_gdt_size - 1; gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table); - asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) - : "memory"); + asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) : "memory"); } void reload_idt() @@ -64,8 +60,7 @@ void reload_idt() // kdebug("gdtvaddr=%#018lx", p.gdt_vaddr); // kdebug("gdt size=%d", p.size); - asm volatile("lidt (%0) \n\t" ::"r"(&idtp) - : "memory"); + asm volatile("lidt (%0) \n\t" ::"r"(&idtp) : "memory"); } // 初始化系统各模块 @@ -141,12 +136,10 @@ void system_initialize() io_mfence(); vfs_init(); - devfs_init(); - procfs_init(); cpu_init(); ps2_keyboard_init(); - tty_init(); + // tty_init(); // ps2_mouse_init(); // ata_init(); pci_init(); @@ -167,7 +160,7 @@ void system_initialize() // 启用double buffer // scm_enable_double_buffer(); // 因为时序问题, 该函数调用被移到 initial_kernel_thread io_mfence(); - + HPET_enable(); io_mfence(); diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 3b00aeba..b382b3c7 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -1,3 +1,17 @@ +use crate::include::bindings::bindings::PAGE_OFFSET; + pub mod allocator; pub mod gfp; pub mod mmio_buddy; + +/// @brief 将内核空间的虚拟地址转换为物理地址 +#[inline(always)] +pub fn virt_2_phys(addr: usize) -> usize { + addr - PAGE_OFFSET as usize +} + +/// @brief 将物理地址转换为内核空间的虚拟地址 +#[inline(always)] +pub fn phys_2_virt(addr: usize) -> usize { + addr + PAGE_OFFSET as usize +} diff --git a/kernel/src/process/fork.c b/kernel/src/process/fork.c index 0a3c14d8..93ccf3a1 100644 --- a/kernel/src/process/fork.c +++ b/kernel/src/process/fork.c @@ -2,14 +2,15 @@ #include #include #include -#include extern spinlock_t process_global_pid_write_lock; extern long process_global_pid; extern void kernel_thread_func(void); +extern uint64_t rs_procfs_register_pid(uint64_t); +extern uint64_t rs_procfs_unregister_pid(uint64_t); -int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb); +extern int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb); int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb); int process_copy_mm(uint64_t clone_flags, struct process_control_block *pcb); int process_copy_thread(uint64_t clone_flags, struct process_control_block *pcb, uint64_t stack_start, @@ -137,7 +138,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned process_wakeup(tsk); // 创建对应procfs文件 - procfs_register_pid(tsk->pid); + rs_procfs_register_pid(tsk->pid); return retval; @@ -147,6 +148,7 @@ copy_thread_failed:; copy_files_failed:; // 回收文件 process_exit_files(tsk); + rs_procfs_unregister_pid(tsk->pid); copy_sighand_failed:; process_exit_sighand(tsk); copy_signal_failed:; @@ -173,35 +175,6 @@ int process_copy_flags(uint64_t clone_flags, struct process_control_block *pcb) return 0; } -/** - * @brief 拷贝当前进程的文件描述符等信息 - * - * @param clone_flags 克隆标志位 - * @param pcb 新的进程的pcb - * @return uint64_t - */ -int process_copy_files(uint64_t clone_flags, struct process_control_block *pcb) -{ - int retval = 0; - // 如果CLONE_FS被置位,那么子进程与父进程共享文件描述符 - // 文件描述符已经在复制pcb时被拷贝 - if (clone_flags & CLONE_FS) - return retval; - - // TODO: 这里是临时性的特殊处理stdio,待文件系统重构及tty设备实现后,需要改写这里 - process_open_stdio(current_pcb); - // 为新进程拷贝新的文件描述符 - for (int i = 3; i < PROC_MAX_FD_NUM; ++i) - { - if (current_pcb->fds[i] == NULL) - continue; - - pcb->fds[i] = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0); - memcpy(pcb->fds[i], current_pcb->fds[i], sizeof(struct vfs_file_t)); - } - - return retval; -} /** * @brief 拷贝当前进程的内存空间分布结构体信息 diff --git a/kernel/src/process/proc-types.h b/kernel/src/process/proc-types.h index ce8633a3..c2dda17c 100644 --- a/kernel/src/process/proc-types.h +++ b/kernel/src/process/proc-types.h @@ -110,9 +110,8 @@ struct process_control_block int64_t virtual_runtime; // 虚拟运行时间 int64_t rt_time_slice; // 由实时调度器管理的时间片 - // 进程拥有的文件描述符的指针数组 - // todo: 改用动态指针数组 - struct vfs_file_t *fds[PROC_MAX_FD_NUM]; + // 进程拥有的文件描述符的指针数组(由Rust进行管理) + void * fds; // 链表中的下一个pcb struct process_control_block *prev_pcb, *next_pcb; diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index e0548d4c..ad3715a0 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -20,11 +20,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include @@ -41,6 +36,7 @@ long process_global_pid = 1; // 系统中最大的pid extern void system_call(void); extern void kernel_thread_func(void); +extern void rs_procfs_unregister_pid(uint64_t); ul _stack_start; // initial proc的栈基地址(虚拟地址) extern struct mm_struct initial_mm; @@ -50,6 +46,7 @@ extern struct sighand_struct INITIAL_SIGHAND; extern void process_exit_sighand(struct process_control_block *pcb); extern void process_exit_signal(struct process_control_block *pcb); extern void initial_proc_init_signal(struct process_control_block *pcb); +extern int process_init_files(); // 设置初始进程的PCB #define INITIAL_PROC(proc) \ @@ -86,7 +83,7 @@ struct tss_struct initial_tss[MAX_CPU_NUM] = {[0 ... MAX_CPU_NUM - 1] = INITIAL_ * @param pcb 要被回收的进程的pcb * @return uint64_t */ -uint64_t process_exit_files(struct process_control_block *pcb); +extern int process_exit_files(struct process_control_block *pcb); /** * @brief 释放进程的页表 @@ -139,32 +136,15 @@ void process_switch_fsgs(uint64_t fs, uint64_t gs) * @brief 打开要执行的程序文件 * * @param path - * @return struct vfs_file_t* + * @return int 文件描述符编号 */ -struct vfs_file_t *process_open_exec_file(char *path) +int process_open_exec_file(char *path) { - struct vfs_dir_entry_t *dentry = NULL; - struct vfs_file_t *filp = NULL; - // kdebug("path=%s", path); - dentry = vfs_path_walk(path, 0); - - if (dentry == NULL) - return (void *)-ENOENT; - - if (dentry->dir_inode->attribute == VFS_IF_DIR) - return (void *)-ENOTDIR; - - filp = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0); - if (filp == NULL) - return (void *)-ENOMEM; - - filp->position = 0; - filp->mode = 0; - filp->dEntry = dentry; - filp->mode = ATTR_READ_ONLY; - filp->file_ops = dentry->dir_inode->file_ops; - - return filp; + struct pt_regs tmp = {0}; + tmp.r8 = (uint64_t)path; + tmp.r9 = O_RDONLY; + int fd = sys_open(&tmp); + return fd; } /** @@ -177,19 +157,38 @@ struct vfs_file_t *process_open_exec_file(char *path) static int process_load_elf_file(struct pt_regs *regs, char *path) { int retval = 0; - struct vfs_file_t *filp = process_open_exec_file(path); + int fd = process_open_exec_file(path); - if ((long)filp <= 0 && (long)filp >= -255) + if ((long)fd < 0) { - kdebug("(long)filp=%ld", (long)filp); - return (unsigned long)filp; + kdebug("(long)fd=%ld", (long)fd); + return (unsigned long)fd; } - void *buf = kmalloc(PAGE_4K_SIZE, 0); - memset(buf, 0, PAGE_4K_SIZE); + void *buf = kzalloc(PAGE_4K_SIZE, 0); uint64_t pos = 0; - pos = filp->file_ops->lseek(filp, 0, SEEK_SET); - retval = filp->file_ops->read(filp, (char *)buf, sizeof(Elf64_Ehdr), &pos); + + struct pt_regs tmp_use_fs = {0}; + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = 0; + tmp_use_fs.r10 = SEEK_SET; + retval = sys_lseek(&tmp_use_fs); + + // 读取 Elf64_Ehdr + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = (uint64_t)buf; + tmp_use_fs.r10 = sizeof(Elf64_Ehdr); + retval = sys_read(&tmp_use_fs); + + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = 0; + tmp_use_fs.r10 = SEEK_CUR; + pos = sys_lseek(&tmp_use_fs); + + if (retval != sizeof(Elf64_Ehdr)) + { + kerror("retval=%d, not equal to sizeof(Elf64_Ehdr):%d", retval, sizeof(Elf64_Ehdr)); + } retval = 0; if (!elf_check(buf)) { @@ -229,18 +228,33 @@ static int process_load_elf_file(struct pt_regs *regs, char *path) // kdebug("ehdr.e_phoff=%#018lx\t ehdr.e_phentsize=%d, ehdr.e_phnum=%d", ehdr.e_phoff, ehdr.e_phentsize, // ehdr.e_phnum); 将指针移动到program header处 - pos = ehdr.e_phoff; + // 读取所有的phdr - pos = filp->file_ops->lseek(filp, pos, SEEK_SET); - filp->file_ops->read(filp, (char *)buf, (uint64_t)ehdr.e_phentsize * (uint64_t)ehdr.e_phnum, &pos); - if ((unsigned long)filp <= 0) + pos = ehdr.e_phoff; + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = pos; + tmp_use_fs.r10 = SEEK_SET; + pos = sys_lseek(&tmp_use_fs); + + memset(buf, 0, PAGE_4K_SIZE); + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = (uint64_t)buf; + tmp_use_fs.r10 = (uint64_t)ehdr.e_phentsize * (uint64_t)ehdr.e_phnum; + sys_read(&tmp_use_fs); + + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = 0; + tmp_use_fs.r10 = SEEK_CUR; + pos = sys_lseek(&tmp_use_fs); + + if ((long)retval < 0) { - kdebug("(unsigned long)filp=%d", (long)filp); + kdebug("(unsigned long)filp=%d", (long)retval); retval = -ENOEXEC; goto load_elf_failed; } - Elf64_Phdr *phdr = buf; + Elf64_Phdr *phdr = buf; // 将程序加载到内存中 for (int i = 0; i < ehdr.e_phnum; ++i, ++phdr) { @@ -310,12 +324,38 @@ static int process_load_elf_file(struct pt_regs *regs, char *path) } } - pos = filp->file_ops->lseek(filp, pos, SEEK_SET); + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = pos; + tmp_use_fs.r10 = SEEK_SET; + pos = sys_lseek(&tmp_use_fs); + int64_t val = 0; if (remain_file_size > 0) { int64_t to_trans = (remain_file_size > PAGE_2M_SIZE) ? PAGE_2M_SIZE : remain_file_size; - val = filp->file_ops->read(filp, (char *)(virt_base + beginning_offset), to_trans, &pos); + + void *buf3 = kzalloc(PAGE_4K_SIZE, 0); + while (to_trans > 0) + { + int64_t x = 0; + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = (uint64_t)buf3; + tmp_use_fs.r10 = to_trans; + x = sys_read(&tmp_use_fs); + memcpy(virt_base + beginning_offset + val, buf3, x); + val += x; + to_trans -= x; + tmp_use_fs.r8 = fd; + tmp_use_fs.r9 = 0; + tmp_use_fs.r10 = SEEK_CUR; + pos = sys_lseek(&tmp_use_fs); + } + kfree(buf3); + + // kdebug("virt_base + beginning_offset=%#018lx, val=%d, to_trans=%d", virt_base + beginning_offset, + // val, + // to_trans); + // kdebug("to_trans=%d", to_trans); } if (val < 0) @@ -346,6 +386,12 @@ static int process_load_elf_file(struct pt_regs *regs, char *path) memset((void *)(current_pcb->mm->stack_start - PAGE_2M_SIZE), 0, PAGE_2M_SIZE); load_elf_failed:; + { + struct pt_regs tmp = {0}; + tmp.r8 = fd; + sys_close(&tmp); + } + if (buf != NULL) kfree(buf); return retval; @@ -409,8 +455,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[]) // 关闭之前的文件描述符 process_exit_files(current_pcb); - - process_open_stdio(current_pcb); + process_init_files(); // 清除进程的vfork标志位 current_pcb->flags &= ~PF_VFORK; @@ -499,18 +544,21 @@ ul initial_kernel_thread(ul arg) scm_enable_double_buffer(); - block_io_scheduler_init(); + // block_io_scheduler_init(); ahci_init(); - fat32_init(); - rootfs_umount(); + mount_root_fs(); c_virtio_probe(); - // 使用单独的内核线程来初始化usb驱动程序 // 注释:由于目前usb驱动程序不完善,因此先将其注释掉 // int usb_pid = kernel_thread(usb_init, 0, 0); kinfo("LZ4 lib Version=%s", LZ4_versionString()); __rust_demo_func(); + // while (1) + // { + // /* code */ + // } + // 对completion完成量进行测试 // __test_completion(); @@ -660,9 +708,9 @@ void process_init() // 初始化init进程的signal相关的信息 initial_proc_init_signal(current_pcb); - - // TODO: 这里是临时性的特殊处理stdio,待文件系统重构及tty设备实现后,需要改写这里 - process_open_stdio(current_pcb); + kdebug("Initial process to init files"); + process_init_files(); + kdebug("Initial process init files ok"); // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错 current_pcb->virtual_runtime = 0; @@ -689,7 +737,6 @@ struct process_control_block *process_find_pcb_by_pid(pid_t pid) { // todo: 当进程管理模块拥有pcblist_lock之后,对其加锁 struct process_control_block *pcb = initial_proc_union.pcb.next_pcb; - // 使用蛮力法搜索指定pid的pcb // todo: 使用哈希表来管理pcb for (; pcb != &initial_proc_union.pcb; pcb = pcb->next_pcb) @@ -736,7 +783,7 @@ int process_wakeup_immediately(struct process_control_block *pcb) if (retval != 0) return retval; // 将当前进程标志为需要调度,缩短新进程被wakeup的时间 - current_pcb->flags |= PF_NEED_SCHED; + current_pcb->flags |= PF_NEED_SCHED; if (pcb->cpu_id == current_pcb->cpu_id) sched(); @@ -745,31 +792,6 @@ int process_wakeup_immediately(struct process_control_block *pcb) return 0; } -/** - * @brief 回收进程的所有文件描述符 - * - * @param pcb 要被回收的进程的pcb - * @return uint64_t - */ -uint64_t process_exit_files(struct process_control_block *pcb) -{ - // TODO: 当stdio不再被以-1来特殊处理时,在这里要释放stdio文件的内存 - - // 不与父进程共享文件描述符 - if (!(pcb->flags & PF_VFORK)) - { - - for (int i = 3; i < PROC_MAX_FD_NUM; ++i) - { - if (pcb->fds[i] == NULL) - continue; - kfree(pcb->fds[i]); - } - } - // 清空当前进程的文件描述符列表 - memset(pcb->fds, 0, sizeof(struct vfs_file_t *) * PROC_MAX_FD_NUM); -} - /** * @brief 释放进程的页表 * @@ -860,33 +882,12 @@ int process_release_pcb(struct process_control_block *pcb) pcb->next_pcb->prev_pcb = pcb->prev_pcb; process_exit_sighand(pcb); process_exit_signal(pcb); + rs_procfs_unregister_pid(pcb->pid); // 释放当前pcb kfree(pcb); return 0; } -/** - * @brief 申请可用的文件句柄 - * - * @return int - */ -int process_fd_alloc(struct vfs_file_t *file) -{ - int fd_num = -1; - - for (int i = 0; i < PROC_MAX_FD_NUM; ++i) - { - /* 找到指针数组中的空位 */ - if (current_pcb->fds[i] == NULL) - { - fd_num = i; - current_pcb->fds[i] = file; - break; - } - } - return fd_num; -} - /** * @brief 给pcb设置名字 * @@ -911,14 +912,3 @@ void process_set_pcb_name(struct process_control_block *pcb, const char *pcb_nam { __set_pcb_name(pcb, pcb_name); } - -void process_open_stdio(struct process_control_block *pcb) -{ - // TODO: 这里是临时性的特殊处理stdio,待文件系统重构及tty设备实现后,需要改写这里 - // stdin - pcb->fds[0] = -1UL; - // stdout - pcb->fds[1] = -1UL; - // stderr - pcb->fds[2] = -1UL; -} \ No newline at end of file diff --git a/kernel/src/process/process.h b/kernel/src/process/process.h index dc451e79..99a0652a 100644 --- a/kernel/src/process/process.h +++ b/kernel/src/process/process.h @@ -23,7 +23,7 @@ #include "proc-types.h" extern void process_exit_thread(struct process_control_block *pcb); -extern uint64_t process_exit_files(struct process_control_block *pcb); +extern int process_exit_files(struct process_control_block *pcb); /** * @brief 任务状态段结构体 @@ -221,5 +221,3 @@ extern int process_try_to_wake_up(struct process_control_block *_pcb, uint64_t _ */ extern int process_wake_up_state(struct process_control_block *pcb, uint64_t state); void __switch_to(struct process_control_block *prev, struct process_control_block *next); - -void process_open_stdio(struct process_control_block * pcb); \ No newline at end of file diff --git a/kernel/src/process/process.rs b/kernel/src/process/process.rs index 5a11b807..355fa151 100644 --- a/kernel/src/process/process.rs +++ b/kernel/src/process/process.rs @@ -1,8 +1,16 @@ -use core::ptr::{read_volatile, write_volatile}; +use core::{ + ffi::c_void, + ptr::{null_mut, read_volatile, write_volatile}, +}; + +use alloc::boxed::Box; use crate::{ arch::asm::current::current_pcb, - include::bindings::bindings::{process_control_block, PROC_RUNNING, PROC_STOPPED}, + filesystem::vfs::file::{File, FileDescriptorVec}, + include::bindings::bindings::{ + process_control_block, CLONE_FS, EBADF, EFAULT, ENFILE, EPERM, PROC_RUNNING, PROC_STOPPED, + }, sched::core::{cpu_executing, sched_enqueue}, smp::core::{smp_get_processor_id, smp_send_reschedule}, }; @@ -99,3 +107,198 @@ pub fn process_cpu(pcb: *const process_control_block) -> u32 { pub fn process_is_executing(pcb: *const process_control_block) -> bool { return cpu_executing(process_cpu(pcb)) as *const process_control_block == pcb; } + +impl process_control_block { + /// @brief 初始化进程PCB的文件描述符数组。 + /// 请注意,如果当前进程已经有文件描述符数组,那么本操作将被禁止 + pub fn init_files(&mut self) -> Result<(), i32> { + if self.fds != null_mut() { + // 这个操作不被允许,否则会产生内存泄露。 + // 原因是,C的pcb里面,文件描述符数组的生命周期是static的,如果继续执行,会产生内存泄露的问题。 + return Err(-(EPERM as i32)); + } + let fd_vec: &mut FileDescriptorVec = Box::leak(FileDescriptorVec::new()); + self.fds = fd_vec as *mut FileDescriptorVec as usize as *mut c_void; + return Ok(()); + } + + /// @brief 拷贝进程的文件描述符 + /// + /// @param clone_flags 进程fork的克隆标志位 + /// @param from 源pcb。从它里面拷贝文件描述符 + /// + /// @return Ok(()) 拷贝成功 + /// @return Err(i32) 拷贝失败,错误码 + pub fn copy_files( + &mut self, + clone_flags: u64, + from: &'static process_control_block, + ) -> Result<(), i32> { + // 不拷贝父进程的文件描述符 + if clone_flags & CLONE_FS as u64 != 0 { + // 由于拷贝pcb的时候,直接copy的指针,因此这里置为空 + self.fds = null_mut(); + self.init_files()?; + return Ok(()); + } + // 获取源pcb的文件描述符数组的引用 + let old_fds: &mut FileDescriptorVec = if let Some(o_fds) = FileDescriptorVec::from_pcb(from) + { + o_fds + } else { + return self.init_files(); + }; + + // 拷贝文件描述符数组 + let new_fd_vec: &mut FileDescriptorVec = Box::leak(Box::new(old_fds.clone())); + + self.fds = new_fd_vec as *mut FileDescriptorVec as usize as *mut c_void; + + return Ok(()); + } + + /// @brief 释放文件描述符数组。本函数会drop掉整个文件描述符数组,并把pcb的fds字段设置为空指针。 + pub fn exit_files(&mut self) -> Result<(), i32> { + if self.fds.is_null() { + return Ok(()); + } + + let old_fds: Box = + unsafe { Box::from_raw(self.fds as *mut FileDescriptorVec) }; + drop(old_fds); + self.fds = null_mut(); + return Ok(()); + } + + /// @brief 申请文件描述符,并把文件对象存入其中。 + /// + /// @return Ok(i32) 申请到的文件描述符编号 + /// @return Err(i32) 申请失败,返回错误码,并且,file对象将被drop掉 + pub fn alloc_fd(&mut self, file: File) -> Result { + // 获取pcb的文件描述符数组的引用 + let fds: &mut FileDescriptorVec = + if let Some(f) = FileDescriptorVec::from_pcb(current_pcb()) { + f + } else { + // 如果进程还没有初始化文件描述符数组,那就初始化它 + self.init_files().ok(); + let r: Option<&mut FileDescriptorVec> = FileDescriptorVec::from_pcb(current_pcb()); + if r.is_none() { + drop(file); + // 初始化失败 + return Err(-(EFAULT as i32)); + } + r.unwrap() + }; + + // 寻找空闲的文件描述符 + let mut cnt = 0; + for x in fds.fds.iter_mut() { + if x.is_none() { + *x = Some(Box::new(file)); + return Ok(cnt); + } + cnt += 1; + } + return Err(-(ENFILE as i32)); + } + + /// @brief 根据文件描述符序号,获取文件结构体的可变引用 + /// + /// @param fd 文件描述符序号 + /// + /// @return Option(&mut File) 文件对象的可变引用 + pub fn get_file_mut_by_fd(&self, fd: i32) -> Option<&mut File> { + if !FileDescriptorVec::validate_fd(fd) { + return None; + } + let r: &mut FileDescriptorVec = FileDescriptorVec::from_pcb(current_pcb()).unwrap(); + return r.fds[fd as usize].as_deref_mut(); + } + + /// @brief 根据文件描述符序号,获取文件结构体的不可变引用 + /// + /// @param fd 文件描述符序号 + /// + /// @return Option(&File) 文件对象的不可变引用 + #[allow(dead_code)] + pub fn get_file_ref_by_fd(&self, fd: i32) -> Option<&File> { + if !FileDescriptorVec::validate_fd(fd) { + return None; + } + let r: &mut FileDescriptorVec = FileDescriptorVec::from_pcb(current_pcb()).unwrap(); + return r.fds[fd as usize].as_deref(); + } + + /// @brief 释放文件描述符,同时关闭文件。 + /// + /// @param fd 文件描述符序号 + pub fn drop_fd(&self, fd: i32) -> Result<(), i32> { + // 判断文件描述符的数字是否超过限制 + if !FileDescriptorVec::validate_fd(fd) { + return Err(-(EBADF as i32)); + } + let r: &mut FileDescriptorVec = FileDescriptorVec::from_pcb(current_pcb()).unwrap(); + + let f: Option<&File> = r.fds[fd as usize].as_deref(); + if f.is_none() { + // 如果文件描述符不存在,报错 + return Err(-(EBADF as i32)); + } + // 释放文件 + drop(f); + + // 把文件描述符数组对应位置设置为空 + r.fds[fd as usize] = None; + + return Ok(()); + } +} + +// =========== 导出到C的函数,在将来,进程管理模块被完全重构之后,需要删掉他们 BEGIN ============ + +/// @brief 初始化当前进程的文件描述符数组 +/// 请注意,如果当前进程已经有文件描述符数组,那么本操作将被禁止 +#[no_mangle] +pub extern "C" fn process_init_files() -> i32 { + let r = current_pcb().init_files(); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err(); + } +} + +/// @brief 拷贝当前进程的文件描述符信息 +/// +/// @param clone_flags 克隆标志位 +/// @param pcb 新的进程的pcb +#[no_mangle] +pub extern "C" fn process_copy_files( + clone_flags: u64, + from: &'static process_control_block, +) -> i32 { + let r = current_pcb().copy_files(clone_flags, from); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err(); + } +} + +/// @brief 回收进程的文件描述符数组 +/// +/// @param pcb 要被回收的进程的pcb +/// +/// @return i32 +#[no_mangle] +pub extern "C" fn process_exit_files(pcb: &'static mut process_control_block) -> i32 { + let r: Result<(), i32> = pcb.exit_files(); + if r.is_ok() { + return 0; + } else { + return r.unwrap_err(); + } +} + +// =========== 以上为导出到C的函数,在将来,进程管理模块被完全重构之后,需要删掉他们 END ============ diff --git a/kernel/src/syscall/syscall.c b/kernel/src/syscall/syscall.c index 2af813d0..babfd0f4 100644 --- a/kernel/src/syscall/syscall.c +++ b/kernel/src/syscall/syscall.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -24,6 +23,48 @@ extern uint64_t sys_rt_sigreturn(struct pt_regs *regs); extern uint64_t sys_getpid(struct pt_regs *regs); extern uint64_t sys_sched(struct pt_regs *regs); +/** + * @brief 关闭文件系统调用 + * + * @param fd_num 文件描述符号 + * + * @param regs + * @return uint64_t + */ +extern uint64_t sys_close(struct pt_regs *regs); + +/** + * @brief 从文件中读取数据 + * + * @param fd_num regs->r8 文件描述符号 + * @param buf regs->r9 输出缓冲区 + * @param count regs->r10 要读取的字节数 + * + * @return uint64_t + */ +extern uint64_t sys_read(struct pt_regs *regs); + +/** + * @brief 向文件写入数据 + * + * @param fd_num regs->r8 文件描述符号 + * @param buf regs->r9 输入缓冲区 + * @param count regs->r10 要写入的字节数 + * + * @return uint64_t + */ +extern uint64_t sys_write(struct pt_regs *regs); + +/** + * @brief 调整文件的访问位置 + * + * @param fd_num 文件描述符号 + * @param offset 偏移量 + * @param whence 调整模式 + * @return uint64_t 调整结束后的文件访问位置 + */ +extern uint64_t sys_lseek(struct pt_regs *regs); + /** * @brief 导出系统调用处理函数的符号 * @@ -125,159 +166,6 @@ ul sys_put_string(struct pt_regs *regs) return 0; } -/** - * @brief 关闭文件系统调用 - * - * @param fd_num 文件描述符号 - * - * @param regs - * @return uint64_t - */ -uint64_t sys_close(struct pt_regs *regs) -{ - int fd_num = (int)regs->r8; - - // kdebug("sys close: fd=%d", fd_num); - return vfs_close(fd_num); -} - -/** - * @brief 从文件中读取数据 - * - * @param fd_num regs->r8 文件描述符号 - * @param buf regs->r9 输出缓冲区 - * @param count regs->r10 要读取的字节数 - * - * @return uint64_t - */ -uint64_t sys_read(struct pt_regs *regs) -{ - int fd_num = (int)regs->r8; - void *buf = (void *)regs->r9; - int64_t count = (int64_t)regs->r10; - - // 校验buf的空间范围 - if (SYSCALL_FROM_USER(regs) && (!verify_area((uint64_t)buf, count))) - return -EPERM; - - // kdebug("sys read: fd=%d", fd_num); - - // 校验文件描述符范围 - if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) - return -EBADF; - - // 文件描述符不存在 - if (current_pcb->fds[fd_num] == NULL) - return -EBADF; - - if (count < 0) - return -EINVAL; - - switch (fd_num) - { - case 0: // stdin - return 0; - break; - case 1: // stdout - return 0; - break; - case 2: // stderr - return 0; - break; - } - struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; - uint64_t ret = 0; - if (file_ptr->file_ops && file_ptr->file_ops->read) - ret = file_ptr->file_ops->read(file_ptr, (char *)buf, count, &(file_ptr->position)); - - return ret; -} - -/** - * @brief 向文件写入数据 - * - * @param fd_num regs->r8 文件描述符号 - * @param buf regs->r9 输入缓冲区 - * @param count regs->r10 要写入的字节数 - * - * @return uint64_t - */ -uint64_t sys_write(struct pt_regs *regs) -{ - int fd_num = (int)regs->r8; - void *buf = (void *)regs->r9; - int64_t count = (int64_t)regs->r10; - - // 校验buf的空间范围 - if (SYSCALL_FROM_USER(regs) && (!verify_area((uint64_t)buf, count))) - return -EPERM; - kdebug("sys write: fd=%d", fd_num); - - // 校验文件描述符范围 - if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) - return -EBADF; - - // 文件描述符不存在 - if (current_pcb->fds[fd_num] == NULL) - return -EBADF; - - if (count < 0) - return -EINVAL; - - switch (fd_num) - { - case 0: // stdin - return 0; - break; - case 1: // stdout - printk("%s", buf); - return count; - break; - case 2: // stderr - printk("%s", buf); - return count; - break; - } - struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; - uint64_t ret = 0; - if (file_ptr->file_ops && file_ptr->file_ops->write) - ret = file_ptr->file_ops->write(file_ptr, (char *)buf, count, &(file_ptr->position)); - - return ret; -} - -/** - * @brief 调整文件的访问位置 - * - * @param fd_num 文件描述符号 - * @param offset 偏移量 - * @param whence 调整模式 - * @return uint64_t 调整结束后的文件访问位置 - */ -uint64_t sys_lseek(struct pt_regs *regs) -{ - int fd_num = (int)regs->r8; - long offset = (long)regs->r9; - int whence = (int)regs->r10; - - // kdebug("sys_lseek: fd=%d", fd_num); - uint64_t retval = 0; - - // 校验文件描述符范围 - if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM) - return -EBADF; - - // 文件描述符不存在 - if (current_pcb->fds[fd_num] == NULL) - return -EBADF; - - struct vfs_file_t *file_ptr = current_pcb->fds[fd_num]; - if (file_ptr->file_ops && file_ptr->file_ops->lseek) - retval = file_ptr->file_ops->lseek(file_ptr, offset, whence); - - return retval; -} - uint64_t sys_fork(struct pt_regs *regs) { return do_fork(regs, 0, regs->rsp, 0); @@ -391,57 +279,7 @@ uint64_t sys_reboot(struct pt_regs *regs) | ENAMETOOLONG | 路径过长 | +--------------+------------------------+ */ -uint64_t sys_chdir(struct pt_regs *regs) -{ - char *dest_path = (char *)regs->r8; - // kdebug("dest_path=%s", dest_path); - // 检查目标路径是否为NULL - if (dest_path == NULL) - return -EFAULT; - - // 计算输入的路径长度 - int dest_path_len; - if (user_mode(regs)) - { - dest_path_len = strnlen_user(dest_path, PAGE_4K_SIZE); - } - else - dest_path_len = strnlen(dest_path, PAGE_4K_SIZE); - - // 长度小于等于0 - if (dest_path_len <= 0) - return -EFAULT; - else if (dest_path_len >= PAGE_4K_SIZE) - return -ENAMETOOLONG; - - // 为路径字符串申请空间 - char *path = kmalloc(dest_path_len + 1, 0); - // 系统内存不足 - if (path == NULL) - return -ENOMEM; - - memset(path, 0, dest_path_len + 1); - if (regs->cs & USER_CS) - { - // 将字符串从用户空间拷贝进来, +1是为了拷贝结尾的\0 - strncpy_from_user(path, dest_path, dest_path_len + 1); - } - else - strncpy(path, dest_path, dest_path_len + 1); - // kdebug("chdir: path = %s", path); - struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0); - - kfree(path); - - if (dentry == NULL) - return -ENOENT; - // kdebug("dentry->name=%s, namelen=%d", dentry->name, dentry->name_length); - // 目标不是目录 - if (dentry->dir_inode->attribute != VFS_IF_DIR) - return -ENOTDIR; - - return 0; -} +extern uint64_t sys_chdir(struct pt_regs *regs); /** * @brief 获取目录中的数据 @@ -449,28 +287,8 @@ uint64_t sys_chdir(struct pt_regs *regs) * @param fd 文件描述符号 * @return uint64_t dirent的总大小 */ -uint64_t sys_getdents(struct pt_regs *regs) -{ - int fd = (int)regs->r8; - void *dirent = (void *)regs->r9; - long count = (long)regs->r10; +extern uint64_t sys_getdents(struct pt_regs *regs); - if (fd < 0 || fd > PROC_MAX_FD_NUM) - return -EBADF; - - if (count < 0) - return -EINVAL; - - struct vfs_file_t *filp = current_pcb->fds[fd]; - if (filp == NULL) - return -EBADF; - - uint64_t retval = 0; - if (filp->file_ops && filp->file_ops->readdir) - retval = filp->file_ops->readdir(filp, dirent, &vfs_fill_dirent); - - return retval; -} /** * @brief 执行新的程序 @@ -589,6 +407,12 @@ void do_syscall_int(struct pt_regs *regs, unsigned long error_code) ul ret = system_call_table[regs->rax](regs); regs->rax = ret; // 返回码 } +uint64_t sys_pipe(struct pt_regs *regs){ + return -ENOTSUP; +} + +extern uint64_t sys_mkdir(struct pt_regs *regs); + system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = { [0] = system_call_not_exists, @@ -603,18 +427,18 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = { [9] = sys_brk, [10] = sys_sbrk, [11] = sys_reboot, - [12] = sys_chdir, - [13] = sys_getdents, + [12] = sys_chdir, + [13] = sys_getdents, [14] = sys_execve, [15] = sys_wait4, [16] = sys_exit, - [17] = sys_mkdir, + [17] = sys_mkdir, [18] = sys_nanosleep, [19] = sys_clock, [20] = sys_pipe, [21] = sys_mstat, - [22] = sys_unlink_at, - [23] = sys_kill, + [22] = sys_unlink_at, + [23] = sys_kill, [24] = sys_sigaction, [25] = sys_rt_sigreturn, [26] = sys_getpid, diff --git a/kernel/src/time/mod.rs b/kernel/src/time/mod.rs index fcf16f8c..acaa2f08 100644 --- a/kernel/src/time/mod.rs +++ b/kernel/src/time/mod.rs @@ -1 +1,8 @@ pub mod timekeep; + +/// 表示时间的结构体 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i64, +} diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index 6f182e5e..de43b143 100644 --- a/user/apps/shell/cmd.c +++ b/user/apps/shell/cmd.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -12,7 +13,6 @@ #include #include #include -#include // 当前工作目录(在main_loop中初始化) char *shell_current_path = NULL; @@ -68,7 +68,7 @@ static char *get_target_filepath(const char *filename, int *result_path_len) memset(file_path, 0, *result_path_len + 2); strncpy(file_path, filename, *result_path_len); - if(filename[(*result_path_len)-1]!='/') + if (filename[(*result_path_len) - 1] != '/') file_path[*result_path_len] = '/'; } @@ -258,11 +258,11 @@ int shell_cmd_ls(int argc, char **argv) break; int color = COLOR_WHITE; - if (buf->d_type & VFS_IF_DIR) + if (buf->d_type == DT_DIR) color = COLOR_YELLOW; - else if (buf->d_type & VFS_IF_FILE) + else if (buf->d_type == DT_REG) color = COLOR_INDIGO; - else if (buf->d_type & VFS_IF_DEVICE) + else if (buf->d_type == DT_BLK || buf->d_type == DT_CHR) color = COLOR_GREEN; char output_buf[256] = {0}; @@ -315,9 +315,10 @@ int shell_cmd_cat(int argc, char **argv) lseek(fd, 0, SEEK_SET); char *buf = (char *)malloc(512); - memset(buf, 0, 512); + while (file_size > 0) { + memset(buf, 0, 512); int l = read(fd, buf, 511); buf[l] = '\0'; diff --git a/user/apps/shell/shell.c b/user/apps/shell/shell.c index 6a0c6a05..71a60b2a 100644 --- a/user/apps/shell/shell.c +++ b/user/apps/shell/shell.c @@ -90,7 +90,7 @@ void main_loop(int kb_fd) int main() { // 打开键盘文件 - char kb_file_path[] = "/dev/char/ps2.kb0"; + char kb_file_path[] = "/dev/char/ps2_keyboard"; int kb_fd = open(kb_file_path, 0); print_ascii_logo(); diff --git a/user/libs/libc/src/include/export/dirent.h b/user/libs/libc/src/include/export/dirent.h index 99b1b48f..a7a4e07c 100644 --- a/user/libs/libc/src/include/export/dirent.h +++ b/user/libs/libc/src/include/export/dirent.h @@ -5,15 +5,59 @@ extern "C" { #endif -/** - * @brief inode的属性(copy from vfs.h) +/* + * This is a header for the common implementation of dirent + * to fs on-disk file type conversion. Although the fs on-disk + * bits are specific to every file system, in practice, many + * file systems use the exact same on-disk format to describe + * the lower 3 file type bits that represent the 7 POSIX file + * types. * + * It is important to note that the definitions in this + * header MUST NOT change. This would break both the + * userspace ABI and the on-disk format of filesystems + * using this code. + * + * All those file systems can use this generic code for the + * conversions. */ -#define VFS_IF_FILE (1UL << 0) -#define VFS_IF_DIR (1UL << 1) -#define VFS_IF_DEVICE (1UL << 2) + +/* + * struct dirent file types + * exposed to user via getdents(2), readdir(3) + * + * These match bits 12..15 of stat.st_mode + * (ie "(i_mode >> 12) & 15"). + */ + +// 完整含义请见 http://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html +#define S_DT_SHIFT 12 +#define S_DT(mode) (((mode) & S_IFMT) >> S_DT_SHIFT) +#define S_DT_MASK (S_IFMT >> S_DT_SHIFT) + +/* these are defined by POSIX and also present in glibc's dirent.h */ +#define DT_UNKNOWN 0 +// 命名管道,或者FIFO +#define DT_FIFO 1 +// 字符设备 +#define DT_CHR 2 +// 目录 +#define DT_DIR 4 +// 块设备 +#define DT_BLK 6 +// 常规文件 +#define DT_REG 8 +// 符号链接 +#define DT_LNK 10 +// 是一个socket +#define DT_SOCK 12 +// 这个是抄Linux的,还不知道含义 +#define DT_WHT 14 + +#define DT_MAX (S_DT_MASK + 1) /* 16 */ #define DIR_BUF_SIZE 256 + /** * @brief 文件夹结构体 * diff --git a/user/libs/libc/src/include/export/errno.h b/user/libs/libc/src/include/export/errno.h index cb986337..cab9cda9 100644 --- a/user/libs/libc/src/include/export/errno.h +++ b/user/libs/libc/src/include/export/errno.h @@ -10,63 +10,64 @@ */ #pragma once -#if defined(__cplusplus) -extern "C" { +#if defined(__cplusplus) +extern "C" +{ #endif -#define E2BIG 1 /* 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */ -#define EACCES 2 /* 访问被拒绝 Permission denied */ -#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/ -#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/ -#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */ -#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/ -#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */ -#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */ -#define EBADMSG 9 /* 错误的消息 Bad message. */ +#define E2BIG 1 /* 参数列表过长,或者在输出buffer中缺少空间 或者参数比系统内建的最大值要大 Argument list too long. */ +#define EACCES 2 /* 访问被拒绝 Permission denied */ +#define EADDRINUSE 3 /* 地址正在被使用 Address in use.*/ +#define EADDRNOTAVAIL 4 /* 地址不可用 Address not available.*/ +#define EAFNOSUPPORT 5 /* 地址family不支持 Address family not supported. */ +#define EAGAIN 6 /* 资源不可用,请重试。 Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).*/ +#define EALREADY 7 /* 连接已经在处理 Connection already in progress. */ +#define EBADF 8 /* 错误的文件描述符 Bad file descriptor. */ +#define EBADMSG 9 /* 错误的消息 Bad message. */ -#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */ -#define ECANCELED 11 /* 操作被取消 Operation canceled. */ -#define ECHILD 12 /* 没有子进程 No child processes. */ -#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */ -#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */ -#define ECONNRESET 15 /* 连接被重置 Connection reset. */ -#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */ -#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/ -#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */ -#define EDQUOT 19 /* 保留使用 Reserved */ +#define EBUSY 10 /* 设备或资源忙 Device or resource busy. */ +#define ECANCELED 11 /* 操作被取消 Operation canceled. */ +#define ECHILD 12 /* 没有子进程 No child processes. */ +#define ECONNABORTED 13 /* 连接已断开 Connection aborted. */ +#define ECONNREFUSED 14 /* 连接被拒绝 Connection refused. */ +#define ECONNRESET 15 /* 连接被重置 Connection reset. */ +#define EDEADLK 16 /* 资源死锁将要发生 Resource deadlock would occur. */ +#define EDESTADDRREQ 17 /* 需要目标地址 Destination address required.*/ +#define EDOM 18 /* 数学参数超出作用域 Mathematics argument out of domain of function. */ +#define EDQUOT 19 /* 保留使用 Reserved */ -#define EEXIST 20 /* 文件已存在 File exists. */ -#define EFAULT 21 /* 错误的地址 Bad address */ -#define EFBIG 22 /* 文件太大 File too large. */ -#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/ -#define EIDRM 24 /* 标志符被移除 Identifier removed. */ -#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */ -#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */ -#define EINTR 27 /* 被中断的函数 Interrupted function. */ -#define EINVAL 28 /* 不可用的参数 Invalid argument. */ -#define EIO 29 /* I/O错误 I/O error. */ +#define EEXIST 20 /* 文件已存在 File exists. */ +#define EFAULT 21 /* 错误的地址 Bad address */ +#define EFBIG 22 /* 文件太大 File too large. */ +#define EHOSTUNREACH 23 /* 主机不可达 Host is unreachable.*/ +#define EIDRM 24 /* 标志符被移除 Identifier removed. */ +#define EILSEQ 25 /* 不合法的字符序列 Illegal byte sequence. */ +#define EINPROGRESS 26 /* 操作正在处理 Operation in progress. */ +#define EINTR 27 /* 被中断的函数 Interrupted function. */ +#define EINVAL 28 /* 不可用的参数 Invalid argument. */ +#define EIO 29 /* I/O错误 I/O error. */ -#define EISCONN 30 /* 套接字已连接 Socket is connected. */ -#define EISDIR 31 /* 是一个目录 Is a directory */ -#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */ -#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */ -#define EMLINK 34 /* 链接数过多 Too many links. */ -#define EMSGSIZE 35 /* 消息过大 Message too large. */ -#define EMULTIHOP 36 /* 保留使用 Reserved. */ -#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */ -#define ENETDOWN 38 /* 网络已关闭 Network is down. */ -#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */ +#define EISCONN 30 /* 套接字已连接 Socket is connected. */ +#define EISDIR 31 /* 是一个目录 Is a directory */ +#define ELOOP 32 /* 符号链接级别过多 Too many levels of symbolic links. */ +#define EMFILE 33 /* 文件描述符的值过大 File descriptor value too large. */ +#define EMLINK 34 /* 链接数过多 Too many links. */ +#define EMSGSIZE 35 /* 消息过大 Message too large. */ +#define EMULTIHOP 36 /* 保留使用 Reserved. */ +#define ENAMETOOLONG 37 /* 文件名过长 Filename too long. */ +#define ENETDOWN 38 /* 网络已关闭 Network is down. */ +#define ENETRESET 39 /* 网络连接已断开 Connection aborted by network. */ -#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */ -#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/ -#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */ -#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */ -#define ENODEV 44 /* 没有指定的设备 No such device. */ -#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */ -#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */ -#define ENOLCK 47 /* 没有可用的锁 No locks available. */ -#define ENOLINK 48 /* 保留 Reserved. */ -#define ENOMEM 49 /* 没有足够的空间 Not enough space. */ +#define ENETUNREACH 40 /* 网络不可达 Network unreachable. */ +#define ENFILE 41 /* 系统中打开的文件过多 Too many files open in system.*/ +#define ENOBUFS 42 /* 缓冲区空间不足 No buffer space available. */ +#define ENODATA 43 /* 队列头没有可读取的消息 No message is available on the STREAM head read queue. */ +#define ENODEV 44 /* 没有指定的设备 No such device. */ +#define ENOENT 45 /* 没有指定的文件或目录 No such file or directory. */ +#define ENOEXEC 46 /* 可执行文件格式错误 Executable file format error. */ +#define ENOLCK 47 /* 没有可用的锁 No locks available. */ +#define ENOLINK 48 /* 保留 Reserved. */ +#define ENOMEM 49 /* 没有足够的空间 Not enough space. */ #define ENOMSG 50 /* 没有期待类型的消息 No message of the desired type. */ #define ENOPROTOOPT 51 /* 协议不可用 Protocol not available. */ @@ -77,35 +78,35 @@ extern "C" { #define ENOTCONN 56 /* 套接字未连接 The socket is not connected. */ #define ENOTDIR 57 /* 不是目录 Not a directory. */ #define ENOTEMPTY 58 /* 目录非空 Directory not empty. */ -#define ENOTRECOVERABLE 59 /* 状态不可覆盖 State not recoverable. */ +#define ENOTRECOVERABLE 59 /* 状态不可恢复 State not recoverable. */ -#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/ -#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */ -#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */ -#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */ -#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */ -#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */ -#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */ -#define EPERM 67 /* 操作不被允许 Operation not permitted. */ -#define EPIPE 68 /* 断开的管道 Broken pipe. */ -#define EPROTO 69 /* 协议错误 Protocol error. */ +#define ENOTSOCK 60 /* 不是一个套接字 Not a socket.*/ +#define ENOTSUP 61 /* 不被支持 Not supported (may be the same value as [EOPNOTSUPP]). */ +#define ENOTTY 62 /* 不正确的I/O控制操作 Inappropriate I/O control operation. */ +#define ENXIO 63 /* 没有这样的设备或地址 No such device or address. */ +#define EOPNOTSUPP 64 /* 套接字不支持该操作 Operation not supported on socket (may be the same value as [ENOTSUP]). */ +#define EOVERFLOW 65 /* 数值过大,产生溢出 Value too large to be stored in data type. */ +#define EOWNERDEAD 66 /* 之前的拥有者挂了 Previous owner died. */ +#define EPERM 67 /* 操作不被允许 Operation not permitted. */ +#define EPIPE 68 /* 断开的管道 Broken pipe. */ +#define EPROTO 69 /* 协议错误 Protocol error. */ #define EPROTONOSUPPORT 70 /* 协议不被支持 Protocol not supported. */ #define EPROTOTYPE 71 /* 对于套接字而言,错误的协议 Protocol wrong type for socket. */ #define ERANGE 72 /* 结果过大 Result too large. */ #define EROFS 73 /* 只读的文件系统 Read-only file system. */ -#define ESPIPE 74 /* 错误的寻道 Invalid seek. */ +#define ESPIPE 74 /* 错误的寻道.当前文件是pipe,不允许seek请求 Invalid seek. */ #define ESRCH 75 /* 没有这样的进程 No such process. */ #define ESTALE 76 /* 保留 Reserved. */ #define ETIME 77 /* 流式ioctl()超时 Stream ioctl() timeout */ #define ETIMEDOUT 78 /* 连接超时 Connection timed out.*/ #define ETXTBSY 79 /* 文本文件忙 Text file busy. */ -#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */ -#define EXDEV 81 /* 跨设备连接 Cross-device link. */ +#define EWOULDBLOCK 80 /* 操作将被禁止 Operation would block (may be the same value as [EAGAIN]). */ +#define EXDEV 81 /* 跨设备连接 Cross-device link. */ -extern int errno; + extern int errno; -#if defined(__cplusplus) -} /* extern "C" */ +#if defined(__cplusplus) +} /* extern "C" */ #endif \ No newline at end of file diff --git a/user/libs/libc/src/include/export/fcntl.h b/user/libs/libc/src/include/export/fcntl.h index a703042b..75b02e60 100644 --- a/user/libs/libc/src/include/export/fcntl.h +++ b/user/libs/libc/src/include/export/fcntl.h @@ -12,27 +12,31 @@ #if defined(__cplusplus) extern "C" { -#endif -#define O_RDONLY 00000000 // Open Read-only -#define O_WRONLY 00000001 // Open Write-only -#define O_RDWR 00000002 // Open read/write +#endif +#define O_RDONLY 00000000 // Open Read-only +#define O_WRONLY 00000001 // Open Write-only +#define O_RDWR 00000002 // Open read/write #define O_ACCMODE 00000003 // Mask for file access modes -#define O_CREAT 00000100 // Create file if it does not exist -#define O_EXCL 00000200 // Fail if file already exists +#define O_CREAT 00000100 // Create file if it does not exist +#define O_EXCL 00000200 // Fail if file already exists #define O_NOCTTY 00000400 // Do not assign controlling terminal #define O_TRUNC 00001000 // 文件存在且是普通文件,并以O_RDWR或O_WRONLY打开,则它会被清空 -#define O_APPEND 00002000 // 文件指针会被移动到文件末尾 +#define O_APPEND 00002000 // 文件指针会被移动到文件末尾 #define O_NONBLOCK 00004000 // 非阻塞式IO模式 -#define O_EXEC 00010000 // 以仅执行的方式打开(非目录文件) -#define O_SEARCH 00020000 // Open the directory for search only -#define O_DIRECTORY 00040000 // 打开的必须是一个目录 -#define O_NOFOLLOW 00100000 // Do not follow symbolic links +#define O_DSYNC 00010000 // used to be O_SYNC, see below +#define FASYNC 00020000 // fcntl, for BSD compatibility +#define O_DIRECT 00040000 // direct disk access hint +#define O_LARGEFILE 00100000 +#define O_DIRECTORY 00200000 // 打开的必须是一个目录 +#define O_NOFOLLOW 00400000 // Do not follow symbolic links +#define O_NOATIME 01000000 +#define O_CLOEXEC 02000000 // set close_on_exec /* * The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is