Ticket #6305: htree_update.patch
File htree_update.patch, 38.9 KB (added by , 14 years ago) |
---|
-
src/add-ons/kernel/file_systems/ext2/Inode.cpp
26 26 fID(id), 27 27 fCache(NULL), 28 28 fMap(NULL), 29 fNode(NULL),30 29 fAttributesBlock(NULL) 31 30 { 32 31 rw_lock_init(&fLock, "ext2 inode"); 33 32 34 33 uint32 block; 35 if (volume->GetInodeBlock(id, block) == B_OK) { 36 TRACE("inode %Ld at block %lu\n", ID(), block); 37 uint8* inodeBlock = (uint8*)block_cache_get(volume->BlockCache(), 38 block); 34 fInitStatus = volume->GetInodeBlock(id, block); 35 if (fInitStatus == B_OK) { 36 TRACE("inode %Ld at block %lu\n", id, block); 37 38 CachedBlock cached(volume); 39 const uint8* inodeBlock = cached.SetTo(block); 40 TRACE("Inode table block in memory: %p\n", inodeBlock); 41 39 42 if (inodeBlock != NULL) { 40 fNode = (ext2_inode*)(inodeBlock + volume->InodeBlockIndex(id) 41 * volume->InodeSize()); 42 } 43 TRACE("Inode size: %lu, inode index: %lu\n", volume->InodeSize(), 44 volume->InodeBlockIndex(id)); 45 ext2_inode* inode = (ext2_inode*)(inodeBlock 46 + volume->InodeBlockIndex(id) * volume->InodeSize()); 47 48 fNodeSize = sizeof(ext2_inode) > volume->InodeSize() 49 ? volume->InodeSize() : sizeof(ext2_inode); 50 51 TRACE("Attempting to copy inode data from %p to %p, ext2_inode " 52 "size: %lu\n", inode, &fNode, fNodeSize); 53 54 memcpy(&fNode, inode, fNodeSize); 55 } else 56 fInitStatus = B_IO_ERROR; 43 57 } 44 58 45 if (fNode != NULL) { 46 // TODO: we don't need a cache for short symlinks 47 fCache = file_cache_create(fVolume->ID(), ID(), Size()); 48 fMap = file_map_create(fVolume->ID(), ID(), Size()); 59 if (fInitStatus == B_OK) { 60 if (Size() == 0 || IsDirectory() || (IsSymLink() && Size() < 60)) { 61 fCached = false; 62 } else { 63 fCache = file_cache_create(fVolume->ID(), ID(), Size()); 64 fMap = file_map_create(fVolume->ID(), ID(), Size()); 65 66 if (fCache != NULL) { 67 TRACE("Inode::Inode(): Created file cache\n"); 68 fCached = true; 69 } else { 70 TRACE("Inode::Inode(): Failed to create file cache\n"); 71 fCached = false; 72 fInitStatus = B_ERROR; 73 } 74 } 75 } else { 76 TRACE("Inode: Failed initialization\n"); 77 fCached = false; 49 78 } 50 79 } 51 80 52 81 53 82 Inode::~Inode() 54 83 { 55 file_cache_delete(FileCache()); 56 file_map_delete(Map()); 84 TRACE("Inode destructor\n"); 57 85 86 if (fCached) { 87 TRACE("Deleting the file cache and file map\n"); 88 file_cache_delete(FileCache()); 89 file_map_delete(Map()); 90 } 91 58 92 if (fAttributesBlock) { 93 TRACE("Returning the attributes block\n"); 59 94 uint32 block = B_LENDIAN_TO_HOST_INT32(Node().file_access_control); 60 95 block_cache_put(fVolume->BlockCache(), block); 61 96 } 62 97 63 if (fNode != NULL) { 64 uint32 block; 65 if (fVolume->GetInodeBlock(ID(), block) == B_OK) 66 block_cache_put(fVolume->BlockCache(), block); 67 } 98 TRACE("Inode destructor: Done\n"); 68 99 } 69 100 70 101 71 102 status_t 72 103 Inode::InitCheck() 73 104 { 74 return f Node != NULL ? B_OK : B_ERROR;105 return fInitStatus; 75 106 } 76 107 77 108 … … 95 126 96 127 // shift mode bits, to check directly against accessMode 97 128 mode_t mode = Mode(); 98 if (user == (uid_t)fNode ->UserID())129 if (user == (uid_t)fNode.UserID()) 99 130 mode >>= 6; 100 else if (group == (gid_t)fNode ->GroupID())131 else if (group == (gid_t)fNode.GroupID()) 101 132 mode >>= 3; 102 133 103 134 if (accessMode & ~(mode & S_IRWXO)) … … 114 145 uint32 perIndirectBlock = perBlock * perBlock; 115 146 uint32 index = offset >> fVolume->BlockShift(); 116 147 117 if (offset >= Size()) 148 if (offset >= Size()) { 149 TRACE("FindBlock: offset larger than inode size\n"); 118 150 return B_ENTRY_NOT_FOUND; 151 } 119 152 120 153 // TODO: we could return the size of the sparse range, as this might be more 121 154 // than just a block … … 203 236 204 237 // set/check boundaries for pos/length 205 238 if (pos < 0) { 206 TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos, length); 239 TRACE("inode %Ld: ReadAt failed(pos %Ld, length %lu)\n", ID(), pos, 240 length); 207 241 return B_BAD_VALUE; 208 242 } 209 243 … … 245 279 *_length = length; 246 280 return B_NO_ERROR; 247 281 } 282 283 284 status_t 285 Inode::DisableFileCache() 286 { 287 TRACE("Inode::DisableFileCache()\n"); 288 289 if (!fCached) 290 return B_OK; 291 292 file_cache_delete(FileCache()); 293 file_map_delete(Map()); 294 295 fCached = false; 296 297 return B_OK; 298 } -
src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp
116 116 117 117 status_t status = volume->Mount(device, flags); 118 118 if (status != B_OK) { 119 TRACE("Failed mounting the volume. Error: %s\n", strerror(status)); 119 120 delete volume; 120 121 return status; 121 122 } -
src/add-ons/kernel/file_systems/ext2/Inode.h
32 32 33 33 status_t CheckPermissions(int accessMode) const; 34 34 35 mode_t Mode() const { return fNode ->Mode(); }36 int32 Flags() const { return fNode ->Flags(); }35 mode_t Mode() const { return fNode.Mode(); } 36 int32 Flags() const { return fNode.Flags(); } 37 37 38 off_t Size() const { return fNode ->Size(); }38 off_t Size() const { return fNode.Size(); } 39 39 time_t ModificationTime() const 40 { return fNode ->ModificationTime(); }40 { return fNode.ModificationTime(); } 41 41 time_t CreationTime() const 42 { return fNode ->CreationTime(); }42 { return fNode.CreationTime(); } 43 43 time_t AccessTime() const 44 { return fNode ->AccessTime(); }44 { return fNode.AccessTime(); } 45 45 46 46 //::Volume* _Volume() const { return fVolume; } 47 47 Volume* GetVolume() const { return fVolume; } … … 52 52 status_t AttributeBlockReadAt(off_t pos, uint8 *buffer, 53 53 size_t *length); 54 54 55 ext2_inode& Node() { return *fNode; }55 ext2_inode& Node() { return fNode; } 56 56 57 57 void* FileCache() const { return fCache; } 58 58 void* Map() const { return fMap; } 59 status_t DisableFileCache(); 60 bool IsFileCacheDisabled() const { return !fCached; } 59 61 60 62 private: 61 63 Inode(const Inode&); … … 63 65 // no implementation 64 66 65 67 private: 66 rw_lock fLock; 67 ::Volume* fVolume; 68 ino_t fID; 69 void* fCache; 70 void* fMap; 71 ext2_inode* fNode; 72 ext2_xattr_header* fAttributesBlock; 68 rw_lock fLock; 69 ::Volume* fVolume; 70 ino_t fID; 71 void* fCache; 72 void* fMap; 73 bool fCached; 74 ext2_inode fNode; 75 uint32 fNodeSize; 76 // Inodes have a varible size, but the important 77 // information is always the same size (except in ext4) 78 ext2_xattr_header* fAttributesBlock; 79 status_t fInitStatus; 73 80 }; 74 81 75 82 #endif // INODE_H -
src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp
11 11 12 12 #include <new> 13 13 14 #include "CachedBlock.h" 14 15 #include "HTree.h" 15 16 #include "IndexedDirectoryIterator.h" 16 17 #include "Inode.h" … … 27 28 28 29 HTreeEntryIterator::HTreeEntryIterator(off_t offset, Inode* directory) 29 30 : 31 fDirectory(directory), 32 fVolume(directory->GetVolume()), 30 33 fHasCollision(false), 31 fDirectory(directory), 32 fOffset(offset), 34 fBlockSize(directory->GetVolume()->BlockSize()), 33 35 fParent(NULL), 34 36 fChild(NULL) 35 37 { 36 fBlockSize = fDirectory->GetVolume()->BlockSize(); 38 fInitStatus = fDirectory->FindBlock(offset, fBlockNum); 39 40 if (fInitStatus == B_OK) { 41 fFirstEntry = offset % fBlockSize / sizeof(HTreeEntry); 42 fCurrentEntry = fFirstEntry; 43 } 44 45 TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu entry no. %lu\n", 46 fBlockNum, (uint32)fCurrentEntry); 37 47 } 38 48 39 49 40 50 HTreeEntryIterator::HTreeEntryIterator(uint32 block, uint32 blockSize, 41 51 Inode* directory, HTreeEntryIterator* parent, bool hasCollision) 42 52 : 53 fDirectory(directory), 54 fVolume(directory->GetVolume()), 43 55 fHasCollision(hasCollision), 56 fFirstEntry(1), 57 fCurrentEntry(1), 44 58 fBlockSize(blockSize), 45 fDirectory(directory), 46 fOffset(block * blockSize + sizeof(HTreeFakeDirEntry)), 59 fBlockNum(block), 47 60 fParent(parent), 48 61 fChild(NULL) 49 62 { 50 TRACE("HTreeEntryIterator::HTreeEntryIterator() block %ld offset %Lx\n", 51 block, fOffset); 63 // fCurrentEntry is initialized to 1 to skip the fake directory entry 64 fInitStatus = B_OK; 65 66 TRACE("HTreeEntryIterator::HTreeEntryIterator() block %lu\n", block); 52 67 } 53 68 54 69 55 70 status_t 56 71 HTreeEntryIterator::Init() 57 72 { 58 size_t length = sizeof(HTreeCountLimit);59 HTreeCountLimit countLimit;73 TRACE("HTreeEntryIterator::Init() first entry: %lu\n", 74 (uint32)fFirstEntry); 60 75 61 status_t status = fDirectory->ReadAt(fOffset, (uint8*)&countLimit, 62 &length); 63 64 if (status != B_OK) 65 return status; 66 67 if (length != sizeof(HTreeCountLimit)) { 68 ERROR("HTreeEntryIterator::Init() bad length %ld fOffset 0x%Lx\n", 69 length, fOffset); 76 if (fInitStatus != B_OK) 77 return fInitStatus; 78 79 CachedBlock cached(fVolume); 80 const uint8* block = cached.SetTo(fBlockNum); 81 if (block == NULL) { 82 ERROR("Failed to read htree entry block.\n"); 70 83 fCount = fLimit = 0; 71 return B_ ERROR;84 return B_IO_ERROR; 72 85 } 73 74 fCount = countLimit.Count();75 fLimit = countLimit.Limit();76 86 87 HTreeCountLimit* countLimit = (HTreeCountLimit*)( 88 &((HTreeEntry*)block)[fFirstEntry]); 89 90 fCount = countLimit->Count(); 91 fLimit = countLimit->Limit(); 92 77 93 if (fCount >= fLimit) { 78 ERROR("HTreeEntryIterator::Init() bad fCount %d fOffset 0x%Lx\n", 79 fCount, fOffset); 94 ERROR("HTreeEntryIterator::Init() bad fCount %lu\n", (uint32)fCount); 80 95 fCount = fLimit = 0; 81 96 return B_ERROR; 82 97 } 83 98 84 if (fParent != NULL && 85 fLimit != ((fBlockSize - sizeof(HTreeFakeDirEntry)) 86 / sizeof(HTreeEntry)) ) { 87 ERROR("HTreeEntryIterator::Init() bad fLimit %d should be %ld " 88 "fOffset 0x%Lx\n", fLimit, (fBlockSize - sizeof(HTreeFakeDirEntry)) 89 / sizeof(HTreeEntry), fOffset); 99 if (fLimit != fBlockSize / sizeof(HTreeEntry) - fFirstEntry) { 100 ERROR("HTreeEntryIterator::Init() bad fLimit %lu should be %lu " 101 "at block %lu\n", (uint32)fLimit, fBlockSize / sizeof(HTreeEntry) 102 - fFirstEntry, fBlockNum); 90 103 fCount = fLimit = 0; 91 104 return B_ERROR; 92 } 105 } 93 106 94 TRACE("HTreeEntryIterator::Init() count 0x%x limit 0x%x\n", fCount,95 fLimit);107 TRACE("HTreeEntryIterator::Init() count %lu limit %lu\n", 108 (uint32)fCount, (uint32)fLimit); 96 109 97 fMaxOffset = fOffset + (fCount - 1) * sizeof(HTreeEntry);98 99 110 return B_OK; 100 111 } 101 112 102 113 103 114 HTreeEntryIterator::~HTreeEntryIterator() 104 115 { 116 delete fChild; 105 117 } 106 118 107 119 … … 109 121 HTreeEntryIterator::Lookup(uint32 hash, int indirections, 110 122 DirectoryIterator** directoryIterator) 111 123 { 112 off_t start = fOffset + sizeof(HTreeEntry); 113 off_t end = fMaxOffset; 114 off_t middle = start; 115 size_t entrySize = sizeof(HTreeEntry); 116 HTreeEntry entry; 124 TRACE("HTreeEntryIterator::Lookup()\n"); 125 CachedBlock cached(fVolume); 126 const uint8* block = cached.SetTo(fBlockNum); 127 if (block == NULL) { 128 ERROR("Failed to read htree entry block.\n"); 129 // Fallback to linear search 130 *directoryIterator = new(std::nothrow) 131 DirectoryIterator(fDirectory); 132 133 if (*directoryIterator == NULL) 134 return B_NO_MEMORY; 135 136 return B_OK; 137 } 138 139 HTreeEntry* start = (HTreeEntry*)block + fCurrentEntry + 1; 140 HTreeEntry* end = (HTreeEntry*)block + fCount + fFirstEntry - 1; 141 HTreeEntry* middle = start; 117 142 143 TRACE("HTreeEntryIterator::Lookup() current entry: %lu\n", 144 (uint32)fCurrentEntry); 145 TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n", 146 indirections, start, middle, end); 147 118 148 while (start <= end) { 119 middle = (end - start) / 2; 120 middle -= middle % entrySize; // Alignment 121 middle += start; 149 middle = (HTreeEntry*)((end - start) / 2 150 + start); 122 151 123 TRACE("HTreeEntryIterator::Lookup() %d 0x%Lx 0x%Lx 0x%Lx\n", 124 indirections, start, end, middle); 125 126 status_t status = fDirectory->ReadAt(middle, (uint8*)&entry, 127 &entrySize); 152 TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n", 153 indirections, start, middle, end); 128 154 129 TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, entry.Hash()); 130 131 if (status != B_OK) 132 return status; 133 else if (entrySize != sizeof(entry)) { 134 // Fallback to linear search 135 *directoryIterator = new(std::nothrow) 136 DirectoryIterator(fDirectory); 137 138 if (*directoryIterator == NULL) 139 return B_NO_MEMORY; 140 141 return B_OK; 142 } 143 144 if (hash >= entry.Hash()) 145 start = middle + entrySize; 155 TRACE("HTreeEntryIterator::Lookup() %lx %lx\n", hash, middle->Hash()); 156 157 if (hash >= middle->Hash()) 158 start = middle + 1; 146 159 else 147 end = middle - entrySize;160 end = middle - 1; 148 161 } 149 162 150 status_t status = fDirectory->ReadAt(start - entrySize, (uint8*)&entry, 151 &entrySize); 152 if (status != B_OK) 153 return status; 154 163 --start; 164 165 fCurrentEntry = ((uint8*)start - block) / sizeof(HTreeEntry); 166 155 167 if (indirections == 0) { 168 TRACE("HTreeEntryIterator::Lookup(): Creating an indexed directory " 169 "iterator starting at block: %lu, hash: 0x%lX\n", start->Block(), 170 start->Hash()); 156 171 *directoryIterator = new(std::nothrow) 157 IndexedDirectoryIterator( entry.Block() * fBlockSize, fBlockSize,158 fDirectory,this);159 172 IndexedDirectoryIterator(start->Block() * fBlockSize, fDirectory, 173 this); 174 160 175 if (*directoryIterator == NULL) 161 176 return B_NO_MEMORY; 162 177 163 178 return B_OK; 164 179 } 165 180 181 TRACE("HTreeEntryIterator::Lookup(): Creating a HTree entry iterator " 182 "starting at block: %lu, hash: 0x%lX\n", start->Block(), start->Hash()); 183 uint32 blockNum; 184 status_t status = fDirectory->FindBlock(start->Block() * fBlockSize, 185 blockNum); 186 if (status != B_OK) 187 return status; 188 166 189 delete fChild; 167 190 168 fChild = new(std::nothrow) HTreeEntryIterator(entry.Block(), fBlockSize, 169 fDirectory, this, entry.Hash() & 1 == 1); 170 191 fChild = new(std::nothrow) HTreeEntryIterator(blockNum, fBlockSize, 192 fDirectory, this, start->Hash() & 1 == 1); 171 193 if (fChild == NULL) 172 194 return B_NO_MEMORY; 173 fChildDeleter.SetTo(fChild);174 195 175 196 status = fChild->Init(); 176 197 if (status != B_OK) … … 181 202 182 203 183 204 status_t 184 HTreeEntryIterator::GetNext( off_t& childOffset)205 HTreeEntryIterator::GetNext(uint32& childBlock) 185 206 { 186 size_t entrySize = sizeof(HTreeEntry); 187 fOffset += entrySize; 188 bool firstEntry = fOffset >= fMaxOffset; 189 190 if (firstEntry) { 191 if (fParent == NULL) 207 fCurrentEntry++; 208 TRACE("HTreeEntryIterator::GetNext(): current entry: %lu\n", 209 (uint32)fCurrentEntry); 210 bool endOfBlock = fCurrentEntry >= (fCount + fFirstEntry); 211 212 if (endOfBlock) { 213 TRACE("HTreeEntryIterator::GetNext(): end of entries in the block\n"); 214 if (fParent == NULL) { 215 TRACE("HTreeEntryIterator::GetNext(): block was the root block\n"); 192 216 return B_ENTRY_NOT_FOUND; 217 } 193 218 194 status_t status = fParent->GetNext(fOffset); 219 uint32 logicalBlock; 220 status_t status = fParent->GetNext(logicalBlock); 195 221 if (status != B_OK) 196 222 return status; 197 223 224 TRACE("HTreeEntryIterator::GetNext(): moving to next block: %lu\n", 225 logicalBlock); 226 227 status = fDirectory->FindBlock(logicalBlock * fBlockSize, fBlockNum); 228 if (status != B_OK) 229 return status; 230 231 fFirstEntry = 1; // Skip fake directory entry 232 fCurrentEntry = 1; 198 233 status = Init(); 199 234 if (status != B_OK) 200 235 return status; 201 236 202 237 fHasCollision = fParent->HasCollision(); 203 238 } 239 240 CachedBlock cached(fVolume); 241 const uint8* block = cached.SetTo(fBlockNum); 242 if (block == NULL) 243 return B_IO_ERROR; 244 245 HTreeEntry* entry = &((HTreeEntry*)block)[fCurrentEntry]; 246 247 if (!endOfBlock) 248 fHasCollision = (entry[fCurrentEntry].Hash() & 1) == 1; 204 249 205 HTreeEntry entry; 206 status_t status = fDirectory->ReadAt(fOffset, (uint8*)&entry, &entrySize); 207 if (status != B_OK) 208 return status; 209 else if (entrySize != sizeof(entry)) { 210 // Weird error, try to skip it 211 return GetNext(childOffset); 212 } 250 TRACE("HTreeEntryIterator::GetNext(): next block: %lu\n", 251 entry->Block()); 252 253 childBlock = entry->Block(); 213 254 214 if (!firstEntry)215 fHasCollision = (entry.Hash() & 1) == 1;216 217 childOffset = entry.Block() * fBlockSize;218 219 255 return B_OK; 220 256 } -
src/add-ons/kernel/file_systems/ext2/Volume.cpp
15 15 #include <stdlib.h> 16 16 #include <string.h> 17 17 18 #include <util/AutoLock.h> 19 18 20 #include <fs_cache.h> 19 21 #include <fs_volume.h> 20 22 21 #include <util/AutoLock.h>22 23 23 #include "Inode.h" 24 24 25 25 … … 220 220 221 221 Volume::~Volume() 222 222 { 223 TRACE("Volume destructor.\n"); 223 224 if (fGroupBlocks != NULL) { 224 225 uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1) 225 226 / fGroupsPerBlock; … … 254 255 { 255 256 flags |= B_MOUNT_READ_ONLY; 256 257 // we only support read-only for now 258 259 if ((flags & B_MOUNT_READ_ONLY) != 0) { 260 TRACE("Volume::Mount(): Read only\n"); 261 } else { 262 TRACE("Volume::Mount(): Read write\n"); 263 } 257 264 258 265 DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0 259 266 ? O_RDONLY : O_RDWR); … … 278 285 fBlockSize = 1UL << fSuperBlock.BlockShift(); 279 286 fFirstDataBlock = fSuperBlock.FirstDataBlock(); 280 287 288 fFreeBlocks = fSuperBlock.FreeBlocks(); 289 290 uint32 numBlocks = fSuperBlock.NumBlocks() - fFirstDataBlock; 291 uint32 blocksPerGroup = fSuperBlock.BlocksPerGroup(); 292 fNumGroups = numBlocks / blocksPerGroup; 293 if (numBlocks % blocksPerGroup != 0) 294 fNumGroups++; 295 296 fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group); 281 297 fNumInodes = fSuperBlock.NumInodes(); 282 fNumGroups = (fSuperBlock.NumBlocks() - fFirstDataBlock - 1)283 / fSuperBlock.BlocksPerGroup() + 1;284 fGroupsPerBlock = fBlockSize / sizeof(ext2_block_group);285 298 286 299 TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n", 287 300 fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock); … … 309 322 fBlockCache = opener.InitCache(NumBlocks(), fBlockSize); 310 323 if (fBlockCache == NULL) 311 324 return B_ERROR; 325 326 TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache); 312 327 328 // ready 313 329 status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode); 314 330 if (status != B_OK) { 315 331 TRACE("could not create root node: get_vnode() failed!\n"); … … 342 358 status_t 343 359 Volume::Unmount() 344 360 { 361 TRACE("Volume::Unmount()\n"); 362 363 TRACE("Volume::Unmount(): Putting root node\n"); 345 364 put_vnode(fFSVolume, RootNode()->ID()); 365 TRACE("Volume::Unmount(): Deleting the block cache\n"); 346 366 block_cache_delete(fBlockCache, !IsReadOnly()); 367 TRACE("Volume::Unmount(): Closing device\n"); 347 368 close(fDevice); 348 369 370 TRACE("Volume::Unmount(): Done\n"); 349 371 return B_OK; 350 372 } 351 373 … … 459 481 return _UnsupportedIncompatibleFeatures(*superBlock) == 0 460 482 ? B_OK : B_NOT_SUPPORTED; 461 483 } 462 -
src/add-ons/kernel/file_systems/ext2/HTree.cpp
7 7 */ 8 8 9 9 10 #include "CachedBlock.h" 10 11 #include "HTree.h" 11 12 12 13 #include <new> … … 17 18 #include "Volume.h" 18 19 19 20 21 //#define COLLISION_TEST 22 20 23 //#define TRACE_EXT2 21 24 #ifdef TRACE_EXT2 22 25 # define TRACE(x...) dprintf("\33[34mext2:\33[0m " x) … … 75 78 76 79 HTree::~HTree() 77 80 { 81 delete fRootEntry; 78 82 } 79 83 80 84 81 85 status_t 82 86 HTree::Lookup(const char* name, DirectoryIterator** iterator) 83 87 { 88 TRACE("HTree::Lookup()\n"); 84 89 if (!fIndexed || (name[0] == '.' 85 90 && (name[1] == '\0' || (name[1] == '.' && name[2] == '0')))) { 86 91 // No HTree support or looking for trivial directories 87 92 // TODO: Does these directories get hashed? 88 93 *iterator = new(std::nothrow) DirectoryIterator(fDirectory); 94 TRACE("HTree::Lookup(): Falling back to linear iteration\n"); 89 95 90 96 if (*iterator == NULL) 91 97 return B_NO_MEMORY; 92 98 return B_OK; 93 99 } 94 100 95 HTreeRoot root; 96 size_t length = sizeof(root); 101 uint32 blockNum; 102 status_t status = fDirectory->FindBlock(0, blockNum); 103 if (status != B_OK) { 104 *iterator = new(std::nothrow) DirectoryIterator(fDirectory); 105 TRACE("HTree::Lookup(): Failed to read block in diretory\n"); 106 107 if (*iterator == NULL) 108 return B_NO_MEMORY; 109 return B_OK; 110 } 111 112 CachedBlock cached(fDirectory->GetVolume()); 113 const uint8* block = cached.SetTo(blockNum); 114 115 HTreeRoot* root = (HTreeRoot*)block; 97 116 98 status_t status = fDirectory->ReadAt(0, (uint8*)&root, &length); 99 if (status < B_OK) 100 return status; 101 102 if (length != sizeof(root) || !root.IsValid()) { 117 if (root == NULL || !root->IsValid()) { 103 118 // Fallback to linear search 104 119 *iterator = new(std::nothrow) DirectoryIterator(fDirectory); 120 TRACE("HTree::Lookup(): Invalid root node\n"); 105 121 if (*iterator == NULL) 106 122 return B_NO_MEMORY; 107 123 108 124 return B_OK; 109 125 } 110 126 111 uint32 hash = _Hash(name, root .hash_version);127 uint32 hash = _Hash(name, root->hash_version); 112 128 113 off_t start = (off_t)root .root_info_length129 off_t start = (off_t)root->root_info_length 114 130 + 2 * (sizeof(HTreeFakeDirEntry) + 4); 115 131 132 delete fRootEntry; 133 116 134 fRootEntry = new(std::nothrow) HTreeEntryIterator(start, fDirectory); 117 135 if (fRootEntry == NULL) 118 136 return B_NO_MEMORY; 119 137 120 fRootDeleter.SetTo(fRootEntry);121 138 status = fRootEntry->Init(); 122 139 if (status != B_OK) 123 140 return status; 124 141 125 return fRootEntry->Lookup(hash, (uint32)root .indirection_levels, iterator);142 return fRootEntry->Lookup(hash, (uint32)root->indirection_levels, iterator); 126 143 } 127 144 128 145 … … 131 148 { 132 149 uint32 hash; 133 150 151 #ifndef COLLISION_TEST 134 152 switch (version) { 135 153 case HTREE_HASH_LEGACY: 136 154 hash = _HashLegacy(name); … … 145 163 panic("Hash verification succeeded but then failed?"); 146 164 hash = 0; 147 165 }; 166 #else 167 hash = 0; 168 #endif 148 169 149 TRACE(" Filename hash: %u\n", hash);170 TRACE("HTree::_Hash(): filename hash 0x%lX\n", hash); 150 171 151 172 return hash & ~1; 152 173 } … … 155 176 uint32 156 177 HTree::_HashLegacy(const char* name) 157 178 { 179 TRACE("HTree::_HashLegacy()\n"); 158 180 uint32 hash = 0x12a3fe2d; 159 181 uint32 previous = 0x37abe8f9; 160 182 … … 168 190 hash = next; 169 191 } 170 192 171 return hash ;193 return hash << 1; 172 194 } 173 195 174 196 … … 230 252 shifts[2] = 9; 231 253 shifts[3] = 13; 232 254 233 for (int j = 0; j < 2; ++j) {234 for (int i = j; i < 4; i += 2) {255 for (int j = 1; j >= 0; --j) { 256 for (int i = j; i < 8; i += 2) { 235 257 a += _MD4G(b, c, d) + blocks[i] + 013240474631UL; 236 258 uint32 shift = shifts[i / 2]; 237 259 a = (a << shift) | (a >> (32 - shift)); … … 247 269 248 270 for (int i = 0; i < 4; ++i) { 249 271 a += _MD4H(b, c, d) + blocks[3 - i] + 015666365641UL; 250 uint32 shift = shifts[i *2];272 uint32 shift = shifts[i * 2 % 4]; 251 273 a = (a << shift) | (a >> (32 - shift)); 252 274 253 275 _MD4RotateVars(a, b, c, d); 254 276 255 277 a += _MD4H(b, c, d) + blocks[7 - i] + 015666365641UL; 256 shift = shifts[ i*2 + 1];278 shift = shifts[(i * 2 + 1) % 4]; 257 279 a = (a << shift) | (a >> (32 - shift)); 258 280 259 281 _MD4RotateVars(a, b, c, d); … … 269 291 uint32 270 292 HTree::_HashHalfMD4(const char* name) 271 293 { 294 TRACE("HTree::_HashHalfMD4()\n"); 272 295 uint32 buffer[4]; 273 296 274 297 buffer[0] = fHashSeed[0]; … … 318 341 uint32 319 342 HTree::_HashTEA(const char* name) 320 343 { 344 TRACE("HTree::_HashTEA()\n"); 321 345 uint32 buffer[4]; 322 346 323 347 buffer[0] = fHashSeed[0]; … … 354 378 int completeIterations = length / 4; 355 379 356 380 for (int i = 0; i < completeIterations; ++i) { 357 uint32 value = 0| *(string++);381 uint32 value = (padding << 8) | *(string++); 358 382 value = (value << 8) | *(string++); 359 383 value = (value << 8) | *(string++); 360 384 value = (value << 8) | *(string++); -
src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.h
Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.cpp ___________________________________________________________________ Added: svn:executable + *
14 14 #include "DirectoryIterator.h" 15 15 16 16 17 class Volume; 18 19 17 20 class HTreeEntryIterator { 18 21 public: 19 22 HTreeEntryIterator(off_t offset, … … 26 29 DirectoryIterator** iterator); 27 30 bool HasCollision() { return fHasCollision; } 28 31 29 status_t GetNext( off_t& offset);32 status_t GetNext(uint32& offset); 30 33 private: 31 34 HTreeEntryIterator(uint32 block, 32 35 uint32 blockSize, Inode* directory, … … 34 37 bool hasCollision); 35 38 36 39 private: 40 Inode* fDirectory; 41 Volume* fVolume; 42 status_t fInitStatus; 43 37 44 bool fHasCollision; 38 45 uint16 fLimit, fCount; 46 uint16 fFirstEntry; 47 uint16 fCurrentEntry; 39 48 40 49 uint32 fBlockSize; 41 Inode* fDirectory; 42 off_t fOffset; 43 off_t fMaxOffset; 50 uint32 fBlockNum; 44 51 45 52 HTreeEntryIterator* fParent; 46 53 HTreeEntryIterator* fChild; 47 ObjectDeleter<HTreeEntryIterator> fChildDeleter;48 54 }; 49 55 50 56 #endif // HTREE_ENTRY_ITERATOR_H -
src/add-ons/kernel/file_systems/ext2/HTree.h
9 9 #define HTREE_H 10 10 11 11 12 #include <AutoDeleter.h>13 14 12 #include "ext2.h" 15 13 #include "DirectoryIterator.h" 16 14 #include "HTreeEntryIterator.h" … … 127 125 Inode* fDirectory; 128 126 uint32 fHashSeed[4]; 129 127 HTreeEntryIterator* fRootEntry; 130 ObjectDeleter<HTreeEntryIterator> fRootDeleter;131 128 }; 132 129 133 130 #endif // HTREE_H -
src/add-ons/kernel/file_systems/ext2/Volume.h
Property changes on: src/add-ons/kernel/file_systems/ext2/HTree.h ___________________________________________________________________ Added: svn:executable + *
40 40 41 41 uint32 NumInodes() const 42 42 { return fNumInodes; } 43 uint32 NumGroups() const 44 { return fNumGroups; } 43 45 off_t NumBlocks() const 44 46 { return fSuperBlock.NumBlocks(); } 45 47 off_t FreeBlocks() const 46 { return fSuperBlock.FreeBlocks(); } 48 { return fFreeBlocks; } 49 uint32 FirstDataBlock() const 50 { return fFirstDataBlock; } 47 51 48 52 uint32 BlockSize() const { return fBlockSize; } 49 53 uint32 BlockShift() const { return fBlockShift; } 54 uint32 BlocksPerGroup() const 55 { return fSuperBlock.BlocksPerGroup(); } 50 56 uint32 InodeSize() const 51 57 { return fSuperBlock.InodeSize(); } 58 uint32 InodesPerGroup() const 59 { return fSuperBlock.InodesPerGroup(); } 52 60 ext2_super_block& SuperBlock() { return fSuperBlock; } 53 61 54 62 status_t GetInodeBlock(ino_t id, uint32& block); 55 63 uint32 InodeBlockIndex(ino_t id) const; 56 64 status_t GetBlockGroup(int32 index, 57 65 ext2_block_group** _group); 58 66 59 67 bool IndexedDirectories() const 60 68 { return (fSuperBlock.CompatibleFeatures() 61 69 & EXT2_FEATURE_DIRECTORY_INDEX) != 0; } … … 76 84 int fDevice; 77 85 ext2_super_block fSuperBlock; 78 86 char fName[32]; 87 79 88 uint32 fFlags; 80 89 uint32 fBlockSize; 81 90 uint32 fBlockShift; 82 91 uint32 fFirstDataBlock; 92 83 93 uint32 fNumInodes; 84 94 uint32 fNumGroups; 95 uint32 fFreeBlocks; 85 96 uint32 fGroupsPerBlock; 86 97 ext2_block_group** fGroupBlocks; 87 98 uint32 fInodesPerBlock; -
src/add-ons/kernel/file_systems/ext2/DirectoryIterator.cpp
8 8 9 9 #include <string.h> 10 10 11 #include "CachedBlock.h" 11 12 #include "HTree.h" 12 13 #include "Inode.h" 13 14 … … 23 24 DirectoryIterator::DirectoryIterator(Inode* inode) 24 25 : 25 26 fInode(inode), 26 fOffset(0) 27 fLogicalBlock(0), 28 fDisplacement(0), 29 fBlockSize(inode->GetVolume()->BlockSize()) 27 30 { 31 fInitStatus = fInode->FindBlock(0, fPhysicalBlock); 28 32 } 29 33 30 34 … … 34 38 35 39 36 40 status_t 41 DirectoryIterator::InitCheck() 42 { 43 return fInitStatus; 44 } 45 46 47 status_t 37 48 DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id) 38 49 { 39 if (fOffset + sizeof(ext2_dir_entry) >= fInode->Size()) { 50 if (fLogicalBlock * fBlockSize + fDisplacement 51 + ext2_dir_entry::MinimumSize() >= fInode->Size()) { 40 52 TRACE("DirectoryIterator::GetNext() out of entries\n"); 41 53 return B_ENTRY_NOT_FOUND; 42 54 } 43 55 44 ext2_dir_entry entry; 56 CachedBlock cached(fInode->GetVolume()); 57 ext2_dir_entry* entry; 45 58 46 while (true) { 47 size_t length = ext2_dir_entry::MinimumSize(); 48 status_t status = fInode->ReadAt(fOffset, (uint8*)&entry, &length); 49 if (status != B_OK) 50 return status; 51 if (length < ext2_dir_entry::MinimumSize() || entry.Length() == 0) 59 const uint8* block = cached.SetTo(fPhysicalBlock); 60 if (block == NULL) 61 return B_IO_ERROR; 62 63 bool gotEntry = false; 64 while (!gotEntry) { 65 TRACE("Checking entry at block %lu, displacement %lu\n", fPhysicalBlock, 66 fDisplacement); 67 68 entry = (ext2_dir_entry*)(block + fDisplacement); 69 70 if (entry->Length() == 0) { 71 TRACE("empty entry.\n"); 52 72 return B_ENTRY_NOT_FOUND; 53 if (!entry.IsValid()) 73 } 74 if (!entry->IsValid()) { 75 TRACE("invalid entry.\n"); 54 76 return B_BAD_DATA; 77 } 55 78 56 if (entry.NameLength() != 0) 57 break; 79 if (entry->NameLength() != 0) { 80 // Get name 81 gotEntry = true; 58 82 59 fOffset += entry.Length(); 60 TRACE("DirectoryIterator::GetNext() skipping entry\n"); 61 } 83 size_t length = entry->NameLength(); 62 84 63 TRACE("offset %Ld: entry ino %lu, length %u, name length %u, type %u\n", 64 fOffset, entry.InodeID(), entry.Length(), entry.NameLength(), 65 entry.FileType()); 85 TRACE("block %lu, displacement %lu: entry ino %lu, length %u, " 86 "name length %lu, type %lu\n", fLogicalBlock, fDisplacement, 87 entry->InodeID(), entry->Length(), (uint32)length, 88 (uint32)entry->FileType()); 66 89 67 // read name 90 if (*_nameLength < length) 91 length = *_nameLength - 1; 92 memcpy(name, entry->name, length); 93 name[length] = '\0'; 68 94 69 size_t length = entry.NameLength(); 70 status_t status = fInode->ReadAt(fOffset + ext2_dir_entry::MinimumSize(), 71 (uint8*)entry.name, &length); 72 if (status == B_OK) { 73 if (*_nameLength < length) 74 length = *_nameLength - 1; 75 memcpy(name, entry.name, length); 76 name[length] = '\0'; 95 *_id = entry->InodeID(); 96 *_nameLength = length; 97 } 77 98 78 *_id = entry.InodeID(); 79 *_nameLength = length; 99 fDisplacement += entry->Length(); 80 100 81 fOffset += entry.Length(); 101 if (fDisplacement == fBlockSize) { 102 TRACE("Reached end of block\n"); 103 104 fDisplacement = 0; 105 fLogicalBlock++; 106 107 if (fLogicalBlock * fBlockSize + ext2_dir_entry::MinimumSize() 108 < fInode->Size()) { 109 status_t status = fInode->FindBlock(fLogicalBlock * fBlockSize, 110 fPhysicalBlock); 111 if (status != B_OK) 112 return status; 113 } else if (!gotEntry) { 114 TRACE("DirectoryIterator::GetNext() end of directory file\n"); 115 return B_ENTRY_NOT_FOUND; 116 } 117 118 if (!gotEntry) { 119 block = cached.SetTo(fPhysicalBlock); 120 if (block == NULL) 121 return B_IO_ERROR; 122 } 123 } else if (fDisplacement > fBlockSize && !gotEntry) { 124 TRACE("The entry isn't block aligned.\n"); 125 // TODO: Is block alignment obligatory? 126 return B_BAD_DATA; 127 } 128 129 TRACE("DirectoryIterator::GetNext() skipping entry\n"); 82 130 } 83 131 84 return status;132 return B_OK; 85 133 } 86 134 87 135 88 136 status_t 89 137 DirectoryIterator::Rewind() 90 138 { 91 fOffset = 0; 92 return B_OK; 139 fDisplacement = 0; 140 fLogicalBlock = 0; 141 142 return fInode->FindBlock(0, fPhysicalBlock); 93 143 } -
src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.cpp
15 15 #include "Inode.h" 16 16 17 17 18 //#define COLLISION_TEST 19 18 20 //#define TRACE_EXT2 19 21 #ifdef TRACE_EXT2 20 22 # define TRACE(x...) dprintf("\33[34mext2:\33[0m " x) … … 24 26 25 27 26 28 IndexedDirectoryIterator::IndexedDirectoryIterator(off_t start, 27 uint32 blockSize,Inode* directory, HTreeEntryIterator* parent)29 Inode* directory, HTreeEntryIterator* parent) 28 30 : 29 31 DirectoryIterator(directory), 30 32 fIndexing(true), 31 32 33 fParent(parent), 33 fMaxOffset(start + blockSize), 34 fBlockSize(blockSize), 35 fMaxAttempts(0) 34 fPreviousBlock(start / fBlockSize) 36 35 { 37 fOffset = start; 36 fDisplacement = start % fBlockSize; 37 fLogicalBlock = fPreviousBlock; 38 39 fInitStatus = fInode->FindBlock(fLogicalBlock * fBlockSize, fPhysicalBlock); 38 40 } 39 41 40 42 … … 46 48 status_t 47 49 IndexedDirectoryIterator::GetNext(char* name, size_t* nameLength, ino_t* id) 48 50 { 49 if (fIndexing && fOffset + sizeof(HTreeFakeDirEntry) >= fMaxOffset) { 51 TRACE("IndexedDirectoryIterator::GetNext()\n"); 52 if (fIndexing && fLogicalBlock != fPreviousBlock) { 50 53 TRACE("IndexedDirectoryIterator::GetNext() calling next block\n"); 51 status_t status = fParent->GetNext(fOffset); 54 55 if (!fParent->HasCollision()) { 56 TRACE("IndexedDirectoryIterator::GetNext(): next block doesn't " 57 "contain collisions from previous block\n"); 58 #ifndef COLLISION_TEST 59 return B_ENTRY_NOT_FOUND; 60 #endif 61 } 62 63 fDisplacement = 0; 64 status_t status = fParent->GetNext(fLogicalBlock); 52 65 if (status != B_OK) 53 66 return status; 54 67 55 if (fMaxAttempts++ > 4)56 return B_ERROR;57 58 fMaxOffset = fOffset + fBlockSize;68 fPreviousBlock = fLogicalBlock; 69 status = fInode->FindBlock(fLogicalBlock * fBlockSize, fPhysicalBlock); 70 if (status != B_OK) 71 return status; 59 72 } 60 73 61 74 return DirectoryIterator::GetNext(name, nameLength, id); … … 67 80 { 68 81 // The only way to rewind it is too loose indexing 69 82 70 fOffset = 0; 71 fMaxOffset = fInode->Size(); 83 fLogicalBlock = 0; 84 fPreviousBlock = 0; 85 fDisplacement = 0; 72 86 fIndexing = false; 73 87 74 return B_OK;88 return fInode->FindBlock(fLogicalBlock, fPhysicalBlock); 75 89 } -
src/add-ons/kernel/file_systems/ext2/DirectoryIterator.h
16 16 DirectoryIterator(Inode* inode); 17 17 virtual ~DirectoryIterator(); 18 18 19 virtual status_t InitCheck(); 20 19 21 virtual status_t GetNext(char* name, size_t* _nameLength, ino_t* id); 20 22 21 23 virtual status_t Rewind(); … … 27 29 28 30 protected: 29 31 Inode* fInode; 30 off_t fOffset; 32 uint32 fLogicalBlock; 33 uint32 fPhysicalBlock; 34 uint32 fDisplacement; 35 uint32 fBlockSize; 36 status_t fInitStatus; 31 37 }; 32 38 33 39 #endif // DIRECTORY_ITERATOR_H 40 -
src/add-ons/kernel/file_systems/ext2/IndexedDirectoryIterator.h
17 17 class IndexedDirectoryIterator : public DirectoryIterator { 18 18 public: 19 19 IndexedDirectoryIterator(off_t start, 20 uint32 blockSize,Inode* directory,20 Inode* directory, 21 21 HTreeEntryIterator* parent); 22 22 virtual ~IndexedDirectoryIterator(); 23 23 … … 25 25 ino_t* id); 26 26 27 27 status_t Rewind(); 28 28 29 private: 29 30 bool fIndexing; 30 31 HTreeEntryIterator* fParent; 31 off_t fMaxOffset; 32 uint32 fBlockSize; 33 uint32 fMaxAttempts; 32 uint32 fPreviousBlock; 34 33 }; 35 34 36 35 #endif // INDEXED_DIRECTORY_ITERATOR_H -
src/add-ons/kernel/file_systems/ext2/ext2.h
13 13 #include <KernelExport.h> 14 14 15 15 16 #define TRACE_EXT2 17 16 18 #define EXT2_SUPER_BLOCK_OFFSET 1024 17 19 18 20 struct ext2_super_block { … … 108 110 { return B_LENDIAN_TO_HOST_INT32(read_only_features); } 109 111 uint32 IncompatibleFeatures() const 110 112 { return B_LENDIAN_TO_HOST_INT32(incompatible_features); } 113 ino_t JournalInode() const 114 { return B_LENDIAN_TO_HOST_INT32(journal_inode); } 111 115 uint32 HashSeed(uint8 i) const 112 116 { return B_LENDIAN_TO_HOST_INT32(hash_seed[i]); } 113 117 … … 162 166 uint16 _padding; 163 167 uint32 _reserved[3]; 164 168 169 uint32 BlockBitmap() const 170 { return B_LENDIAN_TO_HOST_INT32(block_bitmap); } 171 uint32 InodeBitmap() const 172 { return B_LENDIAN_TO_HOST_INT32(inode_bitmap); } 165 173 uint32 InodeTable() const 166 174 { return B_LENDIAN_TO_HOST_INT32(inode_table); } 175 uint16 FreeBlocks() const 176 { return B_LENDIAN_TO_HOST_INT16(free_blocks); } 177 uint16 FreeInodes() const 178 { return B_LENDIAN_TO_HOST_INT16(free_inodes); } 167 179 } _PACKED; 168 180 169 181 #define EXT2_DIRECT_BLOCKS 12 … … 214 226 uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } 215 227 uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } 216 228 uint16 NumLinks() const { return B_LENDIAN_TO_HOST_INT16(num_links); } 229 uint32 NumBlocks() const { return B_LENDIAN_TO_HOST_INT32(num_blocks); } 217 230 218 231 time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); } 219 232 time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); } … … 270 283 uint8 file_type; 271 284 char name[EXT2_NAME_LENGTH]; 272 285 273 uint32 274 uint16 275 uint8 276 uint8 286 uint32 InodeID() const { return B_LENDIAN_TO_HOST_INT32(inode_id); } 287 uint16 Length() const { return B_LENDIAN_TO_HOST_INT16(length); } 288 uint8 NameLength() const { return name_length; } 289 uint8 FileType() const { return file_type; } 277 290 278 291 bool IsValid() const 279 292 { -
src/add-ons/kernel/file_systems/ext2/CachedBlock.h
14 14 15 15 class CachedBlock { 16 16 public: 17 CachedBlock(Volume* volume);18 CachedBlock(Volume* volume, uint32 block);19 ~CachedBlock();17 CachedBlock(Volume* volume); 18 CachedBlock(Volume* volume, uint32 block); 19 ~CachedBlock(); 20 20 21 void Keep();22 void Unset();21 void Keep(); 22 void Unset(); 23 23 24 constuint8* SetTo(uint32 block);24 const uint8* SetTo(uint32 block); 25 25 26 constuint8* Block() const { return fBlock; }27 off_t BlockNumber() const { return fBlockNumber; }26 const uint8* Block() const { return fBlock; } 27 off_t BlockNumber() const { return fBlockNumber; } 28 28 29 29 private: 30 CachedBlock(const CachedBlock &);31 CachedBlock &operator=(const CachedBlock &);32 // no implementation33 30 CachedBlock(const CachedBlock &); 31 CachedBlock &operator=(const CachedBlock &); 32 // no implementation 33 34 34 protected: 35 Volume* fVolume;36 uint32 fBlockNumber;37 uint8* fBlock;35 Volume* fVolume; 36 uint32 fBlockNumber; 37 uint8* fBlock; 38 38 }; 39 39 40 40 … … 94 94 return fBlock = (uint8 *)block_cache_get(fVolume->BlockCache(), block); 95 95 } 96 96 97 97 98 #endif // CACHED_BLOCK_H