BTRFS: Implement MakeReference() in Inode that will link file name to inode.

Signed-off-by: Augustin Cavalier <waddlesplash@gmail.com>
This commit is contained in:
hyche 2017-08-29 06:38:42 +07:00 committed by Augustin Cavalier
parent 371935de18
commit b44d924df4
3 changed files with 103 additions and 0 deletions

View File

@ -8,6 +8,7 @@
#include "Inode.h"
#include "CachedBlock.h"
#include "CRCTable.h"
#include "Utility.h"
@ -372,6 +373,21 @@ Inode::FindParent(ino_t* id)
}
uint64
Inode::FindNextIndex(BTree::Path* path) const
{
btrfs_key key;
key.SetObjectID(fID);
key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
key.SetOffset(-1);
if (fVolume->FSTree()->FindPrevious(path, key, NULL))
return 2; // not found any dir index item
return key.Offset() + 1;
}
/* Insert inode_item
*/
status_t
@ -391,6 +407,68 @@ Inode::Insert(Transaction& transaction, BTree::Path* path)
if (status != B_OK)
return status;
return B_OK;
}
/* Insert 3 items: inode_ref, dir_item, dir_index
* Basically, make a link between name and its node (location)
*/
status_t
Inode::MakeReference(Transaction& transaction, BTree::Path* path,
Inode* parent, const char* name, int32 mode)
{
BTree* tree = fVolume->FSTree();
uint16 nameLength = strlen(name);
uint64 index = parent->FindNextIndex(path);
void* data[1];
// insert inode_ref
btrfs_entry entry;
btrfs_inode_ref inodeRef;
inodeRef.index = index;
inodeRef.SetName(name, nameLength);
data[0] = (void*)&inodeRef;
entry.key.SetObjectID(fID);
entry.key.SetType(BTRFS_KEY_TYPE_INODE_REF);
entry.key.SetOffset(parent->ID());
entry.SetSize(inodeRef.Length());
status_t status = tree->InsertEntries(transaction, path, &entry, data, 1);
if (status != B_OK)
return status;
// insert dir_entry
uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength);
btrfs_dir_entry directoryEntry;
directoryEntry.location.SetObjectID(fID);
directoryEntry.location.SetType(BTRFS_KEY_TYPE_INODE_ITEM);
directoryEntry.location.SetOffset(0);
directoryEntry.SetTransactionID(transaction.SystemID());
// TODO: xattribute, 0 for standard directory
directoryEntry.SetAttributeData(NULL, 0);
directoryEntry.SetName(name, nameLength);
directoryEntry.type = get_filetype(mode);
data[0] = (void*)&directoryEntry;
entry.key.SetObjectID(parent->ID());
entry.key.SetType(BTRFS_KEY_TYPE_DIR_ITEM);
entry.key.SetOffset(hash);
entry.SetSize(directoryEntry.Length());
status = tree->InsertEntries(transaction, path, &entry, data, 1);
if (status != B_OK)
return status;
// insert dir_index (has same data with dir_entry)
entry.key.SetType(BTRFS_KEY_TYPE_DIR_INDEX);
entry.key.SetOffset(index);
status = tree->InsertEntries(transaction, path, &entry, data, 1);
if (status != B_OK)
return status;
return B_OK;
}

View File

@ -68,10 +68,13 @@ public:
void* Map() const { return fMap; }
status_t FindParent(ino_t* id);
uint64 FindNextIndex(BTree::Path* path) const;
static Inode* Create(Transaction& transaction, ino_t id,
Inode* parent, int32 mode, uint64 size = 0,
uint64 flags = 0);
status_t Insert(Transaction& transaction, BTree::Path* path);
status_t MakeReference(Transaction& transaction, BTree::Path* path,
Inode* parent, const char* name, int32 mode);
private:
Inode(Volume* volume);
Inode(const Inode&);

View File

@ -319,6 +319,13 @@ struct btrfs_inode_ref {
uint64 Index() const { return index; }
uint16 NameLength() const { return B_LENDIAN_TO_HOST_INT16(name_length); }
uint16 Length() const
{ return sizeof(btrfs_inode_ref) + NameLength(); }
void SetName(const char* name, uint16 nameLength)
{
name_length = B_HOST_TO_LENDIAN_INT16(nameLength);
memcpy(this->name, name, nameLength);
}
} _PACKED;
@ -348,11 +355,26 @@ struct btrfs_dir_entry {
uint16 data_length;
uint16 name_length;
uint8 type;
uint8 name[];
uint8 data[]; // attribute data
uint16 DataLength() const { return B_LENDIAN_TO_HOST_INT16(data_length); }
uint16 NameLength() const { return B_LENDIAN_TO_HOST_INT16(name_length); }
ino_t InodeID() const { return location.ObjectID(); }
uint16 Length() const
{ return sizeof(*this) + NameLength() + DataLength(); }
void SetTransactionID(uint64 id)
{ transaction_id = B_HOST_TO_LENDIAN_INT64(id); }
void SetAttributeData(void* data, uint16 dataLength)
{
data_length = B_HOST_TO_LENDIAN_INT16(dataLength);
if (data != NULL)
memcpy(this->data, data, dataLength);
}
void SetName(const char* name, uint16 nameLength)
{
name_length = B_HOST_TO_LENDIAN_INT16(nameLength);
memcpy(this->name, name, nameLength);
}
} _PACKED;