diff --git a/src/tests/system/kernel/file_corruption/Jamfile b/src/tests/system/kernel/file_corruption/Jamfile index 3ff5c2016a..c181c6af12 100644 --- a/src/tests/system/kernel/file_corruption/Jamfile +++ b/src/tests/system/kernel/file_corruption/Jamfile @@ -1,16 +1,5 @@ SubDir HAIKU_TOP src tests system kernel file_corruption ; - -SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ; -UsePrivateKernelHeaders ; - - -KernelAddon checksum_device : - checksum_device.cpp - - # from src/kits/shared - SHA256.cpp -; - -SEARCH on [ FGristFiles SHA256.cpp ] - = [ FDirName $(HAIKU_TOP) src kits shared ] ; +HaikuSubInclude disk_system ; +HaikuSubInclude driver ; +HaikuSubInclude fs ; diff --git a/src/tests/system/kernel/file_corruption/checksumfs.h b/src/tests/system/kernel/file_corruption/checksumfs.h new file mode 100644 index 0000000000..b76b680d87 --- /dev/null +++ b/src/tests/system/kernel/file_corruption/checksumfs.h @@ -0,0 +1,41 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef CHECK_SUM_FS_H +#define CHECK_SUM_FS_H + + +#include + + +#define CHECK_SUM_FS_PRETTY_NAME "CheckSum File System" + + +static const uint64 kCheckSumFSSuperBlockOffset = 16 * B_PAGE_SIZE; +static const uint64 kCheckSumFSMinSize + = kCheckSumFSSuperBlockOffset + 16 * B_PAGE_SIZE; + + +static const uint32 kCheckSumFSNameLength = 256; + +static const uint32 kCheckSumFSSignatureLength = 16; +#define CHECK_SUM_FS_SIGNATURE_1 "_1!cHEcKsUmfS!1_" +#define CHECK_SUM_FS_SIGNATURE_2 "-2@ChECkSumFs@2-" + +static const uint32 kCheckSumFSVersion = 1; + +struct checksumfs_super_block { + char signature1[kCheckSumFSSignatureLength]; + uint32 version; + uint32 pad1; + uint64 totalBlocks; + uint64 freeBlocks; + uint64 rootDir; + uint64 blockBitmap; + char name[kCheckSumFSNameLength]; + char signature2[kCheckSumFSSignatureLength]; +} _PACKED; + + +#endif // CHECK_SUM_FS_H diff --git a/src/tests/system/kernel/file_corruption/disk_system/Jamfile b/src/tests/system/kernel/file_corruption/disk_system/Jamfile new file mode 100644 index 0000000000..40bcb29ec9 --- /dev/null +++ b/src/tests/system/kernel/file_corruption/disk_system/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src tests system kernel file_corruption disk_system ; + + +UsePrivateHeaders shared storage ; + +UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ; + + +Addon checksumfs : + checksumfs.cpp + + : be $(TARGET_LIBSTDC++) +; diff --git a/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp b/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp new file mode 100644 index 0000000000..a396e4b2b8 --- /dev/null +++ b/src/tests/system/kernel/file_corruption/disk_system/checksumfs.cpp @@ -0,0 +1,212 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include + +#include +#include + +#include "checksumfs.h" + + +static const uint32 kDiskSystemFlags = + 0 +// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME +// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS + | B_DISK_SYSTEM_SUPPORTS_INITIALIZING + | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME +// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED +// | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED +; + + +class CheckSumFSAddOn : public BDiskSystemAddOn { +public: + CheckSumFSAddOn(); + + virtual status_t CreatePartitionHandle( + BMutablePartition* partition, + BPartitionHandle** _handle); + + virtual bool CanInitialize( + const BMutablePartition* partition); + virtual status_t GetInitializationParameterEditor( + const BMutablePartition* partition, + BPartitionParameterEditor** _editor); + virtual status_t ValidateInitialize( + const BMutablePartition* partition, + BString* name, const char* parameters); + virtual status_t Initialize(BMutablePartition* partition, + const char* name, const char* parameters, + BPartitionHandle** _handle); +}; + + +class CheckSumFSPartitionHandle : public BPartitionHandle { +public: + CheckSumFSPartitionHandle( + BMutablePartition* partition); + ~CheckSumFSPartitionHandle(); + + status_t Init(); + + virtual uint32 SupportedOperations(uint32 mask); +}; + + +// #pragma mark - CheckSumFSAddOn + + +CheckSumFSAddOn::CheckSumFSAddOn() + : + BDiskSystemAddOn(CHECK_SUM_FS_PRETTY_NAME, kDiskSystemFlags) +{ +} + + +status_t +CheckSumFSAddOn::CreatePartitionHandle(BMutablePartition* partition, + BPartitionHandle** _handle) +{ +debug_printf("CheckSumFSAddOn::CreatePartitionHandle()\n"); + CheckSumFSPartitionHandle* handle + = new(std::nothrow) CheckSumFSPartitionHandle(partition); + if (handle == NULL) + return B_NO_MEMORY; + + status_t error = handle->Init(); + if (error != B_OK) { + delete handle; + return error; + } + + *_handle = handle; + return B_OK; +} + + +bool +CheckSumFSAddOn::CanInitialize(const BMutablePartition* partition) +{ +debug_printf("CheckSumFSAddOn::CanInitialize()\n"); + return (uint64)partition->Size() >= kCheckSumFSMinSize; +} + + +status_t +CheckSumFSAddOn::GetInitializationParameterEditor( + const BMutablePartition* partition, BPartitionParameterEditor** _editor) +{ +debug_printf("CheckSumFSAddOn::GetInitializationParameterEditor()\n"); + *_editor = NULL; + return B_OK; +} + + +status_t +CheckSumFSAddOn::ValidateInitialize(const BMutablePartition* partition, + BString* name, const char* parameters) +{ +debug_printf("CheckSumFSAddOn::ValidateInitialize()\n"); + if (!CanInitialize(partition) || name == NULL) + return B_BAD_VALUE; + + // truncate name, if too long + if ((uint64)name->Length() >= kCheckSumFSNameLength) + name->Truncate(kCheckSumFSNameLength - 1); + + // replace '/' by '-' + name->ReplaceAll('/', '-'); + + return B_OK; +} + + +status_t +CheckSumFSAddOn::Initialize(BMutablePartition* partition, const char* name, + const char* parameters, BPartitionHandle** _handle) +{ +debug_printf("CheckSumFSAddOn::Initialize()\n"); + if (!CanInitialize(partition) || name == NULL + || strlen(name) >= kCheckSumFSNameLength) { + return B_BAD_VALUE; + } + + CheckSumFSPartitionHandle* handle + = new(std::nothrow) CheckSumFSPartitionHandle(partition); + if (handle == NULL) + return B_NO_MEMORY; + ObjectDeleter handleDeleter(handle); + + status_t error = partition->SetContentType(Name()); + if (error != B_OK) + return error; + + partition->SetContentName(name); + partition->SetContentParameters(parameters); + partition->SetBlockSize(B_PAGE_SIZE); + partition->SetContentSize(partition->Size() / B_PAGE_SIZE * B_PAGE_SIZE); + partition->Changed(B_PARTITION_CHANGED_INITIALIZATION); + + *_handle = handleDeleter.Detach(); + + return B_OK; +} + + +// #pragma mark - CheckSumFSPartitionHandle + + +CheckSumFSPartitionHandle::CheckSumFSPartitionHandle( + BMutablePartition* partition) + : + BPartitionHandle(partition) +{ +} + + +CheckSumFSPartitionHandle::~CheckSumFSPartitionHandle() +{ +} + + +status_t +CheckSumFSPartitionHandle::Init() +{ + return B_OK; +} + + +uint32 +CheckSumFSPartitionHandle::SupportedOperations(uint32 mask) +{ + return kDiskSystemFlags & mask; +} + + + +// #pragma mark - + + +status_t +get_disk_system_add_ons(BList* addOns) +{ +debug_printf("checksumfs: get_disk_system_add_ons()\n"); + CheckSumFSAddOn* addOn = new(std::nothrow) CheckSumFSAddOn; + if (addOn == NULL) + return B_NO_MEMORY; + + if (!addOns->AddItem(addOn)) { + delete addOn; + return B_NO_MEMORY; + } + +debug_printf("checksumfs: get_disk_system_add_ons() done ok\n"); + return B_OK; +} diff --git a/src/tests/system/kernel/file_corruption/driver/Jamfile b/src/tests/system/kernel/file_corruption/driver/Jamfile new file mode 100644 index 0000000000..a0b3b23918 --- /dev/null +++ b/src/tests/system/kernel/file_corruption/driver/Jamfile @@ -0,0 +1,19 @@ +SubDir HAIKU_TOP src tests system kernel file_corruption driver ; + + +SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ; +UsePrivateKernelHeaders ; + +UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ; + + +KernelAddon checksum_device : + checksum_device.cpp + + # from src/kits/shared + SHA256.cpp +; + + +SEARCH on [ FGristFiles SHA256.cpp ] + = [ FDirName $(HAIKU_TOP) src kits shared ] ; diff --git a/src/tests/system/kernel/file_corruption/checksum_device.cpp b/src/tests/system/kernel/file_corruption/driver/checksum_device.cpp similarity index 100% rename from src/tests/system/kernel/file_corruption/checksum_device.cpp rename to src/tests/system/kernel/file_corruption/driver/checksum_device.cpp diff --git a/src/tests/system/kernel/file_corruption/checksum_device.h b/src/tests/system/kernel/file_corruption/driver/checksum_device.h similarity index 100% rename from src/tests/system/kernel/file_corruption/checksum_device.h rename to src/tests/system/kernel/file_corruption/driver/checksum_device.h diff --git a/src/tests/system/kernel/file_corruption/fs/Block.h b/src/tests/system/kernel/file_corruption/fs/Block.h new file mode 100644 index 0000000000..778d6bcdad --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/Block.h @@ -0,0 +1,101 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef BLOCK_H +#define BLOCK_H + + +#include + +#include "Volume.h" + + +class Block { +public: + Block() + : + fVolume(NULL), + fData(NULL) + { + } + + ~Block() + { + Put(); + } + + bool GetReadable(Volume* volume, uint64 blockIndex) + { + Put(); + + return _Init(volume, blockIndex, + block_cache_get(volume->BlockCache(), blockIndex)); + } + + bool GetWritable(Volume* volume, uint64 blockIndex) + { + Put(); + + return _Init(volume, blockIndex, + block_cache_get_writable(volume->BlockCache(), blockIndex, -1)); + } + + bool GetZero(Volume* volume, uint64 blockIndex) + { + Put(); + + return _Init(volume, blockIndex, + block_cache_get_empty(volume->BlockCache(), blockIndex, -1)); + } + + void Put() + { + if (fVolume != NULL) { + block_cache_put(fVolume->BlockCache(), fIndex); + fVolume = NULL; + fData = NULL; + } + } + + void Discard() + { + if (fVolume != NULL) { + block_cache_discard(fVolume->BlockCache(), fIndex, 1); + fVolume = NULL; + fData = NULL; + } + } + + void* Data() const + { + return fData; + } + + uint64 Index() const + { + return fIndex; + } + +private: + bool _Init(Volume* volume, uint64 blockIndex, const void* data) + { + if (data == NULL) + return false; + + fVolume = volume; + fData = const_cast(data); + fIndex = blockIndex; + + return true; + } + + +private: + Volume* fVolume; + void* fData; + uint64 fIndex; +}; + + +#endif // BLOCK_H diff --git a/src/tests/system/kernel/file_corruption/fs/Jamfile b/src/tests/system/kernel/file_corruption/fs/Jamfile new file mode 100644 index 0000000000..ea54d846fd --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/Jamfile @@ -0,0 +1,20 @@ +SubDir HAIKU_TOP src tests system kernel file_corruption fs ; + + +UsePrivateHeaders shared ; + +UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) ] ; + + +KernelAddon checksumfs : + checksumfs.cpp + SuperBlock.cpp + Volume.cpp + + # from src/kits/shared + SHA256.cpp +; + + +SEARCH on [ FGristFiles SHA256.cpp ] + = [ FDirName $(HAIKU_TOP) src kits shared ] ; diff --git a/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp b/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp new file mode 100644 index 0000000000..f65ca9e9ef --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "SuperBlock.h" + +#include + +#include "Volume.h" + + +bool +SuperBlock::Check(uint64 totalBlocks) const +{ + if (strncmp(signature1, CHECK_SUM_FS_SIGNATURE_1, + kCheckSumFSSignatureLength) != 0 + || strncmp(signature2, CHECK_SUM_FS_SIGNATURE_2, + kCheckSumFSSignatureLength) != 0 + || Version() != kCheckSumFSVersion + || TotalBlocks() < kCheckSumFSMinSize / B_PAGE_SIZE + || TotalBlocks() > totalBlocks + || strnlen(name, kCheckSumFSNameLength) >= kCheckSumFSNameLength) { + return false; + } + // TODO: Check free blocks and location of root directory and block bitmap. + + return true; +} + + +void +SuperBlock::Initialize(Volume* volume) +{ + memcpy(signature1, CHECK_SUM_FS_SIGNATURE_1, kCheckSumFSSignatureLength); + memcpy(signature2, CHECK_SUM_FS_SIGNATURE_2, kCheckSumFSSignatureLength); + + version = kCheckSumFSVersion; + totalBlocks = volume->TotalBlocks(); +// freeBlocks = volume->BlockAllocator()->FreeBlocks(); +// blockBitmap = volume->BlockAllocator()->BlockBitmap(); +// rootDir = volume->RootDirBlock(); + strlcpy(name, volume->Name(), kCheckSumFSNameLength); +} diff --git a/src/tests/system/kernel/file_corruption/fs/SuperBlock.h b/src/tests/system/kernel/file_corruption/fs/SuperBlock.h new file mode 100644 index 0000000000..3856da53e0 --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/SuperBlock.h @@ -0,0 +1,29 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef SUPER_BLOCK_H +#define SUPER_BLOCK_H + + +#include "checksumfs.h" + + +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; } + + bool Check(uint64 totalBlocks) const; + void Initialize(Volume* volume); +}; + + +#endif // SUPER_BLOCK_H diff --git a/src/tests/system/kernel/file_corruption/fs/Volume.cpp b/src/tests/system/kernel/file_corruption/fs/Volume.cpp new file mode 100644 index 0000000000..507a1f1d57 --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/Volume.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Volume.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "Block.h" +#include "checksumfs.h" +#include "SuperBlock.h" + + +Volume::Volume(uint32 flags) + : + fFD(-1), + fFlags(flags), + fBlockCache(NULL), + fTotalBlocks(0), + fName(NULL) +{ +} + + +Volume::~Volume() +{ + if (fBlockCache != NULL) + block_cache_delete(fBlockCache, false); + + if (fFD >= 0) + close(fFD); + + free(fName); +} + + +status_t +Volume::Init(const char* device) +{ + // open the device + fFD = open(device, IsReadOnly() ? O_RDONLY : O_RDWR); + if (fFD < 0) + return errno; + + // get the size + struct stat st; + if (fstat(fFD, &st) < 0) + return errno; + + return _Init(st.st_size / B_PAGE_SIZE); +} + + +status_t +Volume::Init(int fd, uint64 totalBlocks) +{ + fFD = dup(fd); + if (fFD < 0) + return errno; + + return _Init(totalBlocks); +} + + +status_t +Volume::Mount() +{ + // TODO:... + return B_UNSUPPORTED; +} + + +status_t +Volume::Initialize(const char* name) +{ + fName = strdup(name); + if (fName == NULL) + return B_NO_MEMORY; + + Block block; + if (!block.GetZero(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE)) + return B_ERROR; + + SuperBlock* superBlock = (SuperBlock*)block.Data(); + superBlock->Initialize(this); + + block.Put(); + + return block_cache_sync(fBlockCache); +} + + +status_t +Volume::_Init(uint64 totalBlocks) +{ + fTotalBlocks = totalBlocks; + if (fTotalBlocks * B_PAGE_SIZE < kCheckSumFSMinSize) + return 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 B_OK; +} diff --git a/src/tests/system/kernel/file_corruption/fs/Volume.h b/src/tests/system/kernel/file_corruption/fs/Volume.h new file mode 100644 index 0000000000..3f51ef1c3c --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/Volume.h @@ -0,0 +1,48 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VOLUME_H +#define VOLUME_H + + +#include +#include + + +class Volume { +public: + Volume(uint32 flags); + ~Volume(); + + status_t Init(const char* device); + status_t Init(int fd, uint64 totalBlocks); + + status_t Mount(); + status_t Initialize(const char* name); + + inline bool IsReadOnly() const; + inline uint64 TotalBlocks() const { return fTotalBlocks; } + inline void* BlockCache() const { return fBlockCache; } + inline const char* Name() const { return fName; } + +private: + status_t _Init(uint64 totalBlocks); + +private: + int fFD; + uint32 fFlags; + void* fBlockCache; + uint64 fTotalBlocks; + char* fName; +}; + + +bool +Volume::IsReadOnly() const +{ + return (fFlags & B_MOUNT_READ_ONLY) != 0; +} + + +#endif // VOLUME_H diff --git a/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp b/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp new file mode 100644 index 0000000000..4cab3543ed --- /dev/null +++ b/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp @@ -0,0 +1,193 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include + +#include + +#include "checksumfs.h" +#include "SuperBlock.h" +#include "Volume.h" + + +static const char* const kCheckSumFSModuleName = "file_systems/checksumfs" + B_CURRENT_FS_API_VERSION; +static const char* const kCheckSumFSShortName = "checksumfs"; + + +// #pragma mark - + + +static float +checksumfs_identify_partition(int fd, partition_data* partition, + void** _cookie) +{ + if ((uint64)partition->size < kCheckSumFSMinSize) + return -1; + + SuperBlock* superBlock = new(std::nothrow) SuperBlock; + if (superBlock == NULL) + return -1; + ObjectDeleter superBlockDeleter(superBlock); + + if (pread(fd, superBlock, sizeof(*superBlock), kCheckSumFSSuperBlockOffset) + != sizeof(*superBlock)) { + return -1; + } + + if (!superBlock->Check((uint64)partition->size / B_PAGE_SIZE)) + return -1; + + *_cookie = superBlockDeleter.Detach(); + return 0.8f; +} + + +static status_t +checksumfs_scan_partition(int fd, partition_data* partition, void* cookie) +{ + SuperBlock* superBlock = (SuperBlock*)cookie; + + partition->status = B_PARTITION_VALID; + partition->flags |= B_PARTITION_FILE_SYSTEM; + partition->content_size = superBlock->TotalBlocks() * B_PAGE_SIZE; + partition->block_size = B_PAGE_SIZE; + partition->content_name = strdup(superBlock->Name()); + if (partition->content_name == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +static void +checksumfs_free_identify_partition_cookie(partition_data* partition, + void* cookie) +{ + SuperBlock* superBlock = (SuperBlock*)cookie; + delete superBlock; +} + + +static status_t +checksumfs_mount(fs_volume* volume, const char* device, uint32 flags, + const char* args, ino_t* _rootVnodeID) +{ + // TODO: Implement! + return B_UNSUPPORTED; +} + + +static status_t +checksumfs_set_content_name(int fd, partition_id partition, const char* name, + disk_job_id job) +{ + // TODO: Implement! + return B_UNSUPPORTED; +} + + +static status_t +checksumfs_initialize(int fd, partition_id partition, const char* name, + const char* parameters, off_t partitionSize, disk_job_id job) +{ + if (name == NULL || strlen(name) >= kCheckSumFSNameLength) + return B_BAD_VALUE; + + // TODO: Forcing a non-empty name here. Superfluous when the userland disk + // system add-on has a parameter editor for it. + if (*name == '\0') + name = "Unnamed"; + + update_disk_device_job_progress(job, 0); + + Volume volume(0); + + status_t error = volume.Init(fd, partitionSize / B_PAGE_SIZE); + if (error != B_OK) + return error; + + error = volume.Initialize(name); + if (error != B_OK) + return error; + + // rescan partition + error = scan_partition(partition); + if (error != B_OK) + return error; + + update_disk_device_job_progress(job, 1); + + return B_OK; +} + + +static status_t +checksumfs_std_ops(int32 operation, ...) +{ + switch (operation) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + default: + return B_BAD_VALUE; + } +} + + +static file_system_module_info sFSModule = { + { + kCheckSumFSModuleName, + 0, + checksumfs_std_ops + }, + kCheckSumFSShortName, + CHECK_SUM_FS_PRETTY_NAME, + // DDM flags + B_DISK_SYSTEM_SUPPORTS_INITIALIZING + | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME + | B_DISK_SYSTEM_SUPPORTS_WRITING, + + /* scanning (the device is write locked) */ + checksumfs_identify_partition, + checksumfs_scan_partition, + checksumfs_free_identify_partition_cookie, + NULL, // free_partition_content_cookie + + /* general operations */ + checksumfs_mount, + + /* capability querying (the device is read locked) */ + NULL, // get_supported_operations + + NULL, // validate_resize + NULL, // validate_move + NULL, // validate_set_content_name + NULL, // validate_set_content_parameters + NULL, // validate_initialize + + /* shadow partition modification (device is write locked) */ + NULL, // shadow_changed + + /* writing (the device is NOT locked) */ + NULL, // defragment + NULL, // repair + NULL, // resize + NULL, // move + checksumfs_set_content_name, + NULL, // set_content_parameters + checksumfs_initialize +}; + + +const module_info* modules[] = { + (module_info*)&sFSModule, + NULL +};