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