虚拟硬盘
bximage hd.img -q hd -mode=flat -size=80
创建一个虚拟硬盘(-hd),-q表示不交互,-mode=flat连续硬盘,-size=80大小为80M。
重新配置告诉bochs 虚拟硬盘是以hd.img来展现的,CHS柱面柱头的信息
BIOS 运行后会遍历系统中的硬件, 并记录相关信息。其中, 硬盘数量被BIOS主动记录于 0x475 地址处。因此我们可以通过读取0x475地址的数据拿到硬盘数量信息
1 2 3 4
| byte* pb = (byte*)0x475; PrintString( "Number of Hard Disk: " ); PrintIntDec(*pb); PrintChar('\n');
|
IDE
IDE 是什么?
早期,硬盘控制器和硬盘本身是分开的。软件控制硬盘控制器来读取硬盘的数据。后来,硬盘控制器和硬盘本身合二为一(Integrated Drive Electronics)。
再后来, 有了别名 ATA, 然后是ATA / IDE。
最初的硬盘是用并口传输数据, 所以 IDE 常指代并口硬盘接口。并口由于太慢了因此后来有了串口硬盘接口, 名为: SerialATA, 缩写: SATA。 。 。
硬盘控制器
怎么具体地读写硬盘?
也就是通过固定I/O端口对硬盘控制器进行操作就可以读写硬盘了
而操作的本质是读写硬盘控制器中的寄存器
命令块寄存器 (Command Block Register)
控制块寄存器 (Control Block Register)
primary和secondary对应主盘和从盘
注意同一个端口(例如主盘的0x1F7)可以读也可以写,但是可能读写操作意义是不一样的。假设操作硬盘时有错误信息可以通过0x1F1读取错误信息。本OS只有一块硬盘因此只操作Primary
针对端口0x1F7判断硬盘是否忙碌,设备是否就绪,数据是否就绪:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| static uint IsBusy() { uint ret = 0; uint i = 0; while( (i < 500) && (ret = (ReadPort(REG_STATUS) & STATUS_BSY)) ) { i++; } return ret; }
static uint IsDevReady() { return !(ReadPort(REG_STATUS) & STATUS_DRDY); }
static uint IsDataReady() { return ReadPort(REG_STATUS) & STATUS_DRQ; }
|
LBA Register
LBA 即: Logical Block Addressing, 逻辑块地址, 是一种线性寻址的方式 ( 0- n ) 。LBA存储扇区编号
目前绝大多数硬盘支持 LBA 扇区寻址方式
通过 3.5 个寄存器(即: 28 位) 读写硬盘扇区
- LBA Low: 保存逻辑扇区地址的低8 位
- LBAMid: 保存逻辑扇区地址的中8 位
- LBAHigh: 保存逻辑扇区地址的高8 位
Device Register
LBA还有4位存储于Device Register的低4位,如图所示
1 2 3 4 5 6
| static uint MakeDevRegVal(uint si) { return 0xE0 | ((si >> 24) & 0x0F); }
|
Command Register
- 获取硬盘信息:0xEC
- 读取扇区数据:0x20
- 数据写入扇区:0x30
status Register
硬盘读写
硬盘以扇区为基本读写单位
- 读写数据时需要计算目标扇区的逻辑地址 (LBA)
- 确定逻辑地址后, 读取扇区数据到内存,每次先把512字节读到内存中,再从512字节中寻找需要的数据
读: 从读取的扇区中拷贝目标数据(拷贝到内存中)
写: 数据写入读取的扇区中,之后将扇区数据写回硬盘
硬盘数据端口 (0x1F0) 的读写需要以双字节为单位(WORD)
- cld 清空方向标志位,向高地址方向增加地址值
- insw 端口操作,从DX指出的外设端口输入**一个字(双字节)**到由ES: DI指定的存储器中
- outsw 端口操作,向端口写入一个字
- rep 重复指令, 重复次数由 ecx寄存器指定
端口写入
从 edx 指定的端口中读取 2n 个字节并存入 edi 指向的地址(传入buf)中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ; ; void ReadPortW(ushort port, ushort* buf, uint n) ; ReadPortW: push ebp mov ebp, esp mov edx, [ebp + 8] ; port mov edi, [ebp + 12] ; buf mov ecx, [ebp + 16] ; n cld rep insw nop nop nop leave ret
|
端口读出:将 esi 指向的 2n 个字节写入 edx 指定的端口中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ; ; void WritePortW(ushort port, ushort* buf, uint n) ; WritePortW: push ebp mov ebp, esp mov edx, [ebp + 8] ; port mov esi, [ebp + 12] ; buf mov ecx, [ebp + 16] ; n cld rep outsw ; 反复向端口写入一个字 nop nop nop leave ret
|
逻辑块地址结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| typedef struct { byte lbaLow; byte lbaMid; byte lbaHigh; byte device; byte command; } HDRegValue; static HDRegValue MakeRegVals(uint si, uint action) { HDRegValue ret = {0}; ret.lbaLow = si & 0xFF; ret.lbaMid = (si >> 8) & 0xFF; ret.lbaHigh = (si >> 16) & 0xFF; ret.device = MakeDevRegVal(si); ret.command = action; return ret; }
|
硬盘操作基本步骤
往命令块寄存器写数据(操作哪块硬盘,读取哪块扇区,如何读取)
往控制块寄存器写数据()
从数据端口中读取数据readportw来读取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #define REG_DEV_CTRL 0x3F6 #define REG_DATA 0x1F0 #define REG_FEATURES 0x1F1 #define REG_ERROR 0x1F1 #define REG_NSECTOR 0x1F2 #define REG_LBA_LOW 0x1F3 #define REG_LBA_MID 0x1F4 #define REG_LBA_HIGH 0x1F5 #define REG_DEVICE 0x1F6 #define REG_STATUS 0x1F7 #define REG_COMMAND 0x1F7
static void WritePorts(HDRegValue hdrv) { WritePort(REG_FEATURES, 0); WritePort(REG_NSECTOR, 1); WritePort(REG_LBA_LOW, hdrv.lbaLow); WritePort(REG_LBA_MID, hdrv.lbaMid); WritePort(REG_LBA_HIGH, hdrv.lbaHigh); WritePort(REG_DEVICE, hdrv.device); WritePort(REG_COMMAND, hdrv.command); WritePort(REG_DEV_CTRL, 0); }
uint HDRawRead(uint si, byte* buf) { uint ret = 0; if( (si < HDRawSectors()) && buf && !IsBusy() ) { HDRegValue hdrv = MakeRegVals(si, ATA_READ); WritePorts(hdrv); if( ret = (!IsBusy() && IsDataReady()) ) { ushort* data = (ushort*)buf; ReadPortW(REG_DATA, data, SECT_SIZE >> 1); } } return ret; }
uint HDRawWrite(uint si, byte* buf) { uint ret = 0; if( (si < HDRawSectors()) && buf && !IsBusy() ) { HDRegValue hdrv = MakeRegVals(si, ATA_WRITE); WritePorts(hdrv); if( ret = (!IsBusy() && IsDataReady()) ) { ushort* data = (ushort*)buf; WritePortW(REG_DATA, data, SECT_SIZE >> 1); } } return ret; }
|
获取扇区总数
0号扇区的60-61字的位置记录了扇区总数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| uint HDRawSectors() { static uint ret = -1; if( (ret == -1) && IsDevReady() ) { HDRegValue hdrv = MakeRegVals(0, ATA_IDENTIFY); byte* buf = Malloc(SECT_SIZE); WritePorts(hdrv); if( !IsBusy() && IsDataReady() && buf ) { ushort* data = (ushort*)buf; ReadPortW(REG_DATA, data, SECT_SIZE >> 1); ret = (data[61] << 16) | (data[60]); } Free(buf); } return ret; }
|
文件系统概要设计
对于硬盘而言不知道所谓的文件系统,硬盘只有一个个的扇区,文件系统时操作系统的概念,文件是有逻辑关联的数据集合,并且数据之间有存储的先后关系
整个硬盘最大扇区数量为max,第0号扇区可以存储引导程序和文件系统基本信息。1号扇区存储根目录区。
扇区分配表记录扇区之间的逻辑关系,记录扇区是否可用。注意扇区分配表和文件数据区一一对应
扇区分配表
比如设置文件test.txt
的secBegin = addr_C
。扇区分配表的addr_C存储了下一个扇区是O
扇区分配表组织成不同的链表,每个链表代表一个文件,同时的未使用的扇区也组织成一个空闲链表。
当一个文件需要更多扇区时,从空闲链表头部中取出一个链表头即可
文件管理的过程可看作扇区在不同链表中移动的过程
注意扇区分配表的大小,已知的硬盘扇区共有MAX个,那么512/4*n = max-2-n
可以求出扇区分配表占用扇区数目n = (max-2)/129
(向上取整)
引导区
1 2 3 4 5 6 7 8 9 10
| typedef struct { byte forJmp[4]; char magic[32]; uint sctNum; uint mapSize; uint freeNum; uint freeBegin; } FSHeader;
|
根目录区
1 2 3 4 5 6 7 8
| typedef struct { char magic[32]; uint sctBegin; uint sctNum; uint lastBytes; } FSRoot;
|
根目录区也是一个文件,后面随着新建的文件越来越多,FSRoot的sctNum也会增加,FSRoot这条链表记录了FileEntry(文件的基本信息),然后通过FileEntry可以获得各个文件自己的链表
1 2 3 4 5 6 7 8 9 10 11
| typedef struct { char name[32]; uint sctBegin; uint sctNum; uint lastBytes; uint type; uint inSctIdx; uint inSctOff; uint reserved[2]; } FileEntry;
|
硬盘格式化操作
即建立引导区,根目录区和扇区分配表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| uint FSFormat() { FSHeader* header = (FSHeader*)Malloc(SECT_SIZE); FSRoot* root = (FSRoot*)Malloc(SECT_SIZE); uint* p = (uint*)Malloc(MAP_ITEM_CNT * sizeof(uint)); uint ret = 0;
if( header && root && p ) { uint i = 0; uint j = 0; uint current = 0;
StrCpy(header->magic, FS_MAGIC, sizeof(header->magic)-1); header->sctNum = HDRawSectors(); header->mapSize = (header->sctNum - FIXED_SCT_SIZE) / 129 + !!((header->sctNum - FIXED_SCT_SIZE) % 129);9 header->freeNum = header->sctNum - header->mapSize - FIXED_SCT_SIZE; header->freeBegin = FIXED_SCT_SIZE + header->mapSize; ret = HDRawWrite(HEADER_SCT_IDX, (byte*)header);
StrCpy(root->magic, ROOT_MAGIC, sizeof(root->magic)-1); root->sctNum = 0; root->sctBegin = SCT_END_FLAG; root->lastBytes = SECT_SIZE; ret = ret && HDRawWrite(ROOT_SCT_IDX, (byte*)root);
for(i=0; ret && (i<header->mapSize) && (current<header->freeNum); i++) { for(j=0; j<MAP_ITEM_CNT; j++) { uint* pInt = AddrOff(p, j);
if( current < header->freeNum ) { *pInt = current + 1;
if( current == (header->freeNum - 1) ) { *pInt = SCT_END_FLAG; }
current++; } else { break; } } ret = ret && HDRawWrite(i + FIXED_SCT_SIZE, (byte*)p); } }
Free(header); Free(root); Free(p);
return ret; }
|
创建文件
如何根据扇区号获取处于扇区分配表中的位置?
扇区操作是一种外存操作,需要仔细计算出位于哪一个扇区,扇区内偏移地址是多少,扇区管理时使用相对扇区地址,扇区读写使用绝对地址
1 2 3 4
| 扇区相对地址:offset = si - mapsize - 2 si = offset + mapsize + 2 位于哪个扇区:sctOff = offset/MAP_ITEM_CNT 扇区内的偏移:idxOff = offset%MAP_ITEM_CNT
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| typedef struct { uint* pSct; uint sctIdx; uint sctOff; uint idxOff; } MapPos;
static MapPos FindInMap(uint si) { MapPos ret = {0}; FSHeader* header = (si != SCT_END_FLAG) ? ReadSector(HEADER_SCT_IDX) : NULL;
if( header ) { uint offset = si - header->mapSize - FIXED_SCT_SIZE; uint sctOff = offset / MAP_ITEM_CNT; uint idxOff = offset % MAP_ITEM_CNT; uint* ps = ReadSector(sctOff + FIXED_SCT_SIZE);
if( ps ) { ret.pSct = ps; ret.sctIdx = si; ret.sctOff = sctOff; ret.idxOff = idxOff; } }
Free(header); return ret; }
|
扇区分配函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| static uint AllocSector() { uint ret = SCT_END_FLAG; FSHeader* header = ReadSector(HEADER_SCT_IDX);
if( header && (header->freeBegin != SCT_END_FLAG) ) { MapPos mp = FindInMap(header->freeBegin);
if( mp.pSct ) { uint* pInt = AddrOff(mp.pSct, mp.idxOff); uint next = *pInt; uint flag = 1;
ret = header->freeBegin; header->freeBegin = next + FIXED_SCT_SIZE + header->mapSize; header->freeNum--; *pInt = SCT_END_FLAG; flag = flag && HDRawWrite(HEADER_SCT_IDX, (byte*)header); flag = flag && HDRawWrite(mp.sctOff + FIXED_SCT_SIZE, (byte*)mp.pSct);
if( !flag ) { ret = SCT_END_FLAG; } }
Free(mp.pSct); }
Free(header);
return ret; }
|
扇区归还函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| static uint FreeSector(uint si) { FSHeader* header = (si != SCT_END_FLAG) ? ReadSector(HEADER_SCT_IDX) : NULL; uint ret = 0;
if( header ) { MapPos mp = FindInMap(si);
if( mp.pSct ) { uint* pInt = AddrOff(mp.pSct, mp.idxOff); *pInt = header->freeBegin - FIXED_SCT_SIZE - header->mapSize;
header->freeBegin = si; header->freeNum++;
ret = HDRawWrite(HEADER_SCT_IDX, (byte*)header) && HDRawWrite(mp.sctOff + FIXED_SCT_SIZE, (byte*)mp.pSct); }
Free(mp.pSct); }
Free(header);
return ret; }
|
获取下一个分配单元
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| static uint NextSector(uint si) { FSHeader* header = (si != SCT_END_FLAG) ? ReadSector(HEADER_SCT_IDX) : NULL; uint ret = SCT_END_FLAG;
if( header ) { MapPos mp = FindInMap(si);
if( mp.pSct ) { uint* pInt = AddrOff(mp.pSct, mp.idxOff);
if( *pInt != SCT_END_FLAG ) { ret = *pInt + header->mapSize + FIXED_SCT_SIZE; } }
Free(mp.pSct); }
Free(header);
return ret; }
|
辅助功能函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| static uint FindLast(uint sctBegin) { uint ret = SCT_END_FLAG; uint next = sctBegin;
while( next != SCT_END_FLAG ) { ret = next; next = NextSector(next); }
return ret; }
static uint FindPrev(uint sctBegin, uint si) { uint ret = SCT_END_FLAG; uint next = sctBegin;
while( (next != SCT_END_FLAG) && (next != si) ) { ret = next; next = NextSector(next); }
if( next == SCT_END_FLAG ) { ret = SCT_END_FLAG; }
return ret; }
static uint FindIndex(uint sctBegin, uint idx) { uint ret = sctBegin; uint i = 0;
while( (i < idx) && (ret != SCT_END_FLAG) ) { ret = NextSector(ret);
i++; }
return ret; }
static uint MarkSector(uint si) { uint ret = (si == SCT_END_FLAG) ? 1 : 0; MapPos mp = FindInMap(si);
if( mp.pSct ) { uint *pInt = AddrOff(mp.pSct, mp.idxOff);
*pInt = SCT_END_FLAG;
ret = HDRawWrite(mp.sctOff + FIXED_SCT_SIZE, (byte*)mp.pSct); }
Free(mp.pSct);
return ret; }
|
创建文件流程-构建FileEntry
根目录存储的时FileEntry类型的值,每个FileEntry值表示一个硬盘的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| typedef struct { char magic[32]; uint sctBegin; uint sctNum; uint lastBytes; } FSRoot;
typedef struct { char name[32]; uint sctBegin; uint sctNum; uint lastBytes; uint type; uint inSctIdx; uint inSctOff; uint reserved[2]; } FileEntry;
|
如图所示每个fileEntry对应一个文件。一个扇区可以存储8个FileEntry(示意图上3个有点问题)。根目录的数据链表存储了所有的fileEntry值(随着文件数目越来越多,根目录区的FSRoot数据结构成员sctNum会增加)
- 是否有足够空间写入数据,如果空间不足,(比如初始化时把root的lastbytes赋值为512,属于空间不足的情况)因此会找另外一个新的空扇区存放下一个,并且设置sctNum++和lastbyte为0
- 在ROOT链表尾部的扇区存放FileEntry并且赋值,最后写入硬盘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| static void AddToLast(uint sctBegin, uint si) { uint last = FindLast(sctBegin);
if( last != SCT_END_FLAG ) { MapPos lmp = FindInMap(last); MapPos smp = FindInMap(si);
if( lmp.pSct && smp.pSct ) { if( lmp.sctOff == smp.sctOff ) { uint* pInt = AddrOff(lmp.pSct, lmp.idxOff); *pInt = lmp.sctOff * MAP_ITEM_CNT + smp.idxOff; pInt = AddrOff(lmp.pSct, smp.idxOff); *pInt = SCT_END_FLAG; HDRawWrite(lmp.sctOff + FIXED_SCT_SIZE, (byte*)lmp.pSct); } else { uint* pInt = AddrOff(lmp.pSct, lmp.idxOff); *pInt = smp.sctOff * MAP_ITEM_CNT + smp.idxOff;
pInt = AddrOff(smp.pSct, smp.idxOff);
*pInt = SCT_END_FLAG; HDRawWrite(lmp.sctOff + FIXED_SCT_SIZE, (byte*)lmp.pSct); HDRawWrite(smp.sctOff + FIXED_SCT_SIZE, (byte*)smp.pSct); } }
Free(lmp.pSct); Free(smp.pSct); } }
static uint CheckStorage(FSRoot* fe) { uint ret = 0; if( fe->lastBytes == SECT_SIZE ) { uint si = AllocSector();
if( si != SCT_END_FLAG ) { if( fe->sctBegin == SCT_END_FLAG ) { fe->sctBegin = si; } else { AddToLast(fe->sctBegin, si); }
fe->sctNum++; fe->lastBytes = 0;
ret = 1; } }
return ret; }
static uint CreateFileEntry(const char* name, uint sctBegin, uint lastBytes) { uint ret = 0; uint last = FindLast(sctBegin); FileEntry* feBase = NULL;
if( (last != SCT_END_FLAG) && (feBase = (FileEntry*)ReadSector(last)) ) { uint offset = lastBytes / FE_BYTES; FileEntry* fe = AddrOff(feBase, offset); StrCpy(fe->name, name, sizeof(fe->name) - 1);
fe->type = 0; fe->sctBegin = SCT_END_FLAG; fe->sctNum = 0; fe->inSctIdx = last; fe->inSctOff = offset; fe->lastBytes = SECT_SIZE; ret = HDRawWrite(last, (byte*)feBase); }
Free(feBase);
return ret; }
static uint CreateInRoot(const char* name) { FSRoot* root = (FSRoot*)ReadSector(ROOT_SCT_IDX); uint ret = 0;
if( root ) { CheckStorage(root); if( CreateFileEntry(name, root->sctBegin, root->lastBytes) ) { root->lastBytes += FE_BYTES;
ret = HDRawWrite(ROOT_SCT_IDX, (byte*)root); } }
Free(root);
return ret; }
|
删除文件
判断文件是否存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| static FileEntry* FindFileEntry(const char* name, uint sctBegin, uint sctNum, uint lastBytes) { FileEntry* ret = NULL; uint next = sctBegin; uint i = 0; for(i=0; i<(sctNum-1); i++) { FileEntry* feBase = (FileEntry*)ReadSector(next);
if( feBase ) { ret = FindInSector(name, feBase, FE_ITEM_CNT); }
Free(feBase);
if( !ret ) { next = NextSector(next); } else { break; } } if( !ret ) { uint cnt = lastBytes / FE_BYTES; FileEntry* feBase = (FileEntry*)ReadSector(next);
if( feBase ) { ret = FindInSector(name, feBase, cnt); }
Free(feBase); }
return ret; }
static FileEntry* FindInRoot(const char* name) { FileEntry* ret = NULL; FSRoot* root = (FSRoot*)ReadSector(ROOT_SCT_IDX);
if( root && root->sctNum ) { ret = FindFileEntry(name, root->sctBegin, root->sctNum, root->lastBytes); }
Free(root);
return ret; }
uint FExisted(const char* fn) { uint ret = FS_FAILED;
if( fn ) { FileEntry* fe = FindInRoot(fn);
ret = fe ? FS_EXISTED : FS_NONEXISTED;
Free(fe); }
return ret; }
|
删除文件流程
- 根据文件名在根目录的数据链表中查找FileEntry值。从数据链表中删除FileEntry值
- 注意需要判断目标文件是否已经打开,只有在关闭状态才能被删除
- 将数据链表的最后一个
FileEntry
移动到被删除的FileEntry
位置(注意如图所示FileEntry5
的inSctIdx,inSctOff
)处并且更新lastbyte
值的大小(lastbytes大小减小64,注意如果lastbytes
大小为64,减去后变为0,那么还需要把整个扇区给归还AdjustStorage
到空闲链表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| static uint FreeFile(uint sctBegin) { uint slider = sctBegin; uint ret = 0; while( slider != SCT_END_FLAG ) { uint next = NextSector(slider);
ret += FreeSector(slider);
slider = next; } return ret; }
static void MoveFileEntry(FileEntry* dst, FileEntry* src) { uint inSctIdx = dst->inSctIdx; uint inSctOff = dst->inSctOff;
*dst = *src;
dst->inSctIdx = inSctIdx; dst->inSctOff = inSctOff; }
static uint AdjustStorage(FSRoot* fe) { uint ret = 0;
if( !fe->lastBytes ) { uint last = FindLast(fe->sctBegin); uint prev = FindPrev(fe->sctBegin, last); if( FreeSector(last) && MarkSector(prev) ) { fe->sctNum--; fe->lastBytes = SECT_SIZE;
if( !fe->sctNum ) { fe->sctBegin = SCT_END_FLAG; }
ret = 1; } }
return ret; }
static uint EraseLast(FSRoot* fe, uint bytes) { uint ret = 0;
while( fe->sctNum && bytes ) { if( bytes < fe->lastBytes ) { fe->lastBytes -= bytes;
ret += bytes;
bytes = 0; } else { bytes -= fe->lastBytes;
ret += fe->lastBytes;
fe->lastBytes = 0; AdjustStorage(fe); } }
return ret; }
static uint DeleteInRoot(const char* name) { FSRoot* root = (FSRoot*)ReadSector(ROOT_SCT_IDX); FileEntry* fe = FindInRoot(name); uint ret = 0;
if( root && fe ) { uint last = FindLast(root->sctBegin); FileEntry* feTarget = ReadSector(fe->inSctIdx); FileEntry* feLast = (last != SCT_END_FLAG) ? ReadSector(last) : NULL;
if( feTarget && feLast ) { uint lastOff = root->lastBytes / FE_BYTES - 1; FileEntry* lastItem = AddrOff(feLast, lastOff); FileEntry* targetItem = AddrOff(feTarget, fe->inSctOff); FreeFile(targetItem->sctBegin); MoveFileEntry(targetItem, lastItem); EraseLast(root, FE_BYTES); ret = HDRawWrite(ROOT_SCT_IDX, (byte*)root) && HDRawWrite(fe->inSctIdx, (byte*)feTarget); }
Free(feTarget); Free(feLast); }
Free(root); Free(fe);
return ret; }
|
重命名根目录中的文件
- 判断目标文件是否打开,只有关闭状态才能重命名
- 根据名字查找目标FileEntry的位置
- 查找新名字是否已经被占用,未被占用才可修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| static uint FlushFileEntry(FileEntry* fe) { uint ret = 0; FileEntry* feBase = ReadSector(fe->inSctIdx); FileEntry* feInSct = AddrOff(feBase, fe->inSctOff);
*feInSct = *fe; ret = HDRawWrite(fe->inSctIdx, (byte*)feBase);
Free(feBase);
return ret; }
uint FRename(const char* ofn, const char* nfn) { uint ret = FS_FAILED; if( ofn && !IsOpened(ofn) && nfn ) { FileEntry* ofe = FindInRoot(ofn); FileEntry* nfe = FindInRoot(nfn); if( ofe && !nfe ) { StrCpy(ofe->name, nfn, sizeof(ofe->name) - 1); if( FlushFileEntry(ofe) ) { ret = FS_SUCCEED; } }
Free(ofe); Free(nfe); }
return ret; }
|
读写文件
文件描述符
用于描述已经打开的文件,文件的信息FileEntry,文件读写位置等信息
1 2 3 4 5 6 7 8 9 10 11
| static List gFDList = {0};
typedef struct { ListNode head; FileEntry fe; uint objIdx; uint offset; uint changed; byte cache[SECT_SIZE]; } FileDesc;
|
文件打开关闭函数
会将文件描述符加入/删除全局文件描述符链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| static uint IsFDValid(FileDesc* fd) { uint ret = 0; ListNode* pos = NULL;
List_ForEach(&gFDList, pos) { if( IsEqual(pos, fd) ) { ret = 1; break; } }
return ret; }
static uint FlushCache(FileDesc* fd) { uint ret = 1;
if( fd->changed ) { uint sctIdx = FindIndex(fd->fe.sctBegin, fd->objIdx);
ret = 0;
if( (sctIdx != SCT_END_FLAG) && (ret = HDRawWrite(sctIdx, fd->cache)) ) { fd->changed = 0; } }
return ret; }
static uint ToFlush(FileDesc* fd) { return FlushCache(fd) && FlushFileEntry(&fd->fe); }
uint FOpen(const char *fn) { FileDesc* ret = NULL; if( fn && !IsOpened(fn) ) { FileEntry* fe = NULL; ret = (FileDesc*)Malloc(FD_BYTES); fe = ret ? FindInRoot(fn) : NULL;
if( ret && fe ) { ret->fe = *fe; ret->objIdx = SCT_END_FLAG; ret->offset = SECT_SIZE; ret->changed = 0;
List_Add(&gFDList, (ListNode*)ret); }
Free(fe); }
return (uint)ret; }
void FClose(uint fd) { FileDesc* pf = (FileDesc*)fd; if( IsFDValid(pf) ) { ToFlush(pf); List_DelNode((ListNode*)pf);
Free(pf); } }
|
文件数据写入函数
写入数据的时候,文件数据链表可能变长。写入数据先写入缓冲区中,当缓冲区写满了之后,要将缓冲区写入扇区并且将下一个扇区的内容读取到缓冲区中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| static uint ReadToCache(FileDesc* fd, uint idx) { uint ret = 0;
if( idx < fd->fe.sctNum ) { uint sctIdx = FindIndex(fd->fe.sctBegin, idx);
ToFlush(fd);
if( (sctIdx != SCT_END_FLAG) && (ret = HDRawRead(sctIdx, fd->cache)) ) { fd->objIdx = idx; fd->offset = 0; fd->changed = 0; } }
return ret; }
static uint PrepareCache(FileDesc* fd, uint objIdx) { CheckStorage(&fd->fe); return ReadToCache(fd, objIdx); }
static uint CopyToCache(FileDesc* fd, byte* buf, uint len) { uint ret = -1;
if( fd->objIdx != SCT_END_FLAG ) { uint n = SECT_SIZE - fd->offset; byte* p = AddrOff(fd->cache, fd->offset);
n = (n < len) ? n : len;
MemCpy(p, buf, n);
fd->offset += n; fd->changed = 1; if( ((fd->fe.sctNum - 1) == fd->objIdx) && (fd->fe.lastBytes < fd->offset) ) { fd->fe.lastBytes = fd->offset; }
ret = n; }
return ret; }
static uint ToWrite(FileDesc* fd, byte* buf, uint len) { uint ret = 1; uint i = 0; uint n = 0;
while( (i < len) && ret ) { byte* p = AddrOff(buf, i);
if( fd->offset == SECT_SIZE ) { ret = PrepareCache(fd, fd->objIdx + 1); }
if( ret ) { n = CopyToCache(fd, p, len - i);
i += n; } }
ret = i;
return ret; }
uint FWrite(uint fd, byte* buf, uint len) { uint ret = -1;
if( IsFDValid((FileDesc*)fd) && buf ) { ret = ToWrite((FileDesc*)fd, buf, len); }
return ret; }
|
文件中读数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| static uint GetFilePos(FileDesc* fd) { uint ret = 0;
if( fd->objIdx != SCT_END_FLAG ) { ret = fd->objIdx * SECT_SIZE + fd->offset; }
return ret; }
static uint CopyFromCache(FileDesc* fd, byte* buf, uint len) { uint ret = (fd->objIdx != SCT_END_FLAG);
if( ret ) { uint n = SECT_SIZE - fd->offset; byte* p = AddrOff(fd->cache, fd->offset);
n = (n < len) ? n : len;
MemCpy(buf, p, n);
fd->offset += n;
ret = n; }
return ret; }
static uint ToRead(FileDesc* fd, byte* buf, uint len) { uint ret = -1; uint n = GetFileLen(fd) - GetFilePos(fd); uint i = 0;
len = (len < n) ? len : n; while( (i < len) && ret ) { byte* p = AddrOff(buf, i); if( fd->offset == SECT_SIZE ) { ret = PrepareCache(fd, fd->objIdx + 1); }
if( ret ) { n = CopyFromCache(fd, p, len - i); }
i += n; }
ret = i;
return ret; }
uint FRead(uint fd, byte* buf, uint len) { uint ret = -1;
if( IsFDValid((FileDesc*)fd) && buf ) { ret = ToRead((FileDesc*)fd, buf, len); }
return ret; }
|
辅助函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| static uint ToLocate(FileDesc* fd, uint pos) { uint ret = -1; uint len = GetFileLen(fd); pos = (pos < len) ? pos : len;
{ uint objIdx = pos / SECT_SIZE; uint offset = pos % SECT_SIZE; uint sctIdx = FindIndex(fd->fe.sctBegin, objIdx);
ToFlush(fd); if( (sctIdx != SCT_END_FLAG) && HDRawRead(sctIdx, fd->cache) ) { fd->objIdx = objIdx; fd->offset = offset;
ret = pos; } }
return ret; }
uint FErase(uint fd, uint bytes) { uint ret = 0; FileDesc* pf = (FileDesc*)fd;
if( IsFDValid(pf) ) { uint pos = GetFilePos(pf); uint len = GetFileLen(pf);
ret = EraseLast(&pf->fe, bytes);
len -= ret;
if( ret && (pos > len) ) { ToLocate(pf, len); } }
return ret; }
uint FSeek(uint fd, uint pos) { uint ret = -1; FileDesc* pf = (FileDesc*)fd;
if( IsFDValid(pf) ) { ret = ToLocate(pf, pos); }
return ret; }
uint FLength(uint fd) { uint ret = -1; FileDesc* pf = (FileDesc*)fd;
if( IsFDValid(pf) ) { ret = GetFileLen(pf); }
return ret; }
uint FTell(uint fd) { uint ret = -1; FileDesc* pf = (FileDesc*)fd;
if( IsFDValid(pf) ) { ret = GetFilePos(pf); }
return ret; }
uint FFlush(uint fd) { uint ret = -1; FileDesc* pf = (FileDesc*)fd;
if( IsFDValid(pf) ) { ret = ToFlush(pf); }
return ret; }
|