xref: /haiku/src/build/libroot/fs_descriptors.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
1 
2 #ifdef BUILDING_FS_SHELL
3 #	include "compat.h"
4 #	define B_OK			0
5 #	define B_FILE_ERROR	EBADF
6 #else
7 #	include <BeOSBuildCompatibility.h>
8 #endif
9 
10 #include "fs_descriptors.h"
11 
12 #include <map>
13 
14 #include <stdio.h>
15 #include <unistd.h>
16 
17 #include <fs_attr.h>
18 
19 #include "fs_impl.h"
20 
21 using std::map;
22 
23 static const int kVirtualDescriptorStart = 10000;
24 
25 typedef map<int, BPrivate::Descriptor*> DescriptorMap;
26 static DescriptorMap *sDescriptors;
27 
28 namespace BPrivate {
29 
30 
31 // #pragma mark - Descriptor
32 
33 
34 // constructor
35 Descriptor::~Descriptor()
36 {
37 }
38 
39 // IsSystemFD
40 bool
41 Descriptor::IsSystemFD() const
42 {
43 	return false;
44 }
45 
46 // GetPath
47 status_t
48 Descriptor::GetPath(string& path) const
49 {
50 	return get_path(fd, NULL, path);
51 }
52 
53 // GetNodeRef
54 status_t
55 Descriptor::GetNodeRef(NodeRef &ref)
56 {
57 	struct stat st;
58 	status_t error = GetStat(false, &st);
59 	if (error != B_OK)
60 		return error;
61 
62 	ref = NodeRef(st);
63 
64 	return B_OK;
65 }
66 
67 
68 // #pragma mark - FileDescriptor
69 
70 
71 // constructor
72 FileDescriptor::FileDescriptor(int fd)
73 {
74 	this->fd = fd;
75 }
76 
77 // destructor
78 FileDescriptor::~FileDescriptor()
79 {
80 	Close();
81 }
82 
83 // Close
84 status_t
85 FileDescriptor::Close()
86 {
87 	if (fd >= 0) {
88 		int oldFD = fd;
89 		fd = -1;
90 		if (close(oldFD) < 0)
91 			return errno;
92 	}
93 
94 	return B_OK;
95 }
96 
97 // Dup
98 status_t
99 FileDescriptor::Dup(Descriptor *&clone)
100 {
101 	int dupFD = dup(fd);
102 	if (dupFD < 0)
103 		return errno;
104 
105 	clone = new FileDescriptor(dupFD);
106 	return B_OK;
107 }
108 
109 // GetStat
110 status_t
111 FileDescriptor::GetStat(bool traverseLink, struct stat *st)
112 {
113 	if (fstat(fd, st) < 0)
114 		return errno;
115 	return B_OK;
116 }
117 
118 // IsSystemFD
119 bool
120 FileDescriptor::IsSystemFD() const
121 {
122 	return true;
123 }
124 
125 
126 // #pragma mark - DirectoryDescriptor
127 
128 
129 // constructor
130 DirectoryDescriptor::DirectoryDescriptor(DIR *dir, const NodeRef &ref)
131 {
132 	this->dir = dir;
133 	this->ref = ref;
134 }
135 
136 // destructor
137 DirectoryDescriptor::~DirectoryDescriptor()
138 {
139 	Close();
140 }
141 
142 // Close
143 status_t
144 DirectoryDescriptor::Close()
145 {
146 	if (dir) {
147 		DIR *oldDir = dir;
148 		dir = NULL;
149 		if (closedir(oldDir) < 0)
150 			return errno;
151 	}
152 
153 	return B_OK;
154 }
155 
156 // Dup
157 status_t
158 DirectoryDescriptor::Dup(Descriptor *&clone)
159 {
160 	string path;
161 	status_t error = get_path(fd, NULL, path);
162 	if (error != B_OK)
163 		return error;
164 
165 	DIR *dupDir = opendir(path.c_str());
166 	if (!dupDir)
167 		return errno;
168 
169 	clone = new DirectoryDescriptor(dupDir, ref);
170 	return B_OK;
171 }
172 
173 // GetStat
174 status_t
175 DirectoryDescriptor::GetStat(bool traverseLink, struct stat *st)
176 {
177 	// get a usable path
178 	string realPath;
179 	status_t error = get_path(fd, NULL, realPath);
180 	if (error != B_OK)
181 		return error;
182 
183 	// stat
184 	int result;
185 	result = stat(realPath.c_str(), st);
186 
187 	if (result < 0)
188 		return errno;
189 
190 	return B_OK;
191 }
192 
193 // GetNodeRef
194 status_t
195 DirectoryDescriptor::GetNodeRef(NodeRef &ref)
196 {
197 	ref = this->ref;
198 
199 	return B_OK;
200 }
201 
202 
203 // #pragma mark - SymlinkDescriptor
204 
205 
206 // constructor
207 SymlinkDescriptor::SymlinkDescriptor(const char *path)
208 {
209 	this->path = path;
210 }
211 
212 // Close
213 status_t
214 SymlinkDescriptor::Close()
215 {
216 	return B_OK;
217 }
218 
219 // Dup
220 status_t
221 SymlinkDescriptor::Dup(Descriptor *&clone)
222 {
223 	clone = new SymlinkDescriptor(path.c_str());
224 	return B_OK;
225 }
226 
227 // GetStat
228 status_t
229 SymlinkDescriptor::GetStat(bool traverseLink, struct stat *st)
230 {
231 	// stat
232 	int result;
233 	if (traverseLink)
234 		result = stat(path.c_str(), st);
235 	else
236 		result = lstat(path.c_str(), st);
237 
238 	if (result < 0)
239 		return errno;
240 
241 	return B_OK;
242 }
243 
244 // GetPath
245 status_t
246 SymlinkDescriptor::GetPath(string& path) const
247 {
248 	path = this->path;
249 	return B_OK;
250 }
251 
252 
253 // #pragma mark - AttrDirDescriptor
254 
255 
256 // constructor
257 AttrDirDescriptor::AttrDirDescriptor(DIR *dir, const NodeRef &ref)
258 	: DirectoryDescriptor(dir, ref)
259 {
260 }
261 
262 // destructor
263 AttrDirDescriptor::~AttrDirDescriptor()
264 {
265 	Close();
266 }
267 
268 // Close
269 status_t
270 AttrDirDescriptor::Close()
271 {
272 	if (dir) {
273 		DIR *oldDir = dir;
274 		dir = NULL;
275 		if (fs_close_attr_dir(oldDir) < 0)
276 			return errno;
277 	}
278 
279 	return B_OK;
280 }
281 
282 // Dup
283 status_t
284 AttrDirDescriptor::Dup(Descriptor *&clone)
285 {
286 	// we don't allow dup()int attr dir descriptors
287 	return B_FILE_ERROR;
288 }
289 
290 // GetStat
291 status_t
292 AttrDirDescriptor::GetStat(bool traverseLink, struct stat *st)
293 {
294 	// we don't allow stat()int attr dir descriptors
295 	return B_FILE_ERROR;
296 }
297 
298 // GetNodeRef
299 status_t
300 AttrDirDescriptor::GetNodeRef(NodeRef &ref)
301 {
302 	ref = this->ref;
303 
304 	return B_OK;
305 }
306 
307 
308 // get_descriptor
309 Descriptor *
310 get_descriptor(int fd)
311 {
312 	if (!sDescriptors)
313 		return NULL;
314 	DescriptorMap::iterator it = sDescriptors->find(fd);
315 	if (it == sDescriptors->end())
316 		return NULL;
317 	return it->second;
318 }
319 
320 // add_descriptor
321 int
322 add_descriptor(Descriptor *descriptor)
323 {
324 	if (!sDescriptors)
325 		sDescriptors = new DescriptorMap;
326 
327 	int fd = -1;
328 	if (FileDescriptor *file = dynamic_cast<FileDescriptor*>(descriptor)) {
329 		fd = file->fd;
330 	} else {
331 		// find a free slot
332 		for (fd = kVirtualDescriptorStart;
333 			sDescriptors->find(fd) != sDescriptors->end();
334 			fd++) {
335 		}
336 	}
337 
338 	(*sDescriptors)[fd] = descriptor;
339 	descriptor->fd = fd;
340 
341 	return fd;
342 }
343 
344 // delete_descriptor
345 status_t
346 delete_descriptor(int fd)
347 {
348 	DescriptorMap::iterator it = sDescriptors->find(fd);
349 	if (it == sDescriptors->end())
350 		return B_FILE_ERROR;
351 
352 	status_t error = it->second->Close();
353 	delete it->second;
354 	sDescriptors->erase(it);
355 
356 	if (sDescriptors->size() == 0) {
357 		delete sDescriptors;
358 		sDescriptors = NULL;
359 	}
360 	return error;
361 }
362 
363 } // namespace BPrivate
364