* Volume::Create{File,Directory,SymLink}():
- Simplified by using the new common _CreateNode(). Changed the constructors slightly -- the block index is now set via a separate SetBlockIndex() method. - The block allocated for the node was not cleared. At least for directories that is required, though. * Added attribute support: - Refactored/extended {open,create}_file() and DirCookie a bit, so they can also be used for attributes/attribute directories. - Implemented all relevant attribute FS hooks. - Node::DeletingNode(): Changed interface (it creates the transaction(s) as needed, now and doesn't return the error code anymore. The base class implementation frees the attribute directory, the Directory implementation also unlinks all entries and frees the entry tree. * checksumfs_write_stat(): B_STAT_MODE was not handled. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37626 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
7461b83d3b
commit
8794d8c48f
src/tests/system/kernel/file_corruption/fs
@ -72,6 +72,10 @@ public:
|
||||
status_t RemoveEntry(const char* name,
|
||||
Transaction& transaction);
|
||||
|
||||
status_t FreeTree(Transaction& transaction);
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
bool Check();
|
||||
|
||||
private:
|
||||
@ -975,6 +979,71 @@ ASSERT(nextInfo.entryBlock.Check());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DirEntryTree::FreeTree(Transaction& transaction)
|
||||
{
|
||||
status_t error = _InitReadOnly();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
int32 depth = _Depth();
|
||||
if (depth == 0)
|
||||
return B_OK;
|
||||
|
||||
LevelInfo* infos = new(std::nothrow) LevelInfo[
|
||||
kCheckSumFSMaxDirEntryTreeDepth + 1];
|
||||
if (infos == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
ArrayDeleter<LevelInfo> infosDeleter(infos);
|
||||
|
||||
infos[0].entryBlock.SetTo(fRootEntryBlock, fRootEntryBlockSize);
|
||||
infos[0].index = 0;
|
||||
|
||||
// Iterate through the tree in post order. We don't touch the content of
|
||||
// any block, we only free the blocks.
|
||||
int32 level = 0;
|
||||
while (true) {
|
||||
LevelInfo& info = infos[level];
|
||||
|
||||
if (level == depth || info.index >= info.entryBlock.EntryCount()) {
|
||||
// we're through with the block
|
||||
if (level == 0)
|
||||
break;
|
||||
|
||||
// free it
|
||||
error = fDirectory->GetVolume()->GetBlockAllocator()->Free(
|
||||
info.block.Index(), 1, transaction);
|
||||
|
||||
// continue with the next sibling branch
|
||||
infos[--level].index++;
|
||||
}
|
||||
|
||||
// descend to next level
|
||||
uint64 nextBlockIndex = info.entryBlock.BlockIndexAt(info.index);
|
||||
|
||||
LevelInfo& nextInfo = infos[++level];
|
||||
if (!nextInfo.block.GetReadable(fDirectory->GetVolume(),
|
||||
nextBlockIndex)) {
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
|
||||
nextInfo.entryBlock.SetTo(
|
||||
(checksumfs_dir_entry_block*)nextInfo.block.Data(),
|
||||
B_PAGE_SIZE);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DirEntryTree::IsEmpty() const
|
||||
{
|
||||
DirEntryBlock entryBlock(fRootEntryBlock, fRootEntryBlockSize);
|
||||
return entryBlock.EntryCount() == 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DirEntryTree::Check()
|
||||
{
|
||||
@ -1442,9 +1511,9 @@ Directory::Directory(Volume* volume, uint64 blockIndex,
|
||||
}
|
||||
|
||||
|
||||
Directory::Directory(Volume* volume, uint64 blockIndex, mode_t mode)
|
||||
Directory::Directory(Volume* volume, mode_t mode)
|
||||
:
|
||||
Node(volume, blockIndex, mode)
|
||||
Node(volume, mode)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1454,6 +1523,72 @@ Directory::~Directory()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Directory::DeletingNode()
|
||||
{
|
||||
Node::DeletingNode();
|
||||
|
||||
// iterate through the directory and remove references to all entries' nodes
|
||||
char* name = (char*)malloc(kCheckSumFSNameLength + 1);
|
||||
if (name != NULL) {
|
||||
name[0] = '\0';
|
||||
|
||||
DirEntryTree entryTree(this);
|
||||
size_t nameLength;
|
||||
uint64 blockIndex;
|
||||
while (entryTree.LookupNextEntry(name, name, nameLength,
|
||||
blockIndex) == B_OK) {
|
||||
Node* node;
|
||||
if (GetVolume()->GetNode(blockIndex, node) == B_OK) {
|
||||
Transaction transaction(GetVolume());
|
||||
if (transaction.StartAndAddNode(node) == B_OK) {
|
||||
node->SetHardLinks(node->HardLinks() - 1);
|
||||
if (node->HardLinks() == 0)
|
||||
GetVolume()->RemoveNode(node);
|
||||
|
||||
if (transaction.Commit() != B_OK) {
|
||||
ERROR("Failed to commit transaction for dereferencing "
|
||||
"entry node of deleted directory at %" B_PRIu64
|
||||
"\n", BlockIndex());
|
||||
}
|
||||
} else {
|
||||
ERROR("Failed to start transaction for dereferencing "
|
||||
"entry node of deleted directory at %" B_PRIu64 "\n",
|
||||
BlockIndex());
|
||||
}
|
||||
|
||||
GetVolume()->PutNode(node);
|
||||
} else {
|
||||
ERROR("Failed to get node %" B_PRIu64 " referenced by deleted "
|
||||
"directory at %" B_PRIu64 "\n", blockIndex, BlockIndex());
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
}
|
||||
|
||||
// free the directory entry block tree
|
||||
Transaction transaction(GetVolume());
|
||||
if (transaction.Start() != B_OK) {
|
||||
ERROR("Failed to start transaction for freeing entry tree of deleted "
|
||||
"directory at %" B_PRIu64 "\n", BlockIndex());
|
||||
return;
|
||||
}
|
||||
|
||||
DirEntryTree entryTree(this);
|
||||
if (entryTree.FreeTree(transaction) != B_OK) {
|
||||
ERROR("Failed to freeing entry tree of deleted directory at %" B_PRIu64
|
||||
"\n", BlockIndex());
|
||||
return;
|
||||
}
|
||||
|
||||
if (transaction.Commit() != B_OK) {
|
||||
ERROR("Failed to commit transaction for freeing entry tree of deleted "
|
||||
"directory at %" B_PRIu64 "\n", BlockIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Directory::LookupEntry(const char* name, uint64& _blockIndex)
|
||||
{
|
||||
@ -1486,12 +1621,19 @@ Directory::InsertEntry(const char* name, uint64 blockIndex,
|
||||
|
||||
|
||||
status_t
|
||||
Directory::RemoveEntry(const char* name, Transaction& transaction)
|
||||
Directory::RemoveEntry(const char* name, Transaction& transaction,
|
||||
bool* _lastEntryRemoved)
|
||||
{
|
||||
DirEntryTree entryTree(this);
|
||||
|
||||
status_t error = entryTree.RemoveEntry(name, transaction);
|
||||
if (error == B_OK)
|
||||
ASSERT(entryTree.Check());
|
||||
return error;
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
ASSERT(entryTree.Check());
|
||||
|
||||
if (_lastEntryRemoved != NULL)
|
||||
*_lastEntryRemoved = entryTree.IsEmpty();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -13,10 +13,11 @@ class Directory : public Node {
|
||||
public:
|
||||
Directory(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData);
|
||||
Directory(Volume* volume, uint64 blockIndex,
|
||||
mode_t mode);
|
||||
Directory(Volume* volume, mode_t mode);
|
||||
virtual ~Directory();
|
||||
|
||||
virtual void DeletingNode();
|
||||
|
||||
status_t LookupEntry(const char* name,
|
||||
uint64& _blockIndex);
|
||||
status_t LookupNextEntry(const char* name,
|
||||
@ -26,7 +27,8 @@ public:
|
||||
status_t InsertEntry(const char* name, uint64 blockIndex,
|
||||
Transaction& transaction);
|
||||
status_t RemoveEntry(const char* name,
|
||||
Transaction& transaction);
|
||||
Transaction& transaction,
|
||||
bool* _lastEntryRemoved = NULL);
|
||||
};
|
||||
|
||||
|
||||
|
@ -54,9 +54,9 @@ File::File(Volume* volume, uint64 blockIndex, const checksumfs_node& nodeData)
|
||||
}
|
||||
|
||||
|
||||
File::File(Volume* volume, uint64 blockIndex, mode_t mode)
|
||||
File::File(Volume* volume, mode_t mode)
|
||||
:
|
||||
Node(volume, blockIndex, mode),
|
||||
Node(volume, mode),
|
||||
fFileCache(NULL),
|
||||
fFileMap(NULL)
|
||||
{
|
||||
@ -89,10 +89,32 @@ File::InitForVFS()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
File::DeletingNode(Transaction& transaction)
|
||||
void
|
||||
File::DeletingNode()
|
||||
{
|
||||
return Resize(0, false, transaction);
|
||||
Node::DeletingNode();
|
||||
|
||||
// start a transaction
|
||||
Transaction transaction(GetVolume());
|
||||
status_t error = transaction.Start();
|
||||
if (error != B_OK) {
|
||||
ERROR("Failed to start transaction for deleting contents of file at %"
|
||||
B_PRIu64 "\n", BlockIndex());
|
||||
return;
|
||||
}
|
||||
|
||||
error = Resize(0, false, transaction);
|
||||
if (error != B_OK) {
|
||||
ERROR("Failed to delete contents of file at %" B_PRIu64 "\n",
|
||||
BlockIndex());
|
||||
return;
|
||||
}
|
||||
|
||||
error = transaction.Commit();
|
||||
if (error != B_OK) {
|
||||
ERROR("Failed to commit transaction for deleting contents of file at %"
|
||||
B_PRIu64 "\n", BlockIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,12 +16,11 @@ class File : public Node {
|
||||
public:
|
||||
File(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData);
|
||||
File(Volume* volume, uint64 blockIndex,
|
||||
mode_t mode);
|
||||
File(Volume* volume, mode_t mode);
|
||||
virtual ~File();
|
||||
|
||||
virtual status_t InitForVFS();
|
||||
virtual status_t DeletingNode(Transaction& transaction);
|
||||
virtual void DeletingNode();
|
||||
|
||||
virtual status_t Resize(uint64 newSize, bool fillWithZeroes,
|
||||
Transaction& transaction);
|
||||
|
@ -37,10 +37,10 @@ Node::Node(Volume* volume, uint64 blockIndex, const checksumfs_node& nodeData)
|
||||
}
|
||||
|
||||
|
||||
Node::Node(Volume* volume, uint64 blockIndex, mode_t mode)
|
||||
Node::Node(Volume* volume, mode_t mode)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlockIndex(blockIndex),
|
||||
fBlockIndex(0),
|
||||
fNodeDataDirty(true)
|
||||
{
|
||||
_Init();
|
||||
@ -70,6 +70,13 @@ Node::~Node()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetBlockIndex(uint64 blockIndex)
|
||||
{
|
||||
fBlockIndex = blockIndex;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Node::InitForVFS()
|
||||
{
|
||||
@ -77,10 +84,22 @@ Node::InitForVFS()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Node::DeletingNode(Transaction& transaction)
|
||||
void
|
||||
Node::DeletingNode()
|
||||
{
|
||||
return B_OK;
|
||||
// delete the node's attribute directory
|
||||
if (AttributeDirectory() == 0)
|
||||
return;
|
||||
|
||||
Node* attributeDirectory;
|
||||
if (fVolume->GetNode(AttributeDirectory(), attributeDirectory) == B_OK) {
|
||||
fVolume->RemoveNode(attributeDirectory);
|
||||
fVolume->PutNode(attributeDirectory);
|
||||
} else {
|
||||
ERROR("Failed to get attribute directory (at %" B_PRIu64 ") for "
|
||||
"deleted node at %" B_PRIu64 "\n", AttributeDirectory(),
|
||||
BlockIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -113,6 +132,24 @@ Node::Sync()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetMode(uint32 mode)
|
||||
{
|
||||
ASSERT((mode & S_IFMT) == (Mode() & S_IFMT));
|
||||
|
||||
fNode.mode = mode;
|
||||
fNodeDataDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetAttributeType(uint32 type)
|
||||
{
|
||||
fNode.attributeType = type;
|
||||
fNodeDataDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetParentDirectory(uint32 blockIndex)
|
||||
{
|
||||
@ -121,6 +158,14 @@ Node::SetParentDirectory(uint32 blockIndex)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetAttributeDirectory(uint32 blockIndex)
|
||||
{
|
||||
fNode.attributeDirectory = blockIndex;
|
||||
fNodeDataDirty = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Node::SetHardLinks(uint32 value)
|
||||
{
|
||||
|
@ -30,12 +30,13 @@ class Node {
|
||||
public:
|
||||
Node(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData);
|
||||
Node(Volume* volume, uint64 blockIndex,
|
||||
mode_t mode);
|
||||
Node(Volume* volume, mode_t mode);
|
||||
virtual ~Node();
|
||||
|
||||
void SetBlockIndex(uint64 blockIndex);
|
||||
|
||||
virtual status_t InitForVFS();
|
||||
virtual status_t DeletingNode(Transaction& transaction);
|
||||
virtual void DeletingNode();
|
||||
|
||||
virtual status_t Resize(uint64 newSize, bool fillWithZeroes,
|
||||
Transaction& transaction);
|
||||
@ -50,7 +51,9 @@ public:
|
||||
inline Volume* GetVolume() const { return fVolume; }
|
||||
inline uint64 BlockIndex() const { return fBlockIndex; }
|
||||
inline uint32 Mode() const { return fNode.mode; }
|
||||
inline uint32 AttributeType() const;
|
||||
inline uint64 ParentDirectory() const;
|
||||
inline uint64 AttributeDirectory() const;
|
||||
inline uint32 HardLinks() const { return fNode.hardLinks; }
|
||||
inline uint32 UID() const { return fNode.uid; }
|
||||
inline uint32 GID() const { return fNode.gid; }
|
||||
@ -60,7 +63,10 @@ public:
|
||||
inline uint64 ModificationTime() const;
|
||||
inline uint64 ChangeTime() const;
|
||||
|
||||
void SetMode(uint32 mode);
|
||||
void SetAttributeType(uint32 type);
|
||||
void SetParentDirectory(uint32 blockIndex);
|
||||
void SetAttributeDirectory(uint32 blockIndex);
|
||||
void SetHardLinks(uint32 value);
|
||||
void SetUID(uint32 uid);
|
||||
void SetGID(uint32 gid);
|
||||
@ -94,6 +100,13 @@ private:
|
||||
};
|
||||
|
||||
|
||||
uint32
|
||||
Node::AttributeType() const
|
||||
{
|
||||
return fNode.attributeType;
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
Node::ParentDirectory() const
|
||||
{
|
||||
@ -101,6 +114,13 @@ Node::ParentDirectory() const
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
Node::AttributeDirectory() const
|
||||
{
|
||||
return fNode.attributeDirectory;
|
||||
}
|
||||
|
||||
|
||||
uint64
|
||||
Node::CreationTime() const
|
||||
{
|
||||
|
@ -24,9 +24,9 @@ SymLink::SymLink(Volume* volume, uint64 blockIndex,
|
||||
}
|
||||
|
||||
|
||||
SymLink::SymLink(Volume* volume, uint64 blockIndex, mode_t mode)
|
||||
SymLink::SymLink(Volume* volume, mode_t mode)
|
||||
:
|
||||
Node(volume, blockIndex, mode)
|
||||
Node(volume, mode)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,7 @@ class SymLink : public Node {
|
||||
public:
|
||||
SymLink(Volume* volume, uint64 blockIndex,
|
||||
const checksumfs_node& nodeData);
|
||||
SymLink(Volume* volume, uint64 blockIndex,
|
||||
mode_t mode);
|
||||
SymLink(Volume* volume, mode_t mode);
|
||||
virtual ~SymLink();
|
||||
|
||||
status_t ReadSymLink(char* buffer, size_t toRead,
|
||||
|
@ -35,7 +35,7 @@ Volume::Volume(uint32 flags)
|
||||
:
|
||||
fFSVolume(NULL),
|
||||
fFD(-1),
|
||||
fFlags(B_FS_IS_PERSISTENT
|
||||
fFlags(B_FS_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME
|
||||
| (flags & B_FS_IS_READONLY != 0 ? B_FS_IS_READONLY : 0)),
|
||||
fBlockCache(NULL),
|
||||
fTotalBlocks(0),
|
||||
@ -281,6 +281,13 @@ Volume::RemoveNode(Node* node)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::UnremoveNode(Node* node)
|
||||
{
|
||||
return unremove_vnode(fFSVolume, node->BlockIndex());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::ReadNode(uint64 blockIndex, Node*& _node)
|
||||
{
|
||||
@ -326,28 +333,14 @@ status_t
|
||||
Volume::CreateDirectory(mode_t mode, Transaction& transaction,
|
||||
Directory*& _directory)
|
||||
{
|
||||
// allocate a free block
|
||||
AllocatedBlock allocatedBlock(fBlockAllocator, transaction);
|
||||
status_t error = allocatedBlock.Allocate();
|
||||
Directory* directory = new(std::nothrow) Directory(this,
|
||||
(mode & S_IUMSK) | S_IFDIR);
|
||||
|
||||
status_t error = _CreateNode(directory, transaction);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the directory
|
||||
Directory* directory = new(std::nothrow) Directory(this,
|
||||
allocatedBlock.Index(), (mode & S_IUMSK) | S_IFDIR);
|
||||
if (directory == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// attach the directory to the transaction
|
||||
error = transaction.AddNode(directory, TRANSACTION_DELETE_NODE);
|
||||
if (error != B_OK) {
|
||||
delete directory;
|
||||
return error;
|
||||
}
|
||||
|
||||
allocatedBlock.Detach();
|
||||
_directory = directory;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -355,28 +348,13 @@ Volume::CreateDirectory(mode_t mode, Transaction& transaction,
|
||||
status_t
|
||||
Volume::CreateFile(mode_t mode, Transaction& transaction, File*& _file)
|
||||
{
|
||||
// allocate a free block
|
||||
AllocatedBlock allocatedBlock(fBlockAllocator, transaction);
|
||||
status_t error = allocatedBlock.Allocate();
|
||||
File* file = new(std::nothrow) File(this, (mode & S_IUMSK) | S_IFREG);
|
||||
|
||||
status_t error = _CreateNode(file, transaction);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the file
|
||||
File* file = new(std::nothrow) File(this, allocatedBlock.Index(),
|
||||
(mode & S_IUMSK) | S_IFREG);
|
||||
if (file == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// attach the file to the transaction
|
||||
error = transaction.AddNode(file, TRANSACTION_DELETE_NODE);
|
||||
if (error != B_OK) {
|
||||
delete file;
|
||||
return error;
|
||||
}
|
||||
|
||||
allocatedBlock.Detach();
|
||||
_file = file;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -384,28 +362,14 @@ Volume::CreateFile(mode_t mode, Transaction& transaction, File*& _file)
|
||||
status_t
|
||||
Volume::CreateSymLink(mode_t mode, Transaction& transaction, SymLink*& _symLink)
|
||||
{
|
||||
// allocate a free block
|
||||
AllocatedBlock allocatedBlock(fBlockAllocator, transaction);
|
||||
status_t error = allocatedBlock.Allocate();
|
||||
SymLink* symLink = new(std::nothrow) SymLink(this,
|
||||
(mode & S_IUMSK) | S_IFLNK);
|
||||
|
||||
status_t error = _CreateNode(symLink, transaction);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create the symlink
|
||||
SymLink* symLink = new(std::nothrow) SymLink(this, allocatedBlock.Index(),
|
||||
(mode & S_IUMSK) | S_IFLNK);
|
||||
if (symLink == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// attach the symlink to the transaction
|
||||
error = transaction.AddNode(symLink, TRANSACTION_DELETE_NODE);
|
||||
if (error != B_OK) {
|
||||
delete symLink;
|
||||
return error;
|
||||
}
|
||||
|
||||
allocatedBlock.Detach();
|
||||
_symLink = symLink;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -413,32 +377,35 @@ Volume::CreateSymLink(mode_t mode, Transaction& transaction, SymLink*& _symLink)
|
||||
status_t
|
||||
Volume::DeleteNode(Node* node)
|
||||
{
|
||||
// let the node delete data associated with it
|
||||
node->DeletingNode();
|
||||
|
||||
uint64 blockIndex = node->BlockIndex();
|
||||
|
||||
// delete the node itself
|
||||
Transaction transaction(this);
|
||||
status_t error = transaction.Start();
|
||||
if (error == B_OK) {
|
||||
error = node->DeletingNode(transaction);
|
||||
if (error != B_OK) {
|
||||
ERROR("Preparing deletion of failed for node at %" B_PRIu64 "\n",
|
||||
node->BlockIndex());
|
||||
}
|
||||
|
||||
error = fBlockAllocator->Free(node->BlockIndex(), 1, transaction);
|
||||
if (error == B_OK) {
|
||||
error = transaction.Commit();
|
||||
if (error != B_OK) {
|
||||
ERROR("Failed to commit transaction for delete node at %"
|
||||
B_PRIu64 "\n", node->BlockIndex());
|
||||
ERROR("Failed to commit transaction for deleting node at %"
|
||||
B_PRIu64 "\n", blockIndex);
|
||||
}
|
||||
} else {
|
||||
ERROR("Failed to free block for node at %" B_PRIu64 "\n",
|
||||
node->BlockIndex());
|
||||
blockIndex);
|
||||
}
|
||||
} else {
|
||||
ERROR("Failed to start transaction for delete node at %" B_PRIu64 "\n",
|
||||
node->BlockIndex());
|
||||
ERROR("Failed to start transaction for deleting node at %" B_PRIu64
|
||||
"\n", blockIndex);
|
||||
}
|
||||
|
||||
transaction.Abort();
|
||||
|
||||
delete node;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -510,3 +477,38 @@ Volume::_Init(uint64 totalBlocks)
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::_CreateNode(Node* node, Transaction& transaction)
|
||||
{
|
||||
if (node == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
ObjectDeleter<Node> nodeDeleter(node);
|
||||
|
||||
// allocate a free block
|
||||
AllocatedBlock allocatedBlock(fBlockAllocator, transaction);
|
||||
status_t error = allocatedBlock.Allocate();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// clear the block
|
||||
{
|
||||
Block block;
|
||||
if (!block.GetZero(this, allocatedBlock.Index(), transaction))
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
node->SetBlockIndex(allocatedBlock.Index());
|
||||
|
||||
// attach the node to the transaction
|
||||
error = transaction.AddNode(node, TRANSACTION_DELETE_NODE);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
allocatedBlock.Detach();
|
||||
nodeDeleter.Detach();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
status_t GetNode(uint64 blockIndex, Node*& _node);
|
||||
status_t PutNode(Node* node);
|
||||
status_t RemoveNode(Node* node);
|
||||
status_t UnremoveNode(Node* node);
|
||||
|
||||
status_t ReadNode(uint64 blockIndex, Node*& _node);
|
||||
|
||||
@ -73,6 +74,10 @@ public:
|
||||
private:
|
||||
status_t _Init(uint64 totalBlocks);
|
||||
|
||||
status_t _CreateNode(Node* node,
|
||||
Transaction& transaction);
|
||||
status_t _DeleteDirectoryEntries(Directory* directory);
|
||||
|
||||
private:
|
||||
fs_volume* fFSVolume;
|
||||
int fFD;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user