159 lines
5.6 KiB
C
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);
|
|
}
|
|
|