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 24 DirectoryIterator::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 38 DirectoryIterator::~DirectoryIterator() 39 { 40 delete fIterator; 41 } 42 43 44 status_t 45 DirectoryIterator::InitCheck() 46 { 47 return fIterator != NULL ? B_OK : B_NO_MEMORY; 48 } 49 50 51 status_t 52 DirectoryIterator::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 101 status_t 102 DirectoryIterator::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 148 status_t 149 DirectoryIterator::Rewind() 150 { 151 fIterator->Rewind(); 152 fOffset = BPLUSTREE_BEGIN; 153 return B_OK; 154 } 155 156