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
24DirectoryIterator::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
38DirectoryIterator::~DirectoryIterator()
39{
40	delete fIterator;
41}
42
43
44status_t
45DirectoryIterator::InitCheck()
46{
47	return fIterator != NULL ? B_OK : B_NO_MEMORY;
48}
49
50
51status_t
52DirectoryIterator::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
101status_t
102DirectoryIterator::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
148status_t
149DirectoryIterator::Rewind()
150{
151	fIterator->Rewind();
152	fOffset = BPLUSTREE_BEGIN;
153	return B_OK;
154}
155
156