xref: /haiku/src/add-ons/kernel/file_systems/btrfs/DirectoryIterator.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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