feat: add SfsInode and SfsDirEntry
This commit is contained in:
1 parent
3376f44f5e
commit
3dfdda8771
1 file changed
+158
@@ -0,0 +1,158 @@
|
||||
#include "sfs.h"
|
||||
#include "ata.h"
|
||||
#include "heap.h"
|
||||
#include "string.h"
|
||||
#include "rtc.h"
|
||||
#include "fs.h"
|
||||
#include "sched.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#define sfsDirectBlocks 10
|
||||
#define sfsPtrsPerBlock (sfsBlockSize / sizeof(uint32)) /* 128 */
|
||||
|
||||
/* 88 bytes: 512/88 = 5 inodes per block (72 bytes/block left unused --
|
||||
inodeLocation and the format-time inodeTableBlocks math already derive
|
||||
everything from sizeof(SfsInode) generically, so this shrinking density
|
||||
is the honest cost of the extra fields, not a layout hack, same story as
|
||||
84 bytes/6-per-block was before gid). Addressing is direct (10 blocks) +
|
||||
single indirect (128 blocks) + double indirect (128 * 128 blocks) +
|
||||
triple indirect (128 * 128 * 128 blocks): a max file size of roughly
|
||||
(10 + 128 + 128*128 + 128*128*128) * 512 bytes ~= 1032 MiB, versus ~8 MiB
|
||||
with direct/single/double alone. mtime/ctime (rtc.h's rtcNow(), seconds
|
||||
since the Unix epoch, truncated to 32 bits -- valid through year 2106,
|
||||
same honest scope as rtc.c's own 2000-2099 century limit), mode (fs.h's
|
||||
fsModeOwner*, real chmod(2) bits), uid (fs.h's FbStat.uid, sched.h's
|
||||
currentThreadUid() at creation) and now gid (fs.h's FbStat.gid, sched.h's
|
||||
currentThreadGid() at creation) are the newest fields, genuinely growing
|
||||
the struct like tripleIndirect did before them -- there is no padding
|
||||
left to repurpose. */
|
||||
typedef struct SfsInode {
|
||||
uint32 type;
|
||||
uint32 size;
|
||||
uint32 linkCount;
|
||||
uint32 blockCount;
|
||||
uint32 direct[sfsDirectBlocks];
|
||||
uint32 indirect;
|
||||
uint32 doubleIndirect;
|
||||
uint32 tripleIndirect;
|
||||
uint32 mtime;
|
||||
uint32 ctime;
|
||||
uint32 mode;
|
||||
uint32 uid;
|
||||
uint32 gid;
|
||||
} SfsInode;
|
||||
|
||||
/* Exactly 64 bytes: 512/64 = 8 directory entries per block. name[56] leaves
|
||||
room for sfsNameMax (55) chars plus the null terminator. */
|
||||
typedef struct SfsDirEntry {
|
||||
uint32 inode;
|
||||
uint32 type;
|
||||
char name[56];
|
||||
} SfsDirEntry;
|
||||
|
||||
typedef struct SfsSuperblock {
|
||||
uint32 magic;
|
||||
uint32 blockSize;
|
||||
uint32 totalBlocks;
|
||||
uint32 inodeCount;
|
||||
uint32 inodeBitmapStart;
|
||||
uint32 inodeBitmapBlocks;
|
||||
uint32 blockBitmapStart;
|
||||
uint32 blockBitmapBlocks;
|
||||
uint32 inodeTableStart;
|
||||
uint32 inodeTableBlocks;
|
||||
uint32 dataStart;
|
||||
uint32 rootInode;
|
||||
} SfsSuperblock;
|
||||
|
||||
#define sfsMagic 0x53465331u /* "SFS1" */
|
||||
|
||||
static SfsSuperblock sb;
|
||||
static uint8* inodeBitmap = nullptr;
|
||||
static uint8* blockBitmap = nullptr;
|
||||
static bool isMounted = false;
|
||||
|
||||
/* See sfsGeneration()'s doc comment (sfs.h). Starts at 1 (not 0) so a caller
|
||||
that zero-initializes its own cache can use generation 0 to mean "never
|
||||
bound to anything yet" without that ever colliding with a real one. */
|
||||
static uint64 formatGeneration = 1;
|
||||
|
||||
/* --- internal helpers (forward-declared so definition order can follow the
|
||||
dependency graph without header noise) --- */
|
||||
static bool bitTest(const uint8* map, uint32 bit);
|
||||
static void bitSet(uint8* map, uint32 bit);
|
||||
static void bitClear(uint8* map, uint32 bit);
|
||||
static bool blockRead(uint32 blockAbs, void* buffer);
|
||||
static bool blockWrite(uint32 blockAbs, const void* buffer);
|
||||
static bool flushInodeBitmap(void);
|
||||
static bool flushBlockBitmap(void);
|
||||
static bool flushSuperblock(void);
|
||||
static void inodeLocation(int32 inodeNum, uint32* blockAbs, uint32* index);
|
||||
static bool readInode(int32 inodeNum, SfsInode* out);
|
||||
static bool writeInodeRaw(int32 inodeNum, const SfsInode* in);
|
||||
static int32 allocInodeNum(void);
|
||||
static void freeInodeNum(int32 inodeNum);
|
||||
static int32 allocDataBlockAbs(void);
|
||||
static void freeDataBlockAbs(uint32 blockAbs);
|
||||
static bool loadOrAllocPointerBlock(SfsInode* inode, uint32* holderAbs, uint8* buf);
|
||||
static bool getOrAllocBlockForWrite(SfsInode* inode, uint32 logicalIndex, uint32* outAbs);
|
||||
static bool getBlockForRead(const SfsInode* inode, uint32 logicalIndex, uint32* outAbs);
|
||||
static bool sfsWriteRaw(SfsInode* inode, int32 inodeNum, uint64 position, const void* data, uint64 length);
|
||||
static bool sfsTruncateInode(SfsInode* inode, int32 inodeNum, uint32 newSize);
|
||||
static bool splitPath(const char* path, char* parentOut, uint64 parentCap, char* leafOut, uint64 leafCap);
|
||||
static int32 dirFind(int32 dirInode, const char* name, uint64 nameLen);
|
||||
static bool dirAdd(int32 dirInode, const char* name, uint64 nameLen, int32 childInode, uint32 type);
|
||||
static bool dirRemove(int32 dirInode, const char* name, uint64 nameLen);
|
||||
static int32 createNode(const char* path, uint32 type);
|
||||
static bool readSymlinkTarget(int32 inodeNum, char* buf, uint64 cap);
|
||||
static int32 lookupFrom(const char* path, bool followFinal, int depth);
|
||||
|
||||
static bool bitTest(const uint8* map, uint32 bit)
|
||||
{
|
||||
return (map[bit / 8] >> (bit % 8)) & 1u;
|
||||
}
|
||||
|
||||
static void bitSet(uint8* map, uint32 bit)
|
||||
{
|
||||
map[bit / 8] = (uint8)(map[bit / 8] | (uint8)(1u << (bit % 8)));
|
||||
}
|
||||
|
||||
static void bitClear(uint8* map, uint32 bit)
|
||||
{
|
||||
map[bit / 8] = (uint8)(map[bit / 8] & (uint8)~(1u << (bit % 8)));
|
||||
}
|
||||
|
||||
static bool blockRead(uint32 blockAbs, void* buffer)
|
||||
{
|
||||
return ataReadSectors(sfsBaseLba + blockAbs, 1, buffer);
|
||||
}
|
||||
|
||||
static bool blockWrite(uint32 blockAbs, const void* buffer)
|
||||
{
|
||||
return ataWriteSectors(sfsBaseLba + blockAbs, 1, buffer);
|
||||
}
|
||||
|
||||
static bool flushInodeBitmap(void)
|
||||
{
|
||||
for (uint32 i = 0; i < sb.inodeBitmapBlocks; i++)
|
||||
if (!blockWrite(sb.inodeBitmapStart + i, inodeBitmap + (uint64)i * sfsBlockSize))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool flushBlockBitmap(void)
|
||||
{
|
||||
for (uint32 i = 0; i < sb.blockBitmapBlocks; i++)
|
||||
if (!blockWrite(sb.blockBitmapStart + i, blockBitmap + (uint64)i * sfsBlockSize))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool flushSuperblock(void)
|
||||
{
|
||||
uint8 buf[sfsBlockSize];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, &sb, sizeof(sb));
|
||||
return blockWrite(0, buf);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user