The file system is now almost endian-aware.
Used lazy unreadable conversion: ==, !=, == 0, != 0 are endian-safe and don't need byte swapping. If the platform endian differs from the one selected at compile time, it will mount all volumes read-only for now. Uncomment BFS_BIG_ENDIAN_ONLY in the Jamfile to build the big endian version under x86. No matter on what platform, the compilation defaults to build BFS as little endian file system (see bfs_endian.h for details). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4715 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -83,7 +83,7 @@ CachedNode::SetTo(off_t offset,bool check)
|
||||
// You can only ask for nodes at valid positions - you can't
|
||||
// even access the b+tree header with this method (use SetToHeader()
|
||||
// instead)
|
||||
if (offset > fTree->fHeader->maximum_size - fTree->fNodeSize
|
||||
if (offset > fTree->fHeader->MaximumSize() - fTree->fNodeSize
|
||||
|| offset <= 0
|
||||
|| (offset % fTree->fNodeSize) != 0)
|
||||
return NULL;
|
||||
@@ -91,10 +91,10 @@ CachedNode::SetTo(off_t offset,bool check)
|
||||
if (InternalSetTo(offset) != NULL && check) {
|
||||
// sanity checks (links, all_key_count)
|
||||
bplustree_header *header = fTree->fHeader;
|
||||
if (!header->IsValidLink(fNode->left_link)
|
||||
|| !header->IsValidLink(fNode->right_link)
|
||||
|| !header->IsValidLink(fNode->overflow_link)
|
||||
|| (int8 *)fNode->Values() + fNode->all_key_count * sizeof(off_t) >
|
||||
if (!header->IsValidLink(fNode->LeftLink())
|
||||
|| !header->IsValidLink(fNode->RightLink())
|
||||
|| !header->IsValidLink(fNode->OverflowLink())
|
||||
|| (int8 *)fNode->Values() + fNode->NumKeys() * sizeof(off_t) >
|
||||
(int8 *)fNode + fTree->fNodeSize) {
|
||||
FATAL(("invalid node read from offset %Ld, inode at %Ld\n",
|
||||
offset,fTree->fStream->ID()));
|
||||
@@ -160,9 +160,9 @@ CachedNode::Free(Transaction *transaction,off_t offset)
|
||||
|
||||
// if the node is the last one in the tree, we shrink
|
||||
// the tree and file size by one node
|
||||
off_t lastOffset = fTree->fHeader->maximum_size - fTree->fNodeSize;
|
||||
off_t lastOffset = fTree->fHeader->MaximumSize() - fTree->fNodeSize;
|
||||
if (offset == lastOffset) {
|
||||
fTree->fHeader->maximum_size = lastOffset;
|
||||
fTree->fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(lastOffset);
|
||||
|
||||
status_t status = fTree->fStream->SetFileSize(transaction,lastOffset);
|
||||
if (status < B_OK)
|
||||
@@ -173,10 +173,10 @@ CachedNode::Free(Transaction *transaction,off_t offset)
|
||||
|
||||
// add the node to the free nodes list
|
||||
fNode->left_link = fTree->fHeader->free_node_pointer;
|
||||
fNode->overflow_link = BPLUSTREE_FREE;
|
||||
fNode->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_FREE);
|
||||
|
||||
if (WriteBack(transaction) == B_OK) {
|
||||
fTree->fHeader->free_node_pointer = offset;
|
||||
fTree->fHeader->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64(offset);
|
||||
return fTree->fCachedHeader.WriteBack(transaction);
|
||||
}
|
||||
return B_ERROR;
|
||||
@@ -194,8 +194,8 @@ CachedNode::Allocate(Transaction *transaction, bplustree_node **_node, off_t *_o
|
||||
status_t status;
|
||||
|
||||
// if there are any free nodes, recycle them
|
||||
if (SetTo(fTree->fHeader->free_node_pointer,false) != NULL) {
|
||||
*_offset = fTree->fHeader->free_node_pointer;
|
||||
if (SetTo(fTree->fHeader->FreeNode(), false) != NULL) {
|
||||
*_offset = fTree->fHeader->FreeNode();
|
||||
|
||||
// set new free node pointer
|
||||
fTree->fHeader->free_node_pointer = fNode->left_link;
|
||||
@@ -208,15 +208,15 @@ CachedNode::Allocate(Transaction *transaction, bplustree_node **_node, off_t *_o
|
||||
}
|
||||
// allocate space for a new node
|
||||
Inode *stream = fTree->fStream;
|
||||
if ((status = stream->Append(transaction,fTree->fNodeSize)) < B_OK)
|
||||
if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK)
|
||||
return status;
|
||||
|
||||
// the maximum_size has to be changed before the call to SetTo() - or
|
||||
// else it will fail because the requested node is out of bounds
|
||||
off_t offset = fTree->fHeader->maximum_size;
|
||||
fTree->fHeader->maximum_size += fTree->fNodeSize;
|
||||
off_t offset = fTree->fHeader->MaximumSize();
|
||||
fTree->fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(fTree->fHeader->MaximumSize() + fTree->fNodeSize);
|
||||
|
||||
if (SetTo(offset,false) != NULL) {
|
||||
if (SetTo(offset, false) != NULL) {
|
||||
*_offset = offset;
|
||||
|
||||
if (fTree->fCachedHeader.WriteBack(transaction) >= B_OK) {
|
||||
@@ -235,7 +235,7 @@ CachedNode::WriteBack(Transaction *transaction)
|
||||
if (transaction == NULL || fTree == NULL || fTree->fStream == NULL || fNode == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
return transaction->WriteBlocks(fBlockNumber,fBlock);
|
||||
return transaction->WriteBlocks(fBlockNumber, fBlock);
|
||||
}
|
||||
|
||||
|
||||
@@ -319,19 +319,19 @@ BPlusTree::SetTo(Transaction *transaction, Inode *stream, int32 nodeSize)
|
||||
fNodeSize = nodeSize;
|
||||
|
||||
// initialize b+tree header
|
||||
fHeader->magic = BPLUSTREE_MAGIC;
|
||||
fHeader->node_size = fNodeSize;
|
||||
fHeader->max_number_of_levels = 1;
|
||||
fHeader->data_type = ModeToKeyType(stream->Mode());
|
||||
fHeader->root_node_pointer = nodeSize;
|
||||
fHeader->free_node_pointer = BPLUSTREE_NULL;
|
||||
fHeader->maximum_size = nodeSize * 2;
|
||||
fHeader->magic = HOST_ENDIAN_TO_BFS_INT32(BPLUSTREE_MAGIC);
|
||||
fHeader->node_size = HOST_ENDIAN_TO_BFS_INT32(fNodeSize);
|
||||
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
|
||||
fHeader->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode()));
|
||||
fHeader->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize);
|
||||
fHeader->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||
fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
|
||||
|
||||
if (fCachedHeader.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(fStatus = B_ERROR);
|
||||
|
||||
// initialize b+tree root node
|
||||
CachedNode cached(this,fHeader->root_node_pointer,false);
|
||||
CachedNode cached(this, fHeader->RootNode(), false);
|
||||
if (cached.Node() == NULL)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
@@ -357,14 +357,14 @@ BPlusTree::SetTo(Inode *stream)
|
||||
|
||||
// is header valid?
|
||||
|
||||
if (fHeader->magic != BPLUSTREE_MAGIC
|
||||
|| fHeader->maximum_size != stream->Size()
|
||||
|| (fHeader->root_node_pointer % fHeader->node_size) != 0
|
||||
|| !fHeader->IsValidLink(fHeader->root_node_pointer)
|
||||
|| !fHeader->IsValidLink(fHeader->free_node_pointer))
|
||||
if (fHeader->Magic() != BPLUSTREE_MAGIC
|
||||
|| fHeader->MaximumSize() != stream->Size()
|
||||
|| (fHeader->RootNode() % fHeader->NodeSize()) != 0
|
||||
|| !fHeader->IsValidLink(fHeader->RootNode())
|
||||
|| !fHeader->IsValidLink(fHeader->FreeNode()))
|
||||
RETURN_ERROR(fStatus = B_BAD_DATA);
|
||||
|
||||
fNodeSize = fHeader->node_size;
|
||||
fNodeSize = fHeader->NodeSize();
|
||||
|
||||
{
|
||||
uint32 toMode[] = {S_STR_INDEX, S_INT_INDEX, S_UINT_INDEX, S_LONG_LONG_INDEX,
|
||||
@@ -372,8 +372,8 @@ BPlusTree::SetTo(Inode *stream)
|
||||
uint32 mode = stream->Mode() & (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX
|
||||
| S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX);
|
||||
|
||||
if (fHeader->data_type > BPLUSTREE_DOUBLE_TYPE
|
||||
|| (stream->Mode() & S_INDEX_DIR) && toMode[fHeader->data_type] != mode
|
||||
if (fHeader->DataType() > BPLUSTREE_DOUBLE_TYPE
|
||||
|| (stream->Mode() & S_INDEX_DIR) && toMode[fHeader->DataType()] != mode
|
||||
|| !stream->IsContainer()) {
|
||||
D( dump_bplustree_header(fHeader);
|
||||
dump_inode(stream->Node());
|
||||
@@ -388,7 +388,7 @@ BPlusTree::SetTo(Inode *stream)
|
||||
|| (stream->Mode() & S_ALLOW_DUPS) != 0;
|
||||
}
|
||||
|
||||
CachedNode cached(this,fHeader->root_node_pointer);
|
||||
CachedNode cached(this, fHeader->RootNode());
|
||||
RETURN_ERROR(fStatus = cached.Node() ? B_OK : B_BAD_DATA);
|
||||
}
|
||||
|
||||
@@ -406,10 +406,13 @@ BPlusTree::TypeCodeToKeyType(type_code code)
|
||||
switch (code) {
|
||||
case B_STRING_TYPE:
|
||||
return BPLUSTREE_STRING_TYPE;
|
||||
case B_SSIZE_T_TYPE:
|
||||
case B_INT32_TYPE:
|
||||
return BPLUSTREE_INT32_TYPE;
|
||||
case B_SIZE_T_TYPE:
|
||||
case B_UINT32_TYPE:
|
||||
return BPLUSTREE_UINT32_TYPE;
|
||||
case B_OFF_T_TYPE:
|
||||
case B_INT64_TYPE:
|
||||
return BPLUSTREE_INT64_TYPE;
|
||||
case B_UINT64_TYPE:
|
||||
@@ -533,7 +536,7 @@ BPlusTree::FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, uin
|
||||
if (index)
|
||||
*index = 0;
|
||||
if (next)
|
||||
*next = node->overflow_link;
|
||||
*next = node->OverflowLink();
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -541,11 +544,11 @@ BPlusTree::FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, uin
|
||||
int16 saveIndex = -1;
|
||||
|
||||
// binary search in the key array
|
||||
for (int16 first = 0, last = node->all_key_count - 1; first <= last;) {
|
||||
for (int16 first = 0, last = node->NumKeys() - 1; first <= last;) {
|
||||
uint16 i = (first + last) >> 1;
|
||||
|
||||
uint16 searchLength;
|
||||
uint8 *searchKey = node->KeyAt(i,&searchLength);
|
||||
uint8 *searchKey = node->KeyAt(i, &searchLength);
|
||||
if (searchKey + searchLength + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fNodeSize
|
||||
|| searchLength > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||
fStream->GetVolume()->Panic();
|
||||
@@ -562,7 +565,7 @@ BPlusTree::FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, uin
|
||||
if (index)
|
||||
*index = i;
|
||||
if (next)
|
||||
*next = values[i];
|
||||
*next = BFS_ENDIAN_TO_HOST_INT64(values[i]);
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
@@ -570,10 +573,10 @@ BPlusTree::FindKey(bplustree_node *node, const uint8 *key, uint16 keyLength, uin
|
||||
if (index)
|
||||
*index = saveIndex;
|
||||
if (next) {
|
||||
if (saveIndex == node->all_key_count)
|
||||
*next = node->overflow_link;
|
||||
if (saveIndex == node->NumKeys())
|
||||
*next = node->OverflowLink();
|
||||
else
|
||||
*next = values[saveIndex];
|
||||
*next = BFS_ENDIAN_TO_HOST_INT64(values[saveIndex]);
|
||||
}
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
@@ -589,13 +592,13 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
|
||||
{
|
||||
// set the root node to begin with
|
||||
node_and_key nodeAndKey;
|
||||
nodeAndKey.nodeOffset = fHeader->root_node_pointer;
|
||||
nodeAndKey.nodeOffset = fHeader->RootNode();
|
||||
|
||||
CachedNode cached(this);
|
||||
bplustree_node *node;
|
||||
while ((node = cached.SetTo(nodeAndKey.nodeOffset)) != NULL) {
|
||||
// if we are already on leaf level, we're done
|
||||
if (node->overflow_link == BPLUSTREE_NULL) {
|
||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||
// node that the keyIndex is not properly set here (but it's not
|
||||
// needed in the calling functions anyway)!
|
||||
nodeAndKey.keyIndex = 0;
|
||||
@@ -623,7 +626,7 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode *cached, o
|
||||
bplustree_node **_fragment, uint32 *_index)
|
||||
{
|
||||
off_t *values = node->Values();
|
||||
for (int32 i = 0;i < node->all_key_count;i++) {
|
||||
for (int32 i = 0; i < node->NumKeys(); i++) {
|
||||
// does the value link to a duplicate fragment?
|
||||
if (bplustree_node::LinkType(values[i]) != BPLUSTREE_DUPLICATE_FRAGMENT)
|
||||
continue;
|
||||
@@ -687,8 +690,8 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
// reuse it as a duplicate node
|
||||
offset = bplustree_node::FragmentOffset(oldValue);
|
||||
|
||||
memmove(duplicate->DuplicateArray(),array,(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
duplicate->left_link = duplicate->right_link = BPLUSTREE_NULL;
|
||||
memmove(duplicate->DuplicateArray(), array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
duplicate->left_link = duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||
|
||||
array = duplicate->DuplicateArray();
|
||||
array->Insert(value);
|
||||
@@ -696,13 +699,13 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
// create a new duplicate node
|
||||
CachedNode cachedNewDuplicate(this);
|
||||
bplustree_node *newDuplicate;
|
||||
status = cachedNewDuplicate.Allocate(transaction,&newDuplicate,&offset);
|
||||
status = cachedNewDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// copy the array from the fragment node to the duplicate node
|
||||
// and free the old entry (by zero'ing all values)
|
||||
newDuplicate->overflow_link = array->count;
|
||||
newDuplicate->overflow_link = HOST_ENDIAN_TO_BFS_INT64(array->count);
|
||||
memcpy(&newDuplicate->all_key_count, &array->values[0],
|
||||
array->count * sizeof(off_t));
|
||||
memset(array,0,(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
@@ -747,7 +750,7 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
} while (array->count >= NUM_DUPLICATE_VALUES
|
||||
&& (oldValue = duplicate->right_link) != BPLUSTREE_NULL);
|
||||
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
|
||||
|
||||
if (array->count < NUM_DUPLICATE_VALUES) {
|
||||
array->Insert(value);
|
||||
@@ -761,8 +764,8 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
return status;
|
||||
|
||||
// link the two nodes together
|
||||
duplicate->right_link = offset;
|
||||
newDuplicate->left_link = duplicateOffset;
|
||||
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(offset);
|
||||
newDuplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(duplicateOffset);
|
||||
|
||||
array = newDuplicate->DuplicateArray();
|
||||
array->count = 0;
|
||||
@@ -807,27 +810,27 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
|
||||
off_t value)
|
||||
{
|
||||
// should never happen, but who knows?
|
||||
if (index > node->all_key_count)
|
||||
if (index > node->NumKeys())
|
||||
return;
|
||||
|
||||
off_t *values = node->Values();
|
||||
uint16 *keyLengths = node->KeyLengths();
|
||||
uint8 *keys = node->Keys();
|
||||
|
||||
node->all_key_count++;
|
||||
node->all_key_length += keyLength;
|
||||
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(node->NumKeys() + 1);
|
||||
node->all_key_length = HOST_ENDIAN_TO_BFS_INT16(node->AllKeyLength() + keyLength);
|
||||
|
||||
off_t *newValues = node->Values();
|
||||
uint16 *newKeyLengths = node->KeyLengths();
|
||||
|
||||
// move values and copy new value into them
|
||||
memmove(newValues + index + 1,values + index,sizeof(off_t) * (node->all_key_count - 1 - index));
|
||||
memmove(newValues,values,sizeof(off_t) * index);
|
||||
memmove(newValues + index + 1, values + index, sizeof(off_t) * (node->NumKeys() - 1 - index));
|
||||
memmove(newValues, values, sizeof(off_t) * index);
|
||||
|
||||
newValues[index] = value;
|
||||
|
||||
// move and update key length index
|
||||
for (uint16 i = node->all_key_count;i-- > index + 1;)
|
||||
for (uint16 i = node->NumKeys(); i-- > index + 1;)
|
||||
newKeyLengths[i] = keyLengths[i - 1] + keyLength;
|
||||
memmove(newKeyLengths,keyLengths,sizeof(uint16) * index);
|
||||
|
||||
@@ -835,7 +838,7 @@ BPlusTree::InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyL
|
||||
newKeyLengths[index] = keyLength + (keyStart = index > 0 ? newKeyLengths[index - 1] : 0);
|
||||
|
||||
// move keys and copy new key into them
|
||||
int32 size = node->all_key_length - newKeyLengths[index];
|
||||
int32 size = node->AllKeyLength() - newKeyLengths[index];
|
||||
if (size > 0)
|
||||
memmove(keys + newKeyLengths[index],keys + newKeyLengths[index] - keyLength,size);
|
||||
|
||||
@@ -847,7 +850,7 @@ status_t
|
||||
BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other,
|
||||
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength, off_t *_value)
|
||||
{
|
||||
if (*_keyIndex > node->all_key_count + 1)
|
||||
if (*_keyIndex > node->NumKeys() + 1)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint16 *inKeyLengths = node->KeyLengths();
|
||||
@@ -867,7 +870,7 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
|
||||
size_t size = fNodeSize >> 1;
|
||||
int32 out,in;
|
||||
for (in = out = 0;in < node->all_key_count + 1;) {
|
||||
for (in = out = 0; in < node->NumKeys() + 1;) {
|
||||
if (!bytes)
|
||||
bytesBefore = in > 0 ? inKeyLengths[in - 1] : 0;
|
||||
|
||||
@@ -897,9 +900,9 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
return B_BAD_DATA;
|
||||
|
||||
other->left_link = node->left_link;
|
||||
other->right_link = nodeOffset;
|
||||
other->all_key_length = bytes + bytesBefore + bytesAfter;
|
||||
other->all_key_count = out;
|
||||
other->right_link = HOST_ENDIAN_TO_BFS_INT64(nodeOffset);
|
||||
other->all_key_length = HOST_ENDIAN_TO_BFS_INT16(bytes + bytesBefore + bytesAfter);
|
||||
other->all_key_count = HOST_ENDIAN_TO_BFS_INT16(out);
|
||||
|
||||
uint16 *outKeyLengths = other->KeyLengths();
|
||||
off_t *outKeyValues = other->Values();
|
||||
@@ -943,12 +946,12 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
// of the next node (which can also be the new key to insert).
|
||||
// The dropped key is also the one which has to be inserted in
|
||||
// the parent node, so we will set the "newKey" already here.
|
||||
if (node->overflow_link != BPLUSTREE_NULL) {
|
||||
if (node->OverflowLink() != BPLUSTREE_NULL) {
|
||||
if (in == keyIndex) {
|
||||
newKey = key;
|
||||
newLength = *_keyLength;
|
||||
|
||||
other->overflow_link = *_value;
|
||||
other->overflow_link = HOST_ENDIAN_TO_BFS_INT64(*_value);
|
||||
keyIndex--;
|
||||
} else {
|
||||
// If a key is dropped (is not the new key), we have to copy
|
||||
@@ -962,7 +965,7 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
newKey = (uint8 *)malloc(newLength);
|
||||
if (newKey == NULL)
|
||||
return B_NO_MEMORY;
|
||||
memcpy(newKey,droppedKey,newLength);
|
||||
memcpy(newKey, droppedKey, newLength);
|
||||
|
||||
other->overflow_link = inKeyValues[in];
|
||||
total = inKeyLengths[in++];
|
||||
@@ -975,7 +978,7 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
bytesBefore = bytesAfter = bytes = 0;
|
||||
out = 0;
|
||||
int32 skip = in;
|
||||
while (in < node->all_key_count + 1) {
|
||||
while (in < node->NumKeys() + 1) {
|
||||
if (in == keyIndex && !bytes) {
|
||||
// it's enough to set bytesBefore once here, because we do
|
||||
// not need to know the exact length of all keys in this
|
||||
@@ -983,7 +986,7 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
bytesBefore = in > skip ? inKeyLengths[in - 1] : 0;
|
||||
bytes = *_keyLength;
|
||||
} else {
|
||||
if (in < node->all_key_count) {
|
||||
if (in < node->NumKeys()) {
|
||||
inKeyLengths[in] -= total;
|
||||
if (bytes) {
|
||||
inKeyLengths[in] += bytes;
|
||||
@@ -996,7 +999,7 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
out++;
|
||||
|
||||
// break out when all keys are done
|
||||
if (in > node->all_key_count && keyIndex < in)
|
||||
if (in > node->NumKeys() && keyIndex < in)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1004,15 +1007,15 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
if (keyIndex >= in && keyIndex - skip < out)
|
||||
bytesAfter = inKeyLengths[in] - bytesBefore - total;
|
||||
else if (keyIndex < skip)
|
||||
bytesBefore = node->all_key_length - total;
|
||||
bytesBefore = node->AllKeyLength() - total;
|
||||
|
||||
if (bytesBefore < 0 || bytesAfter < 0)
|
||||
return B_BAD_DATA;
|
||||
|
||||
node->left_link = otherOffset;
|
||||
node->left_link = HOST_ENDIAN_TO_BFS_INT64(otherOffset);
|
||||
// right link, and overflow link can stay the same
|
||||
node->all_key_length = bytes + bytesBefore + bytesAfter;
|
||||
node->all_key_count = out - 1;
|
||||
node->all_key_length = HOST_ENDIAN_TO_BFS_INT16(bytes + bytesBefore + bytesAfter);
|
||||
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(out - 1);
|
||||
|
||||
// array positions have changed
|
||||
outKeyLengths = node->KeyLengths();
|
||||
@@ -1052,7 +1055,7 @@ BPlusTree::SplitNode(bplustree_node *node,off_t nodeOffset,bplustree_node *other
|
||||
// If it's the dropped key, "newKey" was already set earlier.
|
||||
|
||||
if (newKey == NULL)
|
||||
newKey = other->KeyAt(other->all_key_count - 1, &newLength);
|
||||
newKey = other->KeyAt(other->NumKeys() - 1, &newLength);
|
||||
|
||||
memcpy(key,newKey,newLength);
|
||||
*_keyLength = newLength;
|
||||
@@ -1075,12 +1078,12 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
WriteLocked locked(fStream->Lock());
|
||||
|
||||
Stack<node_and_key> stack;
|
||||
if (SeekDown(stack,key,keyLength) != B_OK)
|
||||
if (SeekDown(stack, key, keyLength) != B_OK)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH + 1];
|
||||
|
||||
memcpy(keyBuffer,key,keyLength);
|
||||
memcpy(keyBuffer, key, keyLength);
|
||||
keyBuffer[keyLength] = 0;
|
||||
|
||||
node_and_key nodeAndKey;
|
||||
@@ -1093,7 +1096,7 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
#endif
|
||||
if (node->IsLeaf()) {
|
||||
// first round, check for duplicate entries
|
||||
status_t status = FindKey(node,key,keyLength,&nodeAndKey.keyIndex);
|
||||
status_t status = FindKey(node, key, keyLength, &nodeAndKey.keyIndex);
|
||||
|
||||
// is this a duplicate entry?
|
||||
if (status == B_OK) {
|
||||
@@ -1105,8 +1108,8 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
}
|
||||
|
||||
// is the node big enough to hold the pair?
|
||||
if (int32(round_up(sizeof(bplustree_node) + node->all_key_length + keyLength)
|
||||
+ (node->all_key_count + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
|
||||
if (int32(round_up(sizeof(bplustree_node) + node->AllKeyLength() + keyLength)
|
||||
+ (node->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
|
||||
{
|
||||
InsertKey(node, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
|
||||
UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1);
|
||||
@@ -1119,7 +1122,7 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// do we need to allocate a new root node? if so, then do
|
||||
// it now
|
||||
off_t newRoot = BPLUSTREE_NULL;
|
||||
if (nodeAndKey.nodeOffset == fHeader->root_node_pointer) {
|
||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
|
||||
bplustree_node *root;
|
||||
status_t status = cachedNewRoot.Allocate(transaction, &root, &newRoot);
|
||||
if (status < B_OK) {
|
||||
@@ -1158,11 +1161,11 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex,
|
||||
node->all_key_count, 1);
|
||||
node->NumKeys(), 1);
|
||||
|
||||
// update the right link of the node in the left of the new node
|
||||
if ((other = cachedOther.SetTo(other->left_link)) != NULL) {
|
||||
other->right_link = otherOffset;
|
||||
if ((other = cachedOther.SetTo(other->LeftLink())) != NULL) {
|
||||
other->right_link = HOST_ENDIAN_TO_BFS_INT64(otherOffset);
|
||||
if (cachedOther.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
@@ -1171,15 +1174,15 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
if (newRoot != BPLUSTREE_NULL) {
|
||||
bplustree_node *root = cachedNewRoot.Node();
|
||||
|
||||
InsertKey(root, 0, keyBuffer, keyLength, node->left_link);
|
||||
root->overflow_link = nodeAndKey.nodeOffset;
|
||||
InsertKey(root, 0, keyBuffer, keyLength, node->LeftLink());
|
||||
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset);
|
||||
|
||||
if (cachedNewRoot.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
// finally, update header to point to the new root
|
||||
fHeader->root_node_pointer = newRoot;
|
||||
fHeader->max_number_of_levels++;
|
||||
fHeader->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(newRoot);
|
||||
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(fHeader->MaxNumberOfLevels() + 1);
|
||||
|
||||
return fCachedHeader.WriteBack(transaction);
|
||||
}
|
||||
@@ -1242,8 +1245,8 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
|
||||
duplicate_array *array;
|
||||
|
||||
if (duplicate->left_link != BPLUSTREE_NULL) {
|
||||
FATAL(("invalid duplicate node: first left link points to %Ld!\n",duplicate->left_link));
|
||||
if (duplicate->LeftLink() != BPLUSTREE_NULL) {
|
||||
FATAL(("invalid duplicate node: first left link points to %Ld!\n", duplicate->LeftLink()));
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
@@ -1259,7 +1262,7 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
if (array->Remove(value))
|
||||
break;
|
||||
|
||||
if ((duplicateOffset = duplicate->right_link) == BPLUSTREE_NULL)
|
||||
if ((duplicateOffset = duplicate->RightLink()) == BPLUSTREE_NULL)
|
||||
RETURN_ERROR(B_ENTRY_NOT_FOUND);
|
||||
|
||||
duplicate = cachedDuplicate.SetTo(duplicateOffset,false);
|
||||
@@ -1268,8 +1271,8 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
while (true) {
|
||||
off_t left = duplicate->left_link;
|
||||
off_t right = duplicate->right_link;
|
||||
off_t left = duplicate->LeftLink();
|
||||
off_t right = duplicate->RightLink();
|
||||
bool isLast = left == BPLUSTREE_NULL && right == BPLUSTREE_NULL;
|
||||
|
||||
if (isLast && array->count == 1 || array->count == 0) {
|
||||
@@ -1289,17 +1292,17 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
if ((status = cached->WriteBack(transaction)) < B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
if ((status = cachedDuplicate.Free(transaction,duplicateOffset)) < B_OK)
|
||||
return status;
|
||||
|
||||
|
||||
if (left != BPLUSTREE_NULL
|
||||
&& (duplicate = cachedDuplicate.SetTo(left,false)) != NULL) {
|
||||
duplicate->right_link = right;
|
||||
|
||||
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(right);
|
||||
|
||||
// If the next node is the last node, we need to free that node
|
||||
// and convert the duplicate entry back into a normal entry
|
||||
if (right == BPLUSTREE_NULL && duplicate->left_link == BPLUSTREE_NULL
|
||||
if (right == BPLUSTREE_NULL && duplicate->LeftLink() == BPLUSTREE_NULL
|
||||
&& duplicate->DuplicateArray()->count <= NUM_FRAGMENT_VALUES) {
|
||||
duplicateOffset = left;
|
||||
continue;
|
||||
@@ -1310,12 +1313,12 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
return status;
|
||||
}
|
||||
if (right != BPLUSTREE_NULL
|
||||
&& (duplicate = cachedDuplicate.SetTo(right,false)) != NULL) {
|
||||
duplicate->left_link = left;
|
||||
|
||||
&& (duplicate = cachedDuplicate.SetTo(right, false)) != NULL) {
|
||||
duplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(left);
|
||||
|
||||
// Again, we may need to turn the duplicate entry back into a normal entry
|
||||
array = duplicate->DuplicateArray();
|
||||
if (left == BPLUSTREE_NULL && duplicate->right_link == BPLUSTREE_NULL
|
||||
if (left == BPLUSTREE_NULL && duplicate->RightLink() == BPLUSTREE_NULL
|
||||
&& duplicate->DuplicateArray()->count <= NUM_FRAGMENT_VALUES) {
|
||||
duplicateOffset = right;
|
||||
continue;
|
||||
@@ -1368,7 +1371,7 @@ void
|
||||
BPlusTree::RemoveKey(bplustree_node *node,uint16 index)
|
||||
{
|
||||
// should never happen, but who knows?
|
||||
if (index > node->all_key_count && node->all_key_count > 0) {
|
||||
if (index > node->NumKeys() && node->NumKeys() > 0) {
|
||||
FATAL(("Asked me to remove key outer limits: %u\n",index));
|
||||
return;
|
||||
}
|
||||
@@ -1378,7 +1381,7 @@ BPlusTree::RemoveKey(bplustree_node *node,uint16 index)
|
||||
// if we would have to drop the overflow link, drop
|
||||
// the last key instead and update the overflow link
|
||||
// to the value of that one
|
||||
if (!node->IsLeaf() && index == node->all_key_count)
|
||||
if (!node->IsLeaf() && index == node->NumKeys())
|
||||
node->overflow_link = values[--index];
|
||||
|
||||
uint16 length;
|
||||
@@ -1393,26 +1396,26 @@ BPlusTree::RemoveKey(bplustree_node *node,uint16 index)
|
||||
uint16 *keyLengths = node->KeyLengths();
|
||||
uint8 *keys = node->Keys();
|
||||
|
||||
node->all_key_count--;
|
||||
node->all_key_length -= length;
|
||||
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(node->NumKeys() - 1);
|
||||
node->all_key_length = HOST_ENDIAN_TO_BFS_INT64(node->AllKeyLength() - length);
|
||||
|
||||
off_t *newValues = node->Values();
|
||||
uint16 *newKeyLengths = node->KeyLengths();
|
||||
|
||||
// move key data
|
||||
memmove(key,key + length,node->all_key_length - (key - keys));
|
||||
memmove(key, key + length, node->AllKeyLength() - (key - keys));
|
||||
|
||||
// move and update key lengths
|
||||
if (index > 0 && newKeyLengths != keyLengths)
|
||||
memmove(newKeyLengths,keyLengths,index * sizeof(uint16));
|
||||
for (uint16 i = index;i < node->all_key_count;i++)
|
||||
memmove(newKeyLengths, keyLengths, index * sizeof(uint16));
|
||||
for (uint16 i = index; i < node->NumKeys(); i++)
|
||||
newKeyLengths[i] = keyLengths[i + 1] - length;
|
||||
|
||||
// move values
|
||||
if (index > 0)
|
||||
memmove(newValues,values,index * sizeof(off_t));
|
||||
if (node->all_key_count > index)
|
||||
memmove(newValues + index,values + index + 1,(node->all_key_count - index) * sizeof(off_t));
|
||||
if (node->NumKeys() > index)
|
||||
memmove(newValues + index, values + index + 1, (node->NumKeys() - index) * sizeof(off_t));
|
||||
}
|
||||
|
||||
|
||||
@@ -1453,14 +1456,14 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// to the next node after the current - if there aren't any
|
||||
// more nodes, we need a way to prevent the TreeIterators to
|
||||
// touch the old node again, we use BPLUSTREE_FREE for this
|
||||
off_t next = node->right_link == BPLUSTREE_NULL ? BPLUSTREE_FREE : node->right_link;
|
||||
UpdateIterators(nodeAndKey.nodeOffset,node->all_key_count == 1 ?
|
||||
next : BPLUSTREE_NULL,nodeAndKey.keyIndex,0,-1);
|
||||
off_t next = node->RightLink() == BPLUSTREE_NULL ? BPLUSTREE_FREE : node->RightLink();
|
||||
UpdateIterators(nodeAndKey.nodeOffset, node->NumKeys() == 1 ?
|
||||
next : BPLUSTREE_NULL,nodeAndKey.keyIndex,0 , -1);
|
||||
|
||||
// is this a duplicate entry?
|
||||
if (bplustree_node::IsDuplicate(node->Values()[nodeAndKey.keyIndex])) {
|
||||
if (fAllowDuplicates)
|
||||
return RemoveDuplicate(transaction,node,&cached,nodeAndKey.keyIndex,value);
|
||||
return RemoveDuplicate(transaction, node, &cached, nodeAndKey.keyIndex, value);
|
||||
else
|
||||
RETURN_ERROR(B_NAME_IN_USE);
|
||||
}
|
||||
@@ -1469,10 +1472,10 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// if it's an empty root node, we have to convert it
|
||||
// to a leaf node by dropping the overflow link, or,
|
||||
// if it's a leaf node, just empty it
|
||||
if (nodeAndKey.nodeOffset == fHeader->root_node_pointer
|
||||
&& node->all_key_count == 0
|
||||
|| node->all_key_count == 1 && node->IsLeaf()) {
|
||||
node->overflow_link = BPLUSTREE_NULL;
|
||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()
|
||||
&& node->NumKeys() == 0
|
||||
|| node->NumKeys() == 1 && node->IsLeaf()) {
|
||||
node->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||
node->all_key_count = 0;
|
||||
node->all_key_length = 0;
|
||||
|
||||
@@ -1481,8 +1484,8 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
|
||||
// if we've cleared the root node, reset the maximum
|
||||
// number of levels in the header
|
||||
if (nodeAndKey.nodeOffset == fHeader->root_node_pointer) {
|
||||
fHeader->max_number_of_levels = 1;
|
||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
|
||||
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
|
||||
return fCachedHeader.WriteBack(transaction);
|
||||
}
|
||||
return B_OK;
|
||||
@@ -1491,8 +1494,8 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// if there is only one key left, we don't have to remove
|
||||
// it, we can just dump the node (index nodes still have
|
||||
// the overflow link, so we have to drop the last key)
|
||||
if (node->all_key_count > 1
|
||||
|| !node->IsLeaf() && node->all_key_count == 1) {
|
||||
if (node->NumKeys() > 1
|
||||
|| !node->IsLeaf() && node->NumKeys() == 1) {
|
||||
RemoveKey(node,nodeAndKey.keyIndex);
|
||||
return cached.WriteBack(transaction);
|
||||
}
|
||||
@@ -1501,14 +1504,14 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// we have to update the right/left link of the
|
||||
// siblings first
|
||||
CachedNode otherCached(this);
|
||||
bplustree_node *other = otherCached.SetTo(node->left_link);
|
||||
bplustree_node *other = otherCached.SetTo(node->LeftLink());
|
||||
if (other != NULL) {
|
||||
other->right_link = node->right_link;
|
||||
if (otherCached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
if ((other = otherCached.SetTo(node->right_link)) != NULL) {
|
||||
if ((other = otherCached.SetTo(node->RightLink())) != NULL) {
|
||||
other->left_link = node->left_link;
|
||||
if (otherCached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
@@ -1542,7 +1545,7 @@ BPlusTree::Replace(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// lock access to stream (a read lock is okay for this purpose)
|
||||
ReadLocked locked(fStream->Lock());
|
||||
|
||||
off_t nodeOffset = fHeader->root_node_pointer;
|
||||
off_t nodeOffset = fHeader->RootNode();
|
||||
CachedNode cached(this);
|
||||
bplustree_node *node;
|
||||
|
||||
@@ -1551,7 +1554,7 @@ BPlusTree::Replace(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
off_t nextOffset;
|
||||
status_t status = FindKey(node, key, keyLength, &keyIndex, &nextOffset);
|
||||
|
||||
if (node->overflow_link == BPLUSTREE_NULL) {
|
||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||
if (status == B_OK) {
|
||||
node->Values()[keyIndex] = value;
|
||||
return cached.WriteBack(transaction);
|
||||
@@ -1592,7 +1595,7 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
|
||||
// lock access to stream
|
||||
ReadLocked locked(fStream->Lock());
|
||||
|
||||
off_t nodeOffset = fHeader->root_node_pointer;
|
||||
off_t nodeOffset = fHeader->RootNode();
|
||||
CachedNode cached(this);
|
||||
bplustree_node *node;
|
||||
|
||||
@@ -1608,12 +1611,12 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
|
||||
#ifdef DEBUG
|
||||
levels++;
|
||||
#endif
|
||||
if (node->overflow_link == BPLUSTREE_NULL) {
|
||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||
if (status == B_OK && _value != NULL)
|
||||
*_value = node->Values()[keyIndex];
|
||||
*_value = BFS_ENDIAN_TO_HOST_INT64(node->Values()[keyIndex]);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (levels != (int32)fHeader->max_number_of_levels)
|
||||
if (levels != (int32)fHeader->MaxNumberOfLevels())
|
||||
DEBUGGER(("levels don't match"));
|
||||
#endif
|
||||
return status;
|
||||
@@ -1656,15 +1659,15 @@ TreeIterator::Goto(int8 to)
|
||||
// lock access to stream
|
||||
ReadLocked locked(fTree->fStream->Lock());
|
||||
|
||||
off_t nodeOffset = fTree->fHeader->root_node_pointer;
|
||||
off_t nodeOffset = fTree->fHeader->RootNode();
|
||||
CachedNode cached(fTree);
|
||||
bplustree_node *node;
|
||||
|
||||
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
||||
// is the node a leaf node?
|
||||
if (node->overflow_link == BPLUSTREE_NULL) {
|
||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||
fCurrentNodeOffset = nodeOffset;
|
||||
fCurrentKey = to == BPLUSTREE_BEGIN ? -1 : node->all_key_count;
|
||||
fCurrentKey = to == BPLUSTREE_BEGIN ? -1 : node->NumKeys();
|
||||
fDuplicateNode = BPLUSTREE_NULL;
|
||||
|
||||
return B_OK;
|
||||
@@ -1674,13 +1677,13 @@ TreeIterator::Goto(int8 to)
|
||||
// are any keys in that node at all)
|
||||
off_t nextOffset;
|
||||
if (to == BPLUSTREE_END || node->all_key_count == 0)
|
||||
nextOffset = node->overflow_link;
|
||||
nextOffset = node->OverflowLink();
|
||||
else {
|
||||
if (node->all_key_length > fTree->fNodeSize
|
||||
|| (uint32)node->Values() > (uint32)node + fTree->fNodeSize - 8 * node->all_key_count)
|
||||
if (node->AllKeyLength() > fTree->fNodeSize
|
||||
|| (uint32)node->Values() > (uint32)node + fTree->fNodeSize - 8 * node->NumKeys())
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
nextOffset = node->Values()[0];
|
||||
nextOffset = BFS_ENDIAN_TO_HOST_INT64(node->Values()[0]);
|
||||
}
|
||||
if (nextOffset == nodeOffset)
|
||||
break;
|
||||
@@ -1740,7 +1743,7 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
|
||||
if (!fIsFragment && fDuplicate >= fNumDuplicates)
|
||||
{
|
||||
// if the node is out of duplicates, we go directly to the next one
|
||||
fDuplicateNode = node->right_link;
|
||||
fDuplicateNode = node->RightLink();
|
||||
if (fDuplicateNode != BPLUSTREE_NULL
|
||||
&& (node = cached.SetTo(fDuplicateNode, false)) != NULL)
|
||||
{
|
||||
@@ -1769,10 +1772,10 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
|
||||
fCurrentKey += direction;
|
||||
|
||||
// is the current key in the current node?
|
||||
while ((direction == BPLUSTREE_FORWARD && fCurrentKey >= node->all_key_count)
|
||||
while ((direction == BPLUSTREE_FORWARD && fCurrentKey >= node->NumKeys())
|
||||
|| (direction == BPLUSTREE_BACKWARD && fCurrentKey < 0))
|
||||
{
|
||||
fCurrentNodeOffset = direction == BPLUSTREE_FORWARD ? node->right_link : node->left_link;
|
||||
fCurrentNodeOffset = direction == BPLUSTREE_FORWARD ? node->RightLink() : node->LeftLink();
|
||||
|
||||
// are there any more nodes?
|
||||
if (fCurrentNodeOffset != BPLUSTREE_NULL)
|
||||
@@ -1782,13 +1785,13 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
// reset current key
|
||||
fCurrentKey = direction == BPLUSTREE_FORWARD ? 0 : node->all_key_count;
|
||||
fCurrentKey = direction == BPLUSTREE_FORWARD ? 0 : node->NumKeys();
|
||||
}
|
||||
else
|
||||
{
|
||||
// there are no nodes left, so turn back to the last key
|
||||
fCurrentNodeOffset = savedNodeOffset;
|
||||
fCurrentKey = direction == BPLUSTREE_FORWARD ? node->all_key_count : -1;
|
||||
fCurrentKey = direction == BPLUSTREE_FORWARD ? node->NumKeys() : -1;
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
@@ -1798,15 +1801,15 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
|
||||
RETURN_ERROR(B_ERROR); // B_ENTRY_NOT_FOUND ?
|
||||
|
||||
uint16 length;
|
||||
uint8 *keyStart = node->KeyAt(fCurrentKey,&length);
|
||||
uint8 *keyStart = node->KeyAt(fCurrentKey, &length);
|
||||
if (keyStart + length + sizeof(off_t) + sizeof(uint16) > (uint8 *)node + fTree->fNodeSize
|
||||
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||
fTree->fStream->GetVolume()->Panic();
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
}
|
||||
|
||||
length = min_c(length,maxLength);
|
||||
memcpy(key,keyStart,length);
|
||||
length = min_c(length, maxLength);
|
||||
memcpy(key, keyStart, length);
|
||||
|
||||
if (fTree->fHeader->data_type == BPLUSTREE_STRING_TYPE) // terminate string type
|
||||
{
|
||||
@@ -1816,7 +1819,7 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength, uint16 maxL
|
||||
}
|
||||
*keyLength = length;
|
||||
|
||||
off_t offset = node->Values()[fCurrentKey];
|
||||
off_t offset = BFS_ENDIAN_TO_HOST_INT64(node->Values()[fCurrentKey]);
|
||||
|
||||
// duplicate fragments?
|
||||
uint8 type = bplustree_node::LinkType(offset);
|
||||
@@ -1868,7 +1871,7 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
||||
// lock access to stream
|
||||
ReadLocked locked(fTree->fStream->Lock());
|
||||
|
||||
off_t nodeOffset = fTree->fHeader->root_node_pointer;
|
||||
off_t nodeOffset = fTree->fHeader->RootNode();
|
||||
|
||||
CachedNode cached(fTree);
|
||||
bplustree_node *node;
|
||||
@@ -1877,7 +1880,7 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
||||
off_t nextOffset;
|
||||
status_t status = fTree->FindKey(node, key, keyLength, &keyIndex, &nextOffset);
|
||||
|
||||
if (node->overflow_link == BPLUSTREE_NULL) {
|
||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||
fCurrentNodeOffset = nodeOffset;
|
||||
fCurrentKey = keyIndex - 1;
|
||||
fDuplicateNode = BPLUSTREE_NULL;
|
||||
@@ -1952,7 +1955,7 @@ TreeIterator::Dump()
|
||||
void
|
||||
bplustree_node::Initialize()
|
||||
{
|
||||
left_link = right_link = overflow_link = BPLUSTREE_NULL;
|
||||
left_link = right_link = overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||
all_key_count = 0;
|
||||
all_key_length = 0;
|
||||
}
|
||||
@@ -1961,15 +1964,16 @@ bplustree_node::Initialize()
|
||||
uint8 *
|
||||
bplustree_node::KeyAt(int32 index, uint16 *keyLength) const
|
||||
{
|
||||
if (index < 0 || index > all_key_count)
|
||||
if (index < 0 || index > NumKeys())
|
||||
return NULL;
|
||||
|
||||
uint8 *keyStart = Keys();
|
||||
uint16 *keyLengths = KeyLengths();
|
||||
|
||||
*keyLength = keyLengths[index] - (index != 0 ? keyLengths[index - 1] : 0);
|
||||
*keyLength = BFS_ENDIAN_TO_HOST_INT16(keyLengths[index])
|
||||
- (index != 0 ? BFS_ENDIAN_TO_HOST_INT16(keyLengths[index - 1]) : 0);
|
||||
if (index > 0)
|
||||
keyStart += keyLengths[index - 1];
|
||||
keyStart += BFS_ENDIAN_TO_HOST_INT16(keyLengths[index - 1]);
|
||||
|
||||
return keyStart;
|
||||
}
|
||||
@@ -1986,7 +1990,7 @@ bplustree_node::CountDuplicates(off_t offset, bool isFragment) const
|
||||
|
||||
return ((off_t *)this)[fragment];
|
||||
}
|
||||
return overflow_link;
|
||||
return OverflowLink();
|
||||
}
|
||||
|
||||
|
||||
@@ -2026,10 +2030,10 @@ bplustree_node::FragmentsUsed(uint32 nodeSize)
|
||||
void
|
||||
bplustree_node::CheckIntegrity(uint32 nodeSize)
|
||||
{
|
||||
if (all_key_count > nodeSize || all_key_length > nodeSize)
|
||||
if (NumKeys() > nodeSize || AllKeyLength() > nodeSize)
|
||||
DEBUGGER(("invalid node: key/length count"));
|
||||
|
||||
for (int32 i = 0; i < all_key_count; i++) {
|
||||
for (int32 i = 0; i < NumKeys(); i++) {
|
||||
uint16 length;
|
||||
uint8 *key = KeyAt(i, &length);
|
||||
if (key + length + sizeof(off_t) + sizeof(uint16) > (uint8 *)this + nodeSize
|
||||
|
||||
@@ -28,7 +28,15 @@ struct bplustree_header {
|
||||
off_t root_node_pointer;
|
||||
off_t free_node_pointer;
|
||||
off_t maximum_size;
|
||||
|
||||
|
||||
uint32 Magic() const { return BFS_ENDIAN_TO_HOST_INT32(magic); }
|
||||
uint32 NodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(node_size); }
|
||||
uint32 DataType() const { return BFS_ENDIAN_TO_HOST_INT32(data_type); }
|
||||
off_t RootNode() const { return BFS_ENDIAN_TO_HOST_INT64(root_node_pointer); }
|
||||
off_t FreeNode() const { return BFS_ENDIAN_TO_HOST_INT64(free_node_pointer); }
|
||||
off_t MaximumSize() const { return BFS_ENDIAN_TO_HOST_INT64(maximum_size); }
|
||||
uint32 MaxNumberOfLevels() const { return BFS_ENDIAN_TO_HOST_INT32(max_number_of_levels); }
|
||||
|
||||
inline bool IsValidLink(off_t link);
|
||||
};
|
||||
|
||||
@@ -56,13 +64,19 @@ struct bplustree_node {
|
||||
off_t overflow_link;
|
||||
uint16 all_key_count;
|
||||
uint16 all_key_length;
|
||||
|
||||
|
||||
off_t LeftLink() const { return BFS_ENDIAN_TO_HOST_INT64(left_link); }
|
||||
off_t RightLink() const { return BFS_ENDIAN_TO_HOST_INT64(right_link); }
|
||||
off_t OverflowLink() const { return BFS_ENDIAN_TO_HOST_INT64(overflow_link); }
|
||||
uint16 NumKeys() const { return BFS_ENDIAN_TO_HOST_INT16(all_key_count); }
|
||||
uint16 AllKeyLength() const { return BFS_ENDIAN_TO_HOST_INT16(all_key_length); }
|
||||
|
||||
inline uint16 *KeyLengths() const;
|
||||
inline off_t *Values() const;
|
||||
inline uint8 *Keys() const;
|
||||
inline int32 Used() const;
|
||||
uint8 *KeyAt(int32 index,uint16 *keyLength) const;
|
||||
|
||||
uint8 *KeyAt(int32 index, uint16 *keyLength) const;
|
||||
|
||||
inline bool IsLeaf() const;
|
||||
|
||||
void Initialize();
|
||||
@@ -381,7 +395,7 @@ TreeIterator::GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
|
||||
inline bool
|
||||
bplustree_header::IsValidLink(off_t link)
|
||||
{
|
||||
return link == BPLUSTREE_NULL || (link > 0 && link <= maximum_size - node_size);
|
||||
return link == BPLUSTREE_NULL || (link > 0 && link <= MaximumSize() - NodeSize());
|
||||
}
|
||||
|
||||
|
||||
@@ -392,31 +406,35 @@ bplustree_header::IsValidLink(off_t link)
|
||||
inline uint16 *
|
||||
bplustree_node::KeyLengths() const
|
||||
{
|
||||
return (uint16 *)(((char *)this) + round_up(sizeof(bplustree_node) + all_key_length));
|
||||
return (uint16 *)(((char *)this) + round_up(sizeof(bplustree_node) + AllKeyLength()));
|
||||
}
|
||||
|
||||
|
||||
inline off_t *
|
||||
bplustree_node::Values() const
|
||||
{
|
||||
return (off_t *)((char *)KeyLengths() + all_key_count * sizeof(uint16));
|
||||
return (off_t *)((char *)KeyLengths() + NumKeys() * sizeof(uint16));
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
bplustree_node::Keys() const
|
||||
{
|
||||
return (uint8 *)this + sizeof(bplustree_node);
|
||||
}
|
||||
|
||||
|
||||
inline int32
|
||||
bplustree_node::Used() const
|
||||
{
|
||||
return round_up(sizeof(bplustree_node) + all_key_length) + all_key_count * (sizeof(uint16) + sizeof(off_t));
|
||||
return round_up(sizeof(bplustree_node) + AllKeyLength()) + NumKeys() * (sizeof(uint16) + sizeof(off_t));
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
bplustree_node::IsLeaf() const
|
||||
{
|
||||
return overflow_link == BPLUSTREE_NULL;
|
||||
return OverflowLink() == BPLUSTREE_NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -440,24 +458,28 @@ bplustree_node::LinkType(off_t link)
|
||||
return *(uint64 *)&link >> 62;
|
||||
}
|
||||
|
||||
|
||||
inline off_t
|
||||
bplustree_node::MakeLink(uint8 type, off_t link, uint32 fragmentIndex)
|
||||
{
|
||||
return ((off_t)type << 62) | (link & 0x3ffffffffffffc00LL) | (fragmentIndex & 0x3ff);
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
bplustree_node::IsDuplicate(off_t link)
|
||||
{
|
||||
return (LinkType(link) & (BPLUSTREE_DUPLICATE_NODE | BPLUSTREE_DUPLICATE_FRAGMENT)) > 0;
|
||||
}
|
||||
|
||||
|
||||
inline off_t
|
||||
bplustree_node::FragmentOffset(off_t link)
|
||||
{
|
||||
return link & 0x3ffffffffffffc00LL;
|
||||
}
|
||||
|
||||
|
||||
inline uint32
|
||||
bplustree_node::FragmentIndex(off_t link)
|
||||
{
|
||||
|
||||
@@ -112,7 +112,7 @@ AllocationBlock::IsUsed(uint16 block)
|
||||
if (block > fNumBits)
|
||||
return true;
|
||||
// the block bitmap is accessed in 32-bit blocks
|
||||
return Block(block >> 5) & (1UL << (block % 32));
|
||||
return Block(block >> 5) & HOST_ENDIAN_TO_BFS_INT32(1UL << (block % 32));
|
||||
}
|
||||
|
||||
|
||||
@@ -136,12 +136,12 @@ AllocationBlock::Allocate(uint16 start, uint16 numBlocks)
|
||||
|
||||
#ifdef DEBUG
|
||||
// check for already set blocks
|
||||
if (mask & ((uint32 *)fBlock)[block]) {
|
||||
if (HOST_ENDIAN_TO_BFS_INT32(mask) & ((uint32 *)fBlock)[block]) {
|
||||
FATAL(("AllocationBlock::Allocate(): some blocks are already allocated, start = %u, numBlocks = %u\n", start, numBlocks));
|
||||
DEBUGGER(("blocks already set!"));
|
||||
}
|
||||
#endif
|
||||
Block(block++) |= mask;
|
||||
Block(block++) |= HOST_ENDIAN_TO_BFS_INT32(mask);
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ AllocationBlock::Free(uint16 start, uint16 numBlocks)
|
||||
for (int32 i = start % 32; i < 32 && numBlocks; i++, numBlocks--)
|
||||
mask |= 1UL << (i % 32);
|
||||
|
||||
Block(block++) &= ~mask;
|
||||
Block(block++) &= HOST_ENDIAN_TO_BFS_INT32(~mask);
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
@@ -332,7 +332,7 @@ BlockAllocator::Initialize()
|
||||
return B_ERROR;
|
||||
|
||||
fNumGroups = fVolume->AllocationGroups();
|
||||
fBlocksPerGroup = fVolume->SuperBlock().blocks_per_ag;
|
||||
fBlocksPerGroup = fVolume->SuperBlock().BlocksPerAllocationGroup();
|
||||
fGroups = new AllocationGroup[fNumGroups];
|
||||
if (fGroups == NULL)
|
||||
return B_NO_MEMORY;
|
||||
@@ -397,7 +397,7 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
||||
free(buffer);
|
||||
|
||||
// check if block bitmap and log area are reserved
|
||||
uint32 reservedBlocks = volume->Log().start + volume->Log().length;
|
||||
uint32 reservedBlocks = volume->Log().Start() + volume->Log().Length();
|
||||
if (allocator->CheckBlockRun(block_run::Run(0, 0, reservedBlocks)) < B_OK) {
|
||||
Transaction transaction(volume, 0);
|
||||
if (groups[0].Allocate(&transaction, 0, reservedBlocks) < B_OK) {
|
||||
@@ -415,7 +415,7 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
||||
// If the disk in a dirty state at mount time, it's
|
||||
// normal that the values don't match
|
||||
INFORM(("volume reports %Ld used blocks, correct is %Ld\n", volume->UsedBlocks(), usedBlocks));
|
||||
volume->SuperBlock().used_blocks = usedBlocks;
|
||||
volume->SuperBlock().used_blocks = HOST_ENDIAN_TO_BFS_INT64(usedBlocks);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
@@ -502,11 +502,12 @@ BlockAllocator::AllocateBlocks(Transaction *transaction, int32 group, uint16 sta
|
||||
if (fGroups[group].Allocate(transaction, rangeStart, numBlocks) < B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
run.allocation_group = group;
|
||||
run.start = rangeStart;
|
||||
run.length = numBlocks;
|
||||
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(group);
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(rangeStart);
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(numBlocks);
|
||||
|
||||
fVolume->SuperBlock().used_blocks += numBlocks;
|
||||
fVolume->SuperBlock().used_blocks =
|
||||
HOST_ENDIAN_TO_BFS_INT64(fVolume->UsedBlocks() + numBlocks);
|
||||
// We are not writing back the disk's super block - it's
|
||||
// either done by the journaling code, or when the disk
|
||||
// is unmounted.
|
||||
@@ -534,7 +535,7 @@ BlockAllocator::AllocateForInode(Transaction *transaction, const block_run *pare
|
||||
|
||||
// files are going in the same allocation group as its parent, sub-directories
|
||||
// will be inserted 8 allocation groups after the one of the parent
|
||||
uint16 group = parent->allocation_group;
|
||||
uint16 group = parent->AllocationGroup();
|
||||
if ((type & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY)
|
||||
group += 8;
|
||||
|
||||
@@ -567,7 +568,7 @@ BlockAllocator::Allocate(Transaction *transaction, const Inode *inode, off_t num
|
||||
|
||||
// apply some allocation policies here (AllocateBlocks() will break them
|
||||
// if necessary)
|
||||
uint16 group = inode->BlockRun().allocation_group;
|
||||
uint16 group = inode->BlockRun().AllocationGroup();
|
||||
uint16 start = 0;
|
||||
|
||||
// are there already allocated blocks? (then just try to allocate near the last one)
|
||||
@@ -579,20 +580,20 @@ BlockAllocator::Allocate(Transaction *transaction, const Inode *inode, off_t num
|
||||
&& data->max_indirect_range == 0) {
|
||||
// Since size > 0, there must be a valid block run in this stream
|
||||
int32 last = 0;
|
||||
for (;last < NUM_DIRECT_BLOCKS - 1;last++)
|
||||
for (; last < NUM_DIRECT_BLOCKS - 1; last++)
|
||||
if (data->direct[last + 1].IsZero())
|
||||
break;
|
||||
|
||||
group = data->direct[last].allocation_group;
|
||||
start = data->direct[last].start + data->direct[last].length;
|
||||
group = data->direct[last].AllocationGroup();
|
||||
start = data->direct[last].Start() + data->direct[last].Length();
|
||||
}
|
||||
} else if (inode->IsContainer() || inode->IsSymLink()) {
|
||||
// directory and symbolic link data will go in the same allocation
|
||||
// group as the inode is in but after the inode data
|
||||
start = inode->BlockRun().start;
|
||||
start = inode->BlockRun().Start();
|
||||
} else {
|
||||
// file data will start in the next allocation group
|
||||
group = inode->BlockRun().allocation_group + 1;
|
||||
group = inode->BlockRun().AllocationGroup() + 1;
|
||||
}
|
||||
|
||||
return AllocateBlocks(transaction, group, start, numBlocks, minimum, run);
|
||||
@@ -604,9 +605,9 @@ BlockAllocator::Free(Transaction *transaction, block_run run)
|
||||
{
|
||||
Locker lock(fLock);
|
||||
|
||||
int32 group = run.allocation_group;
|
||||
uint16 start = run.start;
|
||||
uint16 length = run.length;
|
||||
int32 group = run.AllocationGroup();
|
||||
uint16 start = run.Start();
|
||||
uint16 length = run.Length();
|
||||
|
||||
// doesn't use Volume::IsValidBlockRun() here because it can check better
|
||||
// against the group size (the last group may have a different length)
|
||||
@@ -619,7 +620,7 @@ BlockAllocator::Free(Transaction *transaction, block_run run)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
// check if someone tries to free reserved areas at the beginning of the drive
|
||||
if (group == 0 && start < uint32(fVolume->Log().start + fVolume->Log().length)) {
|
||||
if (group == 0 && start < uint32(fVolume->Log().Start() + fVolume->Log().Length())) {
|
||||
FATAL(("tried to free a reserved block_run (%ld, %u, %u)\n", group, start, length));
|
||||
DEBUGGER(("tried to free reserved block"));
|
||||
return B_BAD_VALUE;
|
||||
@@ -632,7 +633,8 @@ BlockAllocator::Free(Transaction *transaction, block_run run)
|
||||
if (fGroups[group].Free(transaction, start, length) < B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
fVolume->SuperBlock().used_blocks -= run.length;
|
||||
fVolume->SuperBlock().used_blocks =
|
||||
HOST_ENDIAN_TO_BFS_INT64(fVolume->UsedBlocks() - run.Length());
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -683,7 +685,7 @@ BlockAllocator::StartChecking(check_control *control)
|
||||
|
||||
// initialize bitmap
|
||||
memset(fCheckBitmap, 0, size);
|
||||
for (int32 block = fVolume->Log().start + fVolume->Log().length; block-- > 0;)
|
||||
for (int32 block = fVolume->Log().Start() + fVolume->Log().Length(); block-- > 0;)
|
||||
SetCheckBitmapAt(block);
|
||||
|
||||
cookie->stack.Push(fVolume->Root());
|
||||
@@ -747,14 +749,14 @@ BlockAllocator::StopChecking(check_control *control)
|
||||
// and use transactions here to play safe - we even use several
|
||||
// transactions, so that we don't blow the maximum log size
|
||||
// on large disks; since we don't need to make this atomic
|
||||
fVolume->SuperBlock().used_blocks = usedBlocks;
|
||||
|
||||
fVolume->SuperBlock().used_blocks = HOST_ENDIAN_TO_BFS_INT64(usedBlocks);
|
||||
|
||||
int32 blocksInBitmap = fNumGroups * fBlocksPerGroup;
|
||||
int32 blockSize = fVolume->BlockSize();
|
||||
|
||||
for (int32 i = 0; i < blocksInBitmap; i += 512) {
|
||||
Transaction transaction(fVolume, 1 + i);
|
||||
|
||||
|
||||
int32 blocksToWrite = 512;
|
||||
if (blocksToWrite + i > blocksInBitmap)
|
||||
blocksToWrite = blocksInBitmap - i;
|
||||
@@ -943,7 +945,7 @@ BlockAllocator::CheckBitmapIsUsedAt(off_t block) const
|
||||
if (index > size / 4)
|
||||
return false;
|
||||
|
||||
return fCheckBitmap[index] & (1UL << (block & 0x1f));
|
||||
return BFS_ENDIAN_TO_HOST_INT32(fCheckBitmap[index]) & (1UL << (block & 0x1f));
|
||||
}
|
||||
|
||||
|
||||
@@ -955,18 +957,18 @@ BlockAllocator::SetCheckBitmapAt(off_t block)
|
||||
if (index > size / 4)
|
||||
return;
|
||||
|
||||
fCheckBitmap[index] |= (1UL << (block & 0x1f));
|
||||
fCheckBitmap[index] |= HOST_ENDIAN_TO_BFS_INT32(1UL << (block & 0x1f));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *control)
|
||||
{
|
||||
if (run.allocation_group < 0 || run.allocation_group >= fNumGroups
|
||||
|| run.start > fGroups[run.allocation_group].fNumBits
|
||||
|| uint32(run.start + run.length) > fGroups[run.allocation_group].fNumBits
|
||||
if (run.AllocationGroup() < 0 || run.AllocationGroup() >= fNumGroups
|
||||
|| run.Start() > fGroups[run.allocation_group].fNumBits
|
||||
|| uint32(run.Start() + run.Length()) > fGroups[run.AllocationGroup()].fNumBits
|
||||
|| run.length == 0) {
|
||||
PRINT(("%s: block_run(%ld, %u, %u) is invalid!\n", type, run.allocation_group, run.start, run.length));
|
||||
PRINT(("%s: block_run(%ld, %u, %u) is invalid!\n", type, run.AllocationGroup(), run.Start(), run.Length()));
|
||||
if (control == NULL)
|
||||
return B_BAD_DATA;
|
||||
|
||||
@@ -975,16 +977,16 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
||||
}
|
||||
|
||||
uint32 bitsPerBlock = fVolume->BlockSize() << 3;
|
||||
uint32 block = run.start / bitsPerBlock;
|
||||
uint32 pos = run.start % bitsPerBlock;
|
||||
uint32 block = run.Start() / bitsPerBlock;
|
||||
uint32 pos = run.Start() % bitsPerBlock;
|
||||
int32 length = 0;
|
||||
off_t firstMissing = -1, firstSet = -1;
|
||||
off_t firstGroupBlock = (off_t)run.allocation_group << fVolume->AllocationGroupShift();
|
||||
off_t firstGroupBlock = (off_t)run.AllocationGroup() << fVolume->AllocationGroupShift();
|
||||
|
||||
AllocationBlock cached(fVolume);
|
||||
|
||||
for (; block < fBlocksPerGroup && length < run.length; block++, pos = 0) {
|
||||
if (cached.SetTo(fGroups[run.allocation_group], block) < B_OK)
|
||||
for (; block < fBlocksPerGroup && length < run.Length(); block++, pos = 0) {
|
||||
if (cached.SetTo(fGroups[run.AllocationGroup()], block) < B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
if (pos >= cached.NumBlockBits()) {
|
||||
@@ -992,10 +994,10 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
|
||||
while (length < run.length && pos < cached.NumBlockBits()) {
|
||||
while (length < run.Length() && pos < cached.NumBlockBits()) {
|
||||
if (!cached.IsUsed(pos)) {
|
||||
if (control == NULL) {
|
||||
PRINT(("%s: block_run(%ld, %u, %u) is only partially allocated!\n", type, run.allocation_group, run.start, run.length));
|
||||
PRINT(("%s: block_run(%ld, %u, %u) is only partially allocated!\n", type, run.AllocationGroup(), run.Start(), run.Length()));
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
if (firstMissing == -1) {
|
||||
@@ -1004,7 +1006,8 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
||||
}
|
||||
control->stats.missing++;
|
||||
} else if (firstMissing != -1) {
|
||||
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not allocated!\n", type, run.allocation_group, run.start, run.length, firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1));
|
||||
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not allocated!\n",
|
||||
type, run.allocation_group, run.start, run.length, firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1));
|
||||
firstMissing = -1;
|
||||
}
|
||||
|
||||
@@ -1020,7 +1023,8 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
||||
control->stats.already_set++;
|
||||
} else {
|
||||
if (firstSet != -1) {
|
||||
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are already set!\n", type, run.allocation_group, run.start, run.length, firstSet, firstGroupBlock + offset - 1));
|
||||
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are already set!\n",
|
||||
type, run.AllocationGroup(), run.Start(), run.Length(), firstSet, firstGroupBlock + offset - 1));
|
||||
firstSet = -1;
|
||||
}
|
||||
SetCheckBitmapAt(firstGroupBlock + offset);
|
||||
@@ -1030,11 +1034,11 @@ BlockAllocator::CheckBlockRun(block_run run, const char *type, check_control *co
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (block + 1 >= fBlocksPerGroup || length >= run.length) {
|
||||
if (block + 1 >= fBlocksPerGroup || length >= run.Length()) {
|
||||
if (firstMissing != -1)
|
||||
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not allocated!\n", type, run.allocation_group, run.start, run.length, firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1));
|
||||
PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are not allocated!\n", type, run.AllocationGroup(), run.Start(), run.Length(), firstMissing, firstGroupBlock + pos + block * bitsPerBlock - 1));
|
||||
if (firstSet != -1)
|
||||
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are already set!\n", type, run.allocation_group, run.start, run.length, firstSet, firstGroupBlock + pos + block * bitsPerBlock - 1));
|
||||
FATAL(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are already set!\n", type, run.AllocationGroup(), run.Start(), run.Length(), firstSet, firstGroupBlock + pos + block * bitsPerBlock - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1059,10 +1063,10 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
|
||||
// check the direct range
|
||||
|
||||
if (data->max_direct_range) {
|
||||
for (int32 i = 0;i < NUM_DIRECT_BLOCKS;i++) {
|
||||
for (int32 i = 0; i < NUM_DIRECT_BLOCKS; i++) {
|
||||
if (data->direct[i].IsZero())
|
||||
break;
|
||||
|
||||
|
||||
status = CheckBlockRun(data->direct[i], "direct", control);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
@@ -1080,7 +1084,7 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
|
||||
|
||||
off_t block = fVolume->ToBlock(data->indirect);
|
||||
|
||||
for (int32 i = 0; i < data->indirect.length; i++) {
|
||||
for (int32 i = 0; i < data->indirect.Length(); i++) {
|
||||
block_run *runs = (block_run *)cached.SetTo(block + i);
|
||||
if (runs == NULL)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
@@ -1111,7 +1115,8 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
|
||||
int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT;
|
||||
|
||||
CachedBlock cachedDirect(fVolume);
|
||||
int32 maxIndirectIndex = (data->double_indirect.length << fVolume->BlockShift()) / sizeof(block_run);
|
||||
int32 maxIndirectIndex = (data->double_indirect.Length() << fVolume->BlockShift())
|
||||
/ sizeof(block_run);
|
||||
|
||||
for (int32 indirectIndex = 0; indirectIndex < maxIndirectIndex; indirectIndex++) {
|
||||
// get the indirect array block
|
||||
@@ -1129,7 +1134,7 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
int32 maxIndex = (indirect.length << fVolume->BlockShift()) / sizeof(block_run);
|
||||
int32 maxIndex = (indirect.Length() << fVolume->BlockShift()) / sizeof(block_run);
|
||||
|
||||
for (int32 index = 0; index < maxIndex; ) {
|
||||
block_run *runs = (block_run *)cachedDirect.SetTo(fVolume->ToBlock(indirect)
|
||||
|
||||
@@ -76,22 +76,23 @@ InodeAllocator::New(block_run *parentRun, mode_t mode, block_run &run, Inode **_
|
||||
|
||||
bfs_inode *node = fInode->Node();
|
||||
|
||||
node->magic1 = INODE_MAGIC1;
|
||||
node->magic1 = HOST_ENDIAN_TO_BFS_INT32(INODE_MAGIC1);
|
||||
node->inode_num = run;
|
||||
node->mode = mode;
|
||||
node->flags = INODE_IN_USE | INODE_NOT_READY;
|
||||
node->mode = HOST_ENDIAN_TO_BFS_INT32(mode);
|
||||
node->flags = HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE | INODE_NOT_READY);
|
||||
// INODE_NOT_READY prevents the inode from being opened - it is
|
||||
// cleared in InodeAllocator::Keep()
|
||||
node->etc = (uint32)fInode;
|
||||
// this is temporarily set along INODE_NOT_READY and lets bfs_read_vnode()
|
||||
// find the associated Inode object
|
||||
|
||||
node->create_time = (bigtime_t)time(NULL) << INODE_TIME_SHIFT;
|
||||
node->last_modified_time = node->create_time | (volume->GetUniqueID() & INODE_TIME_MASK);
|
||||
node->create_time = HOST_ENDIAN_TO_BFS_INT64((bigtime_t)time(NULL) << INODE_TIME_SHIFT);
|
||||
node->last_modified_time = HOST_ENDIAN_TO_BFS_INT64(node->create_time
|
||||
| (volume->GetUniqueID() & INODE_TIME_MASK));
|
||||
// we use Volume::GetUniqueID() to avoid having too many duplicates in the
|
||||
// last_modified index
|
||||
|
||||
node->inode_size = volume->InodeSize();
|
||||
node->inode_size = HOST_ENDIAN_TO_BFS_INT32(volume->InodeSize());
|
||||
|
||||
*_inode = fInode;
|
||||
return B_OK;
|
||||
@@ -105,7 +106,7 @@ InodeAllocator::CreateTree()
|
||||
|
||||
// force S_STR_INDEX to be set, if no type is set
|
||||
if ((fInode->Mode() & S_INDEX_TYPES) == 0)
|
||||
fInode->Node()->mode |= S_STR_INDEX;
|
||||
fInode->Node()->mode |= HOST_ENDIAN_TO_BFS_INT32(S_STR_INDEX);
|
||||
|
||||
BPlusTree *tree = fInode->fTree = new BPlusTree(fTransaction, fInode);
|
||||
if (tree == NULL || tree->InitCheck() < B_OK)
|
||||
@@ -146,20 +147,20 @@ bfs_inode::InitCheck(Volume *volume)
|
||||
return B_BUSY;
|
||||
}
|
||||
|
||||
if (magic1 != INODE_MAGIC1
|
||||
|| !(flags & INODE_IN_USE)
|
||||
|| inode_num.length != 1
|
||||
if (Magic1() != INODE_MAGIC1
|
||||
|| !(Flags() & INODE_IN_USE)
|
||||
|| inode_num.Length() != 1
|
||||
// matches inode size?
|
||||
|| (uint32)inode_size != volume->InodeSize()
|
||||
|| (uint32)InodeSize() != volume->InodeSize()
|
||||
// parent resides on disk?
|
||||
|| parent.allocation_group > int32(volume->AllocationGroups())
|
||||
|| parent.allocation_group < 0
|
||||
|| parent.start > (1L << volume->AllocationGroupShift())
|
||||
|| parent.length != 1
|
||||
|| parent.AllocationGroup() > int32(volume->AllocationGroups())
|
||||
|| parent.AllocationGroup() < 0
|
||||
|| parent.Start() > (1L << volume->AllocationGroupShift())
|
||||
|| parent.Length() != 1
|
||||
// attributes, too?
|
||||
|| attributes.allocation_group > int32(volume->AllocationGroups())
|
||||
|| attributes.allocation_group < 0
|
||||
|| attributes.start > (1L << volume->AllocationGroupShift()))
|
||||
|| attributes.AllocationGroup() > int32(volume->AllocationGroups())
|
||||
|| attributes.AllocationGroup() < 0
|
||||
|| attributes.Start() > (1L << volume->AllocationGroupShift()))
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
|
||||
// ToDo: Add some tests to check the integrity of the other stuff here,
|
||||
@@ -200,10 +201,10 @@ void
|
||||
Inode::Initialize()
|
||||
{
|
||||
char lockName[32];
|
||||
sprintf(lockName, "bfs inode %ld.%d", BlockRun().allocation_group, BlockRun().start);
|
||||
sprintf(lockName, "bfs inode %ld.%d", BlockRun().AllocationGroup(), BlockRun().Start());
|
||||
fLock.Initialize(lockName);
|
||||
|
||||
Node()->flags &= INODE_PERMANENT_FLAGS;
|
||||
Node()->flags &= HOST_ENDIAN_TO_BFS_INT32(INODE_PERMANENT_FLAGS);
|
||||
|
||||
// these two will help to maintain the indices
|
||||
fOldSize = Size();
|
||||
@@ -251,9 +252,9 @@ Inode::CheckPermissions(int accessMode) const
|
||||
|
||||
// shift mode bits, to check directly against accessMode
|
||||
mode_t mode = Mode();
|
||||
if (user == (uid_t)Node()->uid)
|
||||
if (user == (uid_t)Node()->UserID())
|
||||
mode >>= 6;
|
||||
else if (group == (gid_t)Node()->gid)
|
||||
else if (group == (gid_t)Node()->GroupID())
|
||||
mode >>= 3;
|
||||
|
||||
if (accessMode & ~(mode & S_IRWXO))
|
||||
@@ -327,11 +328,11 @@ Inode::MakeSpaceForSmallData(Transaction *transaction, const char *name, int32 b
|
||||
// Luckily, this doesn't cause any index updates
|
||||
|
||||
Inode *attribute;
|
||||
status_t status = CreateAttribute(transaction, item->Name(), item->type, &attribute);
|
||||
status_t status = CreateAttribute(transaction, item->Name(), item->Type(), &attribute);
|
||||
if (status < B_OK)
|
||||
RETURN_ERROR(status);
|
||||
|
||||
size_t length = item->data_size;
|
||||
size_t length = item->DataSize();
|
||||
status = attribute->WriteAt(transaction, 0, item->Data(), &length);
|
||||
|
||||
ReleaseAttribute(attribute);
|
||||
@@ -466,18 +467,18 @@ Inode::AddSmallData(Transaction *transaction, const char *name, uint32 type,
|
||||
// try to change the attributes value
|
||||
if (item->data_size > length
|
||||
|| force
|
||||
|| ((uint8 *)last + length - item->data_size) <= ((uint8 *)Node() + fVolume->InodeSize())) {
|
||||
|| ((uint8 *)last + length - item->DataSize()) <= ((uint8 *)Node() + fVolume->InodeSize())) {
|
||||
// make room for the new attribute if needed (and we are forced to do so)
|
||||
if (force
|
||||
&& ((uint8 *)last + length - item->data_size) > ((uint8 *)Node() + fVolume->InodeSize())) {
|
||||
&& ((uint8 *)last + length - item->DataSize()) > ((uint8 *)Node() + fVolume->InodeSize())) {
|
||||
// We also take the free space at the end of the small_data section
|
||||
// into account, and request only what's really needed
|
||||
uint32 needed = length - item->data_size -
|
||||
uint32 needed = length - item->DataSize() -
|
||||
(uint32)((uint8 *)Node() + fVolume->InodeSize() - (uint8 *)last);
|
||||
|
||||
if (MakeSpaceForSmallData(transaction, name, needed) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
|
||||
// reset our pointers
|
||||
item = Node()->small_data_start;
|
||||
index = 0;
|
||||
@@ -502,8 +503,8 @@ Inode::AddSmallData(Transaction *transaction, const char *name, uint32 type,
|
||||
if ((uint8 *)last < (uint8 *)Node() + fVolume->BlockSize())
|
||||
memset(last, 0, (uint8 *)Node() + fVolume->BlockSize() - (uint8 *)last);
|
||||
|
||||
item->type = type;
|
||||
item->data_size = length;
|
||||
item->type = HOST_ENDIAN_TO_BFS_INT32(type);
|
||||
item->data_size = HOST_ENDIAN_TO_BFS_INT16(length);
|
||||
memcpy(item->Data(), data, length);
|
||||
item->Data()[length] = '\0';
|
||||
|
||||
@@ -539,9 +540,9 @@ Inode::AddSmallData(Transaction *transaction, const char *name, uint32 type,
|
||||
}
|
||||
|
||||
memset(item, 0, spaceNeeded);
|
||||
item->type = type;
|
||||
item->name_size = nameLength;
|
||||
item->data_size = length;
|
||||
item->type = HOST_ENDIAN_TO_BFS_INT32(type);
|
||||
item->name_size = HOST_ENDIAN_TO_BFS_INT16(nameLength);
|
||||
item->data_size = HOST_ENDIAN_TO_BFS_INT16(length);
|
||||
strcpy(item->Name(), name);
|
||||
memcpy(item->Data(), data, length);
|
||||
|
||||
@@ -628,7 +629,7 @@ Inode::Name() const
|
||||
|
||||
small_data *smallData = NULL;
|
||||
while (GetNextSmallData(&smallData) == B_OK) {
|
||||
if (*smallData->Name() == FILE_NAME_NAME && smallData->name_size == FILE_NAME_NAME_LENGTH)
|
||||
if (*smallData->Name() == FILE_NAME_NAME && smallData->NameSize() == FILE_NAME_NAME_LENGTH)
|
||||
return (const char *)smallData->Data();
|
||||
}
|
||||
return NULL;
|
||||
@@ -694,8 +695,8 @@ Inode::ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer, siz
|
||||
*_length = 0;
|
||||
return B_OK;
|
||||
}
|
||||
if (length + pos > smallData->data_size)
|
||||
length = smallData->data_size - pos;
|
||||
if (length + pos > smallData->DataSize())
|
||||
length = smallData->DataSize() - pos;
|
||||
|
||||
memcpy(buffer, smallData->Data() + pos, length);
|
||||
*_length = length;
|
||||
@@ -749,7 +750,7 @@ Inode::WriteAttribute(Transaction *transaction, const char *name, int32 type, of
|
||||
|
||||
small_data *smallData = FindSmallData(name);
|
||||
if (smallData != NULL) {
|
||||
oldLength = smallData->data_size;
|
||||
oldLength = smallData->DataSize();
|
||||
if (oldLength > BPLUSTREE_MAX_KEY_LENGTH)
|
||||
oldLength = BPLUSTREE_MAX_KEY_LENGTH;
|
||||
memcpy(oldData = oldBuffer, smallData->Data(), oldLength);
|
||||
@@ -820,10 +821,10 @@ Inode::RemoveAttribute(Transaction *transaction, const char *name)
|
||||
|
||||
small_data *smallData = FindSmallData(name);
|
||||
if (smallData != NULL) {
|
||||
uint32 length = smallData->data_size;
|
||||
uint32 length = smallData->DataSize();
|
||||
if (length > BPLUSTREE_MAX_KEY_LENGTH)
|
||||
length = BPLUSTREE_MAX_KEY_LENGTH;
|
||||
index.Update(transaction, name, smallData->type, smallData->Data(), length, NULL, 0, this);
|
||||
index.Update(transaction, name, smallData->Type(), smallData->Data(), length, NULL, 0, this);
|
||||
}
|
||||
fSmallDataLock.Unlock();
|
||||
}
|
||||
@@ -857,7 +858,7 @@ Inode::RemoveAttribute(Transaction *transaction, const char *name)
|
||||
// remove attribute directory (don't fail if that can't be done)
|
||||
if (remove_vnode(fVolume->ID(), attributes->ID()) == B_OK) {
|
||||
// update the inode, so that no one will ever doubt it's deleted :-)
|
||||
attributes->Node()->flags |= INODE_DELETED;
|
||||
attributes->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_DELETED);
|
||||
if (attributes->WriteBack(transaction) == B_OK) {
|
||||
Attributes().SetTo(0, 0, 0);
|
||||
WriteBack(transaction);
|
||||
@@ -1103,12 +1104,12 @@ Inode::FillGapWithZeros(off_t pos, off_t newSize)
|
||||
|
||||
while (length > 0) {
|
||||
// offset is the offset to the current pos in the block_run
|
||||
run.start += (pos - offset) >> blockShift;
|
||||
run.length -= (pos - offset) >> blockShift;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
CachedBlock cached(fVolume);
|
||||
off_t blockNumber = fVolume->ToBlock(run);
|
||||
for (int32 i = 0; i < run.length; i++) {
|
||||
for (int32 i = 0; i < run.Length(); i++) {
|
||||
if ((block = cached.SetTo(blockNumber + i, true)) == NULL)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
@@ -1116,7 +1117,7 @@ Inode::FillGapWithZeros(off_t pos, off_t newSize)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
}
|
||||
|
||||
int32 bytes = run.length << blockShift;
|
||||
int32 bytes = run.Length() << blockShift;
|
||||
length -= bytes;
|
||||
bytesWritten += bytes;
|
||||
|
||||
@@ -1152,7 +1153,7 @@ Inode::AllocateBlockArray(Transaction *transaction, block_run &run)
|
||||
CachedBlock cached(fVolume);
|
||||
off_t block = fVolume->ToBlock(run);
|
||||
|
||||
for (int32 i = 0;i < run.length;i++) {
|
||||
for (int32 i = 0; i < run.Length(); i++) {
|
||||
block_run *runs = (block_run *)cached.SetTo(block + i, true);
|
||||
if (runs == NULL)
|
||||
return B_IO_ERROR;
|
||||
@@ -1171,26 +1172,26 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
|
||||
// is the data stream already large enough to hold the new size?
|
||||
// (can be the case with preallocated blocks)
|
||||
if (size < data->max_direct_range
|
||||
|| size < data->max_indirect_range
|
||||
|| size < data->max_double_indirect_range) {
|
||||
data->size = size;
|
||||
if (size < data->MaxDirectRange()
|
||||
|| size < data->MaxIndirectRange()
|
||||
|| size < data->MaxDoubleIndirectRange()) {
|
||||
data->size = HOST_ENDIAN_TO_BFS_INT64(size);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// how many bytes are still needed? (unused ranges are always zero)
|
||||
uint16 minimum = 1;
|
||||
off_t bytes;
|
||||
if (data->size < data->max_double_indirect_range) {
|
||||
bytes = size - data->max_double_indirect_range;
|
||||
if (data->Size() < data->MaxDoubleIndirectRange()) {
|
||||
bytes = size - data->MaxDoubleIndirectRange();
|
||||
// the double indirect range can only handle multiple of NUM_ARRAY_BLOCKS
|
||||
minimum = NUM_ARRAY_BLOCKS;
|
||||
} else if (data->size < data->max_indirect_range)
|
||||
bytes = size - data->max_indirect_range;
|
||||
else if (data->size < data->max_direct_range)
|
||||
bytes = size - data->max_direct_range;
|
||||
} else if (data->Size() < data->MaxIndirectRange())
|
||||
bytes = size - data->MaxIndirectRange();
|
||||
else if (data->Size() < data->MaxDirectRange())
|
||||
bytes = size - data->MaxDirectRange();
|
||||
else
|
||||
bytes = size - data->size;
|
||||
bytes = size - data->Size();
|
||||
|
||||
// do we have enough free blocks on the disk?
|
||||
off_t blocksRequested = (bytes + fVolume->BlockSize() - 1) >> fVolume->BlockShift();
|
||||
@@ -1221,7 +1222,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
// ToDo: if anything goes wrong here, we probably want to free the
|
||||
// blocks that couldn't be distributed into the stream!
|
||||
|
||||
blocksNeeded -= run.length;
|
||||
blocksNeeded -= run.Length();
|
||||
// don't preallocate if the first allocation was already too small
|
||||
blocksRequested = blocksNeeded;
|
||||
if (minimum > 1) {
|
||||
@@ -1231,10 +1232,10 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
|
||||
// Direct block range
|
||||
|
||||
if (data->size <= data->max_direct_range) {
|
||||
if (data->Size() <= data->MaxDirectRange()) {
|
||||
// let's try to put them into the direct block range
|
||||
int32 free = 0;
|
||||
for (;free < NUM_DIRECT_BLOCKS;free++)
|
||||
for (; free < NUM_DIRECT_BLOCKS; free++)
|
||||
if (data->direct[free].IsZero())
|
||||
break;
|
||||
|
||||
@@ -1242,19 +1243,19 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
// can we merge the last allocated run with the new one?
|
||||
int32 last = free - 1;
|
||||
if (free > 0 && data->direct[last].MergeableWith(run))
|
||||
data->direct[last].length += run.length;
|
||||
data->direct[last].length = HOST_ENDIAN_TO_BFS_INT16(data->direct[last].Length() + run.Length());
|
||||
else
|
||||
data->direct[free] = run;
|
||||
|
||||
data->max_direct_range += run.length * fVolume->BlockSize();
|
||||
data->size = blocksNeeded > 0 ? data->max_direct_range : size;
|
||||
data->max_direct_range = HOST_ENDIAN_TO_BFS_INT64(data->MaxDirectRange() + run.Length() * fVolume->BlockSize());
|
||||
data->size = HOST_ENDIAN_TO_BFS_INT64(blocksNeeded > 0 ? data->max_direct_range : size);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Indirect block range
|
||||
|
||||
if (data->size <= data->max_indirect_range || !data->max_indirect_range) {
|
||||
if (data->Size() <= data->MaxIndirectRange() || !data->MaxIndirectRange()) {
|
||||
CachedBlock cached(fVolume);
|
||||
block_run *runs = NULL;
|
||||
uint32 free = 0;
|
||||
@@ -1266,7 +1267,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
data->max_indirect_range = data->max_direct_range;
|
||||
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(data->MaxDirectRange());
|
||||
// insert the block_run in the first block
|
||||
runs = (block_run *)cached.SetTo(data->indirect);
|
||||
} else {
|
||||
@@ -1275,7 +1276,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
|
||||
// search first empty entry
|
||||
int32 i = 0;
|
||||
for (; i < data->indirect.length; i++) {
|
||||
for (; i < data->indirect.Length(); i++) {
|
||||
if ((runs = (block_run *)cached.SetTo(block + i)) == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@@ -1286,7 +1287,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
if (free < numberOfRuns)
|
||||
break;
|
||||
}
|
||||
if (i == data->indirect.length)
|
||||
if (i == data->indirect.Length())
|
||||
runs = NULL;
|
||||
}
|
||||
|
||||
@@ -1295,12 +1296,12 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
// take block borders into account, so it could be further optimized
|
||||
int32 last = free - 1;
|
||||
if (free > 0 && runs[last].MergeableWith(run))
|
||||
runs[last].length += run.length;
|
||||
runs[last].length = HOST_ENDIAN_TO_BFS_INT16(runs[last].Length() + run.Length());
|
||||
else
|
||||
runs[free] = run;
|
||||
|
||||
data->max_indirect_range += run.length << fVolume->BlockShift();
|
||||
data->size = blocksNeeded > 0 ? data->max_indirect_range : size;
|
||||
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(data->MaxIndirectRange() + (run.Length() << fVolume->BlockShift()));
|
||||
data->size = HOST_ENDIAN_TO_BFS_INT64(blocksNeeded > 0 ? data->MaxIndirectRange() : size);
|
||||
|
||||
cached.WriteBack(transaction);
|
||||
continue;
|
||||
@@ -1309,18 +1310,18 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
|
||||
// Double indirect block range
|
||||
|
||||
if (data->size <= data->max_double_indirect_range || !data->max_double_indirect_range) {
|
||||
while ((run.length % NUM_ARRAY_BLOCKS) != 0) {
|
||||
if (data->Size() <= data->MaxDoubleIndirectRange() || !data->max_double_indirect_range) {
|
||||
while ((run.Length() % NUM_ARRAY_BLOCKS) != 0) {
|
||||
// The number of allocated blocks isn't a multiple of NUM_ARRAY_BLOCKS,
|
||||
// so we have to change this. This can happen the first time the stream
|
||||
// grows into the double indirect range.
|
||||
// First, free the remaining blocks that don't fit into a multiple
|
||||
// of NUM_ARRAY_BLOCKS
|
||||
int32 rest = run.length % NUM_ARRAY_BLOCKS;
|
||||
run.length -= rest;
|
||||
int32 rest = run.Length() % NUM_ARRAY_BLOCKS;
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - rest);
|
||||
|
||||
status = fVolume->Free(transaction, block_run::Run(run.allocation_group,
|
||||
run.start + run.length, rest));
|
||||
status = fVolume->Free(transaction, block_run::Run(run.AllocationGroup(),
|
||||
run.Start() + run.Length(), rest));
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
@@ -1352,7 +1353,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
int32 directSize = NUM_ARRAY_BLOCKS << fVolume->BlockShift();
|
||||
int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT;
|
||||
|
||||
off_t start = data->max_double_indirect_range - data->max_indirect_range;
|
||||
off_t start = data->MaxDoubleIndirectRange() - data->MaxIndirectRange();
|
||||
int32 indirectIndex = start / indirectSize;
|
||||
int32 index = start / directSize;
|
||||
|
||||
@@ -1362,7 +1363,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
CachedBlock cached(fVolume);
|
||||
CachedBlock cachedDirect(fVolume);
|
||||
block_run *array = NULL;
|
||||
uint32 runLength = run.length;
|
||||
uint32 runLength = run.Length();
|
||||
|
||||
// ToDo: the following code is commented - it could be used to
|
||||
// preallocate all needed block arrays to see in advance if the
|
||||
@@ -1394,15 +1395,15 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
}
|
||||
*/
|
||||
|
||||
while (run.length) {
|
||||
while (run.length != 0) {
|
||||
// get the indirect array block
|
||||
if (array == NULL) {
|
||||
if (cached.Block() != NULL
|
||||
&& cached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
array = (block_run *)cached.SetTo(fVolume->ToBlock(data->double_indirect) +
|
||||
indirectIndex / runsPerBlock);
|
||||
array = (block_run *)cached.SetTo(fVolume->ToBlock(data->double_indirect)
|
||||
+ indirectIndex / runsPerBlock);
|
||||
if (array == NULL)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
@@ -1424,11 +1425,11 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
do {
|
||||
// insert the block_run into the array
|
||||
runs[index % runsPerBlock] = run;
|
||||
runs[index % runsPerBlock].length = NUM_ARRAY_BLOCKS;
|
||||
runs[index % runsPerBlock].length = HOST_ENDIAN_TO_BFS_INT16(NUM_ARRAY_BLOCKS);
|
||||
|
||||
// alter the remaining block_run
|
||||
run.start += NUM_ARRAY_BLOCKS;
|
||||
run.length -= NUM_ARRAY_BLOCKS;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + NUM_ARRAY_BLOCKS);
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - NUM_ARRAY_BLOCKS);
|
||||
} while ((++index % runsPerBlock) != 0 && run.length);
|
||||
|
||||
if (cachedDirect.WriteBack(transaction) < B_OK)
|
||||
@@ -1441,8 +1442,8 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
}
|
||||
}
|
||||
|
||||
data->max_double_indirect_range += runLength << fVolume->BlockShift();
|
||||
data->size = blocksNeeded > 0 ? data->max_double_indirect_range : size;
|
||||
data->max_double_indirect_range = HOST_ENDIAN_TO_BFS_INT64(data->MaxDoubleIndirectRange() + (runLength << fVolume->BlockShift()));
|
||||
data->size = blocksNeeded > 0 ? HOST_ENDIAN_TO_BFS_INT64(data->max_double_indirect_range) : size;
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -1450,7 +1451,7 @@ Inode::GrowStream(Transaction *transaction, off_t size)
|
||||
RETURN_ERROR(EFBIG);
|
||||
}
|
||||
// update the size of the data stream
|
||||
data->size = size;
|
||||
data->size = HOST_ENDIAN_TO_BFS_INT64(size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -1482,7 +1483,7 @@ Inode::FreeStaticStreamArray(Transaction *transaction, int32 level, block_run ru
|
||||
// set the file offset to the current block run
|
||||
offset += (off_t)index * indirectSize;
|
||||
|
||||
for (int32 i = index / runsPerBlock; i < run.length; i++) {
|
||||
for (int32 i = index / runsPerBlock; i < run.Length(); i++) {
|
||||
block_run *array = (block_run *)cached.SetTo(blockNumber + i);
|
||||
if (array == NULL)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
@@ -1490,7 +1491,7 @@ Inode::FreeStaticStreamArray(Transaction *transaction, int32 level, block_run ru
|
||||
for (index = index % runsPerBlock; index < runsPerBlock; index++) {
|
||||
if (array[index].IsZero()) {
|
||||
// we also want to break out of the outer loop
|
||||
i = run.length;
|
||||
i = run.Length();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1500,7 +1501,7 @@ Inode::FreeStaticStreamArray(Transaction *transaction, int32 level, block_run ru
|
||||
else if (offset >= size)
|
||||
status = fVolume->Free(transaction, array[index]);
|
||||
else
|
||||
max = offset + indirectSize;
|
||||
max = HOST_ENDIAN_TO_BFS_INT64(offset + indirectSize);
|
||||
|
||||
if (status < B_OK)
|
||||
RETURN_ERROR(status);
|
||||
@@ -1523,6 +1524,7 @@ Inode::FreeStaticStreamArray(Transaction *transaction, int32 level, block_run ru
|
||||
* "offset" and "max" are maintained until the last block_run that doesn't
|
||||
* have to be freed - after this, the values won't be correct anymore, but
|
||||
* will still assure correct function for all subsequent calls.
|
||||
* "max" is considered to be in file system byte order.
|
||||
*/
|
||||
|
||||
status_t
|
||||
@@ -1535,7 +1537,7 @@ Inode::FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayL
|
||||
if (array[i].IsZero())
|
||||
break;
|
||||
|
||||
newOffset += (off_t)array[i].length << fVolume->BlockShift();
|
||||
newOffset += (off_t)array[i].Length() << fVolume->BlockShift();
|
||||
if (newOffset <= size)
|
||||
continue;
|
||||
|
||||
@@ -1545,20 +1547,20 @@ Inode::FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayL
|
||||
if (newOffset > size && offset < size) {
|
||||
// free partial block_run (and update the original block_run)
|
||||
run.start = array[i].start + ((size - offset) >> fVolume->BlockShift()) + 1;
|
||||
array[i].length = run.start - array[i].start;
|
||||
run.length -= array[i].length;
|
||||
array[i].length = HOST_ENDIAN_TO_BFS_INT16(run.Start() - array[i].Start());
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - array[i].Length());
|
||||
|
||||
if (run.length == 0)
|
||||
continue;
|
||||
|
||||
// update maximum range
|
||||
max = offset + ((off_t)array[i].length << fVolume->BlockShift());
|
||||
max = HOST_ENDIAN_TO_BFS_INT64(offset + ((off_t)array[i].Length() << fVolume->BlockShift()));
|
||||
} else {
|
||||
// free the whole block_run
|
||||
array[i].SetTo(0, 0, 0);
|
||||
|
||||
if (max > offset)
|
||||
max = offset;
|
||||
if ((off_t)BFS_ENDIAN_TO_HOST_INT64(max) > offset)
|
||||
max = HOST_ENDIAN_TO_BFS_INT64(offset);
|
||||
}
|
||||
|
||||
if (fVolume->Free(transaction, run) < B_OK)
|
||||
@@ -1573,22 +1575,22 @@ Inode::ShrinkStream(Transaction *transaction, off_t size)
|
||||
{
|
||||
data_stream *data = &Node()->data;
|
||||
|
||||
if (data->max_double_indirect_range > size) {
|
||||
if (data->MaxDoubleIndirectRange() > size) {
|
||||
FreeStaticStreamArray(transaction, 0, data->double_indirect, size,
|
||||
data->max_indirect_range, data->max_double_indirect_range);
|
||||
data->MaxIndirectRange(), data->max_double_indirect_range);
|
||||
|
||||
if (size <= data->max_indirect_range) {
|
||||
if (size <= data->MaxIndirectRange()) {
|
||||
fVolume->Free(transaction, data->double_indirect);
|
||||
data->double_indirect.SetTo(0, 0, 0);
|
||||
data->max_double_indirect_range = 0;
|
||||
}
|
||||
}
|
||||
if (data->max_indirect_range > size) {
|
||||
if (data->MaxIndirectRange() > size) {
|
||||
CachedBlock cached(fVolume);
|
||||
off_t block = fVolume->ToBlock(data->indirect);
|
||||
off_t offset = data->max_direct_range;
|
||||
off_t offset = data->MaxDirectRange();
|
||||
|
||||
for (int32 i = 0; i < data->indirect.length; i++) {
|
||||
for (int32 i = 0; i < data->indirect.Length(); i++) {
|
||||
block_run *array = (block_run *)cached.SetTo(block + i);
|
||||
if (array == NULL)
|
||||
break;
|
||||
@@ -1603,13 +1605,13 @@ Inode::ShrinkStream(Transaction *transaction, off_t size)
|
||||
data->max_indirect_range = 0;
|
||||
}
|
||||
}
|
||||
if (data->max_direct_range > size) {
|
||||
if (data->MaxDirectRange() > size) {
|
||||
off_t offset = 0;
|
||||
FreeStreamArray(transaction, data->direct, NUM_DIRECT_BLOCKS, size, offset,
|
||||
data->max_direct_range);
|
||||
}
|
||||
|
||||
data->size = size;
|
||||
data->size = HOST_ENDIAN_TO_BFS_INT64(size);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1624,7 +1626,7 @@ Inode::SetFileSize(Transaction *transaction, off_t size)
|
||||
|| Flags() & INODE_NO_CACHE)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
off_t oldSize = Node()->data.size;
|
||||
off_t oldSize = Size();
|
||||
|
||||
if (size == oldSize)
|
||||
return B_OK;
|
||||
@@ -1709,12 +1711,12 @@ Inode::Sync()
|
||||
|
||||
// flush direct range
|
||||
|
||||
for (int32 i = 0;i < NUM_DIRECT_BLOCKS;i++) {
|
||||
for (int32 i = 0; i < NUM_DIRECT_BLOCKS; i++) {
|
||||
if (data->direct[i].IsZero())
|
||||
return B_OK;
|
||||
|
||||
|
||||
status = flush_blocks(fVolume->Device(), fVolume->ToBlock(data->direct[i]),
|
||||
data->direct[i].length);
|
||||
data->direct[i].Length());
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
@@ -1728,7 +1730,7 @@ Inode::Sync()
|
||||
off_t block = fVolume->ToBlock(data->indirect);
|
||||
int32 count = fVolume->BlockSize() / sizeof(block_run);
|
||||
|
||||
for (int32 j = 0; j < data->indirect.length; j++) {
|
||||
for (int32 j = 0; j < data->indirect.Length(); j++) {
|
||||
block_run *runs = (block_run *)cached.SetTo(block + j);
|
||||
if (runs == NULL)
|
||||
break;
|
||||
@@ -1737,7 +1739,7 @@ Inode::Sync()
|
||||
if (runs[i].IsZero())
|
||||
return B_OK;
|
||||
|
||||
status = flush_blocks(fVolume->Device(), fVolume->ToBlock(runs[i]), runs[i].length);
|
||||
status = flush_blocks(fVolume->Device(), fVolume->ToBlock(runs[i]), runs[i].Length());
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
@@ -1750,7 +1752,7 @@ Inode::Sync()
|
||||
|
||||
off_t indirectBlock = fVolume->ToBlock(data->double_indirect);
|
||||
|
||||
for (int32 l = 0; l < data->double_indirect.length; l++) {
|
||||
for (int32 l = 0; l < data->double_indirect.Length(); l++) {
|
||||
block_run *indirectRuns = (block_run *)cached.SetTo(indirectBlock + l);
|
||||
if (indirectRuns == NULL)
|
||||
return B_FILE_ERROR;
|
||||
@@ -1762,7 +1764,7 @@ Inode::Sync()
|
||||
return B_OK;
|
||||
|
||||
block = fVolume->ToBlock(indirectRuns[k]);
|
||||
for (int32 j = 0; j < indirectRuns[k].length; j++) {
|
||||
for (int32 j = 0; j < indirectRuns[k].Length(); j++) {
|
||||
block_run *runs = (block_run *)directCached.SetTo(block + j);
|
||||
if (runs == NULL)
|
||||
return B_FILE_ERROR;
|
||||
@@ -1774,7 +1776,7 @@ Inode::Sync()
|
||||
// ToDo: combine single block_runs to bigger ones when
|
||||
// they are adjacent
|
||||
status = flush_blocks(fVolume->Device(), fVolume->ToBlock(runs[i]),
|
||||
runs[i].length);
|
||||
runs[i].Length());
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
@@ -1840,7 +1842,7 @@ Inode::Remove(Transaction *transaction, const char *name, off_t *_id, bool isDir
|
||||
}
|
||||
|
||||
// update the inode, so that no one will ever doubt it's deleted :-)
|
||||
inode->Node()->flags |= INODE_DELETED;
|
||||
inode->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_DELETED);
|
||||
|
||||
// In balance to the Inode::Create() method, the main indices
|
||||
// are updated here (name, size, & last_modified)
|
||||
@@ -1957,11 +1959,11 @@ Inode::Create(Transaction *transaction, Inode *parent, const char *name, int32 m
|
||||
|
||||
node->parent = parentRun;
|
||||
|
||||
node->uid = geteuid();
|
||||
node->gid = parent ? parent->Node()->gid : getegid();
|
||||
node->uid = HOST_ENDIAN_TO_BFS_INT32(geteuid());
|
||||
node->gid = HOST_ENDIAN_TO_BFS_INT32(parent ? parent->Node()->gid : getegid());
|
||||
// the group ID is inherited from the parent, if available
|
||||
|
||||
node->type = type;
|
||||
node->type = HOST_ENDIAN_TO_BFS_INT32(type);
|
||||
|
||||
// only add the name to regular files, directories, or symlinks
|
||||
// don't add it to attributes, or indices
|
||||
@@ -2098,7 +2100,7 @@ AttributeIterator::GetNext(char *name, size_t *_length, uint32 *_type, vnode_id
|
||||
if (item->IsLast(fInode->Node()))
|
||||
break;
|
||||
|
||||
if (item->name_size == FILE_NAME_NAME_LENGTH
|
||||
if (item->NameSize() == FILE_NAME_NAME_LENGTH
|
||||
&& *item->Name() == FILE_NAME_NAME)
|
||||
continue;
|
||||
|
||||
@@ -2108,8 +2110,8 @@ AttributeIterator::GetNext(char *name, size_t *_length, uint32 *_type, vnode_id
|
||||
|
||||
if (!item->IsLast(fInode->Node())) {
|
||||
strncpy(name, item->Name(), B_FILE_NAME_LENGTH);
|
||||
*_type = item->type;
|
||||
*_length = item->name_size;
|
||||
*_type = item->Type();
|
||||
*_length = item->NameSize();
|
||||
*_id = (vnode_id)fCurrentSmallData;
|
||||
|
||||
fCurrentSmallData = i;
|
||||
@@ -2158,8 +2160,8 @@ AttributeIterator::GetNext(char *name, size_t *_length, uint32 *_type, vnode_id
|
||||
Vnode vnode(volume,id);
|
||||
Inode *attribute;
|
||||
if ((status = vnode.Get(&attribute)) == B_OK) {
|
||||
*_type = attribute->Node()->type;
|
||||
*_length = attribute->Node()->data.size;
|
||||
*_type = attribute->Type();
|
||||
*_length = attribute->Size();
|
||||
*_id = id;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,9 +97,9 @@ class Inode : public CachedBlock {
|
||||
ReadWriteLock &Lock() { return fLock; }
|
||||
SimpleLock &SmallDataLock() { return fSmallDataLock; }
|
||||
|
||||
mode_t Mode() const { return Node()->mode; }
|
||||
uint32 Type() const { return Node()->type; }
|
||||
int32 Flags() const { return Node()->flags; }
|
||||
mode_t Mode() const { return Node()->Mode(); }
|
||||
uint32 Type() const { return Node()->Type(); }
|
||||
int32 Flags() const { return Node()->Flags(); }
|
||||
bool IsContainer() const { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); }
|
||||
// note, that this test will also be true for S_IFBLK (not that it's used in the fs :)
|
||||
bool IsDirectory() const { return (Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY; }
|
||||
@@ -114,7 +114,7 @@ class Inode : public CachedBlock {
|
||||
bool HasUserAccessableStream() const { return S_ISREG(Mode()); }
|
||||
// currently only files can be accessed with bfs_read()/bfs_write()
|
||||
|
||||
off_t Size() const { return Node()->data.size; }
|
||||
off_t Size() const { return Node()->data.Size(); }
|
||||
off_t LastModified() const { return Node()->last_modified_time; }
|
||||
|
||||
block_run &BlockRun() const { return Node()->inode_num; }
|
||||
@@ -173,7 +173,7 @@ class Inode : public CachedBlock {
|
||||
|
||||
// index maintaining helper
|
||||
void UpdateOldSize() { fOldSize = Size(); }
|
||||
void UpdateOldLastModified() { fOldLastModified = Node()->last_modified_time; }
|
||||
void UpdateOldLastModified() { fOldLastModified = Node()->LastModifiedTime(); }
|
||||
off_t OldSize() { return fOldSize; }
|
||||
off_t OldLastModified() { return fOldLastModified; }
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ oldOPTIM = $(OPTIM) ;
|
||||
{
|
||||
local defines =
|
||||
KEEP_WRONG_DIRENT_RECLEN
|
||||
#BFS_BIG_ENDIAN_ONLY
|
||||
;
|
||||
|
||||
if $(COMPILE_FOR_R5) {
|
||||
|
||||
@@ -146,14 +146,14 @@ Uncached::WriteBack(Transaction *transaction)
|
||||
status_t
|
||||
Uncached::Read(Volume *volume, block_run run, uint8 *buffer)
|
||||
{
|
||||
return read_pos(volume->Device(), volume->ToBlock(run) << volume->BlockShift(), buffer, run.length << volume->BlockShift());
|
||||
return read_pos(volume->Device(), volume->ToBlock(run) << volume->BlockShift(), buffer, run.Length() << volume->BlockShift());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Uncached::Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer)
|
||||
{
|
||||
return write_pos(volume->Device(), volume->ToBlock(run) << volume->BlockShift(), buffer, run.length << volume->BlockShift());
|
||||
return write_pos(volume->Device(), volume->ToBlock(run) << volume->BlockShift(), buffer, run.Length() << volume->BlockShift());
|
||||
}
|
||||
|
||||
|
||||
@@ -191,14 +191,14 @@ Cached::WriteBack(Transaction *transaction)
|
||||
status_t
|
||||
Cached::Read(Volume *volume, block_run run, uint8 *buffer)
|
||||
{
|
||||
return cached_read(volume->Device(), volume->ToBlock(run), buffer, run.length, volume->BlockSize());
|
||||
return cached_read(volume->Device(), volume->ToBlock(run), buffer, run.Length(), volume->BlockSize());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Cached::Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer)
|
||||
{
|
||||
return volume->WriteBlocks(volume->ToBlock(run), buffer, run.length);
|
||||
return volume->WriteBlocks(volume->ToBlock(run), buffer, run.Length());
|
||||
}
|
||||
|
||||
|
||||
@@ -226,14 +226,14 @@ Logged::Logged(Volume *volume, block_run run, bool empty = false)
|
||||
status_t
|
||||
Logged::Read(Volume *volume, block_run run, uint8 *buffer)
|
||||
{
|
||||
return cached_read(volume->Device(), volume->ToBlock(run), buffer, run.length, volume->BlockSize());
|
||||
return cached_read(volume->Device(), volume->ToBlock(run), buffer, run.Length(), volume->BlockSize());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Logged::Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer)
|
||||
{
|
||||
return transaction->WriteBlocks(volume->ToBlock(run), buffer, run.length);
|
||||
return transaction->WriteBlocks(volume->ToBlock(run), buffer, run.Length());
|
||||
}
|
||||
|
||||
}; // namespace Access
|
||||
@@ -271,13 +271,13 @@ Stream<Cache>::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||
|
||||
// find matching block run
|
||||
|
||||
if (data->max_direct_range > 0 && pos >= data->max_direct_range) {
|
||||
if (data->max_double_indirect_range > 0 && pos >= data->max_indirect_range) {
|
||||
if (data->MaxDirectRange() > 0 && pos >= data->MaxDirectRange()) {
|
||||
if (data->MaxDoubleIndirectRange() > 0 && pos >= data->MaxIndirectRange()) {
|
||||
// access to double indirect blocks
|
||||
|
||||
Cache cached(fVolume);
|
||||
|
||||
off_t start = pos - data->max_indirect_range;
|
||||
off_t start = pos - data->MaxIndirectRange();
|
||||
int32 indirectSize = (1L << (INDIRECT_BLOCKS_SHIFT + cached.BlockShift()))
|
||||
* (fVolume->BlockSize() / sizeof(block_run));
|
||||
int32 directSize = NUM_ARRAY_BLOCKS << cached.BlockShift();
|
||||
@@ -300,18 +300,18 @@ Stream<Cache>::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
run = indirect[current % runsPerBlock];
|
||||
offset = data->max_indirect_range + (index * indirectSize) + (current * directSize);
|
||||
offset = data->MaxIndirectRange() + (index * indirectSize) + (current * directSize);
|
||||
//printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
|
||||
} else {
|
||||
// access to indirect blocks
|
||||
|
||||
int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
|
||||
off_t runBlockEnd = data->max_direct_range;
|
||||
off_t runBlockEnd = data->MaxDirectRange();
|
||||
|
||||
Cache cached(fVolume);
|
||||
off_t block = fVolume->ToBlock(data->indirect);
|
||||
|
||||
for (int32 i = 0;i < data->indirect.length;i++) {
|
||||
for (int32 i = 0; i < data->indirect.Length(); i++) {
|
||||
block_run *indirect = (block_run *)cached.SetTo(block + i);
|
||||
if (indirect == NULL)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
@@ -321,12 +321,12 @@ Stream<Cache>::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||
if (indirect[current].IsZero())
|
||||
break;
|
||||
|
||||
runBlockEnd += indirect[current].length << cached.BlockShift();
|
||||
runBlockEnd += indirect[current].Length() << cached.BlockShift();
|
||||
if (runBlockEnd > pos) {
|
||||
run = indirect[current];
|
||||
offset = runBlockEnd - (run.length << cached.BlockShift());
|
||||
offset = runBlockEnd - (run.Length() << cached.BlockShift());
|
||||
//printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
|
||||
//printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
|
||||
//printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.Length(),fRunFileOffset);
|
||||
return fVolume->ValidateBlockRun(run);
|
||||
}
|
||||
}
|
||||
@@ -343,11 +343,11 @@ Stream<Cache>::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||
if (data->direct[current].IsZero())
|
||||
break;
|
||||
|
||||
runBlockEnd += data->direct[current].length << fVolume->BlockShift();
|
||||
runBlockEnd += data->direct[current].Length() << fVolume->BlockShift();
|
||||
if (runBlockEnd > pos) {
|
||||
run = data->direct[current];
|
||||
offset = runBlockEnd - (run.length << fVolume->BlockShift());
|
||||
//printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
|
||||
offset = runBlockEnd - (run.Length() << fVolume->BlockShift());
|
||||
//printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.Length(),fRunFileOffset);
|
||||
return fVolume->ValidateBlockRun(run);
|
||||
}
|
||||
}
|
||||
@@ -366,15 +366,15 @@ Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
|
||||
if (pos < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (pos >= Node()->data.size) {
|
||||
if (pos >= Node()->data.Size()) {
|
||||
*_length = 0;
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
size_t length = *_length;
|
||||
|
||||
if (pos + length > Node()->data.size)
|
||||
length = Node()->data.size - pos;
|
||||
if (pos + length > Node()->data.Size())
|
||||
length = Node()->data.Size() - pos;
|
||||
|
||||
block_run run;
|
||||
off_t offset;
|
||||
@@ -393,8 +393,8 @@ Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
|
||||
// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
|
||||
if (pos % blockSize != 0) {
|
||||
run.start += (pos - offset) / blockSize;
|
||||
run.length -= (pos - offset) / blockSize;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
Cache cached(fVolume,run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
@@ -429,10 +429,10 @@ Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
|
||||
while (length > 0) {
|
||||
// offset is the offset to the current pos in the block_run
|
||||
run.start += (pos - offset) >> blockShift;
|
||||
run.length -= (pos - offset) >> blockShift;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
if (uint32(run.length << blockShift) > length) {
|
||||
if (uint32(run.Length() << blockShift) > length) {
|
||||
if (length < blockSize) {
|
||||
Cache cached(fVolume, run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
@@ -443,7 +443,7 @@ Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
bytesRead += length;
|
||||
break;
|
||||
}
|
||||
run.length = length >> blockShift;
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(length >> blockShift);
|
||||
partial = true;
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
int32 bytes = run.length << blockShift;
|
||||
int32 bytes = run.Length() << blockShift;
|
||||
#ifdef DEBUG
|
||||
if ((uint32)bytes > length)
|
||||
DEBUGGER(("bytes greater than length"));
|
||||
@@ -467,8 +467,8 @@ Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
if (partial) {
|
||||
// if the last block was read only partially, point block_run
|
||||
// to the remaining part
|
||||
run.start += run.length;
|
||||
run.length = 1;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + run.Length());
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||
offset = pos;
|
||||
} else if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
@@ -490,7 +490,7 @@ Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer,
|
||||
// set/check boundaries for pos/length
|
||||
if (pos < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (pos + length > Node()->data.size) {
|
||||
if (pos + length > Size()) {
|
||||
off_t oldSize = Size();
|
||||
|
||||
// uncached files can't be resized (Inode::SetFileSize() also
|
||||
@@ -539,8 +539,8 @@ Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer,
|
||||
|
||||
// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
|
||||
if (pos % blockSize != 0) {
|
||||
run.start += (pos - offset) / blockSize;
|
||||
run.length -= (pos - offset) / blockSize;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
Cache cached(fVolume, run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
@@ -578,10 +578,10 @@ Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer,
|
||||
|
||||
while (length > 0) {
|
||||
// offset is the offset to the current pos in the block_run
|
||||
run.start += (pos - offset) >> blockShift;
|
||||
run.length -= (pos - offset) >> blockShift;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
if (uint32(run.length << blockShift) > length) {
|
||||
if (uint32(run.Length() << blockShift) > length) {
|
||||
if (length < blockSize) {
|
||||
Cache cached(fVolume,run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
@@ -595,7 +595,7 @@ Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer,
|
||||
bytesWritten += length;
|
||||
break;
|
||||
}
|
||||
run.length = length >> blockShift;
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(length >> blockShift);
|
||||
partial = true;
|
||||
}
|
||||
|
||||
@@ -604,7 +604,7 @@ Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer,
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
int32 bytes = run.length << blockShift;
|
||||
int32 bytes = run.Length() << blockShift;
|
||||
length -= bytes;
|
||||
bytesWritten += bytes;
|
||||
if (length == 0)
|
||||
@@ -615,8 +615,8 @@ Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer,
|
||||
if (partial) {
|
||||
// if the last block was written only partially, point block_run
|
||||
// to the remaining part
|
||||
run.start += run.length;
|
||||
run.length = 1;
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + run.Length());
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||
offset = pos;
|
||||
} else if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesWritten;
|
||||
|
||||
@@ -41,17 +41,18 @@ Volume::~Volume()
|
||||
bool
|
||||
Volume::IsValidSuperBlock()
|
||||
{
|
||||
if (fSuperBlock.magic1 != (int32)SUPER_BLOCK_MAGIC1
|
||||
|| fSuperBlock.magic2 != (int32)SUPER_BLOCK_MAGIC2
|
||||
|| fSuperBlock.magic3 != (int32)SUPER_BLOCK_MAGIC3
|
||||
if (fSuperBlock.Magic1() != (int32)SUPER_BLOCK_MAGIC1
|
||||
|| fSuperBlock.Magic2() != (int32)SUPER_BLOCK_MAGIC2
|
||||
|| fSuperBlock.Magic3() != (int32)SUPER_BLOCK_MAGIC3
|
||||
|| (int32)fSuperBlock.block_size != fSuperBlock.inode_size
|
||||
|| fSuperBlock.fs_byte_order != SUPER_BLOCK_FS_LENDIAN
|
||||
|| (1UL << fSuperBlock.block_shift) != fSuperBlock.block_size
|
||||
|| fSuperBlock.num_ags < 1
|
||||
|| fSuperBlock.ag_shift < 1
|
||||
|| fSuperBlock.blocks_per_ag < 1
|
||||
|| fSuperBlock.num_blocks < 10
|
||||
|| fSuperBlock.num_ags != divide_roundup(fSuperBlock.num_blocks,1L << fSuperBlock.ag_shift))
|
||||
|| fSuperBlock.ByteOrder() != SUPER_BLOCK_FS_LENDIAN
|
||||
|| (1UL << fSuperBlock.BlockShift()) != fSuperBlock.BlockSize()
|
||||
|| fSuperBlock.AllocationGroups() < 1
|
||||
|| fSuperBlock.AllocationGroupShift() < 1
|
||||
|| fSuperBlock.BlocksPerAllocationGroup() < 1
|
||||
|| fSuperBlock.NumBlocks() < 10
|
||||
|| fSuperBlock.AllocationGroups() != divide_roundup(fSuperBlock.NumBlocks(),
|
||||
1L << fSuperBlock.AllocationGroupShift()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -77,8 +78,15 @@ Volume::Mount(const char *deviceName, uint32 flags)
|
||||
if (flags & B_MOUNT_READ_ONLY)
|
||||
fFlags |= VOLUME_READ_ONLY;
|
||||
|
||||
fDevice = open(deviceName,flags & B_MOUNT_READ_ONLY ? O_RDONLY : O_RDWR);
|
||||
|
||||
// ToDo: validate the FS in write mode as well!
|
||||
#if (B_HOST_IS_LENDIAN && defined(BFS_BIG_ENDIAN_ONLY)) \
|
||||
|| (B_HOST_IS_BENDIAN && defined(BFS_LITTLE_ENDIAN_ONLY))
|
||||
// in big endian mode, we only mount read-only for now
|
||||
flags |= B_MOUNT_READ_ONLY;
|
||||
#endif
|
||||
|
||||
fDevice = open(deviceName, flags & B_MOUNT_READ_ONLY ? O_RDONLY : O_RDWR);
|
||||
|
||||
// if we couldn't open the device, try read-only (don't rely on a specific error code)
|
||||
if (fDevice < B_OK && (flags & B_MOUNT_READ_ONLY) == 0) {
|
||||
fDevice = open(deviceName, O_RDONLY);
|
||||
@@ -116,11 +124,28 @@ Volume::Mount(const char *deviceName, uint32 flags)
|
||||
// Note: that does work only for x86, for PowerPC, the super block
|
||||
// is located at offset 0!
|
||||
memcpy(&fSuperBlock, buffer + 512, sizeof(disk_super_block));
|
||||
if (!IsValidSuperBlock()) {
|
||||
#ifndef BFS_LITTLE_ENDIAN_ONLY
|
||||
memcpy(&fSuperBlock, buffer, sizeof(disk_super_block));
|
||||
if (!IsValidSuperBlock()) {
|
||||
close(fDevice);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
#else
|
||||
close(fDevice);
|
||||
return B_BAD_VALUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsValidSuperBlock()) {
|
||||
// set the current log pointers, so that journaling will work correctly
|
||||
fLogStart = fSuperBlock.log_start;
|
||||
fLogEnd = fSuperBlock.log_end;
|
||||
fLogStart = fSuperBlock.LogStart();
|
||||
fLogEnd = fSuperBlock.LogEnd();
|
||||
|
||||
// initialize short hands to the super block (to save byte swapping)
|
||||
fBlockSize = fSuperBlock.BlockSize();
|
||||
fBlockShift = fSuperBlock.BlockShift();
|
||||
fAllocationGroupShift = fSuperBlock.AllocationGroupShift();
|
||||
|
||||
if (init_cache_for_device(fDevice, NumBlocks()) == B_OK) {
|
||||
fJournal = new Journal(this);
|
||||
@@ -130,7 +155,7 @@ Volume::Mount(const char *deviceName, uint32 flags)
|
||||
fRootNode = new Inode(this, ToVnode(Root()));
|
||||
|
||||
if (fRootNode && fRootNode->InitCheck() == B_OK) {
|
||||
if (new_vnode(fID, ToVnode(Root()),(void *)fRootNode) == B_OK) {
|
||||
if (new_vnode(fID, ToVnode(Root()), (void *)fRootNode) == B_OK) {
|
||||
// try to get indices root dir
|
||||
|
||||
// question: why doesn't get_vnode() work here??
|
||||
@@ -208,12 +233,12 @@ Volume::Sync()
|
||||
status_t
|
||||
Volume::ValidateBlockRun(block_run run)
|
||||
{
|
||||
if (run.allocation_group < 0 || run.allocation_group > (int32)AllocationGroups()
|
||||
|| run.start > (1UL << AllocationGroupShift())
|
||||
if (run.AllocationGroup() < 0 || run.AllocationGroup() > (int32)AllocationGroups()
|
||||
|| run.Start() > (1UL << AllocationGroupShift())
|
||||
|| run.length == 0
|
||||
|| uint32(run.length + run.start) > (1UL << AllocationGroupShift())) {
|
||||
|| uint32(run.Length() + run.Start()) > (1UL << AllocationGroupShift())) {
|
||||
Panic();
|
||||
FATAL(("*** invalid run(%ld,%d,%d)\n", run.allocation_group, run.start, run.length));
|
||||
FATAL(("*** invalid run(%ld,%d,%d)\n", run.AllocationGroup(), run.Start(), run.Length()));
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
return B_OK;
|
||||
@@ -224,9 +249,9 @@ block_run
|
||||
Volume::ToBlockRun(off_t block) const
|
||||
{
|
||||
block_run run;
|
||||
run.allocation_group = block >> fSuperBlock.ag_shift;
|
||||
run.start = block & ~((1LL << fSuperBlock.ag_shift) - 1);
|
||||
run.length = 1;
|
||||
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> AllocationGroupShift());
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(block & ~((1LL << AllocationGroupShift()) - 1));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||
return run;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,19 +57,19 @@ class Volume {
|
||||
nspace_id ID() const { return fID; }
|
||||
const char *Name() const { return fSuperBlock.name; }
|
||||
|
||||
off_t NumBlocks() const { return fSuperBlock.num_blocks; }
|
||||
off_t UsedBlocks() const { return fSuperBlock.used_blocks; }
|
||||
off_t FreeBlocks() const { return fSuperBlock.num_blocks - fSuperBlock.used_blocks; }
|
||||
off_t NumBlocks() const { return fSuperBlock.NumBlocks(); }
|
||||
off_t UsedBlocks() const { return fSuperBlock.UsedBlocks(); }
|
||||
off_t FreeBlocks() const { return NumBlocks() - UsedBlocks(); }
|
||||
|
||||
uint32 BlockSize() const { return fSuperBlock.block_size; }
|
||||
uint32 BlockShift() const { return fSuperBlock.block_shift; }
|
||||
uint32 InodeSize() const { return fSuperBlock.inode_size; }
|
||||
uint32 AllocationGroups() const { return fSuperBlock.num_ags; }
|
||||
uint32 AllocationGroupShift() const { return fSuperBlock.ag_shift; }
|
||||
uint32 BlockSize() const { return fBlockSize; }
|
||||
uint32 BlockShift() const { return fBlockShift; }
|
||||
uint32 InodeSize() const { return fSuperBlock.InodeSize(); }
|
||||
uint32 AllocationGroups() const { return fSuperBlock.AllocationGroups(); }
|
||||
uint32 AllocationGroupShift() const { return fAllocationGroupShift; }
|
||||
disk_super_block &SuperBlock() { return fSuperBlock; }
|
||||
|
||||
off_t ToOffset(block_run run) const { return ToBlock(run) << fSuperBlock.block_shift; }
|
||||
off_t ToBlock(block_run run) const { return ((((off_t)run.allocation_group) << fSuperBlock.ag_shift) | (off_t)run.start); }
|
||||
off_t ToOffset(block_run run) const { return ToBlock(run) << BlockShift(); }
|
||||
off_t ToBlock(block_run run) const { return ((((off_t)run.AllocationGroup()) << AllocationGroupShift()) | (off_t)run.Start()); }
|
||||
block_run ToBlockRun(off_t block) const;
|
||||
status_t ValidateBlockRun(block_run run);
|
||||
|
||||
@@ -114,6 +114,11 @@ class Volume {
|
||||
nspace_id fID;
|
||||
int fDevice;
|
||||
disk_super_block fSuperBlock;
|
||||
|
||||
uint32 fBlockSize;
|
||||
uint32 fBlockShift;
|
||||
uint32 fAllocationGroupShift;
|
||||
|
||||
BlockAllocator fBlockAllocator;
|
||||
RecursiveLock fLock;
|
||||
Journal *fJournal;
|
||||
|
||||
@@ -188,6 +188,8 @@ struct bfs_inode {
|
||||
int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
|
||||
int32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); }
|
||||
int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); }
|
||||
bigtime_t LastModifiedTime() const { return BFS_ENDIAN_TO_HOST_INT64(last_modified_time); }
|
||||
bigtime_t CreateTime() const { return BFS_ENDIAN_TO_HOST_INT64(create_time); }
|
||||
|
||||
status_t InitCheck(Volume *volume);
|
||||
// defined in Inode.cpp
|
||||
|
||||
@@ -539,11 +539,11 @@ bfs_walk(void *_ns, void *_directory, const char *file, char **_resolvedPath, vn
|
||||
// for the path, so we're not going to do that
|
||||
|
||||
if (inode->Flags() & INODE_LONG_SYMLINK) {
|
||||
size_t readBytes = inode->Node()->data.size;
|
||||
size_t readBytes = inode->Size();
|
||||
char *data = (char *)malloc(readBytes);
|
||||
if (data != NULL) {
|
||||
status = inode->ReadAt(0, (uint8 *)data, &readBytes);
|
||||
if (status == B_OK && readBytes == inode->Node()->data.size)
|
||||
if (status == B_OK && readBytes == inode->Size())
|
||||
status = new_path(data, &newPath);
|
||||
|
||||
free(data);
|
||||
@@ -597,7 +597,7 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, int cmd, void *buffer, size_t b
|
||||
// using the cache or allocating memory
|
||||
status_t status = volume->Pool().RequestBuffers(volume->BlockSize());
|
||||
if (status == B_OK)
|
||||
inode->Node()->flags |= INODE_NO_CACHE;
|
||||
inode->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_NO_CACHE);
|
||||
return status;
|
||||
}
|
||||
case IOCTL_CREATE_TIME:
|
||||
@@ -606,7 +606,7 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, int cmd, void *buffer, size_t b
|
||||
return B_BAD_VALUE;
|
||||
|
||||
off_t *creationTime = (off_t *)buffer;
|
||||
*creationTime = inode->Node()->create_time;
|
||||
*creationTime = inode->Node()->CreateTime();
|
||||
return B_OK;
|
||||
}
|
||||
case IOCTL_MODIFIED_TIME:
|
||||
@@ -633,7 +633,7 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, int cmd, void *buffer, size_t b
|
||||
|
||||
status_t status = allocator.StartChecking(control);
|
||||
if (status == B_OK && inode != NULL)
|
||||
inode->Node()->flags |= INODE_CHKBFS_RUNNING;
|
||||
inode->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_CHKBFS_RUNNING);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -645,7 +645,7 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, int cmd, void *buffer, size_t b
|
||||
|
||||
status_t status = allocator.StopChecking(control);
|
||||
if (status == B_OK && inode != NULL)
|
||||
inode->Node()->flags &= ~INODE_CHKBFS_RUNNING;
|
||||
inode->Node()->flags &= HOST_ENDIAN_TO_BFS_INT32(~INODE_CHKBFS_RUNNING);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -758,14 +758,14 @@ bfs_read_stat(void *_ns, void *_node, struct stat *st)
|
||||
st->st_nlink = 1;
|
||||
st->st_blksize = BFS_IO_SIZE;
|
||||
|
||||
st->st_uid = node->uid;
|
||||
st->st_gid = node->gid;
|
||||
st->st_mode = node->mode;
|
||||
st->st_size = node->data.size;
|
||||
st->st_uid = node->UserID();
|
||||
st->st_gid = node->GroupID();
|
||||
st->st_mode = node->Mode();
|
||||
st->st_size = node->data.Size();
|
||||
|
||||
st->st_atime = time(NULL);
|
||||
st->st_mtime = st->st_ctime = (time_t)(node->last_modified_time >> INODE_TIME_SHIFT);
|
||||
st->st_crtime = (time_t)(node->create_time >> INODE_TIME_SHIFT);
|
||||
st->st_mtime = st->st_ctime = (time_t)(node->LastModifiedTime() >> INODE_TIME_SHIFT);
|
||||
st->st_crtime = (time_t)(node->CreateTime() >> INODE_TIME_SHIFT);
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
@@ -931,7 +931,7 @@ bfs_symlink(void *_ns, void *_directory, const char *name, const char *path)
|
||||
strcpy(link->Node()->short_symlink, path);
|
||||
status = link->WriteBack(&transaction);
|
||||
} else {
|
||||
link->Node()->flags |= INODE_LONG_SYMLINK | INODE_LOGGED;
|
||||
link->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_LONG_SYMLINK | INODE_LOGGED);
|
||||
// The following call will have to write the inode back, so
|
||||
// we don't have to do that here...
|
||||
status = link->WriteAt(&transaction, 0, (const uint8 *)path, &length);
|
||||
@@ -1376,7 +1376,7 @@ bfs_free_cookie(void *_ns, void *_node, void *_cookie)
|
||||
|
||||
if (inode->Flags() & INODE_NO_CACHE) {
|
||||
volume->Pool().ReleaseBuffers();
|
||||
inode->Node()->flags &= ~INODE_NO_CACHE;
|
||||
inode->Node()->flags &= HOST_ENDIAN_TO_BFS_INT32(~INODE_NO_CACHE);
|
||||
// We don't need to save the inode, because INODE_NO_CACHE is a
|
||||
// non-permanent flag which will be removed when the inode is loaded
|
||||
// into memory.
|
||||
@@ -1758,8 +1758,8 @@ bfs_stat_attr(void *ns, void *_node, const char *name, struct attr_info *attrInf
|
||||
if (inode->SmallDataLock().Lock() == B_OK)
|
||||
{
|
||||
if ((smallData = inode->FindSmallData((const char *)name)) != NULL) {
|
||||
attrInfo->type = smallData->type;
|
||||
attrInfo->size = smallData->data_size;
|
||||
attrInfo->type = smallData->Type();
|
||||
attrInfo->size = smallData->DataSize();
|
||||
}
|
||||
inode->SmallDataLock().Unlock();
|
||||
}
|
||||
@@ -2004,11 +2004,11 @@ bfs_stat_index(void *_ns, const char *name, struct index_info *indexInfo)
|
||||
bfs_inode *node = index.Node()->Node();
|
||||
|
||||
indexInfo->type = index.Type();
|
||||
indexInfo->size = node->data.size;
|
||||
indexInfo->modification_time = (time_t)(node->last_modified_time >> INODE_TIME_SHIFT);
|
||||
indexInfo->creation_time = (time_t)(node->create_time >> INODE_TIME_SHIFT);
|
||||
indexInfo->uid = node->uid;
|
||||
indexInfo->gid = node->gid;
|
||||
indexInfo->size = node->data.Size();
|
||||
indexInfo->modification_time = (time_t)(node->LastModifiedTime() >> INODE_TIME_SHIFT);
|
||||
indexInfo->creation_time = (time_t)(node->CreateTime() >> INODE_TIME_SHIFT);
|
||||
indexInfo->uid = node->UserID();
|
||||
indexInfo->gid = node->GroupID();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user