* 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:
Ingo Weinhold 2010-07-05 16:53:06 +00:00
parent e66231742e
commit 74956f4385
15 changed files with 1049 additions and 25 deletions

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,7 @@
/*
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "packagefs/DebugSupport.h"

View 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()
{
}

View 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

View File

@ -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 ;

View 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");
}

View 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

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
};

View File

@ -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

View 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 ] ;