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