* Added the beginnings of node support.
* Added the bare minimum of file system hooks to mount the file system. Can't do anything more than listing the (empty) root directory yet, though. * Added Jamfile for building the file system for the userlandfs. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37406 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
e66231742e
commit
74956f4385
@ -38,4 +38,34 @@ struct checksumfs_super_block {
|
||||
} _PACKED;
|
||||
|
||||
|
||||
struct checksumfs_node {
|
||||
uint32 mode; // node type + permissions
|
||||
uint32 attributeType; // attribute type (attributes only)
|
||||
uint32 uid; // owning user ID
|
||||
uint32 gid; // owning group ID
|
||||
uint64 creationTime; // in ns since the epoche
|
||||
uint64 modificationTime; //
|
||||
uint64 changeTime; //
|
||||
uint64 hardLinks; // number of references to the node
|
||||
uint64 content; // block index of the content (0 if empty)
|
||||
uint64 size; // content size in bytes
|
||||
uint64 parentDirectory; // block index of the parent directory
|
||||
// (directories and attributes only)
|
||||
uint64 attributeDirectory; // block index of the attribute directory (0 if
|
||||
// empty)
|
||||
} _PACKED;
|
||||
|
||||
|
||||
struct checksumfs_dir_entry_block {
|
||||
uint16 entryCount;
|
||||
uint16 nameEnds[0]; // end (in-block) offsets of the names,
|
||||
// e.g. nameEnds[0] == length of first name
|
||||
// char names[]; // string of all (unterminated) names,
|
||||
// directly follows the nameEnds array
|
||||
// ...
|
||||
// uint64 nodes[];
|
||||
// node array ends at the end of the block
|
||||
};
|
||||
|
||||
|
||||
#endif // CHECK_SUM_FS_H
|
||||
|
@ -58,4 +58,46 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class AllocatedBlock {
|
||||
public:
|
||||
AllocatedBlock(BlockAllocator* allocator)
|
||||
:
|
||||
fAllocator(allocator),
|
||||
fIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
~AllocatedBlock()
|
||||
{
|
||||
if (fIndex > 0)
|
||||
fAllocator->Free(fIndex, 1);
|
||||
}
|
||||
|
||||
uint64 Index() const
|
||||
{
|
||||
return fIndex;
|
||||
}
|
||||
|
||||
status_t Allocate(uint64 baseHint = 0)
|
||||
{
|
||||
uint64 allocatedBlocks;
|
||||
status_t error = fAllocator->Allocate(0, 1, fIndex, allocatedBlocks);
|
||||
if (error != B_OK)
|
||||
fIndex = 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
uint64 Detach()
|
||||
{
|
||||
uint64 index = fIndex;
|
||||
fIndex = 0;
|
||||
return index;
|
||||
}
|
||||
|
||||
private:
|
||||
BlockAllocator* fAllocator;
|
||||
uint64 fIndex;
|
||||
};
|
||||
|
||||
|
||||
#endif // BLOCK_ALLOCATOR_H
|
||||
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "packagefs/DebugSupport.h"
|
27
src/tests/system/kernel/file_corruption/fs/Directory.cpp
Normal file
27
src/tests/system/kernel/file_corruption/fs/Directory.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Directory.h"
|
||||
|
||||
|
||||
Directory::Directory(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData)
|
||||
:
|
||||
Node(volume, blockIndex, nodeData)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Directory::Directory(Volume* volume, uint64 blockIndex, mode_t mode)
|
||||
:
|
||||
Node(volume, blockIndex, mode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Directory::~Directory()
|
||||
{
|
||||
}
|
22
src/tests/system/kernel/file_corruption/fs/Directory.h
Normal file
22
src/tests/system/kernel/file_corruption/fs/Directory.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DIRECTORY_H
|
||||
#define DIRECTORY_H
|
||||
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
|
||||
class Directory : public Node {
|
||||
public:
|
||||
Directory(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData);
|
||||
Directory(Volume* volume, uint64 blockIndex,
|
||||
mode_t mode);
|
||||
virtual ~Directory();
|
||||
};
|
||||
|
||||
|
||||
#endif // DIRECTORY_H
|
@ -6,17 +6,37 @@ UsePrivateHeaders shared ;
|
||||
|
||||
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems ] ;
|
||||
# We use packagefs's DebugSupport.h header, but we don't want to add that
|
||||
# header to avoid clashes with other headers.
|
||||
|
||||
KernelAddon checksumfs :
|
||||
|
||||
DEFINES += DEBUG_APP="\\\"checksumfs\\\"" ;
|
||||
|
||||
|
||||
HAIKU_CHECKSUM_FS_SOURCES =
|
||||
BlockAllocator.cpp
|
||||
checksumfs.cpp
|
||||
Directory.cpp
|
||||
Node.cpp
|
||||
SuperBlock.cpp
|
||||
Volume.cpp
|
||||
;
|
||||
|
||||
KernelAddon checksumfs :
|
||||
$(HAIKU_CHECKSUM_FS_SOURCES)
|
||||
|
||||
# from packagefs
|
||||
DebugSupport.cpp
|
||||
|
||||
# from src/kits/shared
|
||||
SHA256.cpp
|
||||
;
|
||||
|
||||
|
||||
SEARCH on [ FGristFiles DebugSupport.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems packagefs ] ;
|
||||
SEARCH on [ FGristFiles SHA256.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src kits shared ] ;
|
||||
|
||||
HaikuSubInclude userland ;
|
||||
|
76
src/tests/system/kernel/file_corruption/fs/Node.cpp
Normal file
76
src/tests/system/kernel/file_corruption/fs/Node.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Node.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "Block.h"
|
||||
|
||||
|
||||
Node::Node(Volume* volume, uint64 blockIndex, const checksumfs_node& nodeData)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlockIndex(blockIndex),
|
||||
fNode(nodeData),
|
||||
fNodeDataDirty(false)
|
||||
{
|
||||
_Init();
|
||||
}
|
||||
|
||||
|
||||
Node::Node(Volume* volume, uint64 blockIndex, mode_t mode)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlockIndex(blockIndex),
|
||||
fNodeDataDirty(true)
|
||||
{
|
||||
_Init();
|
||||
|
||||
memset(&fNode, 0, sizeof(fNode));
|
||||
|
||||
fNode.mode = mode;
|
||||
|
||||
// set the times
|
||||
timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
|
||||
fNode.creationTime = (uint64)time.tv_sec * 1000000000
|
||||
+ (uint64)time.tv_usec * 1000;
|
||||
fNode.modificationTime = fNode.creationTime;
|
||||
fNode.changeTime = fNode.creationTime;
|
||||
}
|
||||
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
rw_lock_destroy(&fLock);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Node::Flush()
|
||||
{
|
||||
if (!fNodeDataDirty)
|
||||
return B_OK;
|
||||
|
||||
Block block;
|
||||
if (!block.GetWritable(fVolume, fBlockIndex))
|
||||
return B_ERROR;
|
||||
|
||||
memcpy(block.Data(), &fNode, sizeof(fNode));
|
||||
|
||||
fNodeDataDirty = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::_Init()
|
||||
{
|
||||
rw_lock_init(&fLock, "checkfs node");
|
||||
}
|
114
src/tests/system/kernel/file_corruption/fs/Node.h
Normal file
114
src/tests/system/kernel/file_corruption/fs/Node.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
#include "checksumfs.h"
|
||||
|
||||
|
||||
class Volume;
|
||||
|
||||
|
||||
class Node {
|
||||
public:
|
||||
Node(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData);
|
||||
Node(Volume* volume, uint64 blockIndex,
|
||||
mode_t mode);
|
||||
virtual ~Node();
|
||||
|
||||
inline Volume* GetVolume() const { return fVolume; }
|
||||
inline uint64 BlockIndex() const { return fBlockIndex; }
|
||||
inline uint32 Mode() const { return fNode.mode; }
|
||||
inline uint64 ParentDirectory() const;
|
||||
inline uint32 HardLinks() const { return fNode.hardLinks; }
|
||||
inline uint32 UID() const { return fNode.uid; }
|
||||
inline uint32 GID() const { return fNode.gid; }
|
||||
inline uint64 Size() const { return fNode.size; }
|
||||
inline uint64 CreationTime() const;
|
||||
inline uint64 ModificationTime() const;
|
||||
inline uint64 ChangeTime() const;
|
||||
|
||||
inline bool ReadLock();
|
||||
inline void ReadUnlock();
|
||||
inline bool WriteLock();
|
||||
inline void WriteUnlock();
|
||||
|
||||
status_t Flush();
|
||||
|
||||
private:
|
||||
void _Init();
|
||||
|
||||
private:
|
||||
rw_lock fLock;
|
||||
Volume* fVolume;
|
||||
uint64 fBlockIndex;
|
||||
checksumfs_node fNode;
|
||||
bool fNodeDataDirty;
|
||||
};
|
||||
|
||||
|
||||
uint64
|
||||
Node::ParentDirectory() const
|
||||
{
|
||||
return fNode.parentDirectory;
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
Node::CreationTime() const
|
||||
{
|
||||
return fNode.creationTime;
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
Node::ModificationTime() const
|
||||
{
|
||||
return fNode.modificationTime;
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
Node::ChangeTime() const
|
||||
{
|
||||
return fNode.changeTime;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Node::ReadLock()
|
||||
{
|
||||
return rw_lock_read_lock(&fLock) == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::ReadUnlock()
|
||||
{
|
||||
rw_lock_read_unlock(&fLock);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Node::WriteLock()
|
||||
{
|
||||
return rw_lock_write_lock(&fLock) == B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::WriteUnlock()
|
||||
{
|
||||
rw_lock_write_unlock(&fLock);
|
||||
}
|
||||
|
||||
|
||||
#endif // NODE_H
|
@ -9,6 +9,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "BlockAllocator.h"
|
||||
#include "Directory.h"
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
@ -41,6 +42,6 @@ SuperBlock::Initialize(Volume* volume)
|
||||
totalBlocks = volume->TotalBlocks();
|
||||
freeBlocks = volume->GetBlockAllocator()->FreeBlocks();
|
||||
blockBitmap = volume->GetBlockAllocator()->BaseBlock();
|
||||
// rootDir = volume->RootDirBlock();
|
||||
rootDir = volume->RootDirectory()->BlockIndex();
|
||||
strlcpy(name, volume->Name(), kCheckSumFSNameLength);
|
||||
}
|
||||
|
@ -14,12 +14,12 @@ class Volume;
|
||||
|
||||
struct SuperBlock : private checksumfs_super_block {
|
||||
public:
|
||||
uint64 TotalBlocks() const { return totalBlocks; }
|
||||
uint64 FreeBlocks() const { return freeBlocks; }
|
||||
uint32 Version() const { return version; }
|
||||
const char* Name() const { return name; }
|
||||
uint64 BlockBitmap() const { return blockBitmap; }
|
||||
uint64 RootDir() const { return rootDir; }
|
||||
uint64 TotalBlocks() const { return totalBlocks; }
|
||||
uint64 FreeBlocks() const { return freeBlocks; }
|
||||
uint32 Version() const { return version; }
|
||||
const char* Name() const { return name; }
|
||||
uint64 BlockBitmap() const { return blockBitmap; }
|
||||
uint64 RootDirectory() const { return rootDir; }
|
||||
|
||||
bool Check(uint64 totalBlocks) const;
|
||||
void Initialize(Volume* volume);
|
||||
|
@ -20,23 +20,30 @@
|
||||
#include "Block.h"
|
||||
#include "BlockAllocator.h"
|
||||
#include "checksumfs.h"
|
||||
#include "checksumfs_private.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "Directory.h"
|
||||
#include "SuperBlock.h"
|
||||
|
||||
|
||||
Volume::Volume(uint32 flags)
|
||||
:
|
||||
fFSVolume(NULL),
|
||||
fFD(-1),
|
||||
fFlags(flags),
|
||||
fFlags(B_FS_IS_PERSISTENT
|
||||
| (flags & B_FS_IS_READONLY != 0 ? B_FS_IS_READONLY : 0)),
|
||||
fBlockCache(NULL),
|
||||
fTotalBlocks(0),
|
||||
fName(NULL),
|
||||
fBlockAllocator(NULL)
|
||||
fBlockAllocator(NULL),
|
||||
fRootDirectory(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Volume::~Volume()
|
||||
{
|
||||
delete fRootDirectory;
|
||||
delete fBlockAllocator;
|
||||
|
||||
if (fBlockCache != NULL)
|
||||
@ -62,7 +69,27 @@ Volume::Init(const char* device)
|
||||
if (fstat(fFD, &st) < 0)
|
||||
return errno;
|
||||
|
||||
return _Init(st.st_size / B_PAGE_SIZE);
|
||||
off_t size;
|
||||
switch (st.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
size = st.st_size;
|
||||
break;
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
{
|
||||
device_geometry geometry;
|
||||
if (ioctl(fFD, B_GET_GEOMETRY, &geometry, sizeof(geometry)) < 0)
|
||||
return errno;
|
||||
|
||||
size = (off_t)geometry.bytes_per_sector * geometry.sectors_per_track
|
||||
* geometry.cylinder_count * geometry.head_count;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
return _Init(size / B_PAGE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
@ -71,17 +98,68 @@ Volume::Init(int fd, uint64 totalBlocks)
|
||||
{
|
||||
fFD = dup(fd);
|
||||
if (fFD < 0)
|
||||
return errno;
|
||||
RETURN_ERROR(errno);
|
||||
|
||||
return _Init(totalBlocks);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::Mount()
|
||||
Volume::Mount(fs_volume* fsVolume)
|
||||
{
|
||||
// TODO:...
|
||||
return B_UNSUPPORTED;
|
||||
fFSVolume = fsVolume;
|
||||
|
||||
// load the superblock
|
||||
Block block;
|
||||
if (!block.GetReadable(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE))
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
SuperBlock* superBlock = (SuperBlock*)block.Data();
|
||||
if (!superBlock->Check(fTotalBlocks))
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
|
||||
// copy the volume name
|
||||
fName = strdup(superBlock->Name());
|
||||
if (fName == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
// init the block allocator
|
||||
status_t error = fBlockAllocator->Init(superBlock->BlockBitmap(),
|
||||
superBlock->FreeBlocks());
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// load the root directory
|
||||
Node* rootNode;
|
||||
error = ReadNode(superBlock->RootDirectory(), rootNode);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
fRootDirectory = dynamic_cast<Directory*>(rootNode);
|
||||
if (fRootDirectory == NULL) {
|
||||
delete rootNode;
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
}
|
||||
|
||||
error = PublishNode(fRootDirectory, 0);
|
||||
if (error != B_OK) {
|
||||
delete fRootDirectory;
|
||||
fRootDirectory = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Volume::Unmount()
|
||||
{
|
||||
status_t error = block_cache_sync(fBlockCache);
|
||||
if (error != B_OK) {
|
||||
dprintf("checksumfs: Error: Failed to sync block cache when "
|
||||
"unmounting!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -96,6 +174,17 @@ Volume::Initialize(const char* name)
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the root directory
|
||||
error = CreateDirectory(S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,
|
||||
fRootDirectory);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
error = fRootDirectory->Flush();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// write the super block
|
||||
Block block;
|
||||
if (!block.GetZero(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE))
|
||||
return B_ERROR;
|
||||
@ -109,23 +198,117 @@ Volume::Initialize(const char* name)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Volume::GetInfo(fs_info& info)
|
||||
{
|
||||
info.flags = fFlags;
|
||||
info.block_size = B_PAGE_SIZE;
|
||||
info.io_size = B_PAGE_SIZE * 16; // random value
|
||||
info.total_blocks = fTotalBlocks;
|
||||
info.free_blocks = fBlockAllocator->FreeBlocks();
|
||||
info.total_nodes = 1; // phew, who cares?
|
||||
info.free_nodes = info.free_blocks;
|
||||
strlcpy(info.volume_name, fName, sizeof(info.volume_name));
|
||||
// TODO: We need locking once we are able to change the name!
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::PublishNode(Node* node, uint32 flags)
|
||||
{
|
||||
return publish_vnode(fFSVolume, node->BlockIndex(), node,
|
||||
&gCheckSumFSVnodeOps, node->Mode(), flags);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::GetNode(uint64 blockIndex, Node*& _node)
|
||||
{
|
||||
return get_vnode(fFSVolume, blockIndex, (void**)&_node);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::PutNode(Node* node)
|
||||
{
|
||||
return put_vnode(fFSVolume, node->BlockIndex());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::ReadNode(uint64 blockIndex, Node*& _node)
|
||||
{
|
||||
if (blockIndex == 0 || blockIndex >= fTotalBlocks)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// load the node's block
|
||||
Block block;
|
||||
if (!block.GetReadable(this, blockIndex))
|
||||
return B_ERROR;
|
||||
|
||||
checksumfs_node* nodeData = (checksumfs_node*)block.Data();
|
||||
|
||||
// create the Node object
|
||||
Node* node;
|
||||
switch (nodeData->mode & S_IFMT) {
|
||||
// TODO: Don't directly access mode!
|
||||
case S_IFDIR:
|
||||
node = new(std::nothrow) Directory(this, blockIndex, *nodeData);
|
||||
break;
|
||||
default:
|
||||
node = new(std::nothrow) Node(this, blockIndex, *nodeData);
|
||||
break;
|
||||
}
|
||||
|
||||
if (node == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// TODO: Sanity check the node!
|
||||
|
||||
_node = node;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::CreateDirectory(mode_t mode, Directory*& _directory)
|
||||
{
|
||||
// allocate a free block
|
||||
AllocatedBlock allocatedBlock(fBlockAllocator);
|
||||
status_t error = allocatedBlock.Allocate();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the directory
|
||||
Directory* directory = new(std::nothrow) Directory(this,
|
||||
allocatedBlock.Index(), (mode & ~(mode_t)S_IFMT) | S_IFDIR);
|
||||
if (directory == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
allocatedBlock.Detach();
|
||||
_directory = directory;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::_Init(uint64 totalBlocks)
|
||||
{
|
||||
fTotalBlocks = totalBlocks;
|
||||
if (fTotalBlocks * B_PAGE_SIZE < kCheckSumFSMinSize)
|
||||
return B_BAD_VALUE;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
// create a block cache
|
||||
fBlockCache = block_cache_create(fFD, fTotalBlocks, B_PAGE_SIZE,
|
||||
IsReadOnly());
|
||||
if (fBlockCache == NULL)
|
||||
return B_NO_MEMORY;
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
// create the block allocator
|
||||
fBlockAllocator = new(std::nothrow) BlockAllocator(this);
|
||||
if (fBlockAllocator == NULL)
|
||||
return B_NO_MEMORY;
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -6,11 +6,14 @@
|
||||
#define VOLUME_H
|
||||
|
||||
|
||||
#include <fs_info.h>
|
||||
#include <fs_interface.h>
|
||||
#include <fs_volume.h>
|
||||
|
||||
|
||||
class BlockAllocator;
|
||||
class Directory;
|
||||
class Node;
|
||||
|
||||
|
||||
class Volume {
|
||||
@ -21,33 +24,51 @@ public:
|
||||
status_t Init(const char* device);
|
||||
status_t Init(int fd, uint64 totalBlocks);
|
||||
|
||||
status_t Mount();
|
||||
status_t Mount(fs_volume* fsVolume);
|
||||
void Unmount();
|
||||
|
||||
status_t Initialize(const char* name);
|
||||
|
||||
void GetInfo(fs_info& info);
|
||||
|
||||
status_t PublishNode(Node* node, uint32 flags);
|
||||
status_t GetNode(uint64 blockIndex, Node*& _node);
|
||||
status_t PutNode(Node* node);
|
||||
|
||||
status_t ReadNode(uint64 blockIndex, Node*& _node);
|
||||
|
||||
status_t CreateDirectory(mode_t mode,
|
||||
Directory*& _directory);
|
||||
|
||||
inline dev_t ID() const { return fFSVolume->id; }
|
||||
inline bool IsReadOnly() const;
|
||||
inline uint64 TotalBlocks() const { return fTotalBlocks; }
|
||||
inline void* BlockCache() const { return fBlockCache; }
|
||||
inline const char* Name() const { return fName; }
|
||||
inline BlockAllocator* GetBlockAllocator() const
|
||||
{ return fBlockAllocator; }
|
||||
inline Directory* RootDirectory() const
|
||||
{ return fRootDirectory; }
|
||||
|
||||
private:
|
||||
status_t _Init(uint64 totalBlocks);
|
||||
|
||||
private:
|
||||
fs_volume* fFSVolume;
|
||||
int fFD;
|
||||
uint32 fFlags;
|
||||
void* fBlockCache;
|
||||
uint64 fTotalBlocks;
|
||||
char* fName;
|
||||
BlockAllocator* fBlockAllocator;
|
||||
Directory* fRootDirectory;
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
Volume::IsReadOnly() const
|
||||
{
|
||||
return (fFlags & B_MOUNT_READ_ONLY) != 0;
|
||||
return (fFlags & B_FS_IS_READONLY) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <new>
|
||||
@ -13,6 +14,9 @@
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include "checksumfs.h"
|
||||
#include "checksumfs_private.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "Directory.h"
|
||||
#include "SuperBlock.h"
|
||||
#include "Volume.h"
|
||||
|
||||
@ -22,7 +26,15 @@ static const char* const kCheckSumFSModuleName = "file_systems/checksumfs"
|
||||
static const char* const kCheckSumFSShortName = "checksumfs";
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
static void
|
||||
set_timespec(timespec& time, uint64 nanos)
|
||||
{
|
||||
time.tv_sec = nanos / 1000000000;
|
||||
time.tv_nsec = nanos % 1000000000;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - FS operations
|
||||
|
||||
|
||||
static float
|
||||
@ -77,11 +89,27 @@ checksumfs_free_identify_partition_cookie(partition_data* partition,
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_mount(fs_volume* volume, const char* device, uint32 flags,
|
||||
checksumfs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
|
||||
const char* args, ino_t* _rootVnodeID)
|
||||
{
|
||||
// TODO: Implement!
|
||||
return B_UNSUPPORTED;
|
||||
Volume* volume = new(std::nothrow) Volume(flags);
|
||||
if (volume == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
ObjectDeleter<Volume> volumeDeleter(volume);
|
||||
|
||||
status_t error = volume->Init(device);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
error = volume->Mount(fsVolume);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
fsVolume->private_volume = volumeDeleter.Detach();
|
||||
fsVolume->ops = &gCheckSumFSVolumeOps;
|
||||
*_rootVnodeID = volume->RootDirectory()->BlockIndex();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -129,13 +157,299 @@ checksumfs_initialize(int fd, partition_id partition, const char* name,
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - volume operations
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_unmount(fs_volume* fsVolume)
|
||||
{
|
||||
Volume* volume = (Volume*)fsVolume->private_volume;
|
||||
volume->Unmount();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
|
||||
{
|
||||
Volume* volume = (Volume*)fsVolume->private_volume;
|
||||
volume->GetInfo(*info);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_get_vnode(fs_volume* fsVolume, ino_t id, fs_vnode* vnode,
|
||||
int* _type, uint32* _flags, bool reenter)
|
||||
{
|
||||
Volume* volume = (Volume*)fsVolume->private_volume;
|
||||
|
||||
Node* node;
|
||||
status_t error = volume->ReadNode(id, node);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
vnode->private_node = node;
|
||||
vnode->ops = &gCheckSumFSVnodeOps;
|
||||
*_type = node->Mode();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - vnode operations
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* name,
|
||||
ino_t* _id)
|
||||
{
|
||||
Volume* volume = (Volume*)fsVolume->private_volume;
|
||||
Node* node = (Node*)fsDir->private_node;
|
||||
|
||||
Directory* directory = dynamic_cast<Directory*>(node);
|
||||
if (directory == NULL)
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
uint64 blockIndex;
|
||||
|
||||
if (strcmp(name, ".") == 0) {
|
||||
blockIndex = directory->BlockIndex();
|
||||
} else if (strcmp(name, "..") == 0) {
|
||||
blockIndex = directory->ParentDirectory();
|
||||
} else {
|
||||
// TODO: Implement!
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
// get the node
|
||||
Node* childNode;
|
||||
status_t error = volume->GetNode(blockIndex, childNode);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
*_id = blockIndex;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_put_vnode(fs_volume* fsVolume, fs_vnode* vnode, bool reenter)
|
||||
{
|
||||
Node* node = (Node*)vnode->private_node;
|
||||
delete node;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - common operations
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_read_stat(fs_volume* fsVolume, fs_vnode* vnode, struct stat* st)
|
||||
{
|
||||
Node* node = (Node*)vnode->private_node;
|
||||
|
||||
st->st_mode = node->Mode();
|
||||
st->st_nlink = node->HardLinks();
|
||||
st->st_uid = node->UID();
|
||||
st->st_gid = node->GID();
|
||||
st->st_size = node->Size();
|
||||
st->st_blksize = B_PAGE_SIZE * 16; // random number
|
||||
set_timespec(st->st_mtim, node->ModificationTime());
|
||||
set_timespec(st->st_ctim, node->ChangeTime());
|
||||
set_timespec(st->st_crtim, node->CreationTime());
|
||||
st->st_atim = st->st_ctim;
|
||||
// we don't support access time
|
||||
st->st_type = 0; /* attribute/index type */
|
||||
st->st_blocks = 1 + (st->st_size + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
|
||||
// TODO: That does neither count management structures for the content
|
||||
// nor attributes.
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - file operations
|
||||
|
||||
|
||||
struct FileCookie {
|
||||
int openMode;
|
||||
|
||||
FileCookie(int openMode)
|
||||
:
|
||||
openMode(openMode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_open(fs_volume* fsVolume, fs_vnode* vnode, int openMode,
|
||||
void** _cookie)
|
||||
{
|
||||
// TODO: Check permissions!
|
||||
|
||||
FileCookie* cookie = new(std::nothrow) FileCookie(openMode);
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_close(fs_volume* fsVolume, fs_vnode* vnode, void* cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_free_cookie(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie)
|
||||
{
|
||||
FileCookie* cookie = (FileCookie*)_cookie;
|
||||
delete cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - directory operations
|
||||
|
||||
|
||||
struct DirCookie {
|
||||
enum {
|
||||
DOT,
|
||||
DOT_DOT,
|
||||
OTHERS
|
||||
};
|
||||
|
||||
Directory* directory;
|
||||
int iterationState;
|
||||
|
||||
DirCookie(Directory* directory)
|
||||
:
|
||||
directory(directory),
|
||||
iterationState(DOT)
|
||||
{
|
||||
}
|
||||
|
||||
status_t ReadNextEntry(struct dirent* buffer, size_t size,
|
||||
uint32& _countRead)
|
||||
{
|
||||
const char* name;
|
||||
uint64 blockIndex;
|
||||
|
||||
int nextIterationState = OTHERS;
|
||||
switch (iterationState) {
|
||||
case DOT:
|
||||
name = ".";
|
||||
blockIndex = directory->BlockIndex();
|
||||
nextIterationState = DOT_DOT;
|
||||
break;
|
||||
case DOT_DOT:
|
||||
name = "..";
|
||||
blockIndex = directory->ParentDirectory();
|
||||
break;
|
||||
default:
|
||||
// TODO: Implement!
|
||||
_countRead = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
size_t entrySize = sizeof(dirent) + strlen(name);
|
||||
if (entrySize > size)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
buffer->d_dev = directory->GetVolume()->ID();
|
||||
buffer->d_ino = blockIndex;
|
||||
buffer->d_reclen = entrySize;
|
||||
strcpy(buffer->d_name, name);
|
||||
|
||||
iterationState = nextIterationState;
|
||||
|
||||
_countRead = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
iterationState = DOT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_open_dir(fs_volume* fsVolume, fs_vnode* vnode, void** _cookie)
|
||||
{
|
||||
Directory* directory = dynamic_cast<Directory*>((Node*)vnode->private_node);
|
||||
if (directory == NULL)
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
DirCookie* cookie = new(std::nothrow) DirCookie(directory);
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_close_dir(fs_volume* fsVolume, fs_vnode* vnode, void* cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie)
|
||||
{
|
||||
DirCookie* cookie = (DirCookie*)_cookie;
|
||||
delete cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_read_dir(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie,
|
||||
struct dirent* buffer, size_t bufferSize, uint32* _num)
|
||||
{
|
||||
if (*_num == 0)
|
||||
return B_OK;
|
||||
|
||||
DirCookie* cookie = (DirCookie*)_cookie;
|
||||
return cookie->ReadNextEntry(buffer, bufferSize, *_num);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_rewind_dir(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie)
|
||||
{
|
||||
DirCookie* cookie = (DirCookie*)_cookie;
|
||||
cookie->Rewind();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - module
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_std_ops(int32 operation, ...)
|
||||
{
|
||||
switch (operation) {
|
||||
case B_MODULE_INIT:
|
||||
case B_MODULE_UNINIT:
|
||||
init_debugging();
|
||||
PRINT("checksumfs_std_ops(): B_MODULE_INIT\n");
|
||||
return B_OK;
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
PRINT("checksumfs_std_ops(): B_MODULE_UNINIT\n");
|
||||
exit_debugging();
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
@ -191,3 +505,118 @@ const module_info* modules[] = {
|
||||
(module_info*)&sFSModule,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
fs_volume_ops gCheckSumFSVolumeOps = {
|
||||
checksumfs_unmount,
|
||||
|
||||
checksumfs_read_fs_info,
|
||||
NULL, // write_fs_info
|
||||
NULL, // sync
|
||||
|
||||
checksumfs_get_vnode,
|
||||
|
||||
/* index directory & index operations */
|
||||
NULL, // open_index_dir
|
||||
NULL, // close_index_dir
|
||||
NULL, // free_index_dir_cookie
|
||||
NULL, // read_index_dir
|
||||
NULL, // rewind_index_dir
|
||||
|
||||
NULL, // create_index
|
||||
NULL, // remove_index
|
||||
NULL, // read_index_stat
|
||||
|
||||
/* query operations */
|
||||
NULL, // open_query
|
||||
NULL, // close_query
|
||||
NULL, // free_query_cookie
|
||||
NULL, // read_query
|
||||
NULL, // rewind_query
|
||||
|
||||
/* support for FS layers */
|
||||
NULL, // all_layers_mounted
|
||||
NULL, // create_sub_vnode
|
||||
NULL, // delete_sub_vnode
|
||||
};
|
||||
|
||||
|
||||
fs_vnode_ops gCheckSumFSVnodeOps = {
|
||||
/* vnode operations */
|
||||
checksumfs_lookup,
|
||||
NULL, // get_vnode_name
|
||||
|
||||
checksumfs_put_vnode,
|
||||
NULL, // checksumfs_remove_vnode,
|
||||
|
||||
/* VM file access */
|
||||
NULL, // can_page
|
||||
NULL, // read_pages
|
||||
NULL, // write_pages
|
||||
|
||||
/* asynchronous I/O */
|
||||
NULL, // checksumfs_io,
|
||||
NULL, // checksumfs_cancel_io,
|
||||
|
||||
/* cache file access */
|
||||
NULL, // checksumfs_get_file_map,
|
||||
|
||||
/* common operations */
|
||||
NULL, // checksumfs_ioctl,
|
||||
NULL, // checksumfs_set_flags,
|
||||
NULL, // checksumfs_select,
|
||||
NULL, // checksumfs_deselect,
|
||||
NULL, // checksumfs_fsync,
|
||||
|
||||
NULL, // checksumfs_read_symlink,
|
||||
NULL, // checksumfs_create_symlink,
|
||||
|
||||
NULL, // checksumfs_link,
|
||||
NULL, // checksumfs_unlink,
|
||||
NULL, // checksumfs_rename,
|
||||
|
||||
NULL, // checksumfs_access,
|
||||
checksumfs_read_stat,
|
||||
NULL, // checksumfs_write_stat,
|
||||
|
||||
/* file operations */
|
||||
NULL, // checksumfs_create,
|
||||
checksumfs_open,
|
||||
checksumfs_close,
|
||||
checksumfs_free_cookie,
|
||||
NULL, // checksumfs_read,
|
||||
NULL, // checksumfs_write,
|
||||
|
||||
/* directory operations */
|
||||
NULL, // checksumfs_create_dir,
|
||||
NULL, // checksumfs_remove_dir,
|
||||
checksumfs_open_dir,
|
||||
checksumfs_close_dir,
|
||||
checksumfs_free_dir_cookie,
|
||||
checksumfs_read_dir,
|
||||
checksumfs_rewind_dir,
|
||||
|
||||
/* attribute directory operations */
|
||||
NULL, // checksumfs_open_attr_dir,
|
||||
NULL, // checksumfs_close_attr_dir,
|
||||
NULL, // checksumfs_free_attr_dir_cookie,
|
||||
NULL, // checksumfs_read_attr_dir,
|
||||
NULL, // checksumfs_rewind_attr_dir,
|
||||
|
||||
/* attribute operations */
|
||||
NULL, // checksumfs_create_attr,
|
||||
NULL, // checksumfs_open_attr,
|
||||
NULL, // checksumfs_close_attr,
|
||||
NULL, // checksumfs_free_attr_cookie,
|
||||
NULL, // checksumfs_read_attr,
|
||||
NULL, // checksumfs_write_attr,
|
||||
|
||||
NULL, // checksumfs_read_attr_stat,
|
||||
NULL, // checksumfs_write_attr_stat,
|
||||
NULL, // checksumfs_rename_attr,
|
||||
NULL, // checksumfs_remove_attr,
|
||||
|
||||
/* support for node and FS layers */
|
||||
NULL, // create_special_node
|
||||
NULL // get_super_vnode
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CHECK_SUM_FS_PRIVATE_H
|
||||
#define CHECK_SUM_FS_PRIVATE_H
|
||||
|
||||
|
||||
#include <fs_interface.h>
|
||||
|
||||
|
||||
extern fs_volume_ops gCheckSumFSVolumeOps;
|
||||
extern fs_vnode_ops gCheckSumFSVnodeOps;
|
||||
|
||||
|
||||
#endif // CHECK_SUM_FS_PRIVATE_H
|
36
src/tests/system/kernel/file_corruption/fs/userland/Jamfile
Normal file
36
src/tests/system/kernel/file_corruption/fs/userland/Jamfile
Normal file
@ -0,0 +1,36 @@
|
||||
SubDir HAIKU_TOP src tests system kernel file_corruption fs userland ;
|
||||
|
||||
|
||||
UsePrivateKernelHeaders ;
|
||||
UsePrivateHeaders shared ;
|
||||
|
||||
UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems ] ;
|
||||
# We use packagefs's DebugSupport.h header, but we don't want to add that
|
||||
# header to avoid clashes with other headers.
|
||||
|
||||
|
||||
DEFINES += DEBUG_APP="\\\"checksumfs\\\"" ;
|
||||
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||
|
||||
|
||||
Addon <userland>checksumfs :
|
||||
$(HAIKU_CHECKSUM_FS_SOURCES)
|
||||
|
||||
# from packagefs
|
||||
DebugSupport.cpp
|
||||
|
||||
# from src/kits/shared
|
||||
SHA256.cpp
|
||||
|
||||
: libuserlandfs_haiku_kernel.so $(TARGET_LIBSUPC++)
|
||||
;
|
||||
|
||||
|
||||
SEARCH on [ FGristFiles DebugSupport.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems packagefs ] ;
|
||||
SEARCH on [ FGristFiles SHA256.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src kits shared ] ;
|
Loading…
Reference in New Issue
Block a user