* Coding style cleanups, no functional changes.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26728 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
|
|
||||||
// TODO: clean this up, find a better separation between Inode and this class
|
// TODO: clean this up, find a better separation between Inode and this class
|
||||||
// TODO: even after Create(), the attribute cannot be stat() for until the first write
|
// TODO: even after Create(), the attribute cannot be stat() for until the
|
||||||
|
// first write
|
||||||
|
|
||||||
|
|
||||||
extern void fill_stat_buffer(Inode* inode, struct stat& stat);
|
extern void fill_stat_buffer(Inode* inode, struct stat& stat);
|
||||||
@@ -203,8 +204,8 @@ Attribute::Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Attribute::Write(Transaction &transaction, attr_cookie *cookie,
|
Attribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos,
|
||||||
off_t pos, const uint8 *buffer, size_t *_length)
|
const uint8* buffer, size_t* _length)
|
||||||
{
|
{
|
||||||
if (!cookie->create && fSmall == NULL && fAttribute == NULL)
|
if (!cookie->create && fSmall == NULL && fAttribute == NULL)
|
||||||
return B_NO_INIT;
|
return B_NO_INIT;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* Attribute - connection between pure inode and kernel_interface attributes
|
/*
|
||||||
*
|
* Copyright 2004-2008, Axel Dörfler, [email protected].
|
||||||
* Copyright 2004, Axel Dörfler, [email protected].
|
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef ATTRIBUTE_H
|
#ifndef ATTRIBUTE_H
|
||||||
@@ -30,15 +29,18 @@ class Attribute {
|
|||||||
status_t Get(const char* name);
|
status_t Get(const char* name);
|
||||||
void Put();
|
void Put();
|
||||||
|
|
||||||
status_t Create(const char *name, type_code type, int openMode,
|
status_t Create(const char* name, type_code type,
|
||||||
|
int openMode, attr_cookie** _cookie);
|
||||||
|
status_t Open(const char* name, int openMode,
|
||||||
attr_cookie** _cookie);
|
attr_cookie** _cookie);
|
||||||
status_t Open(const char *name, int openMode, attr_cookie **_cookie);
|
|
||||||
|
|
||||||
status_t Stat(struct stat& stat);
|
status_t Stat(struct stat& stat);
|
||||||
|
|
||||||
status_t Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length);
|
status_t Read(attr_cookie* cookie, off_t pos, uint8* buffer,
|
||||||
|
size_t* _length);
|
||||||
status_t Write(Transaction& transaction, attr_cookie* cookie,
|
status_t Write(Transaction& transaction, attr_cookie* cookie,
|
||||||
off_t pos, const uint8 *buffer, size_t *_length);
|
off_t pos, const uint8* buffer,
|
||||||
|
size_t* _length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _Truncate();
|
status_t _Truncate();
|
||||||
@@ -50,4 +52,4 @@ class Attribute {
|
|||||||
const char* fName;
|
const char* fName;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ATTRIBUTE_H */
|
#endif // ATTRIBUTE_H
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ CachedNode::Unset()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (fNode != NULL) {
|
if (fNode != NULL) {
|
||||||
block_cache_put(fTree->fStream->GetVolume()->BlockCache(), fBlockNumber);
|
block_cache_put(fTree->fStream->GetVolume()->BlockCache(),
|
||||||
|
fBlockNumber);
|
||||||
fNode = NULL;
|
fNode = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,9 +226,10 @@ CachedNode::InternalSetTo(Transaction *transaction, off_t offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (block) {
|
if (block) {
|
||||||
// the node is somewhere in that block... (confusing offset calculation)
|
// The node is somewhere in that block...
|
||||||
fNode = (bplustree_node *)(block + offset -
|
// (confusing offset calculation)
|
||||||
(fileOffset + (blockOffset << volume->BlockShift())));
|
fNode = (bplustree_node*)(block + offset
|
||||||
|
- (fileOffset + (blockOffset << volume->BlockShift())));
|
||||||
} else
|
} else
|
||||||
REPORT_ERROR(B_IO_ERROR);
|
REPORT_ERROR(B_IO_ERROR);
|
||||||
}
|
}
|
||||||
@@ -246,7 +248,8 @@ CachedNode::Free(Transaction &transaction, off_t offset)
|
|||||||
// function is called, perhaps it should be done when the directory
|
// function is called, perhaps it should be done when the directory
|
||||||
// inode is closed or based on some calculation or whatever...
|
// inode is closed or based on some calculation or whatever...
|
||||||
|
|
||||||
bplustree_header *header = fTree->fCachedHeader.MakeWritableHeader(transaction);
|
bplustree_header* header
|
||||||
|
= fTree->fCachedHeader.MakeWritableHeader(transaction);
|
||||||
if (header == NULL)
|
if (header == NULL)
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
@@ -419,7 +422,8 @@ BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
|
|||||||
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
|
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
|
||||||
header->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode()));
|
header->data_type = HOST_ENDIAN_TO_BFS_INT32(ModeToKeyType(stream->Mode()));
|
||||||
header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize);
|
header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(nodeSize);
|
||||||
header->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
header->free_node_pointer
|
||||||
|
= HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||||
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
|
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
|
||||||
|
|
||||||
// initialize b+tree root node
|
// initialize b+tree root node
|
||||||
@@ -684,8 +688,7 @@ BPlusTree::_FindKey(const bplustree_node *node, const uint8 *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! Prepares the stack to contain all nodes that were passed while
|
||||||
Prepares the stack to contain all nodes that were passed while
|
|
||||||
following the key, from the root node to the leaf node that could
|
following the key, from the root node to the leaf node that could
|
||||||
or should contain that key.
|
or should contain that key.
|
||||||
*/
|
*/
|
||||||
@@ -733,8 +736,7 @@ BPlusTree::_SeekDown(Stack<node_and_key> &stack, const uint8 *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! This will find a free duplicate fragment in the given bplustree_node.
|
||||||
This will find a free duplicate fragment in the given bplustree_node.
|
|
||||||
The CachedNode will be set to the writable fragment on success.
|
The CachedNode will be set to the writable fragment on success.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
@@ -792,8 +794,10 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
// If it's a duplicate fragment, try to insert it into that, or if it
|
// If it's a duplicate fragment, try to insert it into that, or if it
|
||||||
// doesn't fit anymore, create a new duplicate node
|
// doesn't fit anymore, create a new duplicate node
|
||||||
|
|
||||||
if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) {
|
if (bplustree_node::LinkType(oldValue)
|
||||||
bplustree_node *duplicate = cachedDuplicate.SetToWritable(transaction,
|
== BPLUSTREE_DUPLICATE_FRAGMENT) {
|
||||||
|
bplustree_node* duplicate
|
||||||
|
= cachedDuplicate.SetToWritable(transaction,
|
||||||
bplustree_node::FragmentOffset(oldValue), false);
|
bplustree_node::FragmentOffset(oldValue), false);
|
||||||
if (duplicate == NULL)
|
if (duplicate == NULL)
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
@@ -802,19 +806,20 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
bplustree_node::FragmentIndex(oldValue));
|
bplustree_node::FragmentIndex(oldValue));
|
||||||
if (array->count > NUM_FRAGMENT_VALUES
|
if (array->count > NUM_FRAGMENT_VALUES
|
||||||
|| array->count < 1) {
|
|| array->count < 1) {
|
||||||
FATAL(("insertDuplicate: Invalid array[%d] size in fragment %Ld == %Ld!\n",
|
FATAL(("insertDuplicate: Invalid array[%d] size in fragment "
|
||||||
|
"%Ld == %Ld!\n",
|
||||||
(int)bplustree_node::FragmentIndex(oldValue),
|
(int)bplustree_node::FragmentIndex(oldValue),
|
||||||
bplustree_node::FragmentOffset(oldValue),
|
bplustree_node::FragmentOffset(oldValue), array->count));
|
||||||
array->count));
|
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array->count < NUM_FRAGMENT_VALUES) {
|
if (array->count < NUM_FRAGMENT_VALUES) {
|
||||||
array->Insert(value);
|
array->Insert(value);
|
||||||
} else {
|
} else {
|
||||||
// test if the fragment will be empty if we remove this key's values
|
// Test if the fragment will be empty if we remove this key's
|
||||||
|
// values
|
||||||
if (duplicate->FragmentsUsed(fNodeSize) < 2) {
|
if (duplicate->FragmentsUsed(fNodeSize) < 2) {
|
||||||
// the node will be empty without our values, so let us
|
// The node will be empty without our values, so let us
|
||||||
// reuse it as a duplicate node
|
// reuse it as a duplicate node
|
||||||
offset = bplustree_node::FragmentOffset(oldValue);
|
offset = bplustree_node::FragmentOffset(oldValue);
|
||||||
|
|
||||||
@@ -826,10 +831,11 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
array = duplicate->DuplicateArray();
|
array = duplicate->DuplicateArray();
|
||||||
array->Insert(value);
|
array->Insert(value);
|
||||||
} else {
|
} else {
|
||||||
// create a new duplicate node
|
// Create a new duplicate node
|
||||||
|
|
||||||
cachedDuplicate.UnsetUnchanged(transaction);
|
cachedDuplicate.UnsetUnchanged(transaction);
|
||||||
// the old duplicate has not been touched, so we can reuse it
|
// The old duplicate has not been touched, so we can
|
||||||
|
// reuse it
|
||||||
|
|
||||||
bplustree_node* newDuplicate;
|
bplustree_node* newDuplicate;
|
||||||
status = cachedDuplicate.Allocate(transaction,
|
status = cachedDuplicate.Allocate(transaction,
|
||||||
@@ -837,8 +843,8 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
// copy the array from the fragment node to the duplicate node
|
// Copy the array from the fragment node to the duplicate
|
||||||
// and free the old entry (by zero'ing all values)
|
// node and free the old entry (by zero'ing all values)
|
||||||
newDuplicate->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
|
newDuplicate->overflow_link = HOST_ENDIAN_TO_BFS_INT64(
|
||||||
array->count);
|
array->count);
|
||||||
memcpy(&newDuplicate->all_key_count, &array->values[0],
|
memcpy(&newDuplicate->all_key_count, &array->values[0],
|
||||||
@@ -849,11 +855,12 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
array->Insert(value);
|
array->Insert(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the main pointer to link to a duplicate node
|
// Update the main pointer to link to a duplicate node
|
||||||
if (cached.MakeWritable(transaction) == NULL)
|
if (cached.MakeWritable(transaction) == NULL)
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
values[index] = HOST_ENDIAN_TO_BFS_INT64(bplustree_node::MakeLink(
|
values[index]
|
||||||
|
= HOST_ENDIAN_TO_BFS_INT64(bplustree_node::MakeLink(
|
||||||
BPLUSTREE_DUPLICATE_NODE, offset));
|
BPLUSTREE_DUPLICATE_NODE, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,14 +881,15 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
|
|
||||||
array = duplicate->DuplicateArray();
|
array = duplicate->DuplicateArray();
|
||||||
if (array->count > NUM_DUPLICATE_VALUES || array->count < 0) {
|
if (array->count > NUM_DUPLICATE_VALUES || array->count < 0) {
|
||||||
FATAL(("removeDuplicate: Invalid array size in duplicate %Ld == %Ld!\n",
|
FATAL(("removeDuplicate: Invalid array size in duplicate %Ld "
|
||||||
duplicateOffset, array->count));
|
"== %Ld!\n", duplicateOffset, array->count));
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
}
|
}
|
||||||
} while (array->count >= NUM_DUPLICATE_VALUES
|
} while (array->count >= NUM_DUPLICATE_VALUES
|
||||||
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
|
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
|
||||||
|
|
||||||
bplustree_node *writableDuplicate = cachedDuplicate.MakeWritable(transaction);
|
bplustree_node* writableDuplicate
|
||||||
|
= cachedDuplicate.MakeWritable(transaction);
|
||||||
if (writableDuplicate == NULL)
|
if (writableDuplicate == NULL)
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
@@ -892,7 +900,8 @@ BPlusTree::_InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
|||||||
// no space left - add a new duplicate node
|
// no space left - add a new duplicate node
|
||||||
|
|
||||||
bplustree_node* newDuplicate;
|
bplustree_node* newDuplicate;
|
||||||
status = cachedDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
status = cachedDuplicate.Allocate(transaction, &newDuplicate,
|
||||||
|
&offset);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
@@ -984,10 +993,9 @@ BPlusTree::_InsertKey(bplustree_node *node, uint16 index, uint8 *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! Splits the \a node into two halves - the other half will be put into
|
||||||
Splits the \a node into two halves - the other half will be put into \a other.
|
\a other. It also takes care to create a new overflow link if the node
|
||||||
It also takes care to create a new overflow link if the node to split is an
|
to split is an index node.
|
||||||
index node.
|
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
BPlusTree::_SplitNode(bplustree_node* node, off_t nodeOffset,
|
BPlusTree::_SplitNode(bplustree_node* node, off_t nodeOffset,
|
||||||
@@ -1082,7 +1090,8 @@ BPlusTree::_SplitNode(bplustree_node *node, off_t nodeOffset,
|
|||||||
keys = out - keyIndex - 1;
|
keys = out - keyIndex - 1;
|
||||||
for (int32 i = 0;i < keys;i++) {
|
for (int32 i = 0;i < keys;i++) {
|
||||||
outKeyLengths[keyIndex + i + 1] = HOST_ENDIAN_TO_BFS_INT16(
|
outKeyLengths[keyIndex + i + 1] = HOST_ENDIAN_TO_BFS_INT16(
|
||||||
BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[keyIndex + i]) + bytes);
|
BFS_ENDIAN_TO_HOST_INT16(inKeyLengths[keyIndex + i])
|
||||||
|
+ bytes);
|
||||||
}
|
}
|
||||||
memcpy(outKeyValues + keyIndex + 1, inKeyValues + keyIndex,
|
memcpy(outKeyValues + keyIndex + 1, inKeyValues + keyIndex,
|
||||||
keys * sizeof(off_t));
|
keys * sizeof(off_t));
|
||||||
@@ -1421,8 +1430,9 @@ BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
|||||||
|
|
||||||
if (array->count > NUM_FRAGMENT_VALUES
|
if (array->count > NUM_FRAGMENT_VALUES
|
||||||
|| array->count < 1) {
|
|| array->count < 1) {
|
||||||
FATAL(("removeDuplicate: Invalid array[%d] size in fragment %Ld == %Ld!\n",
|
FATAL(("removeDuplicate: Invalid array[%d] size in fragment %Ld "
|
||||||
(int)bplustree_node::FragmentIndex(oldValue), duplicateOffset, array->count));
|
"== %Ld!\n", (int)bplustree_node::FragmentIndex(oldValue),
|
||||||
|
duplicateOffset, array->count));
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
}
|
}
|
||||||
if (!array->Remove(value)) {
|
if (!array->Remove(value)) {
|
||||||
@@ -1442,7 +1452,8 @@ BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
|||||||
// Remove the whole fragment node, if this was the only array,
|
// Remove the whole fragment node, if this was the only array,
|
||||||
// otherwise free just the array
|
// otherwise free just the array
|
||||||
if (duplicate->FragmentsUsed(fNodeSize) == 1) {
|
if (duplicate->FragmentsUsed(fNodeSize) == 1) {
|
||||||
status_t status = cachedDuplicate.Free(transaction, duplicateOffset);
|
status_t status = cachedDuplicate.Free(transaction,
|
||||||
|
duplicateOffset);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
} else
|
} else
|
||||||
@@ -1466,8 +1477,8 @@ BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
|||||||
array = duplicate->DuplicateArray();
|
array = duplicate->DuplicateArray();
|
||||||
if (array->count > NUM_DUPLICATE_VALUES
|
if (array->count > NUM_DUPLICATE_VALUES
|
||||||
|| array->count < 0) {
|
|| array->count < 0) {
|
||||||
FATAL(("removeDuplicate: Invalid array size in duplicate %Ld == %Ld!\n",
|
FATAL(("removeDuplicate: Invalid array size in duplicate %Ld == "
|
||||||
duplicateOffset, array->count));
|
"%Ld!\n", duplicateOffset, array->count));
|
||||||
return B_BAD_DATA;
|
return B_BAD_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1478,7 +1489,8 @@ BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
|||||||
RETURN_ERROR(B_ENTRY_NOT_FOUND);
|
RETURN_ERROR(B_ENTRY_NOT_FOUND);
|
||||||
|
|
||||||
cachedDuplicate.UnsetUnchanged(transaction);
|
cachedDuplicate.UnsetUnchanged(transaction);
|
||||||
duplicate = cachedDuplicate.SetToWritable(transaction, duplicateOffset, false);
|
duplicate = cachedDuplicate.SetToWritable(transaction, duplicateOffset,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
if (duplicate == NULL)
|
if (duplicate == NULL)
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
@@ -1502,41 +1514,48 @@ BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
|||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
if (array->count == 1) {
|
if (array->count == 1) {
|
||||||
// this is the last node, and there is only one value left;
|
// This is the last node, and there is only one value left;
|
||||||
// replace the duplicate link with that value, it's no duplicate
|
// replace the duplicate link with that value, it's no
|
||||||
// anymore
|
// duplicate anymore
|
||||||
values[index] = array->values[0];
|
values[index] = array->values[0];
|
||||||
} else {
|
} else {
|
||||||
// move the duplicate link to the next node
|
// Move the duplicate link to the next node
|
||||||
values[index] = HOST_ENDIAN_TO_BFS_INT64(bplustree_node::MakeLink(
|
values[index] = HOST_ENDIAN_TO_BFS_INT64(
|
||||||
|
bplustree_node::MakeLink(
|
||||||
BPLUSTREE_DUPLICATE_NODE, right));
|
BPLUSTREE_DUPLICATE_NODE, right));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t status;
|
status_t status = cachedDuplicate.Free(transaction,
|
||||||
if ((status = cachedDuplicate.Free(transaction, duplicateOffset)) < B_OK)
|
duplicateOffset);
|
||||||
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (left != BPLUSTREE_NULL
|
if (left != BPLUSTREE_NULL
|
||||||
&& (duplicate = cachedDuplicate.SetToWritable(transaction, left, false)) != NULL) {
|
&& (duplicate = cachedDuplicate.SetToWritable(transaction, left,
|
||||||
|
false)) != NULL) {
|
||||||
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(right);
|
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(right);
|
||||||
|
|
||||||
// If the next node is the last node, we need to free that node
|
// If the next node is the last node, we need to free that node
|
||||||
// and convert the duplicate entry back into a normal entry
|
// and convert the duplicate entry back into a normal entry
|
||||||
array = duplicate->DuplicateArray();
|
array = duplicate->DuplicateArray();
|
||||||
if (right == BPLUSTREE_NULL && duplicate->LeftLink() == BPLUSTREE_NULL
|
if (right == BPLUSTREE_NULL
|
||||||
|
&& duplicate->LeftLink() == BPLUSTREE_NULL
|
||||||
&& array->count <= NUM_FRAGMENT_VALUES) {
|
&& array->count <= NUM_FRAGMENT_VALUES) {
|
||||||
duplicateOffset = left;
|
duplicateOffset = left;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (right != BPLUSTREE_NULL
|
if (right != BPLUSTREE_NULL
|
||||||
&& (duplicate = cachedDuplicate.SetToWritable(transaction, right, false)) != NULL) {
|
&& (duplicate = cachedDuplicate.SetToWritable(transaction,
|
||||||
|
right, false)) != NULL) {
|
||||||
duplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(left);
|
duplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(left);
|
||||||
|
|
||||||
// Again, we may need to turn the duplicate entry back into a normal entry
|
// Again, we may need to turn the duplicate entry back into a
|
||||||
|
// normal entry
|
||||||
array = duplicate->DuplicateArray();
|
array = duplicate->DuplicateArray();
|
||||||
if (left == BPLUSTREE_NULL && duplicate->RightLink() == BPLUSTREE_NULL
|
if (left == BPLUSTREE_NULL
|
||||||
|
&& duplicate->RightLink() == BPLUSTREE_NULL
|
||||||
&& array->count <= NUM_FRAGMENT_VALUES) {
|
&& array->count <= NUM_FRAGMENT_VALUES) {
|
||||||
duplicateOffset = right;
|
duplicateOffset = right;
|
||||||
continue;
|
continue;
|
||||||
@@ -1556,13 +1575,15 @@ BPlusTree::_RemoveDuplicate(Transaction &transaction,
|
|||||||
&offset, &fragment, &fragmentIndex) == B_OK) {
|
&offset, &fragment, &fragmentIndex) == B_OK) {
|
||||||
// move to other node
|
// move to other node
|
||||||
duplicate_array* target = fragment->FragmentAt(fragmentIndex);
|
duplicate_array* target = fragment->FragmentAt(fragmentIndex);
|
||||||
memcpy(target, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
memcpy(target, array,
|
||||||
|
(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||||
|
|
||||||
cachedDuplicate.Free(transaction, duplicateOffset);
|
cachedDuplicate.Free(transaction, duplicateOffset);
|
||||||
duplicateOffset = offset;
|
duplicateOffset = offset;
|
||||||
} else {
|
} else {
|
||||||
// convert node
|
// convert node
|
||||||
memmove(duplicate, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
memmove(duplicate, array,
|
||||||
|
(NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||||
memset((off_t*)duplicate + NUM_FRAGMENT_VALUES + 1, 0,
|
memset((off_t*)duplicate + NUM_FRAGMENT_VALUES + 1, 0,
|
||||||
fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||||
}
|
}
|
||||||
@@ -1605,7 +1626,8 @@ BPlusTree::_RemoveKey(bplustree_node *node, uint16 index)
|
|||||||
if (key + length + sizeof(off_t) + sizeof(uint16) > (uint8*)node + fNodeSize
|
if (key + length + sizeof(off_t) + sizeof(uint16) > (uint8*)node + fNodeSize
|
||||||
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||||
FATAL(("Key length to long: %s, %u (inode at %d,%u)\n", key, length,
|
FATAL(("Key length to long: %s, %u (inode at %d,%u)\n", key, length,
|
||||||
(int)fStream->BlockRun().allocation_group, fStream->BlockRun().start));
|
(int)fStream->BlockRun().allocation_group,
|
||||||
|
fStream->BlockRun().start));
|
||||||
fStream->GetVolume()->Panic();
|
fStream->GetVolume()->Panic();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1614,7 +1636,8 @@ BPlusTree::_RemoveKey(bplustree_node *node, uint16 index)
|
|||||||
uint8* keys = node->Keys();
|
uint8* keys = node->Keys();
|
||||||
|
|
||||||
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(node->NumKeys() - 1);
|
node->all_key_count = HOST_ENDIAN_TO_BFS_INT16(node->NumKeys() - 1);
|
||||||
node->all_key_length = HOST_ENDIAN_TO_BFS_INT64(node->AllKeyLength() - length);
|
node->all_key_length = HOST_ENDIAN_TO_BFS_INT64(
|
||||||
|
node->AllKeyLength() - length);
|
||||||
|
|
||||||
off_t* newValues = node->Values();
|
off_t* newValues = node->Values();
|
||||||
uint16* newKeyLengths = node->KeyLengths();
|
uint16* newKeyLengths = node->KeyLengths();
|
||||||
@@ -1633,8 +1656,10 @@ BPlusTree::_RemoveKey(bplustree_node *node, uint16 index)
|
|||||||
// move values
|
// move values
|
||||||
if (index > 0)
|
if (index > 0)
|
||||||
memmove(newValues, values, index * sizeof(off_t));
|
memmove(newValues, values, index * sizeof(off_t));
|
||||||
if (node->NumKeys() > index)
|
if (node->NumKeys() > index) {
|
||||||
memmove(newValues + index, values + index + 1, (node->NumKeys() - index) * sizeof(off_t));
|
memmove(newValues + index, values + index + 1,
|
||||||
|
(node->NumKeys() - index) * sizeof(off_t));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1689,7 +1714,8 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
return _RemoveDuplicate(transaction, node, cached,
|
return _RemoveDuplicate(transaction, node, cached,
|
||||||
nodeAndKey.keyIndex, value);
|
nodeAndKey.keyIndex, value);
|
||||||
} else {
|
} else {
|
||||||
FATAL(("dupliate node found where no duplicates are allowed!\n"));
|
FATAL(("dupliate node found where no duplicates are "
|
||||||
|
"allowed!\n"));
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1703,15 +1729,18 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
// to a leaf node by dropping the overflow link, or,
|
// to a leaf node by dropping the overflow link, or,
|
||||||
// if it's already a leaf node, just empty it
|
// if it's already a leaf node, just empty it
|
||||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()
|
if (nodeAndKey.nodeOffset == fHeader->RootNode()
|
||||||
&& (node->NumKeys() == 0 || (node->NumKeys() == 1 && node->IsLeaf()))) {
|
&& (node->NumKeys() == 0
|
||||||
writableNode->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
|| (node->NumKeys() == 1 && node->IsLeaf()))) {
|
||||||
|
writableNode->overflow_link
|
||||||
|
= HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||||
writableNode->all_key_count = 0;
|
writableNode->all_key_count = 0;
|
||||||
writableNode->all_key_length = 0;
|
writableNode->all_key_length = 0;
|
||||||
|
|
||||||
// if we've made a leaf node out of the root node, we need
|
// if we've made a leaf node out of the root node, we need
|
||||||
// to reset the maximum number of levels in the header
|
// to reset the maximum number of levels in the header
|
||||||
if (fHeader->MaxNumberOfLevels() != 1) {
|
if (fHeader->MaxNumberOfLevels() != 1) {
|
||||||
bplustree_header *header = fCachedHeader.MakeWritableHeader(transaction);
|
bplustree_header* header
|
||||||
|
= fCachedHeader.MakeWritableHeader(transaction);
|
||||||
if (header == NULL)
|
if (header == NULL)
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
|
|
||||||
@@ -1738,8 +1767,10 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
if (other != NULL)
|
if (other != NULL)
|
||||||
other->right_link = writableNode->right_link;
|
other->right_link = writableNode->right_link;
|
||||||
|
|
||||||
if ((other = otherCached.SetToWritable(transaction, node->RightLink())) != NULL)
|
if ((other = otherCached.SetToWritable(transaction, node->RightLink()))
|
||||||
|
!= NULL) {
|
||||||
other->left_link = writableNode->left_link;
|
other->left_link = writableNode->left_link;
|
||||||
|
}
|
||||||
|
|
||||||
cached.Free(transaction, nodeAndKey.nodeOffset);
|
cached.Free(transaction, nodeAndKey.nodeOffset);
|
||||||
}
|
}
|
||||||
@@ -1757,8 +1788,8 @@ BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength,
|
|||||||
You need to have the inode write locked.
|
You need to have the inode write locked.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
BPlusTree::Replace(Transaction &transaction, const uint8 *key,
|
BPlusTree::Replace(Transaction& transaction, const uint8* key, uint16 keyLength,
|
||||||
uint16 keyLength, off_t value)
|
off_t value)
|
||||||
{
|
{
|
||||||
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|
||||||
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH
|
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH
|
||||||
@@ -1777,14 +1808,16 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key,
|
|||||||
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
||||||
uint16 keyIndex = 0;
|
uint16 keyIndex = 0;
|
||||||
off_t nextOffset;
|
off_t nextOffset;
|
||||||
status_t status = _FindKey(node, key, keyLength, &keyIndex, &nextOffset);
|
status_t status = _FindKey(node, key, keyLength, &keyIndex,
|
||||||
|
&nextOffset);
|
||||||
|
|
||||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
bplustree_node* writableNode = cached.MakeWritable(transaction);
|
bplustree_node* writableNode = cached.MakeWritable(transaction);
|
||||||
if (writableNode != NULL)
|
if (writableNode != NULL) {
|
||||||
writableNode->Values()[keyIndex] = HOST_ENDIAN_TO_BFS_INT64(value);
|
writableNode->Values()[keyIndex]
|
||||||
else
|
= HOST_ENDIAN_TO_BFS_INT64(value);
|
||||||
|
} else
|
||||||
status = B_IO_ERROR;
|
status = B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1798,16 +1831,15 @@ BPlusTree::Replace(Transaction &transaction, const uint8 *key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Searches the key in the tree, and stores the offset found in
|
/*! Searches the key in the tree, and stores the offset found in _value,
|
||||||
_value, if successful.
|
if successful.
|
||||||
It's very similar to BPlusTree::SeekDown(), but doesn't fill
|
It's very similar to BPlusTree::SeekDown(), but doesn't fill a stack
|
||||||
a stack while it descends the tree.
|
while it descends the tree.
|
||||||
Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND
|
Returns B_OK when the key could be found, B_ENTRY_NOT_FOUND if not.
|
||||||
if not. It can also return other errors to indicate that
|
It can also return other errors to indicate that something went wrong.
|
||||||
something went wrong.
|
Note that this doesn't work with duplicates - it will just return
|
||||||
Note that this doesn't work with duplicates - it will just
|
B_BAD_TYPE if you call this function on a tree where duplicates are
|
||||||
return B_BAD_TYPE if you call this function on a tree where
|
allowed.
|
||||||
duplicates are allowed.
|
|
||||||
You need to have the inode read or write locked.
|
You need to have the inode read or write locked.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
@@ -1834,7 +1866,8 @@ BPlusTree::Find(const uint8 *key, uint16 keyLength, off_t *_value)
|
|||||||
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
while ((node = cached.SetTo(nodeOffset)) != NULL) {
|
||||||
uint16 keyIndex = 0;
|
uint16 keyIndex = 0;
|
||||||
off_t nextOffset;
|
off_t nextOffset;
|
||||||
status_t status = _FindKey(node, key, keyLength, &keyIndex, &nextOffset);
|
status_t status = _FindKey(node, key, keyLength, &keyIndex,
|
||||||
|
&nextOffset);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
levels++;
|
levels++;
|
||||||
@@ -1924,8 +1957,7 @@ TreeIterator::Goto(int8 to)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! Iterates through the tree in the specified direction.
|
||||||
Iterates through the tree in the specified direction.
|
|
||||||
When it iterates through duplicates, the "key" is only updated for the
|
When it iterates through duplicates, the "key" is only updated for the
|
||||||
first entry - if you need to know when this happens, use the "duplicate"
|
first entry - if you need to know when this happens, use the "duplicate"
|
||||||
parameter which is 0 for no duplicate, 1 for the first, and 2 for all
|
parameter which is 0 for no duplicate, 1 for the first, and 2 for all
|
||||||
@@ -1960,27 +1992,31 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
|
|||||||
const bplustree_node* node;
|
const bplustree_node* node;
|
||||||
|
|
||||||
if (fDuplicateNode != BPLUSTREE_NULL) {
|
if (fDuplicateNode != BPLUSTREE_NULL) {
|
||||||
// regardless of traverse direction the duplicates are always presented in
|
// regardless of traverse direction the duplicates are always presented
|
||||||
// the same order; since they are all considered as equal, this shouldn't
|
// in the same order; since they are all considered as equal, this
|
||||||
// cause any problems
|
// shouldn't cause any problems
|
||||||
|
|
||||||
if (!fIsFragment || fDuplicate < fNumDuplicates)
|
if (!fIsFragment || fDuplicate < fNumDuplicates) {
|
||||||
node = cached.SetTo(bplustree_node::FragmentOffset(fDuplicateNode), false);
|
node = cached.SetTo(bplustree_node::FragmentOffset(fDuplicateNode),
|
||||||
else
|
false);
|
||||||
|
} else
|
||||||
node = NULL;
|
node = NULL;
|
||||||
|
|
||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
if (!fIsFragment && fDuplicate >= fNumDuplicates) {
|
if (!fIsFragment && fDuplicate >= fNumDuplicates) {
|
||||||
// if the node is out of duplicates, we go directly to the next one
|
// If the node is out of duplicates, we go directly to the next
|
||||||
|
// one
|
||||||
fDuplicateNode = node->RightLink();
|
fDuplicateNode = node->RightLink();
|
||||||
if (fDuplicateNode != BPLUSTREE_NULL
|
if (fDuplicateNode != BPLUSTREE_NULL
|
||||||
&& (node = cached.SetTo(fDuplicateNode, false)) != NULL) {
|
&& (node = cached.SetTo(fDuplicateNode, false)) != NULL) {
|
||||||
fNumDuplicates = node->CountDuplicates(fDuplicateNode, false);
|
fNumDuplicates = node->CountDuplicates(fDuplicateNode,
|
||||||
|
false);
|
||||||
fDuplicate = 0;
|
fDuplicate = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fDuplicate < fNumDuplicates) {
|
if (fDuplicate < fNumDuplicates) {
|
||||||
*value = node->DuplicateAt(fDuplicateNode, fIsFragment, fDuplicate++);
|
*value = node->DuplicateAt(fDuplicateNode, fIsFragment,
|
||||||
|
fDuplicate++);
|
||||||
if (duplicate)
|
if (duplicate)
|
||||||
*duplicate = 2;
|
*duplicate = 2;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -2027,7 +2063,8 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
|
|||||||
|
|
||||||
uint16 length;
|
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
|
if (keyStart + length + sizeof(off_t) + sizeof(uint16)
|
||||||
|
> (uint8*)node + fTree->fNodeSize
|
||||||
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||||
fTree->fStream->GetVolume()->Panic();
|
fTree->fStream->GetVolume()->Panic();
|
||||||
RETURN_ERROR(B_BAD_DATA);
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
@@ -2048,10 +2085,12 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
|
|||||||
|
|
||||||
// duplicate fragments?
|
// duplicate fragments?
|
||||||
uint8 type = bplustree_node::LinkType(offset);
|
uint8 type = bplustree_node::LinkType(offset);
|
||||||
if (type == BPLUSTREE_DUPLICATE_FRAGMENT || type == BPLUSTREE_DUPLICATE_NODE) {
|
if (type == BPLUSTREE_DUPLICATE_FRAGMENT
|
||||||
|
|| type == BPLUSTREE_DUPLICATE_NODE) {
|
||||||
fDuplicateNode = offset;
|
fDuplicateNode = offset;
|
||||||
|
|
||||||
node = cached.SetTo(bplustree_node::FragmentOffset(fDuplicateNode), false);
|
node = cached.SetTo(bplustree_node::FragmentOffset(fDuplicateNode),
|
||||||
|
false);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
@@ -2064,7 +2103,8 @@ TreeIterator::Traverse(int8 direction, void *key, uint16 *keyLength,
|
|||||||
if (duplicate)
|
if (duplicate)
|
||||||
*duplicate = 1;
|
*duplicate = 1;
|
||||||
} else {
|
} else {
|
||||||
// shouldn't happen, but we're dealing here with potentially corrupt disks...
|
// Shouldn't happen, but we're dealing here with potentially
|
||||||
|
// corrupt disks...
|
||||||
fDuplicateNode = BPLUSTREE_NULL;
|
fDuplicateNode = BPLUSTREE_NULL;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
@@ -2084,7 +2124,8 @@ TreeIterator::Find(const uint8 *key, uint16 keyLength)
|
|||||||
{
|
{
|
||||||
if (fTree == NULL)
|
if (fTree == NULL)
|
||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH
|
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH
|
||||||
|
|| keyLength > BPLUSTREE_MAX_KEY_LENGTH
|
||||||
|| key == NULL)
|
|| key == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
@@ -2163,7 +2204,9 @@ TreeIterator::Dump()
|
|||||||
__out("\tfTree = %p\n", fTree);
|
__out("\tfTree = %p\n", fTree);
|
||||||
__out("\tfCurrentNodeOffset = %Ld\n", fCurrentNodeOffset);
|
__out("\tfCurrentNodeOffset = %Ld\n", fCurrentNodeOffset);
|
||||||
__out("\tfCurrentKey = %ld\n", fCurrentKey);
|
__out("\tfCurrentKey = %ld\n", fCurrentKey);
|
||||||
__out("\tfDuplicateNode = %Ld (%Ld, 0x%Lx)\n", bplustree_node::FragmentOffset(fDuplicateNode), fDuplicateNode, fDuplicateNode);
|
__out("\tfDuplicateNode = %Ld (%Ld, 0x%Lx)\n",
|
||||||
|
bplustree_node::FragmentOffset(fDuplicateNode), fDuplicateNode,
|
||||||
|
fDuplicateNode);
|
||||||
__out("\tfDuplicate = %u\n", fDuplicate);
|
__out("\tfDuplicate = %u\n", fDuplicate);
|
||||||
__out("\tfNumDuplicates = %u\n", fNumDuplicates);
|
__out("\tfNumDuplicates = %u\n", fNumDuplicates);
|
||||||
__out("\tfIsFragment = %s\n", fIsFragment ? "true" : "false");
|
__out("\tfIsFragment = %s\n", fIsFragment ? "true" : "false");
|
||||||
@@ -2177,7 +2220,8 @@ TreeIterator::Dump()
|
|||||||
void
|
void
|
||||||
bplustree_node::Initialize()
|
bplustree_node::Initialize()
|
||||||
{
|
{
|
||||||
left_link = right_link = overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
left_link = right_link = overflow_link
|
||||||
|
= HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||||
all_key_count = 0;
|
all_key_count = 0;
|
||||||
all_key_length = 0;
|
all_key_length = 0;
|
||||||
}
|
}
|
||||||
@@ -2257,7 +2301,8 @@ bplustree_node::CheckIntegrity(uint32 nodeSize) const
|
|||||||
for (int32 i = 0; i < NumKeys(); i++) {
|
for (int32 i = 0; i < NumKeys(); i++) {
|
||||||
uint16 length;
|
uint16 length;
|
||||||
uint8* key = KeyAt(i, &length);
|
uint8* key = KeyAt(i, &length);
|
||||||
if (key + length + sizeof(off_t) + sizeof(uint16) > (uint8 *)this + nodeSize
|
if (key + length + sizeof(off_t) + sizeof(uint16)
|
||||||
|
> (uint8*)this + nodeSize
|
||||||
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
|| length > BPLUSTREE_MAX_KEY_LENGTH) {
|
||||||
dprintf("node %p, key %ld\n", this, i);
|
dprintf("node %p, key %ld\n", this, i);
|
||||||
DEBUGGER(("invalid node: keys corrupted"));
|
DEBUGGER(("invalid node: keys corrupted"));
|
||||||
|
|||||||
@@ -29,21 +29,28 @@ class BlockAllocator {
|
|||||||
|
|
||||||
void Uninitialize();
|
void Uninitialize();
|
||||||
|
|
||||||
status_t AllocateForInode(Transaction &transaction, const block_run *parent,
|
status_t AllocateForInode(Transaction& transaction,
|
||||||
mode_t type, block_run &run);
|
const block_run* parent, mode_t type,
|
||||||
status_t Allocate(Transaction &transaction, Inode *inode, off_t numBlocks,
|
block_run& run);
|
||||||
block_run &run, uint16 minimum = 1);
|
status_t Allocate(Transaction& transaction, Inode* inode,
|
||||||
|
off_t numBlocks, block_run& run,
|
||||||
|
uint16 minimum = 1);
|
||||||
status_t Free(Transaction& transaction, block_run run);
|
status_t Free(Transaction& transaction, block_run run);
|
||||||
|
|
||||||
status_t AllocateBlocks(Transaction &transaction, int32 group, uint16 start,
|
status_t AllocateBlocks(Transaction& transaction,
|
||||||
uint16 numBlocks, uint16 minimum, block_run &run);
|
int32 group, uint16 start, uint16 numBlocks,
|
||||||
|
uint16 minimum, block_run& run);
|
||||||
|
|
||||||
status_t StartChecking(check_control* control);
|
status_t StartChecking(check_control* control);
|
||||||
status_t StopChecking(check_control* control);
|
status_t StopChecking(check_control* control);
|
||||||
status_t CheckNextNode(check_control* control);
|
status_t CheckNextNode(check_control* control);
|
||||||
|
|
||||||
status_t CheckBlockRun(block_run run, const char *type = NULL, check_control *control = NULL, bool allocated = true);
|
status_t CheckBlockRun(block_run run,
|
||||||
status_t CheckInode(Inode *inode, check_control *control = NULL);
|
const char* type = NULL,
|
||||||
|
check_control* control = NULL,
|
||||||
|
bool allocated = true);
|
||||||
|
status_t CheckInode(Inode* inode,
|
||||||
|
check_control* control = NULL);
|
||||||
|
|
||||||
size_t BitmapSize() const;
|
size_t BitmapSize() const;
|
||||||
|
|
||||||
@@ -56,7 +63,7 @@ class BlockAllocator {
|
|||||||
bool _CheckBitmapIsUsedAt(off_t block) const;
|
bool _CheckBitmapIsUsedAt(off_t block) const;
|
||||||
void _SetCheckBitmapAt(off_t block);
|
void _SetCheckBitmapAt(off_t block);
|
||||||
|
|
||||||
static status_t _Initialize(BlockAllocator *);
|
static status_t _Initialize(BlockAllocator* self);
|
||||||
|
|
||||||
Volume* fVolume;
|
Volume* fVolume;
|
||||||
mutex fLock;
|
mutex fLock;
|
||||||
@@ -72,4 +79,4 @@ class BlockAllocator {
|
|||||||
int dump_block_allocator(int argc, char** argv);
|
int dump_block_allocator(int argc, char** argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* BLOCK_ALLOCATOR_H */
|
#endif // BLOCK_ALLOCATOR_H
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ Index::Unset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! Sets the index to specified one. Returns an error if the index could
|
||||||
Sets the index to specified one. Returns an error if the index could
|
|
||||||
not be found or initialized.
|
not be found or initialized.
|
||||||
Note, Index::Update() may be called on the object even if this method
|
Note, Index::Update() may be called on the object even if this method
|
||||||
failed previously. In this case, it will only update live queries for
|
failed previously. In this case, it will only update live queries for
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* Index - index access functions
|
/*
|
||||||
*
|
* Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef INDEX_H
|
#ifndef INDEX_H
|
||||||
@@ -9,6 +8,7 @@
|
|||||||
|
|
||||||
#include "system_dependencies.h"
|
#include "system_dependencies.h"
|
||||||
|
|
||||||
|
|
||||||
class Transaction;
|
class Transaction;
|
||||||
class Volume;
|
class Volume;
|
||||||
class Inode;
|
class Inode;
|
||||||
@@ -26,27 +26,36 @@ class Index {
|
|||||||
uint32 Type();
|
uint32 Type();
|
||||||
size_t KeySize();
|
size_t KeySize();
|
||||||
|
|
||||||
status_t Create(Transaction &transaction, const char *name, uint32 type);
|
status_t Create(Transaction& transaction, const char* name,
|
||||||
|
uint32 type);
|
||||||
|
|
||||||
status_t Update(Transaction &transaction, const char *name, int32 type, const uint8 *oldKey,
|
status_t Update(Transaction& transaction, const char* name,
|
||||||
uint16 oldLength, const uint8 *newKey, uint16 newLength, Inode *inode);
|
int32 type, const uint8* oldKey,
|
||||||
|
uint16 oldLength, const uint8* newKey,
|
||||||
|
uint16 newLength, Inode* inode);
|
||||||
|
|
||||||
status_t InsertName(Transaction &transaction, const char *name, Inode *inode);
|
status_t InsertName(Transaction& transaction,
|
||||||
status_t RemoveName(Transaction &transaction, const char *name, Inode *inode);
|
const char* name, Inode* inode);
|
||||||
status_t UpdateName(Transaction &transaction, const char *oldName, const char *newName,
|
status_t RemoveName(Transaction& transaction,
|
||||||
|
const char* name, Inode* inode);
|
||||||
|
status_t UpdateName(Transaction& transaction,
|
||||||
|
const char* oldName, const char* newName,
|
||||||
Inode* inode);
|
Inode* inode);
|
||||||
|
|
||||||
status_t InsertSize(Transaction& transaction, Inode* inode);
|
status_t InsertSize(Transaction& transaction, Inode* inode);
|
||||||
status_t RemoveSize(Transaction& transaction, Inode* inode);
|
status_t RemoveSize(Transaction& transaction, Inode* inode);
|
||||||
status_t UpdateSize(Transaction& transaction, Inode* inode);
|
status_t UpdateSize(Transaction& transaction, Inode* inode);
|
||||||
|
|
||||||
status_t InsertLastModified(Transaction &transaction, Inode *inode);
|
status_t InsertLastModified(Transaction& transaction,
|
||||||
status_t RemoveLastModified(Transaction &transaction, Inode *inode);
|
Inode* inode);
|
||||||
status_t UpdateLastModified(Transaction &transaction, Inode *inode, off_t modified = -1);
|
status_t RemoveLastModified(Transaction& transaction,
|
||||||
|
Inode* inode);
|
||||||
|
status_t UpdateLastModified(Transaction& transaction,
|
||||||
|
Inode* inode, off_t modified = -1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Index(const Index &);
|
Index(const Index& other);
|
||||||
Index &operator=(const Index &);
|
Index& operator=(const Index& other);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
Volume* fVolume;
|
Volume* fVolume;
|
||||||
@@ -54,4 +63,4 @@ class Index {
|
|||||||
const char* fName;
|
const char* fName;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INDEX_H */
|
#endif // INDEX_H
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ class Create : public AbstractTraceEntry {
|
|||||||
int32 fMode;
|
int32 fMode;
|
||||||
int fOpenMode;
|
int fOpenMode;
|
||||||
uint32 fType;
|
uint32 fType;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Remove : public AbstractTraceEntry {
|
class Remove : public AbstractTraceEntry {
|
||||||
@@ -138,13 +137,15 @@ class InodeAllocator {
|
|||||||
InodeAllocator(Transaction& transaction);
|
InodeAllocator(Transaction& transaction);
|
||||||
~InodeAllocator();
|
~InodeAllocator();
|
||||||
|
|
||||||
status_t New(block_run *parentRun, mode_t mode, block_run &run,
|
status_t New(block_run* parentRun, mode_t mode,
|
||||||
fs_vnode_ops *vnodeOps, Inode **_inode);
|
block_run& run, fs_vnode_ops* vnodeOps,
|
||||||
|
Inode** _inode);
|
||||||
status_t CreateTree();
|
status_t CreateTree();
|
||||||
status_t Keep(fs_vnode_ops* vnodeOps, uint32 publishFlags);
|
status_t Keep(fs_vnode_ops* vnodeOps, uint32 publishFlags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _TransactionListener(int32 id, int32 event, void *_inode);
|
static void _TransactionListener(int32 id, int32 event,
|
||||||
|
void* _inode);
|
||||||
|
|
||||||
Transaction* fTransaction;
|
Transaction* fTransaction;
|
||||||
block_run fRun;
|
block_run fRun;
|
||||||
@@ -455,7 +456,7 @@ Inode::CheckPermissions(int accessMode) const
|
|||||||
gid_t group = getegid();
|
gid_t group = getegid();
|
||||||
|
|
||||||
// you never have write access to a read-only volume
|
// you never have write access to a read-only volume
|
||||||
if (accessMode & W_OK && fVolume->IsReadOnly())
|
if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
|
||||||
return B_READ_ONLY_DEVICE;
|
return B_READ_ONLY_DEVICE;
|
||||||
|
|
||||||
// root users always have full access (but they can't execute files without
|
// root users always have full access (but they can't execute files without
|
||||||
@@ -511,7 +512,8 @@ Inode::_MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node,
|
|||||||
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
ASSERT_LOCKED_RECURSIVE(&fSmallDataLock);
|
||||||
|
|
||||||
while (bytes > 0) {
|
while (bytes > 0) {
|
||||||
small_data *item = node->SmallDataStart(), *max = NULL;
|
small_data* item = node->SmallDataStart();
|
||||||
|
small_data* max = NULL;
|
||||||
int32 index = 0, maxIndex = 0;
|
int32 index = 0, maxIndex = 0;
|
||||||
for (; !item->IsLast(node); item = item->Next(), index++) {
|
for (; !item->IsLast(node); item = item->Next(), index++) {
|
||||||
// should not remove those
|
// should not remove those
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ class RunArrays {
|
|||||||
int32 CountArrays() const { return fArrays.CountItems(); }
|
int32 CountArrays() const { return fArrays.CountItems(); }
|
||||||
|
|
||||||
uint32 CountBlocks() const { return fBlockCount; }
|
uint32 CountBlocks() const { return fBlockCount; }
|
||||||
uint32 LogEntryLength() const { return CountBlocks() + CountArrays(); }
|
uint32 LogEntryLength() const
|
||||||
|
{ return CountBlocks() + CountArrays(); }
|
||||||
|
|
||||||
int32 MaxArrayLength();
|
int32 MaxArrayLength();
|
||||||
|
|
||||||
@@ -60,7 +61,8 @@ class RunArrays {
|
|||||||
|
|
||||||
class LogEntry : public DoublyLinkedListLinkImpl<LogEntry> {
|
class LogEntry : public DoublyLinkedListLinkImpl<LogEntry> {
|
||||||
public:
|
public:
|
||||||
LogEntry(Journal *journal, uint32 logStart, uint32 length);
|
LogEntry(Journal* journal, uint32 logStart,
|
||||||
|
uint32 length);
|
||||||
~LogEntry();
|
~LogEntry();
|
||||||
|
|
||||||
uint32 Start() const { return fStart; }
|
uint32 Start() const { return fStart; }
|
||||||
|
|||||||
@@ -8,10 +8,6 @@
|
|||||||
|
|
||||||
#include "system_dependencies.h"
|
#include "system_dependencies.h"
|
||||||
|
|
||||||
#ifndef _IMPEXP_KERNEL
|
|
||||||
# define _IMPEXP_KERNEL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "Volume.h"
|
#include "Volume.h"
|
||||||
#include "Utility.h"
|
#include "Utility.h"
|
||||||
|
|
||||||
@@ -23,17 +19,9 @@ typedef DoublyLinkedList<LogEntry> LogEntryList;
|
|||||||
typedef SinglyLinkedList<Inode> InodeList;
|
typedef SinglyLinkedList<Inode> InodeList;
|
||||||
|
|
||||||
|
|
||||||
// Locking policy in BFS: if you need both, the volume lock and the
|
|
||||||
// journal lock, you must lock the volume first - or else you will
|
|
||||||
// end up in a deadlock.
|
|
||||||
// That is, if you start a transaction, and will need to lock the
|
|
||||||
// volume while the transaction is in progress (for the unsafe
|
|
||||||
// get_vnode() call, for example), you must lock the volume before
|
|
||||||
// starting the transaction.
|
|
||||||
|
|
||||||
class Journal {
|
class Journal {
|
||||||
public:
|
public:
|
||||||
Journal(Volume *);
|
Journal(Volume* volume);
|
||||||
~Journal();
|
~Journal();
|
||||||
|
|
||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
@@ -64,15 +52,17 @@ class Journal {
|
|||||||
status_t _ReplayRunArray(int32* start);
|
status_t _ReplayRunArray(int32* start);
|
||||||
status_t _TransactionDone(bool success);
|
status_t _TransactionDone(bool success);
|
||||||
|
|
||||||
static void _TransactionWritten(int32 transactionID, int32 event,
|
static void _TransactionWritten(int32 transactionID,
|
||||||
void *_logEntry);
|
int32 event, void* _logEntry);
|
||||||
static void _TransactionIdle(int32 transactionID, int32 event,
|
static void _TransactionIdle(int32 transactionID, int32 event,
|
||||||
void* _journal);
|
void* _journal);
|
||||||
|
|
||||||
Volume* fVolume;
|
Volume* fVolume;
|
||||||
recursive_lock fLock;
|
recursive_lock fLock;
|
||||||
Transaction* fOwner;
|
Transaction* fOwner;
|
||||||
uint32 fLogSize, fMaxTransactionSize, fUsed;
|
uint32 fLogSize;
|
||||||
|
uint32 fMaxTransactionSize;
|
||||||
|
uint32 fUsed;
|
||||||
int32 fUnwrittenTransactions;
|
int32 fUnwrittenTransactions;
|
||||||
mutex fEntriesLock;
|
mutex fEntriesLock;
|
||||||
LogEntryList fEntries;
|
LogEntryList fEntries;
|
||||||
@@ -177,8 +167,8 @@ class Transaction {
|
|||||||
void AddInode(Inode* inode);
|
void AddInode(Inode* inode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Transaction(const Transaction &);
|
Transaction(const Transaction& other);
|
||||||
Transaction &operator=(const Transaction &);
|
Transaction& operator=(const Transaction& other);
|
||||||
// no implementation
|
// no implementation
|
||||||
|
|
||||||
void _UnlockInodes();
|
void _UnlockInodes();
|
||||||
@@ -191,4 +181,4 @@ class Transaction {
|
|||||||
int dump_journal(int argc, char** argv);
|
int dump_journal(int argc, char** argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* JOURNAL_H */
|
#endif // JOURNAL_H
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ sorted_array::Remove(off_t value)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
count--;
|
count--;
|
||||||
memmove(&values[index], &values[index + 1], (count - index) * sizeof(off_t));
|
memmove(&values[index], &values[index + 1],
|
||||||
|
(count - index) * sizeof(off_t));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
// TODO: this is not endian safe!!!
|
// TODO: this is not endian safe!!!
|
||||||
|
|
||||||
struct sorted_array {
|
struct sorted_array {
|
||||||
public:
|
|
||||||
off_t count;
|
off_t count;
|
||||||
off_t values[0];
|
off_t values[0];
|
||||||
|
|
||||||
|
|||||||
@@ -53,23 +53,34 @@ class Volume {
|
|||||||
fs_volume* FSVolume() const { return fVolume; }
|
fs_volume* FSVolume() const { return fVolume; }
|
||||||
const char* Name() const { return fSuperBlock.name; }
|
const char* Name() const { return fSuperBlock.name; }
|
||||||
|
|
||||||
off_t NumBlocks() const { return fSuperBlock.NumBlocks(); }
|
off_t NumBlocks() const
|
||||||
off_t UsedBlocks() const { return fSuperBlock.UsedBlocks(); }
|
{ return fSuperBlock.NumBlocks(); }
|
||||||
off_t FreeBlocks() const { return NumBlocks() - UsedBlocks(); }
|
off_t UsedBlocks() const
|
||||||
|
{ return fSuperBlock.UsedBlocks(); }
|
||||||
|
off_t FreeBlocks() const
|
||||||
|
{ return NumBlocks() - UsedBlocks(); }
|
||||||
|
|
||||||
uint32 BlockSize() const { return fBlockSize; }
|
uint32 BlockSize() const { return fBlockSize; }
|
||||||
uint32 BlockShift() const { return fBlockShift; }
|
uint32 BlockShift() const { return fBlockShift; }
|
||||||
uint32 InodeSize() const { return fSuperBlock.InodeSize(); }
|
uint32 InodeSize() const
|
||||||
uint32 AllocationGroups() const { return fSuperBlock.AllocationGroups(); }
|
{ return fSuperBlock.InodeSize(); }
|
||||||
uint32 AllocationGroupShift() const { return fAllocationGroupShift; }
|
uint32 AllocationGroups() const
|
||||||
|
{ return fSuperBlock.AllocationGroups(); }
|
||||||
|
uint32 AllocationGroupShift() const
|
||||||
|
{ return fAllocationGroupShift; }
|
||||||
disk_super_block& SuperBlock() { return fSuperBlock; }
|
disk_super_block& SuperBlock() { return fSuperBlock; }
|
||||||
|
|
||||||
off_t ToOffset(block_run run) const { return ToBlock(run) << BlockShift(); }
|
off_t ToOffset(block_run run) const
|
||||||
off_t ToBlock(block_run run) const { return ((((off_t)run.AllocationGroup()) << AllocationGroupShift()) | (off_t)run.Start()); }
|
{ 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;
|
block_run ToBlockRun(off_t block) const;
|
||||||
status_t ValidateBlockRun(block_run run);
|
status_t ValidateBlockRun(block_run run);
|
||||||
|
|
||||||
off_t ToVnode(block_run run) const { return ToBlock(run); }
|
off_t ToVnode(block_run run) const
|
||||||
|
{ return ToBlock(run); }
|
||||||
off_t ToVnode(off_t block) const { return block; }
|
off_t ToVnode(off_t block) const { return block; }
|
||||||
off_t VnodeToBlock(ino_t id) const { return (off_t)id; }
|
off_t VnodeToBlock(ino_t id) const { return (off_t)id; }
|
||||||
|
|
||||||
@@ -77,12 +88,15 @@ class Volume {
|
|||||||
|
|
||||||
// block bitmap
|
// block bitmap
|
||||||
BlockAllocator& Allocator();
|
BlockAllocator& Allocator();
|
||||||
status_t AllocateForInode(Transaction &transaction, const Inode *parent,
|
status_t AllocateForInode(Transaction& transaction,
|
||||||
mode_t type, block_run &run);
|
const Inode* parent, mode_t type,
|
||||||
status_t AllocateForInode(Transaction &transaction, const block_run *parent,
|
block_run& run);
|
||||||
mode_t type, block_run &run);
|
status_t AllocateForInode(Transaction& transaction,
|
||||||
|
const block_run* parent, mode_t type,
|
||||||
|
block_run& run);
|
||||||
status_t Allocate(Transaction& transaction, Inode* inode,
|
status_t Allocate(Transaction& transaction, Inode* inode,
|
||||||
off_t numBlocks, block_run &run, uint16 minimum = 1);
|
off_t numBlocks, block_run& run,
|
||||||
|
uint16 minimum = 1);
|
||||||
status_t Free(Transaction& transaction, block_run run);
|
status_t Free(Transaction& transaction, block_run run);
|
||||||
|
|
||||||
// cache access
|
// cache access
|
||||||
@@ -90,7 +104,8 @@ class Volume {
|
|||||||
status_t FlushDevice();
|
status_t FlushDevice();
|
||||||
|
|
||||||
// queries
|
// queries
|
||||||
void UpdateLiveQueries(Inode *inode, const char *attribute, int32 type,
|
void UpdateLiveQueries(Inode* inode,
|
||||||
|
const char* attribute, int32 type,
|
||||||
const uint8* oldKey, size_t oldLength,
|
const uint8* oldKey, size_t oldLength,
|
||||||
const uint8* newKey, size_t newLength);
|
const uint8* newKey, size_t newLength);
|
||||||
bool CheckForLiveQuery(const char* attribute);
|
bool CheckForLiveQuery(const char* attribute);
|
||||||
@@ -120,7 +135,8 @@ class Volume {
|
|||||||
BlockAllocator fBlockAllocator;
|
BlockAllocator fBlockAllocator;
|
||||||
mutex fLock;
|
mutex fLock;
|
||||||
Journal* fJournal;
|
Journal* fJournal;
|
||||||
vint32 fLogStart, fLogEnd;
|
vint32 fLogStart;
|
||||||
|
vint32 fLogEnd;
|
||||||
|
|
||||||
Inode* fRootNode;
|
Inode* fRootNode;
|
||||||
Inode* fIndicesNode;
|
Inode* fIndicesNode;
|
||||||
@@ -161,16 +177,19 @@ Volume::Allocator()
|
|||||||
|
|
||||||
|
|
||||||
inline status_t
|
inline status_t
|
||||||
Volume::AllocateForInode(Transaction &transaction, const block_run *parent, mode_t type, block_run &run)
|
Volume::AllocateForInode(Transaction& transaction, const block_run* parent,
|
||||||
|
mode_t type, block_run& run)
|
||||||
{
|
{
|
||||||
return fBlockAllocator.AllocateForInode(transaction, parent, type, run);
|
return fBlockAllocator.AllocateForInode(transaction, parent, type, run);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline status_t
|
inline status_t
|
||||||
Volume::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks, block_run &run, uint16 minimum)
|
Volume::Allocate(Transaction& transaction, Inode* inode, off_t numBlocks,
|
||||||
|
block_run& run, uint16 minimum)
|
||||||
{
|
{
|
||||||
return fBlockAllocator.Allocate(transaction, inode, numBlocks, run, minimum);
|
return fBlockAllocator.Allocate(transaction, inode, numBlocks, run,
|
||||||
|
minimum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -201,4 +220,4 @@ Volume::GetUniqueID()
|
|||||||
return atomic_add(&fUniqueID, 1);
|
return atomic_add(&fUniqueID, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* VOLUME_H */
|
#endif // VOLUME_H
|
||||||
|
|||||||
@@ -1354,9 +1354,7 @@ bfs_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer,
|
|||||||
if (linkLen < *_bufferSize)
|
if (linkLen < *_bufferSize)
|
||||||
*_bufferSize = linkLen;
|
*_bufferSize = linkLen;
|
||||||
|
|
||||||
memcpy(buffer, inode->Node().short_symlink, *_bufferSize);
|
return user_memcpy(buffer, inode->Node().short_symlink, *_bufferSize);
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user