Files
frostbyte/src/sfs.c
T

159 lines
5.6 KiB
C

#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);
}