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