diff --git a/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp b/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp index 330ed6e6bd..0f43331fa6 100644 --- a/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2015, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. * * Roughly based on 'btlib' written by Marcus J. Ranum - it shares @@ -1692,10 +1692,8 @@ BPlusTree::Insert(Transaction& transaction, const uint8* key, uint16 keyLength, if (_SeekDown(stack, key, keyLength) != B_OK) RETURN_ERROR(B_ERROR); - uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH + 1]; - + uint8 keyBuffer[BPLUSTREE_MAX_KEY_LENGTH]; memcpy(keyBuffer, key, keyLength); - keyBuffer[keyLength] = 0; node_and_key nodeAndKey; const bplustree_node* node; @@ -2746,10 +2744,18 @@ TreeIterator::Traverse(int8 direction, void* key, uint16* keyLength, // include the termination for string types bool needsTermination = fTree->fHeader.DataType() == BPLUSTREE_STRING_TYPE; if (length + (needsTermination ? 1 : 0) > maxLength) { - // the buffer is too small, restore the last key and return an error - fCurrentNodeOffset = savedNodeOffset; - fCurrentKey = savedKey; - return B_BUFFER_OVERFLOW; + if (!needsTermination) { + // The buffer is too small, restore the last key and return + // an error + fCurrentNodeOffset = savedNodeOffset; + fCurrentKey = savedKey; + return B_BUFFER_OVERFLOW; + } + + // Always cut off strings at the maximum buffer size, and leave + // room for a terminating null byte. + // This allows to handle larger key sizes gracefully. + length = maxLength - 1; } memcpy(key, keyStart, length); diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index 4ce6e8afb1..2c2de70d6d 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -2175,8 +2175,8 @@ BlockAllocator::_AddInodeToIndex(Inode* inode) if (inode->InSizeIndex()) status = tree->Insert(transaction, inode->Size(), inode->ID()); } else { - uint8 key[BPLUSTREE_MAX_KEY_LENGTH]; - size_t keyLength = BPLUSTREE_MAX_KEY_LENGTH; + uint8 key[MAX_INDEX_KEY_LENGTH]; + size_t keyLength = MAX_INDEX_KEY_LENGTH; if (inode->ReadAttribute(index->name, B_ANY_TYPE, 0, key, &keyLength) == B_OK) { status = tree->Insert(transaction, key, keyLength, inode->ID()); diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp b/src/add-ons/kernel/file_systems/bfs/Inode.cpp index fce958f5c3..cd5287b476 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp @@ -986,8 +986,8 @@ Inode::_RemoveAttribute(Transaction& transaction, const char* name, Inode* attribute; if ((hasIndex || fVolume->CheckForLiveQuery(name)) && GetAttribute(name, &attribute) == B_OK) { - uint8 data[BPLUSTREE_MAX_KEY_LENGTH]; - size_t length = BPLUSTREE_MAX_KEY_LENGTH; + uint8 data[MAX_INDEX_KEY_LENGTH]; + size_t length = MAX_INDEX_KEY_LENGTH; if (attribute->ReadAt(0, data, &length) == B_OK) { index->Update(transaction, name, attribute->Type(), data, length, NULL, 0, this); @@ -1082,7 +1082,7 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type, return B_BAD_VALUE; // needed to maintain the index - uint8 oldBuffer[BPLUSTREE_MAX_KEY_LENGTH]; + uint8 oldBuffer[MAX_INDEX_KEY_LENGTH]; uint8* oldData = NULL; size_t oldLength = 0; bool created = false; @@ -1091,7 +1091,7 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type, // If they get changed during the write (hey, user programs), we may mess // up our index trees! // TODO: for attribute files, we need to log the first - // BPLUSTREE_MAX_KEY_LENGTH bytes of the data stream, or the same as above + // MAX_INDEX_KEY_LENGTH bytes of the data stream, or the same as above // might happen. Index index(fVolume); @@ -1114,8 +1114,8 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type, if (smallData != NULL) { oldLength = smallData->DataSize(); if (oldLength > 0) { - if (oldLength > BPLUSTREE_MAX_KEY_LENGTH) - oldLength = BPLUSTREE_MAX_KEY_LENGTH; + if (oldLength > MAX_INDEX_KEY_LENGTH) + oldLength = MAX_INDEX_KEY_LENGTH; memcpy(oldData = oldBuffer, smallData->Data(), oldLength); } } else @@ -1161,7 +1161,7 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type, bigtime_t oldModified = attribute->LastModified(); writeLocker.Unlock(); - oldLength = BPLUSTREE_MAX_KEY_LENGTH; + oldLength = MAX_INDEX_KEY_LENGTH; if (attribute->ReadAt(0, oldBuffer, &oldLength) == B_OK) oldData = oldBuffer; @@ -1215,10 +1215,10 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type, // TODO: find a better way than this "pos" thing (the begin of the old key // must be copied to the start of the new one for a comparison) if (status == B_OK && pos == 0) { - // index only the first BPLUSTREE_MAX_KEY_LENGTH bytes + // Index only the first MAX_INDEX_KEY_LENGTH bytes uint16 length = *_length; - if (length > BPLUSTREE_MAX_KEY_LENGTH) - length = BPLUSTREE_MAX_KEY_LENGTH; + if (length > MAX_INDEX_KEY_LENGTH) + length = MAX_INDEX_KEY_LENGTH; // Update index. Note, Index::Update() may be called even if // initializing the index failed - it will just update the live @@ -1256,8 +1256,8 @@ Inode::RemoveAttribute(Transaction& transaction, const char* name) small_data* smallData = FindSmallData(node.Node(), name); if (smallData != NULL) { uint32 length = smallData->DataSize(); - if (length > BPLUSTREE_MAX_KEY_LENGTH) - length = BPLUSTREE_MAX_KEY_LENGTH; + if (length > MAX_INDEX_KEY_LENGTH) + length = MAX_INDEX_KEY_LENGTH; index.Update(transaction, name, smallData->Type(), smallData->Data(), length, NULL, 0, this); } @@ -1361,20 +1361,19 @@ Inode::IsEmpty() { TreeIterator iterator(fTree); - // index and attribute directories are really empty when they are - // empty - directories for standard files always contain ".", and - // "..", so we need to ignore those two - uint32 count = 0; - char name[BPLUSTREE_MAX_KEY_LENGTH]; + char name[MAX_INDEX_KEY_LENGTH + 1]; uint16 length; ino_t id; - while (iterator.GetNextEntry(name, &length, B_FILE_NAME_LENGTH, + while (iterator.GetNextEntry(name, &length, MAX_INDEX_KEY_LENGTH + 1, &id) == B_OK) { - if (Mode() & (S_ATTR_DIR | S_INDEX_DIR)) + if ((Mode() & (S_ATTR_DIR | S_INDEX_DIR)) != 0) return false; - if (++count > 2 || (strcmp(".", name) && strcmp("..", name))) + // Unlike index and attribute directories, directories + // for standard files always contain ".", and "..", so + // we need to ignore those two + if (++count > 2 || (strcmp(".", name) != 0 && strcmp("..", name) != 0)) return false; } return true; diff --git a/src/add-ons/kernel/file_systems/bfs/bfs.h b/src/add-ons/kernel/file_systems/bfs/bfs.h index 9a3e395f2f..2d785eb597 100644 --- a/src/add-ons/kernel/file_systems/bfs/bfs.h +++ b/src/add-ons/kernel/file_systems/bfs/bfs.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Parts of this code is based on work previously done by Marcus Overhagen. * * This file may be used under the terms of the MIT License. @@ -166,11 +166,16 @@ struct small_data { inline bool IsLast(const bfs_inode* inode) const; } _PACKED; -// the file name is part of the small_data structure +// The file name is part of the small_data structure #define FILE_NAME_TYPE 'CSTR' #define FILE_NAME_NAME 0x13 #define FILE_NAME_NAME_LENGTH 1 +// The maximum key length of attribute data that is put in the index. +// This excludes a terminating null byte. +// This must be smaller than or equal as BPLUSTREE_MAX_KEY_LENGTH. +#define MAX_INDEX_KEY_LENGTH 255 + //**************************************