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 :
|
KernelStaticLibrary boot_bfs :
|
||||||
bfs.cpp
|
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/partitions.h>
|
||||||
|
#include <boot/platform.h>
|
||||||
#include <boot/vfs.h>
|
#include <boot/vfs.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
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);
|
Volume *volume = new Volume(device);
|
||||||
if (fd >= 0)
|
if (volume == NULL)
|
||||||
close(fd);
|
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