1/* 2 * Copyright 2011, J��r��me Duval, korli@users.berlios.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 6 7#include "DirectoryIterator.h" 8 9#include <new> 10#include <stdlib.h> 11 12#include "CRCTable.h" 13 14 15//#define TRACE_BTRFS 16#ifdef TRACE_BTRFS 17# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x) 18#else 19# define TRACE(x...) ; 20#endif 21# define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x) 22 23 24DirectoryIterator::DirectoryIterator(Inode* inode) 25 : 26 fOffset(0), 27 fInode(inode), 28 fIterator(NULL) 29{ 30 struct btrfs_key key; 31 key.SetType(BTRFS_KEY_TYPE_DIR_INDEX); 32 key.SetObjectID(inode->ID()); 33 fIterator = new(std::nothrow) TreeIterator(inode->GetVolume()->FSTree(), 34 key); 35} 36 37 38DirectoryIterator::~DirectoryIterator() 39{ 40 delete fIterator; 41} 42 43 44status_t 45DirectoryIterator::InitCheck() 46{ 47 return fIterator != NULL ? B_OK : B_NO_MEMORY; 48} 49 50 51status_t 52DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id) 53{ 54 if (fOffset == 0) { 55 *_nameLength = 3; 56 strlcpy(name, "..", *_nameLength); 57 *_id = fInode->ID(); 58 fOffset = 1; 59 return B_OK; 60 } else if (fOffset == 1) { 61 *_nameLength = 2; 62 strlcpy(name, ".", *_nameLength); 63 fOffset = 2; 64 if (fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) { 65 *_id = fInode->ID(); 66 return B_OK; 67 } 68 return fInode->FindParent(_id); 69 } 70 71 btrfs_key key; 72 btrfs_dir_entry *entries; 73 size_t entries_length; 74 status_t status = fIterator->GetNextEntry(key, (void**)&entries, 75 &entries_length); 76 if (status != B_OK) 77 return status; 78 79 btrfs_dir_entry *entry = entries; 80 uint16 current = 0; 81 while (current < entries_length) { 82 current += entry->Length(); 83 break; 84 // TODO there could be several entries with the same name hash 85 entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length()); 86 } 87 88 TRACE("DirectoryIterator::GetNext() entries_length %ld name_length %d\n", 89 entries_length, entry->NameLength()); 90 91 memcpy(name, entry + 1, entry->NameLength()); 92 name[entry->NameLength()] = '\0'; 93 *_nameLength = entry->NameLength(); 94 *_id = entry->InodeID(); 95 free(entries); 96 97 return B_OK; 98} 99 100 101status_t 102DirectoryIterator::Lookup(const char* name, size_t nameLength, ino_t* _id) 103{ 104 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 105 if (strcmp(name, ".") == 0 106 || fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) { 107 *_id = fInode->ID(); 108 return B_OK; 109 } 110 return fInode->FindParent(_id); 111 } 112 113 uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength); 114 struct btrfs_key key; 115 key.SetType(BTRFS_KEY_TYPE_DIR_ITEM); 116 key.SetObjectID(fInode->ID()); 117 key.SetOffset(hash); 118 119 btrfs_dir_entry *entries; 120 size_t length; 121 status_t status = fInode->GetVolume()->FSTree()->FindExact(key, 122 (void**)&entries, &length); 123 if (status != B_OK) { 124 TRACE("DirectoryIterator::Lookup(): Couldn't find entry with hash %lu " 125 "\"%s\"\n", hash, name); 126 return status; 127 } 128 129 btrfs_dir_entry *entry = entries; 130 uint16 current = 0; 131 while (current < length) { 132 current += entry->Length(); 133 break; 134 // TODO there could be several entries with the same name hash 135 entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length()); 136 } 137 138 TRACE("DirectoryIterator::Lookup() entries_length %ld name_length %d\n", 139 length, entry->NameLength()); 140 141 *_id = entry->InodeID(); 142 free(entries); 143 144 return B_OK; 145} 146 147 148status_t 149DirectoryIterator::Rewind() 150{ 151 fIterator->Rewind(); 152 fOffset = BPLUSTREE_BEGIN; 153 return B_OK; 154} 155 156