1/*
2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Directory.h"
8#include "File.h"
9#include "Link.h"
10
11#include <StorageDefs.h>
12#include <KernelExport.h>
13#include <util/kernel_cpp.h>
14
15#include <string.h>
16#include <unistd.h>
17
18
19// temp. private VFS API
20extern Node *get_node_from(int fd);
21
22
23namespace BFS {
24
25
26Directory::Directory(Volume &volume, block_run run)
27	:
28	fStream(volume, run),
29	fTree(&fStream)
30{
31}
32
33
34Directory::Directory(Volume &volume, off_t id)
35	:
36	fStream(volume, id),
37	fTree(&fStream)
38{
39}
40
41
42Directory::Directory(const Stream &stream)
43	:
44	fStream(stream),
45	fTree(&fStream)
46{
47}
48
49
50Directory::~Directory()
51{
52}
53
54
55status_t
56Directory::InitCheck()
57{
58	return fStream.InitCheck();
59}
60
61
62status_t
63Directory::Open(void **_cookie, int mode)
64{
65	_inherited::Open(_cookie, mode);
66
67	*_cookie = (void *)new(nothrow) TreeIterator(&fTree);
68	if (*_cookie == NULL)
69		return B_NO_MEMORY;
70
71	return B_OK;
72}
73
74
75status_t
76Directory::Close(void *cookie)
77{
78	_inherited::Close(cookie);
79
80	delete (TreeIterator *)cookie;
81	return B_OK;
82}
83
84
85Node *
86Directory::Lookup(const char *name, bool traverseLinks)
87{
88	off_t id;
89	if (fTree.Find((uint8 *)name, strlen(name), &id) < B_OK)
90		return NULL;
91
92	Node *node = Stream::NodeFactory(fStream.GetVolume(), id);
93	if (!node)
94		return NULL;
95
96	if (S_ISLNK(node->Type())) {
97		// the node is a symbolic link, so we have to resolve the path
98		char linkPath[B_PATH_NAME_LENGTH];
99		((Link *)node)->ReadLink(linkPath, sizeof(linkPath));
100
101		delete node;
102			// we don't need this one anymore
103
104		int fd = open_from(this, linkPath, O_RDONLY);
105		if (fd >= 0) {
106			node = get_node_from(fd);
107			if (node != NULL)
108				node->Acquire();
109
110			close(fd);
111			return node;
112		}
113
114		return NULL;
115	}
116
117	return node;
118}
119
120
121status_t
122Directory::GetNextEntry(void *cookie, char *name, size_t size)
123{
124	TreeIterator *iterator = (TreeIterator *)cookie;
125	uint16 length;
126	off_t id;
127
128	return iterator->GetNextEntry(name, &length, size, &id);
129}
130
131
132status_t
133Directory::GetNextNode(void *cookie, Node **_node)
134{
135	TreeIterator *iterator = (TreeIterator *)cookie;
136	char name[B_FILE_NAME_LENGTH];
137	uint16 length;
138	off_t id;
139
140	status_t status = iterator->GetNextEntry(name, &length, sizeof(name), &id);
141	if (status != B_OK)
142		return status;
143
144	*_node = Stream::NodeFactory(fStream.GetVolume(), id);
145	if (*_node == NULL)
146		return B_ERROR;
147
148	return B_OK;
149}
150
151
152status_t
153Directory::Rewind(void *cookie)
154{
155	TreeIterator *iterator = (TreeIterator *)cookie;
156
157	return iterator->Rewind();
158}
159
160
161bool
162Directory::IsEmpty()
163{
164	TreeIterator iterator(&fTree);
165
166	// index and attribute directories are really empty when they are
167	// empty - directories for standard files always contain ".", and
168	// "..", so we need to ignore those two
169
170	uint32 count = 0;
171	char name[BPLUSTREE_MAX_KEY_LENGTH];
172	uint16 length;
173	off_t id;
174	while (iterator.GetNextEntry(name, &length, B_FILE_NAME_LENGTH, &id)
175			== B_OK) {
176		if (fStream.Mode() & (S_ATTR_DIR | S_INDEX_DIR))
177			return false;
178
179		if (++count > 2 || (strcmp(".", name) && strcmp("..", name)))
180			return false;
181	}
182	return true;
183}
184
185
186status_t
187Directory::GetName(char *name, size_t size) const
188{
189	if (fStream.inode_num == fStream.GetVolume().Root()) {
190		strlcpy(name, fStream.GetVolume().SuperBlock().name, size);
191		return B_OK;
192	}
193
194	return fStream.GetName(name, size);
195}
196
197
198ino_t
199Directory::Inode() const
200{
201	return fStream.ID();
202}
203
204
205}	// namespace BFS
206