1 /* 2 * Copyright 2011-2013, 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 if (*_nameLength < 3) 56 return B_BUFFER_OVERFLOW; 57 *_nameLength = 2; 58 strlcpy(name, "..", *_nameLength + 1); 59 *_id = fInode->ID(); 60 fOffset = 1; 61 return B_OK; 62 } else if (fOffset == 1) { 63 if (*_nameLength < 2) 64 return B_BUFFER_OVERFLOW; 65 *_nameLength = 1; 66 strlcpy(name, ".", *_nameLength + 1); 67 fOffset = 2; 68 if (fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) { 69 *_id = fInode->ID(); 70 return B_OK; 71 } 72 return fInode->FindParent(_id); 73 } 74 75 btrfs_key key; 76 btrfs_dir_entry *entries; 77 size_t entries_length; 78 status_t status = fIterator->GetNextEntry(key, (void**)&entries, 79 &entries_length); 80 if (status != B_OK) 81 return status; 82 83 btrfs_dir_entry *entry = entries; 84 uint16 current = 0; 85 while (current < entries_length) { 86 current += entry->Length(); 87 break; 88 // TODO there could be several entries with the same name hash 89 entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length()); 90 } 91 92 size_t length = entry->NameLength(); 93 94 TRACE("DirectoryIterator::GetNext() entries_length %ld name_length %d\n", 95 entries_length, entry->NameLength()); 96 97 if (length + 1 > *_nameLength) { 98 free(entries); 99 return B_BUFFER_OVERFLOW; 100 } 101 102 memcpy(name, entry + 1, length); 103 name[length] = '\0'; 104 *_nameLength = length; 105 *_id = entry->InodeID(); 106 free(entries); 107 108 return B_OK; 109 } 110 111 112 status_t 113 DirectoryIterator::Lookup(const char* name, size_t nameLength, ino_t* _id) 114 { 115 if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 116 if (strcmp(name, ".") == 0 117 || fInode->ID() == BTRFS_OBJECT_ID_CHUNK_TREE) { 118 *_id = fInode->ID(); 119 return B_OK; 120 } 121 return fInode->FindParent(_id); 122 } 123 124 uint32 hash = calculate_crc((uint32)~1, (uint8*)name, nameLength); 125 struct btrfs_key key; 126 key.SetType(BTRFS_KEY_TYPE_DIR_ITEM); 127 key.SetObjectID(fInode->ID()); 128 key.SetOffset(hash); 129 130 btrfs_dir_entry *entries; 131 size_t length; 132 status_t status = fInode->GetVolume()->FSTree()->FindExact(key, 133 (void**)&entries, &length); 134 if (status != B_OK) { 135 TRACE("DirectoryIterator::Lookup(): Couldn't find entry with hash %" B_PRIu32 136 " \"%s\"\n", hash, name); 137 return status; 138 } 139 140 btrfs_dir_entry *entry = entries; 141 uint16 current = 0; 142 while (current < length) { 143 current += entry->Length(); 144 break; 145 // TODO there could be several entries with the same name hash 146 entry = (btrfs_dir_entry *)((uint8*)entry + entry->Length()); 147 } 148 149 TRACE("DirectoryIterator::Lookup() entries_length %ld name_length %d\n", 150 length, entry->NameLength()); 151 152 *_id = entry->InodeID(); 153 free(entries); 154 155 return B_OK; 156 } 157 158 159 status_t 160 DirectoryIterator::Rewind() 161 { 162 fIterator->Rewind(); 163 fOffset = BPLUSTREE_BEGIN; 164 return B_OK; 165 } 166 167