Started to implement the real BFS module for the boot loader.
Currently, it only recognizes a BFS disk, and will print out its name (and that code is now endian-aware as well). More to come, though :-) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4637 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
** Copyright 2003, Axel Dörfler, [email protected]. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Directory.h"
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
namespace BFS {
|
||||
|
||||
Directory::Directory(Volume &volume, block_run run)
|
||||
:
|
||||
fVolume(volume)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Directory::~Directory()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Directory::InitCheck()
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Directory::Open(void **_cookie, int mode)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Directory::Close(void *cookie)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
Node *
|
||||
Directory::Lookup(const char *name, bool traverseLinks)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Directory::GetNextNode(void *cookie, Node **_node)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Directory::Rewind(void *cookie)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
bfs_inode::InitCheck(Volume *volume)
|
||||
{
|
||||
if (Flags() & INODE_NOT_READY) {
|
||||
// the other fields may not yet contain valid values
|
||||
return B_BUSY;
|
||||
}
|
||||
|
||||
if (Magic1() != INODE_MAGIC1
|
||||
|| !(Flags() & INODE_IN_USE)
|
||||
|| inode_num.Length() != 1
|
||||
// matches inode size?
|
||||
|| (uint32)InodeSize() != volume->InodeSize()
|
||||
// parent resides on disk?
|
||||
|| parent.AllocationGroup() > int32(volume->AllocationGroups())
|
||||
|| parent.AllocationGroup() < 0
|
||||
|| parent.Start() > (1L << volume->AllocationGroupShift())
|
||||
|| parent.Length() != 1
|
||||
// attributes, too?
|
||||
|| attributes.AllocationGroup() > int32(volume->AllocationGroups())
|
||||
|| attributes.AllocationGroup() < 0
|
||||
|| attributes.Start() > (1L << volume->AllocationGroupShift()))
|
||||
return B_BAD_DATA;
|
||||
|
||||
// ToDo: Add some tests to check the integrity of the other stuff here,
|
||||
// especially for the data_stream!
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
} // namespace BFS
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
** Copyright 2003, Axel Dörfler, [email protected]. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
#ifndef DIRECTORY_H
|
||||
#define DIRECTORY_H
|
||||
|
||||
|
||||
#include <boot/vfs.h>
|
||||
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
namespace BFS {
|
||||
|
||||
class Directory : public ::Directory {
|
||||
public:
|
||||
Directory(BFS::Volume &volume, block_run run);
|
||||
virtual ~Directory();
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
virtual status_t Close(void *cookie);
|
||||
|
||||
virtual Node *Lookup(const char *name, bool traverseLinks);
|
||||
|
||||
virtual status_t GetNextNode(void *cookie, Node **_node);
|
||||
virtual status_t Rewind(void *cookie);
|
||||
|
||||
private:
|
||||
Volume &fVolume;
|
||||
bfs_inode fNode;
|
||||
};
|
||||
|
||||
} // namespace BFS
|
||||
|
||||
#endif /* DIRECTORY_H */
|
||||
@@ -8,4 +8,5 @@ SubDirHdrs $(OBOS_TOP) src add-ons kernel file_systems bfs ;
|
||||
|
||||
KernelStaticLibrary boot_bfs :
|
||||
bfs.cpp
|
||||
Directory.cpp
|
||||
;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
** Copyright 2003, Axel Dörfler, [email protected]. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
#ifndef VOLUME_H
|
||||
#define VOLUME_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class Node;
|
||||
|
||||
|
||||
namespace BFS {
|
||||
|
||||
#include "bfs.h"
|
||||
|
||||
class Directory;
|
||||
|
||||
class Volume {
|
||||
public:
|
||||
Volume(Node *device);
|
||||
~Volume();
|
||||
|
||||
status_t InitCheck();
|
||||
bool IsValidSuperBlock();
|
||||
|
||||
block_run Root() const { return fSuperBlock.root_dir; }
|
||||
Directory *RootNode() const { return fRootNode; }
|
||||
block_run Indices() const { return fSuperBlock.indices; }
|
||||
const char *Name() const { return fSuperBlock.name; }
|
||||
|
||||
int Device() const { return fDevice; }
|
||||
|
||||
off_t NumBlocks() const { return fSuperBlock.NumBlocks(); }
|
||||
off_t UsedBlocks() const { return fSuperBlock.UsedBlocks(); }
|
||||
off_t FreeBlocks() const { return NumBlocks() - UsedBlocks(); }
|
||||
|
||||
uint32 BlockSize() const { return fSuperBlock.BlockSize(); }
|
||||
uint32 BlockShift() const { return fSuperBlock.BlockShift(); }
|
||||
uint32 InodeSize() const { return fSuperBlock.InodeSize(); }
|
||||
uint32 AllocationGroups() const { return fSuperBlock.AllocationGroups(); }
|
||||
uint32 AllocationGroupShift() const { return fSuperBlock.AllocationGroupShift(); }
|
||||
disk_super_block &SuperBlock() { return fSuperBlock; }
|
||||
|
||||
off_t ToOffset(block_run run) const { return ToBlock(run) << fSuperBlock.block_shift; }
|
||||
off_t ToBlock(block_run run) const { return ((((off_t)run.AllocationGroup()) << AllocationGroupShift()) | (off_t)run.Start()); }
|
||||
block_run ToBlockRun(off_t block) const;
|
||||
status_t ValidateBlockRun(block_run run);
|
||||
|
||||
off_t ToVnode(block_run run) const { return ToBlock(run); }
|
||||
off_t ToVnode(off_t block) const { return block; }
|
||||
|
||||
protected:
|
||||
int fDevice;
|
||||
disk_super_block fSuperBlock;
|
||||
|
||||
BFS::Directory *fRootNode;
|
||||
};
|
||||
|
||||
} // namespace BFS
|
||||
|
||||
#endif /* VOLUME_H */
|
||||
@@ -4,25 +4,138 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "Volume.h"
|
||||
#include "Directory.h"
|
||||
|
||||
#include <boot/partitions.h>
|
||||
#include <boot/platform.h>
|
||||
#include <boot/vfs.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
using namespace BFS;
|
||||
|
||||
|
||||
Volume::Volume(Node *device)
|
||||
:
|
||||
fRootNode(NULL)
|
||||
{
|
||||
fDevice = open_node(device, O_RDONLY);
|
||||
if (fDevice < B_OK)
|
||||
return;
|
||||
|
||||
if (read_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block)) < B_OK)
|
||||
return;
|
||||
|
||||
if (!IsValidSuperBlock()) {
|
||||
#ifndef BFS_LITTLE_ENDIAN_ONLY
|
||||
// try block 0 again (can only happen on the big endian BFS)
|
||||
if (read_pos(fDevice, 0, &fSuperBlock, sizeof(disk_super_block)) < B_OK)
|
||||
return;
|
||||
|
||||
if (!IsValidSuperBlock())
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("we do have a valid BFS super block (name = %s)!\n", fSuperBlock.name);
|
||||
|
||||
fRootNode = new BFS::Directory(*this, Root());
|
||||
if (fRootNode == NULL)
|
||||
return;
|
||||
|
||||
if (fRootNode->InitCheck() < B_OK) {
|
||||
delete fRootNode;
|
||||
fRootNode = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Volume::~Volume()
|
||||
{
|
||||
close(fDevice);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::InitCheck()
|
||||
{
|
||||
if (fDevice < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return fRootNode != NULL ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Volume::IsValidSuperBlock()
|
||||
{
|
||||
if (fSuperBlock.Magic1() != (int32)SUPER_BLOCK_MAGIC1
|
||||
|| fSuperBlock.Magic2() != (int32)SUPER_BLOCK_MAGIC2
|
||||
|| fSuperBlock.Magic3() != (int32)SUPER_BLOCK_MAGIC3
|
||||
|| (int32)fSuperBlock.block_size != fSuperBlock.inode_size
|
||||
|| fSuperBlock.ByteOrder() != SUPER_BLOCK_FS_LENDIAN
|
||||
|| (1UL << fSuperBlock.BlockShift()) != fSuperBlock.BlockSize()
|
||||
|| fSuperBlock.AllocationGroups() < 1
|
||||
|| fSuperBlock.AllocationGroupShift() < 1
|
||||
|| fSuperBlock.BlocksPerAllocationGroup() < 1
|
||||
|| fSuperBlock.NumBlocks() < 10
|
||||
|| fSuperBlock.AllocationGroups() != divide_roundup(fSuperBlock.NumBlocks(), 1L << fSuperBlock.AllocationGroupShift()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::ValidateBlockRun(block_run run)
|
||||
{
|
||||
if (run.AllocationGroup() < 0 || run.AllocationGroup() > (int32)AllocationGroups()
|
||||
|| run.Start() > (1UL << AllocationGroupShift())
|
||||
|| run.length == 0
|
||||
|| uint32(run.Length() + run.Start()) > (1UL << AllocationGroupShift())) {
|
||||
panic("bfs: invalid run(%ld,%d,%d)\n", run.AllocationGroup(), run.Start(), run.Length());
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
block_run
|
||||
Volume::ToBlockRun(off_t block) const
|
||||
{
|
||||
block_run run;
|
||||
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> fSuperBlock.AllocationGroupShift());
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(block & ~((1LL << fSuperBlock.AllocationGroupShift()) - 1));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||
return run;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static status_t
|
||||
bfs_get_file_system(Node *device, Directory **_root)
|
||||
bfs_get_file_system(Node *device, ::Directory **_root)
|
||||
{
|
||||
int fd = open_node(device, O_RDONLY);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
Volume *volume = new Volume(device);
|
||||
if (volume == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return B_ERROR;
|
||||
if (volume->InitCheck() < B_OK) {
|
||||
delete volume;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
*_root = volume->RootNode();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user