部分完成了readdir

This commit is contained in:
fslongjin 2022-05-27 13:41:10 +08:00
parent 156c2c2389
commit a4157bb4a7
10 changed files with 385 additions and 12 deletions

View File

@ -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)
{
}

View File

@ -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);

View File

@ -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 =
{

View File

@ -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);

View File

@ -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};

View File

@ -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的系统调用

View File

@ -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
View 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
View 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);

View File

@ -16,6 +16,7 @@
#define SYS_SBRK 10
#define SYS_REBOOT 11
#define SYS_CHDIR 12 // 切换工作目录
#define SYS_GET_DENTS 13 // 获取目录中的数据
/**
* @brief