mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
部分完成了readdir
This commit is contained in:
parent
156c2c2389
commit
a4157bb4a7
@ -134,4 +134,13 @@ struct vfs_dir_entry_t *vfs_path_walk(char *path, uint64_t flags)
|
||||
|
||||
parent = dentry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 填充dentry
|
||||
*
|
||||
*/
|
||||
int vfs_fill_dentry(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset)
|
||||
{
|
||||
|
||||
}
|
@ -124,6 +124,12 @@ struct vfs_dir_entry_operations_t
|
||||
long (*iput)(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 填充dirent的函数指针的类型定义
|
||||
*
|
||||
*/
|
||||
typedef int (*vfs_filldir_t)(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset);
|
||||
|
||||
struct vfs_file_operations_t
|
||||
{
|
||||
long (*open)(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr);
|
||||
@ -132,6 +138,8 @@ struct vfs_file_operations_t
|
||||
long (*write)(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position);
|
||||
long (*lseek)(struct vfs_file_t *file_ptr, long offset, long origin);
|
||||
long (*ioctl)(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg);
|
||||
|
||||
long (*readdir)(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler); // 读取文件夹
|
||||
};
|
||||
|
||||
/**
|
||||
@ -161,4 +169,10 @@ struct vfs_superblock_t *vfs_mount_fs(char *name, void *DPTE, uint8_t DPT_type,
|
||||
* @param flags 1:返回父目录项, 0:返回结果目录项
|
||||
* @return struct vfs_dir_entry_t* 目录项
|
||||
*/
|
||||
struct vfs_dir_entry_t *vfs_path_walk(char *path, uint64_t flags);
|
||||
struct vfs_dir_entry_t *vfs_path_walk(char *path, uint64_t flags);
|
||||
|
||||
/**
|
||||
* @brief 填充dentry
|
||||
*
|
||||
*/
|
||||
int vfs_fill_dentry(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset);
|
@ -347,7 +347,7 @@ find_lookup_success:; // 找到目标dentry
|
||||
// todo: 引入devfs后删除这段代码
|
||||
if ((tmp_dEntry->DIR_FstClusHI >> 12) && (p->attribute & VFS_ATTR_FILE))
|
||||
p->attribute |= VFS_ATTR_DEVICE;
|
||||
|
||||
|
||||
dest_dentry->dir_inode = p;
|
||||
kfree(buf);
|
||||
return dest_dentry;
|
||||
@ -868,6 +868,7 @@ struct vfs_file_operations_t fat32_file_ops =
|
||||
.write = fat32_write,
|
||||
.lseek = fat32_lseek,
|
||||
.ioctl = fat32_ioctl,
|
||||
.readdir = fat32_readdir,
|
||||
};
|
||||
|
||||
// todo: create
|
||||
@ -899,6 +900,180 @@ int64_t fat32_getAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr)
|
||||
int64_t fat32_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
|
||||
unsigned char *buf = (unsigned char *)kmalloc(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(fsbi, cluster);
|
||||
if (cluster > 0x0ffffff7) // 文件结尾
|
||||
{
|
||||
kerror("file position out of range! (cluster not exists)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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 != ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num))
|
||||
{
|
||||
// 读取失败
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// 读取目录项成功,返回
|
||||
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)
|
||||
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';
|
||||
|
||||
goto find_dir_success;
|
||||
}
|
||||
}
|
||||
|
||||
// 当前簇不存在目录项
|
||||
cluster = fat32_read_FAT_entry(fsbi, cluster);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
// 在上面的循环中读取到目录项结尾了,仍没有找到
|
||||
return NULL;
|
||||
|
||||
find_dir_success:;
|
||||
// 将文件夹位置坐标加32(即指向下一个目录项)
|
||||
file_ptr->position += 32;
|
||||
// todo: 计算ino_t
|
||||
return filler(dirent, 0, dir_name, name_len, 0, 0);
|
||||
}
|
||||
|
||||
struct vfs_inode_operations_t fat32_inode_ops =
|
||||
{
|
||||
|
@ -155,9 +155,9 @@ typedef struct fat32_partition_info_t fat32_sb_info_t;
|
||||
|
||||
struct fat32_inode_info_t
|
||||
{
|
||||
uint64_t first_clus;
|
||||
uint64_t dEntry_location_clus; // dEntry struct in cluster (0 is root, 1 is invalid)
|
||||
uint64_t dEntry_location_clus_offset; // dEntry struct offset in cluster
|
||||
uint64_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;
|
||||
@ -189,4 +189,14 @@ struct vfs_superblock_t *fat32_read_superblock(void *DPTE, uint8_t DPT_type, voi
|
||||
|
||||
long fat32_create(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dentry, int mode);
|
||||
|
||||
void fat32_init();
|
||||
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);
|
@ -143,8 +143,12 @@ uint64_t sys_open(struct pt_regs *regs)
|
||||
if (dentry == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
// 暂时认为目标是目录是一种错误
|
||||
if (dentry->dir_inode->attribute == VFS_ATTR_DIR)
|
||||
// 要求打开文件夹而目标不是文件夹
|
||||
if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_ATTR_DIR))
|
||||
return -ENOTDIR;
|
||||
|
||||
// 要找的目标是文件夹
|
||||
if ((flags & O_DIRECTORY) && dentry->dir_inode->attribute == VFS_ATTR_DIR)
|
||||
return -EISDIR;
|
||||
|
||||
// todo: 引入devfs后删除这段代码
|
||||
@ -485,7 +489,6 @@ uint64_t sys_chdir(struct pt_regs *regs)
|
||||
// 计算输入的路径长度
|
||||
int dest_path_len = strnlen_user(dest_path, PAGE_4K_SIZE);
|
||||
|
||||
|
||||
// 长度小于等于0
|
||||
if (dest_path_len <= 0)
|
||||
return -EFAULT;
|
||||
@ -503,7 +506,6 @@ uint64_t sys_chdir(struct pt_regs *regs)
|
||||
// 将字符串从用户空间拷贝进来, +1是为了拷贝结尾的\0
|
||||
strncpy_from_user(path, dest_path, dest_path_len + 1);
|
||||
|
||||
|
||||
struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
|
||||
|
||||
kfree(path);
|
||||
@ -518,6 +520,35 @@ uint64_t sys_chdir(struct pt_regs *regs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取目录中的数据
|
||||
*
|
||||
* @param fd 文件描述符号
|
||||
* @return uint64_t
|
||||
*/
|
||||
uint64_t sys_getdents(struct pt_regs *regs)
|
||||
{
|
||||
int fd = (int)regs->r8;
|
||||
void *dirent = (void *)regs->r9;
|
||||
long count = (long)regs->r10;
|
||||
|
||||
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_dentry);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
ul sys_ahci_end_req(struct pt_regs *regs)
|
||||
{
|
||||
ahci_end_request();
|
||||
@ -547,5 +578,6 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] =
|
||||
[10] = sys_sbrk,
|
||||
[11] = sys_reboot,
|
||||
[12] = sys_chdir,
|
||||
[13 ... 254] = system_call_not_exists,
|
||||
[13] = sys_getdents,
|
||||
[14 ... 254] = system_call_not_exists,
|
||||
[255] = sys_ahci_end_req};
|
||||
|
@ -22,5 +22,6 @@
|
||||
#define SYS_SBRK 10
|
||||
#define SYS_REBOOT 11 // 重启
|
||||
#define SYS_CHDIR 12 // 切换工作目录
|
||||
#define SYS_GET_DENTS 13 // 获取目录中的数据
|
||||
|
||||
#define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用
|
@ -35,4 +35,7 @@ ctype.o: ctype.c
|
||||
gcc $(CFLAGS) -c ctype.c -o ctype.o
|
||||
|
||||
string.o: string.c
|
||||
gcc $(CFLAGS) -c string.c -o string.o
|
||||
gcc $(CFLAGS) -c string.c -o string.o
|
||||
|
||||
dirent.o: dirent.c
|
||||
gcc $(CFLAGS) -c dirent.c -o dirent.o
|
71
user/libs/libc/dirent.c
Normal file
71
user/libs/libc/dirent.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include "dirent.h"
|
||||
#include "unistd.h"
|
||||
#include "stdio.h"
|
||||
#include "fcntl.h"
|
||||
#include "stddef.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include <libsystem/syscall.h>
|
||||
|
||||
/**
|
||||
* @brief 打开文件夹
|
||||
*
|
||||
* @param dirname
|
||||
* @return DIR*
|
||||
*/
|
||||
struct DIR *opendir(const char *path)
|
||||
{
|
||||
int fd = open(path, O_DIRECTORY);
|
||||
if (fd < 0) // 目录打开失败
|
||||
return NULL;
|
||||
|
||||
// 分配DIR结构体
|
||||
struct DIR *dirp = (struct DIR *)malloc(sizeof(struct DIR));
|
||||
memset(dirp, 0, sizeof(struct DIR));
|
||||
dirp->fd = fd;
|
||||
dirp->buf_len = DIR_BUF_SIZE;
|
||||
dirp->buf_pos = 0;
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭文件夹
|
||||
*
|
||||
* @param dirp DIR结构体指针
|
||||
* @return int 成功:0, 失败:-1
|
||||
+--------+--------------------------------+
|
||||
| errno | 描述 |
|
||||
+--------+--------------------------------+
|
||||
| 0 | 成功 |
|
||||
| -EBADF | 当前dirp不指向一个打开了的目录 |
|
||||
| -EINTR | 函数执行期间被信号打断 |
|
||||
+--------+--------------------------------+
|
||||
*/
|
||||
int closedir(struct DIR *dirp)
|
||||
{
|
||||
int retval = close(dirp->fd);
|
||||
free(dirp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t getdents(int fd, struct dirent *dirent, long count)
|
||||
{
|
||||
return syscall_invoke(SYS_GET_DENTS, fd, (uint64_t)dirent, count, 0, 0, 0, 0, 0);
|
||||
}
|
||||
/**
|
||||
* @brief 从目录中读取数据
|
||||
*
|
||||
* @param dir
|
||||
* @return struct dirent*
|
||||
*/
|
||||
struct dirent *reaaddir(struct DIR *dir)
|
||||
{
|
||||
memset(dir, 0, DIR_BUF_SIZE);
|
||||
int len = getdents(dir->fd, (struct dirent *)dir->buf, DIR_BUF_SIZE);
|
||||
|
||||
if (len > 0)
|
||||
return (struct dirent *)dir->buf;
|
||||
else
|
||||
return NULL;
|
||||
}
|
57
user/libs/libc/dirent.h
Normal file
57
user/libs/libc/dirent.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include <libc/sys/types.h>
|
||||
|
||||
#define DIR_BUF_SIZE 256
|
||||
/**
|
||||
* @brief 文件夹结构体
|
||||
*
|
||||
*/
|
||||
struct DIR
|
||||
{
|
||||
int fd;
|
||||
int buf_pos;
|
||||
int buf_len;
|
||||
char buf[DIR_BUF_SIZE];
|
||||
|
||||
// todo: 加一个指向dirent结构体的指针
|
||||
};
|
||||
|
||||
struct dirent
|
||||
{
|
||||
ino_t d_ino; // 文件序列号
|
||||
off_t d_off; // dir偏移量
|
||||
unsigned short d_reclen; // 目录下的记录数
|
||||
unsigned char d_type; // entry的类型
|
||||
char d_name[256]; // 文件entry的名字
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 打开文件夹
|
||||
*
|
||||
* @param dirname
|
||||
* @return DIR*
|
||||
*/
|
||||
struct DIR *opendir(const char *dirname);
|
||||
|
||||
/**
|
||||
* @brief 关闭文件夹
|
||||
*
|
||||
* @param dirp DIR结构体指针
|
||||
* @return int 成功:0, 失败:-1
|
||||
+--------+--------------------------------+
|
||||
| errno | 描述 |
|
||||
+--------+--------------------------------+
|
||||
| 0 | 成功 |
|
||||
| -EBADF | 当前dirp不指向一个打开了的目录 |
|
||||
| -EINTR | 函数执行期间被信号打断 |
|
||||
+--------+--------------------------------+
|
||||
*/
|
||||
int closedir(struct DIR *dirp);
|
||||
|
||||
/**
|
||||
* @brief 从目录中读取数据
|
||||
*
|
||||
* @param dir
|
||||
* @return struct dirent*
|
||||
*/
|
||||
struct dirent* reaaddir(struct DIR* dir);
|
@ -16,6 +16,7 @@
|
||||
#define SYS_SBRK 10
|
||||
#define SYS_REBOOT 11
|
||||
#define SYS_CHDIR 12 // 切换工作目录
|
||||
#define SYS_GET_DENTS 13 // 获取目录中的数据
|
||||
|
||||
/**
|
||||
* @brief 用户态系统调用函数
|
||||
|
Loading…
x
Reference in New Issue
Block a user