2020301918-os/kern/fs.c
2022-10-29 19:48:58 +08:00

180 lines
3.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <assert.h>
#include <fat32.h>
#include <mmu.h>
#include <string.h>
#include <x86.h>
#include <kern/keyboard.h>
#include <kern/fs.h>
#include <kern/stdio.h>
#include <kern/syscall.h>
/*
* 内核读入函数,由于没有文件描述符概念,
* 所以强制assert让fd为0平时的读入流也默认是0的
* 现在只有从键盘缓冲区获取字符的能力
*/
ssize_t
kern_read(int fd, void *buf, size_t count)
{
assert(fd == 0);
char *s = buf;
for (size_t i = 0 ; i < count ; i++) {
char c = read_keyboard_buf();
if (c == -1)
return i;
*s++ = c;
}
return count;
}
ssize_t
do_read(int fd, void *buf, size_t count)
{
assert(buf < (void *)KERNBASE);
assert(buf + count < (void *)KERNBASE);
return kern_read(fd, buf, count);
}
/*
* 内核写入函数,由于没有文件描述符概念,
* 所以强制assert让fd为1平时的输出流也默认是1的
* 现在只有输出字符到终端的能力
*/
ssize_t
kern_write(int fd, const void *buf, size_t count)
{
assert(fd == 1);
const char *s = buf;
for (size_t i = 0 ; i < count ; i++)
kprintf("%c", *s++);
return count;
}
ssize_t
do_write(int fd, const void *buf, size_t count)
{
assert(buf < (void *)KERNBASE);
assert(buf + count < (void *)KERNBASE);
return kern_write(fd, buf, count);
}
#define SECTSIZE 512
static void
waitdisk(void)
{
// wait for disk reaady
while ((inb(0x1F7) & 0xC0) != 0x40)
/* do nothing */;
}
static void
readsect(void *dst, u32 offset)
{
// wait for disk to be ready
waitdisk();
outb(0x1F2, 1); // count = 1
outb(0x1F3, offset);
outb(0x1F4, offset >> 8);
outb(0x1F5, offset >> 16);
outb(0x1F6, (offset >> 24) | 0xE0);
outb(0x1F7, 0x20); // cmd 0x20 - read sectors
// wait for disk to be ready
waitdisk();
// read a sector
insl(0x1F0, dst, SECTSIZE/4);
}
u32 fat_start_sec;
u32 data_start_sec;
u32 fat_now_sec;
struct BPB bpb;
/*
* 获取下一个簇号
*/
static u32
get_next_clus(u32 current_clus)
{
u32 sec = current_clus * 4 / SECTSIZE;
u32 off = current_clus * 4 % SECTSIZE;
static u32 buf[SECTSIZE / 4];
if (fat_now_sec != fat_start_sec + sec) {
readsect(buf, fat_start_sec + sec);
fat_now_sec = fat_start_sec + sec;
}
return buf[off / 4];
}
/*
* 读入簇号对应的数据区的所有数据
* 读到dst开头的位置返回读入的尾指针
*/
static void *
read_data_sec(void *dst, u32 current_clus)
{
current_clus -= 2;
current_clus *= bpb.BPB_SecPerClus;
current_clus += data_start_sec;
for (int i = 0 ; i < bpb.BPB_SecPerClus ; i++, dst += SECTSIZE)
readsect(dst, current_clus + i);
return dst;
}
/*
* 根据filename读取文件到dst处
* filename要求是短目录项名11个字节
* dst推荐是3GB + 48MB
*/
void
read_file(const char *filename, void *dst)
{
assert(strlen(filename) == 11);
readsect(&bpb, 0);
fat_start_sec = bpb.BPB_RsvdSecCnt;
data_start_sec = fat_start_sec + bpb.BPB_FATSz32 * bpb.BPB_NumFATs;
u32 root_clus = bpb.BPB_RootClus;
u32 file_clus = 0;
assert(bpb.BPB_BytsPerSec == SECTSIZE && bpb.BPB_SecPerClus == 8);
static char buf[SECTSIZE * 8];
// 遍历目录项获取文件起始簇号
while (root_clus < 0x0FFFFFF8) {
void *read_end = read_data_sec((void *)buf, root_clus);
for (struct Directory_Entry *p = (void *)buf
; (void *)p < read_end ; p++) {
if (strncmp(p->DIR_Name, filename, 11) == 0) {
assert(p->DIR_FileSize <= 16 * MB);
file_clus = (u32)p->DIR_FstClusHI << 16 |
p->DIR_FstClusLO;
break;
}
}
if (file_clus != 0)
break;
root_clus = get_next_clus(root_clus);
}
if (file_clus == 0)
panic("file can't found! filename: %s", filename);
// 读入文件
while (file_clus < 0x0FFFFFF8) {
dst = read_data_sec(dst, file_clus);
file_clus = get_next_clus(file_clus);
}
}