feat: add readSymlinkTarget and lookupFrom to sfs
This commit is contained in:
1 parent
39520e6183
commit
6fdab2178f
1 file changed
+161
@@ -793,3 +793,164 @@ static int32 createNode(const char* path, uint32 type)
|
|||||||
if (newInode < 0)
|
if (newInode < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
SfsInode inode;
|
||||||
|
memset(&inode, 0, sizeof(inode));
|
||||||
|
inode.type = type;
|
||||||
|
inode.linkCount = 1;
|
||||||
|
inode.mtime = inode.ctime = (uint32)rtcNow();
|
||||||
|
inode.mode = (type == sfsTypeDir) ? fsModeDefaultDir : fsModeDefaultFile;
|
||||||
|
inode.uid = currentThreadUid();
|
||||||
|
inode.gid = currentThreadGid();
|
||||||
|
if (!writeInodeRaw(newInode, &inode)) {
|
||||||
|
freeInodeNum(newInode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dirAdd(parentInode, leaf, strlen(leaf), newInode, type)) {
|
||||||
|
freeInodeNum(newInode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return newInode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool readSymlinkTarget(int32 inodeNum, char* buf, uint64 cap)
|
||||||
|
{
|
||||||
|
SfsInode inode;
|
||||||
|
if (!readInode(inodeNum, &inode))
|
||||||
|
return false;
|
||||||
|
if (inode.type != sfsTypeSymlink)
|
||||||
|
return false;
|
||||||
|
if (cap == 0 || (uint64)inode.size >= cap)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int64 got = sfsReadAt(inodeNum, 0, buf, inode.size);
|
||||||
|
if (got != (int64)inode.size)
|
||||||
|
return false;
|
||||||
|
buf[inode.size] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walks path one component at a time from the root, exactly like the old
|
||||||
|
flat sfsLookup used to, except a symlink component (other than possibly
|
||||||
|
the last one, depending on followFinal) is resolved by re-running this
|
||||||
|
same walk on its target and splicing the result back in as `cur` before
|
||||||
|
continuing with whatever of the original path remains. depth counts hops
|
||||||
|
already taken across that splicing, so a cycle (or merely a very long
|
||||||
|
chain) fails cleanly with -1 instead of recursing without bound. */
|
||||||
|
static int32 lookupFrom(const char* path, bool followFinal, int depth)
|
||||||
|
{
|
||||||
|
if (!isMounted)
|
||||||
|
return -1;
|
||||||
|
if (depth > sfsMaxSymlinkHops)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int32 cur = sfsRootInode;
|
||||||
|
const char* p = path ? path : "";
|
||||||
|
while (*p == '/')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
|
const char* start = p;
|
||||||
|
while (*p && *p != '/')
|
||||||
|
p++;
|
||||||
|
uint64 len = (uint64)(p - start);
|
||||||
|
if (len == 0 || len >= sfsNameMax)
|
||||||
|
return -1;
|
||||||
|
if (sfsTypeOf(cur) != sfsTypeDir)
|
||||||
|
return -1;
|
||||||
|
/* Real POSIX search permission on every directory ANCESTOR walked
|
||||||
|
through, mirroring vfs.c's lookupNode's own equivalent check for
|
||||||
|
tmpfs -- resolving a name inside `cur` needs the owner-or-other
|
||||||
|
exec bit for the calling thread's uid, not just "cur is a
|
||||||
|
directory". */
|
||||||
|
if (!vfsPermitted(sfsModeOf(cur), sfsUidOf(cur), sfsGidOf(cur),
|
||||||
|
currentThreadUid(), currentThreadGid(), fsModeOwnerExec))
|
||||||
|
return -1;
|
||||||
|
int32 child = dirFind(cur, start, len);
|
||||||
|
if (child < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (*p == '/')
|
||||||
|
p++;
|
||||||
|
bool isLast = (*p == 0);
|
||||||
|
|
||||||
|
if (sfsTypeOf(child) == sfsTypeSymlink && (!isLast || followFinal)) {
|
||||||
|
char target[sfsSymlinkTargetMax + 1];
|
||||||
|
if (!readSymlinkTarget(child, target, sizeof(target)))
|
||||||
|
return -1;
|
||||||
|
int32 resolved = lookupFrom(target, true, depth + 1);
|
||||||
|
if (resolved < 0)
|
||||||
|
return -1;
|
||||||
|
child = resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = child;
|
||||||
|
}
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- public API --- */
|
||||||
|
|
||||||
|
bool sfsFormat(void)
|
||||||
|
{
|
||||||
|
if (!ataPresent())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint64 sectors = ataSectorCount();
|
||||||
|
if (sectors <= sfsBaseLba + sfsReserveEnd + 64)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SfsSuperblock nsb;
|
||||||
|
memset(&nsb, 0, sizeof(nsb));
|
||||||
|
nsb.magic = sfsMagic;
|
||||||
|
nsb.blockSize = sfsBlockSize;
|
||||||
|
nsb.totalBlocks = (uint32)(sectors - sfsBaseLba - sfsReserveEnd);
|
||||||
|
nsb.inodeCount = sfsMaxNodes;
|
||||||
|
|
||||||
|
nsb.inodeBitmapStart = 1;
|
||||||
|
nsb.inodeBitmapBlocks = (nsb.inodeCount + 8 * sfsBlockSize - 1) / (8 * sfsBlockSize);
|
||||||
|
if (nsb.inodeBitmapBlocks == 0)
|
||||||
|
nsb.inodeBitmapBlocks = 1;
|
||||||
|
|
||||||
|
nsb.blockBitmapStart = nsb.inodeBitmapStart + nsb.inodeBitmapBlocks;
|
||||||
|
nsb.blockBitmapBlocks = (nsb.totalBlocks + 8 * sfsBlockSize - 1) / (8 * sfsBlockSize);
|
||||||
|
if (nsb.blockBitmapBlocks == 0)
|
||||||
|
nsb.blockBitmapBlocks = 1;
|
||||||
|
|
||||||
|
nsb.inodeTableStart = nsb.blockBitmapStart + nsb.blockBitmapBlocks;
|
||||||
|
uint32 inodesPerBlock = sfsBlockSize / sizeof(SfsInode);
|
||||||
|
nsb.inodeTableBlocks = (nsb.inodeCount + inodesPerBlock - 1) / inodesPerBlock;
|
||||||
|
|
||||||
|
nsb.dataStart = nsb.inodeTableStart + nsb.inodeTableBlocks;
|
||||||
|
nsb.rootInode = sfsRootInode;
|
||||||
|
if (nsb.dataStart >= nsb.totalBlocks)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Committed to actually wiping from here on (every earlier return above
|
||||||
|
is a rejected format that touched nothing) -- every inode number's
|
||||||
|
old meaning is about to become garbage, so anything that cached one
|
||||||
|
from before this point must be told apart from anything cached
|
||||||
|
after. */
|
||||||
|
formatGeneration++;
|
||||||
|
|
||||||
|
if (inodeBitmap) {
|
||||||
|
kfree(inodeBitmap);
|
||||||
|
inodeBitmap = nullptr;
|
||||||
|
}
|
||||||
|
if (blockBitmap) {
|
||||||
|
kfree(blockBitmap);
|
||||||
|
blockBitmap = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inodeBitmap = (uint8*)kmalloc((uint64)nsb.inodeBitmapBlocks * sfsBlockSize);
|
||||||
|
blockBitmap = (uint8*)kmalloc((uint64)nsb.blockBitmapBlocks * sfsBlockSize);
|
||||||
|
if (!inodeBitmap || !blockBitmap) {
|
||||||
|
if (inodeBitmap) kfree(inodeBitmap);
|
||||||
|
if (blockBitmap) kfree(blockBitmap);
|
||||||
|
inodeBitmap = nullptr;
|
||||||
|
blockBitmap = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(inodeBitmap, 0, (uint64)nsb.inodeBitmapBlocks * sfsBlockSize);
|
||||||
|
memset(blockBitmap, 0, (uint64)nsb.blockBitmapBlocks * sfsBlockSize);
|
||||||
|
|
||||||
Reference in new issue
Block a user