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