xref: /haiku/src/system/boot/loader/file_systems/bfs/Directory.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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
20 extern Node *get_node_from(int fd);
21 
22 
23 namespace BFS {
24 
25 
26 Directory::Directory(Volume &volume, block_run run)
27 	:
28 	fStream(volume, run),
29 	fTree(&fStream)
30 {
31 }
32 
33 
34 Directory::Directory(Volume &volume, off_t id)
35 	:
36 	fStream(volume, id),
37 	fTree(&fStream)
38 {
39 }
40 
41 
42 Directory::Directory(const Stream &stream)
43 	:
44 	fStream(stream),
45 	fTree(&fStream)
46 {
47 }
48 
49 
50 Directory::~Directory()
51 {
52 }
53 
54 
55 status_t
56 Directory::InitCheck()
57 {
58 	return fStream.InitCheck();
59 }
60 
61 
62 status_t
63 Directory::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 
75 status_t
76 Directory::Close(void *cookie)
77 {
78 	_inherited::Close(cookie);
79 
80 	delete (TreeIterator *)cookie;
81 	return B_OK;
82 }
83 
84 
85 Node *
86 Directory::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 
121 status_t
122 Directory::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 
132 status_t
133 Directory::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 
152 status_t
153 Directory::Rewind(void *cookie)
154 {
155 	TreeIterator *iterator = (TreeIterator *)cookie;
156 
157 	return iterator->Rewind();
158 }
159 
160 
161 bool
162 Directory::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 
186 status_t
187 Directory::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 
198 ino_t
199 Directory::Inode() const
200 {
201 	return fStream.ID();
202 }
203 
204 
205 }	// namespace BFS
206