Implemented hooks write_fs_info(), sync(), set_flags(), fsync(), access().
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37595 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
d869a06172
commit
4b53c2ba4f
@ -237,6 +237,13 @@ File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
File::Sync()
|
||||
{
|
||||
return file_cache_sync(fFileCache);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
File::RevertNodeData(const checksumfs_node& nodeData)
|
||||
{
|
||||
|
@ -29,6 +29,7 @@ public:
|
||||
size_t& _bytesRead);
|
||||
virtual status_t Write(off_t pos, const void* buffer,
|
||||
size_t size, size_t& _bytesWritten);
|
||||
virtual status_t Sync();
|
||||
|
||||
virtual void RevertNodeData(const checksumfs_node& nodeData);
|
||||
|
||||
|
@ -105,6 +105,13 @@ Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Node::Sync()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetParentDirectory(uint32 blockIndex)
|
||||
{
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
size_t& _bytesRead);
|
||||
virtual status_t Write(off_t pos, const void* buffer,
|
||||
size_t size, size_t& _bytesWritten);
|
||||
virtual status_t Sync();
|
||||
|
||||
inline const checksumfs_node& NodeData() const { return fNode; }
|
||||
inline Volume* GetVolume() const { return fVolume; }
|
||||
|
@ -52,3 +52,10 @@ SuperBlock::SetFreeBlocks(uint64 count)
|
||||
{
|
||||
freeBlocks = count;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SuperBlock::SetName(const char* name)
|
||||
{
|
||||
strlcpy(this->name, name, kCheckSumFSNameLength);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ public:
|
||||
void Initialize(Volume* volume);
|
||||
|
||||
void SetFreeBlocks(uint64 count);
|
||||
void SetName(const char* name);
|
||||
};
|
||||
|
||||
|
||||
|
@ -17,6 +17,9 @@
|
||||
|
||||
#include <fs_cache.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#include "Block.h"
|
||||
#include "BlockAllocator.h"
|
||||
#include "checksumfs.h"
|
||||
@ -40,6 +43,7 @@ Volume::Volume(uint32 flags)
|
||||
fBlockAllocator(NULL),
|
||||
fRootDirectory(NULL)
|
||||
{
|
||||
mutex_init(&fLock, "checksumfs volume");
|
||||
mutex_init(&fTransactionLock, "checksumfs transaction");
|
||||
}
|
||||
|
||||
@ -58,6 +62,7 @@ Volume::~Volume()
|
||||
free(fName);
|
||||
|
||||
mutex_destroy(&fTransactionLock);
|
||||
mutex_destroy(&fLock);
|
||||
}
|
||||
|
||||
|
||||
@ -217,6 +222,8 @@ Volume::Initialize(const char* name)
|
||||
void
|
||||
Volume::GetInfo(fs_info& info)
|
||||
{
|
||||
MutexLocker locker(fLock);
|
||||
|
||||
info.flags = fFlags;
|
||||
info.block_size = B_PAGE_SIZE;
|
||||
info.io_size = B_PAGE_SIZE * 16; // random value
|
||||
@ -225,7 +232,6 @@ Volume::GetInfo(fs_info& info)
|
||||
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!
|
||||
}
|
||||
|
||||
|
||||
@ -427,6 +433,53 @@ Volume::DeleteNode(Node* node)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::SetName(const char* name)
|
||||
{
|
||||
if (name == NULL || strlen(name) > kCheckSumFSNameLength)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// clone the name
|
||||
char* newName = strdup(name);
|
||||
if (newName == NULL)
|
||||
return B_NO_MEMORY;
|
||||
MemoryDeleter newNameDeleter(newName);
|
||||
|
||||
// start a transaction
|
||||
Transaction transaction(this);
|
||||
status_t error = transaction.Start();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// we lock the volume now, to keep the locking order (transaction -> volume)
|
||||
MutexLocker locker(fLock);
|
||||
|
||||
// update the super block
|
||||
Block block;
|
||||
if (!block.GetWritable(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE,
|
||||
transaction)) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
SuperBlock* superBlock = (SuperBlock*)block.Data();
|
||||
superBlock->SetName(newName);
|
||||
|
||||
block.Put();
|
||||
|
||||
// commit the transaction
|
||||
error = transaction.Commit();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// Everything went fine. We can replace the name. Since we still have the
|
||||
// volume lock, there's no race condition.
|
||||
free(fName);
|
||||
fName = (char*)newNameDeleter.Detach();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::_Init(uint64 totalBlocks)
|
||||
{
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
SymLink*& _symLink);
|
||||
status_t DeleteNode(Node* node);
|
||||
|
||||
status_t SetName(const char* name);
|
||||
|
||||
inline void TransactionStarted();
|
||||
inline void TransactionFinished();
|
||||
|
||||
@ -80,6 +82,7 @@ private:
|
||||
char* fName;
|
||||
BlockAllocator* fBlockAllocator;
|
||||
Directory* fRootDirectory;
|
||||
mutex fLock;
|
||||
mutex fTransactionLock;
|
||||
};
|
||||
|
||||
|
@ -36,6 +36,107 @@ static const char* const kCheckSumFSModuleName = "file_systems/checksumfs"
|
||||
static const char* const kCheckSumFSShortName = "checksumfs";
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
struct FileCookie {
|
||||
int openMode;
|
||||
|
||||
FileCookie(int openMode)
|
||||
:
|
||||
openMode(openMode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct DirCookie {
|
||||
DirCookie(Directory* directory)
|
||||
:
|
||||
fDirectory(directory)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Directory* GetDirectory() const
|
||||
{
|
||||
return fDirectory;
|
||||
}
|
||||
|
||||
status_t ReadNextEntry(struct dirent* buffer, size_t size,
|
||||
uint32& _countRead)
|
||||
{
|
||||
const char* name;
|
||||
size_t nameLength;
|
||||
uint64 blockIndex;
|
||||
|
||||
int nextIterationState = OTHERS;
|
||||
switch (fIterationState) {
|
||||
case DOT:
|
||||
name = ".";
|
||||
nameLength = 1;
|
||||
blockIndex = fDirectory->BlockIndex();
|
||||
nextIterationState = DOT_DOT;
|
||||
break;
|
||||
case DOT_DOT:
|
||||
name = "..";
|
||||
nameLength = 2;
|
||||
blockIndex = fDirectory->ParentDirectory();
|
||||
break;
|
||||
default:
|
||||
{
|
||||
status_t error = fDirectory->LookupNextEntry(fEntryName,
|
||||
fEntryName, nameLength, blockIndex);
|
||||
if (error != B_OK) {
|
||||
if (error != B_ENTRY_NOT_FOUND)
|
||||
return error;
|
||||
|
||||
_countRead = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
name = fEntryName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t entrySize = sizeof(dirent) + nameLength;
|
||||
if (entrySize > size)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
buffer->d_dev = fDirectory->GetVolume()->ID();
|
||||
buffer->d_ino = blockIndex;
|
||||
buffer->d_reclen = entrySize;
|
||||
strcpy(buffer->d_name, name);
|
||||
|
||||
fIterationState = nextIterationState;
|
||||
|
||||
_countRead = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fIterationState = DOT;
|
||||
fEntryName[0] = '\0';
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
DOT,
|
||||
DOT_DOT,
|
||||
OTHERS
|
||||
};
|
||||
|
||||
Directory* fDirectory;
|
||||
int fIterationState;
|
||||
char fEntryName[kCheckSumFSNameLength + 1];
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static void
|
||||
set_timespec(timespec& time, uint64 nanos)
|
||||
{
|
||||
@ -355,6 +456,31 @@ checksumfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_write_fs_info(fs_volume* fsVolume, const struct fs_info* info,
|
||||
uint32 mask)
|
||||
{
|
||||
Volume* volume = (Volume*)fsVolume->private_volume;
|
||||
|
||||
if ((mask & FS_WRITE_FSINFO_NAME) != 0) {
|
||||
status_t error = volume->SetName(info->volume_name);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_sync(fs_volume* fsVolume)
|
||||
{
|
||||
Volume* volume = (Volume*)fsVolume->private_volume;
|
||||
|
||||
return block_cache_sync(volume->BlockCache());
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_get_vnode(fs_volume* fsVolume, ino_t id, fs_vnode* vnode,
|
||||
int* _type, uint32* _flags, bool reenter)
|
||||
@ -507,6 +633,31 @@ checksumfs_get_file_map(fs_volume* fsVolume, fs_vnode* vnode, off_t offset,
|
||||
// #pragma mark - common operations
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_set_flags(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie,
|
||||
int flags)
|
||||
{
|
||||
FileCookie* cookie = (FileCookie*)_cookie;
|
||||
|
||||
cookie->openMode = (cookie->openMode & ~O_APPEND) | (flags & O_APPEND);
|
||||
|
||||
// TODO: Also support O_NOCACHE!
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_fsync(fs_volume* fsVolume, fs_vnode* vnode)
|
||||
{
|
||||
Node* node = (Node*)vnode->private_node;
|
||||
|
||||
NodeReadLocker nodeLocker(node);
|
||||
|
||||
return node->Sync();
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_read_symlink(fs_volume* fsVolume, fs_vnode* vnode, char* buffer,
|
||||
size_t* _bufferSize)
|
||||
@ -749,6 +900,17 @@ checksumfs_rename(fs_volume* fsVolume, fs_vnode* fromDir, const char* fromName,
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_access(fs_volume* fsVolume, fs_vnode* vnode, int mode)
|
||||
{
|
||||
Node* node = (Node*)vnode->private_node;
|
||||
|
||||
NodeReadLocker nodeLocker(node);
|
||||
|
||||
return check_access(node, mode);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
checksumfs_read_stat(fs_volume* fsVolume, fs_vnode* vnode, struct stat* st)
|
||||
{
|
||||
@ -872,17 +1034,6 @@ checksumfs_write_stat(fs_volume* fsVolume, fs_vnode* vnode,
|
||||
// #pragma mark - file operations
|
||||
|
||||
|
||||
struct FileCookie {
|
||||
int openMode;
|
||||
|
||||
FileCookie(int openMode)
|
||||
:
|
||||
openMode(openMode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*! Opens the node according to the given open mode (if the permissions allow
|
||||
that) and creates a file cookie.
|
||||
The caller must either pass a \a transaction, which is already started and
|
||||
@ -1187,90 +1338,6 @@ checksumfs_write(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||
// #pragma mark - directory operations
|
||||
|
||||
|
||||
struct DirCookie {
|
||||
DirCookie(Directory* directory)
|
||||
:
|
||||
fDirectory(directory)
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
Directory* GetDirectory() const
|
||||
{
|
||||
return fDirectory;
|
||||
}
|
||||
|
||||
status_t ReadNextEntry(struct dirent* buffer, size_t size,
|
||||
uint32& _countRead)
|
||||
{
|
||||
const char* name;
|
||||
size_t nameLength;
|
||||
uint64 blockIndex;
|
||||
|
||||
int nextIterationState = OTHERS;
|
||||
switch (fIterationState) {
|
||||
case DOT:
|
||||
name = ".";
|
||||
nameLength = 1;
|
||||
blockIndex = fDirectory->BlockIndex();
|
||||
nextIterationState = DOT_DOT;
|
||||
break;
|
||||
case DOT_DOT:
|
||||
name = "..";
|
||||
nameLength = 2;
|
||||
blockIndex = fDirectory->ParentDirectory();
|
||||
break;
|
||||
default:
|
||||
{
|
||||
status_t error = fDirectory->LookupNextEntry(fEntryName,
|
||||
fEntryName, nameLength, blockIndex);
|
||||
if (error != B_OK) {
|
||||
if (error != B_ENTRY_NOT_FOUND)
|
||||
return error;
|
||||
|
||||
_countRead = 0;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
name = fEntryName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t entrySize = sizeof(dirent) + nameLength;
|
||||
if (entrySize > size)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
buffer->d_dev = fDirectory->GetVolume()->ID();
|
||||
buffer->d_ino = blockIndex;
|
||||
buffer->d_reclen = entrySize;
|
||||
strcpy(buffer->d_name, name);
|
||||
|
||||
fIterationState = nextIterationState;
|
||||
|
||||
_countRead = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void Rewind()
|
||||
{
|
||||
fIterationState = DOT;
|
||||
fEntryName[0] = '\0';
|
||||
}
|
||||
|
||||
private:
|
||||
enum {
|
||||
DOT,
|
||||
DOT_DOT,
|
||||
OTHERS
|
||||
};
|
||||
|
||||
Directory* fDirectory;
|
||||
int fIterationState;
|
||||
char fEntryName[kCheckSumFSNameLength + 1];
|
||||
};
|
||||
|
||||
|
||||
status_t
|
||||
checksumfs_create_dir(fs_volume* fsVolume, fs_vnode* parent, const char* name,
|
||||
int perms)
|
||||
@ -1469,8 +1536,8 @@ fs_volume_ops gCheckSumFSVolumeOps = {
|
||||
checksumfs_unmount,
|
||||
|
||||
checksumfs_read_fs_info,
|
||||
NULL, // write_fs_info
|
||||
NULL, // sync
|
||||
checksumfs_write_fs_info,
|
||||
checksumfs_sync,
|
||||
|
||||
checksumfs_get_vnode,
|
||||
|
||||
@ -1521,10 +1588,10 @@ fs_vnode_ops gCheckSumFSVnodeOps = {
|
||||
|
||||
/* common operations */
|
||||
NULL, // checksumfs_ioctl,
|
||||
NULL, // checksumfs_set_flags,
|
||||
NULL, // checksumfs_select,
|
||||
NULL, // checksumfs_deselect,
|
||||
NULL, // checksumfs_fsync,
|
||||
checksumfs_set_flags,
|
||||
NULL, // select
|
||||
NULL, // deselect
|
||||
checksumfs_fsync,
|
||||
|
||||
checksumfs_read_symlink,
|
||||
checksumfs_create_symlink,
|
||||
@ -1533,7 +1600,7 @@ fs_vnode_ops gCheckSumFSVnodeOps = {
|
||||
checksumfs_unlink,
|
||||
checksumfs_rename,
|
||||
|
||||
NULL, // checksumfs_access,
|
||||
checksumfs_access,
|
||||
checksumfs_read_stat,
|
||||
checksumfs_write_stat,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user