xref: /haiku/src/build/libroot/fs_descriptors.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #ifdef BUILDING_FS_SHELL
8 #	include "compat.h"
9 #	define B_OK			0
10 #	define B_FILE_ERROR	EBADF
11 #else
12 #	include <BeOSBuildCompatibility.h>
13 #endif
14 
15 #include "fs_descriptors.h"
16 
17 #include <map>
18 
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 
24 #include <fs_attr.h>
25 
26 #include "fs_impl.h"
27 
28 using std::map;
29 
30 static const int kVirtualDescriptorStart = 10000;
31 
32 typedef map<int, BPrivate::Descriptor*> DescriptorMap;
33 static DescriptorMap *sDescriptors;
34 
35 namespace BPrivate {
36 
37 
38 // #pragma mark - Descriptor
39 
40 
41 // constructor
42 Descriptor::~Descriptor()
43 {
44 }
45 
46 // IsSystemFD
47 bool
48 Descriptor::IsSystemFD() const
49 {
50 	return false;
51 }
52 
53 // GetPath
54 status_t
55 Descriptor::GetPath(string& path) const
56 {
57 	return get_path(fd, NULL, path);
58 }
59 
60 // GetNodeRef
61 status_t
62 Descriptor::GetNodeRef(NodeRef &ref)
63 {
64 	struct stat st;
65 	status_t error = GetStat(false, &st);
66 	if (error != B_OK)
67 		return error;
68 
69 	ref = NodeRef(st);
70 
71 	return B_OK;
72 }
73 
74 
75 // #pragma mark - FileDescriptor
76 
77 
78 // constructor
79 FileDescriptor::FileDescriptor(int fd)
80 {
81 	this->fd = fd;
82 }
83 
84 // destructor
85 FileDescriptor::~FileDescriptor()
86 {
87 	Close();
88 }
89 
90 // Close
91 status_t
92 FileDescriptor::Close()
93 {
94 	if (fd >= 0) {
95 		int oldFD = fd;
96 		fd = -1;
97 		if (close(oldFD) < 0)
98 			return errno;
99 	}
100 
101 	return B_OK;
102 }
103 
104 // Dup
105 status_t
106 FileDescriptor::Dup(Descriptor *&clone)
107 {
108 	int dupFD = dup(fd);
109 	if (dupFD < 0)
110 		return errno;
111 
112 	clone = new FileDescriptor(dupFD);
113 	return B_OK;
114 }
115 
116 // GetStat
117 status_t
118 FileDescriptor::GetStat(bool traverseLink, struct stat *st)
119 {
120 	if (fstat(fd, st) < 0)
121 		return errno;
122 	return B_OK;
123 }
124 
125 // IsSystemFD
126 bool
127 FileDescriptor::IsSystemFD() const
128 {
129 	return true;
130 }
131 
132 
133 // #pragma mark - DirectoryDescriptor
134 
135 
136 // constructor
137 DirectoryDescriptor::DirectoryDescriptor(DIR *dir, const NodeRef &ref)
138 {
139 	this->dir = dir;
140 	this->ref = ref;
141 }
142 
143 // destructor
144 DirectoryDescriptor::~DirectoryDescriptor()
145 {
146 	Close();
147 }
148 
149 // Close
150 status_t
151 DirectoryDescriptor::Close()
152 {
153 	if (dir) {
154 		DIR *oldDir = dir;
155 		dir = NULL;
156 		if (closedir(oldDir) < 0)
157 			return errno;
158 	}
159 
160 	return B_OK;
161 }
162 
163 // Dup
164 status_t
165 DirectoryDescriptor::Dup(Descriptor *&clone)
166 {
167 	string path;
168 	status_t error = get_path(fd, NULL, path);
169 	if (error != B_OK)
170 		return error;
171 
172 	DIR *dupDir = opendir(path.c_str());
173 	if (!dupDir)
174 		return errno;
175 
176 	clone = new DirectoryDescriptor(dupDir, ref);
177 	return B_OK;
178 }
179 
180 // GetStat
181 status_t
182 DirectoryDescriptor::GetStat(bool traverseLink, struct stat *st)
183 {
184 	// get a usable path
185 	string realPath;
186 	status_t error = get_path(fd, NULL, realPath);
187 	if (error != B_OK)
188 		return error;
189 
190 	// stat
191 	int result;
192 	result = stat(realPath.c_str(), st);
193 
194 	if (result < 0)
195 		return errno;
196 
197 	return B_OK;
198 }
199 
200 // GetNodeRef
201 status_t
202 DirectoryDescriptor::GetNodeRef(NodeRef &ref)
203 {
204 	ref = this->ref;
205 
206 	return B_OK;
207 }
208 
209 
210 // #pragma mark - SymlinkDescriptor
211 
212 
213 // constructor
214 SymlinkDescriptor::SymlinkDescriptor(const char *path)
215 {
216 	this->path = path;
217 }
218 
219 // Close
220 status_t
221 SymlinkDescriptor::Close()
222 {
223 	return B_OK;
224 }
225 
226 // Dup
227 status_t
228 SymlinkDescriptor::Dup(Descriptor *&clone)
229 {
230 	clone = new SymlinkDescriptor(path.c_str());
231 	return B_OK;
232 }
233 
234 // GetStat
235 status_t
236 SymlinkDescriptor::GetStat(bool traverseLink, struct stat *st)
237 {
238 	// stat
239 	int result;
240 	if (traverseLink)
241 		result = stat(path.c_str(), st);
242 	else
243 		result = lstat(path.c_str(), st);
244 
245 	if (result < 0)
246 		return errno;
247 
248 	return B_OK;
249 }
250 
251 // GetPath
252 status_t
253 SymlinkDescriptor::GetPath(string& path) const
254 {
255 	path = this->path;
256 	return B_OK;
257 }
258 
259 
260 // #pragma mark - AttributeDescriptor
261 
262 
263 AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute,
264 	uint32 type, int openMode)
265 	:
266 	fFileFD(dup(fileFD)),
267 	fType(type),
268 	fOpenMode(openMode),
269 	fData(NULL),
270 	fDataSize(0)
271 
272 {
273 	strlcpy(fAttribute, attribute, sizeof(fAttribute));
274 }
275 
276 
277 AttributeDescriptor::~AttributeDescriptor()
278 {
279 	Close();
280 }
281 
282 
283 status_t
284 AttributeDescriptor::Init()
285 {
286 	if (fFileFD < 0)
287 		return B_IO_ERROR;
288 
289 	// stat the attribute
290 	attr_info info;
291 	if (fs_stat_attr(fFileFD, fAttribute, &info) < 0) {
292 		if (errno == B_ENTRY_NOT_FOUND) {
293 			if ((fOpenMode & O_CREAT) == 0)
294 				return errno;
295 
296 			// create the attribute
297 			if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
298 				return errno;
299 			return B_OK;
300 		}
301 		return errno;
302 	}
303 
304 	if ((fOpenMode & O_TRUNC) == 0) {
305 		// truncate the attribute
306 		if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
307 			return errno;
308 		return B_OK;
309 	}
310 
311 	// we have to read in the attribute data
312 	if (info.size == 0)
313 		return B_OK;
314 
315 	fData = (uint8*)malloc(info.size);
316 	if (fData == NULL)
317 		return B_NO_MEMORY;
318 
319 	fDataSize = info.size;
320 
321 	ssize_t bytesRead = fs_read_attr(fFileFD, fAttribute, fType, 0, fData,
322 		fDataSize);
323 	if (bytesRead < 0)
324 		return errno;
325 	if ((size_t)bytesRead != fDataSize)
326 		return B_IO_ERROR;
327 
328 	return B_OK;
329 }
330 
331 
332 status_t
333 AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize)
334 {
335 	if (offset < 0)
336 		return B_BAD_VALUE;
337 
338 	if ((fOpenMode & O_ACCMODE) != O_WRONLY
339 		&& (fOpenMode & O_ACCMODE) != O_RDWR) {
340 		return B_NOT_ALLOWED;
341 	}
342 
343 	// we may need to resize the buffer
344 	size_t minSize = (size_t)offset + bufferSize;
345 	if (minSize > fDataSize) {
346 		uint8* data = (uint8*)realloc(fData, minSize);
347 		if (data == NULL)
348 			return B_NO_MEMORY;
349 
350 		if ((size_t)offset > fDataSize)
351 			memset(data + offset, 0, offset - fDataSize);
352 
353 		fData = data;
354 		fDataSize = minSize;
355 	}
356 
357 	// copy the data and write all of it
358 	if (bufferSize == 0)
359 		return B_OK;
360 
361 	memcpy((uint8*)fData + offset, buffer, bufferSize);
362 
363 	ssize_t bytesWritten = fs_write_attr(fFileFD, fAttribute, fType, 0,
364 		fData, fDataSize);
365 	if (bytesWritten < 0)
366 		return errno;
367 	if ((size_t)bytesWritten != fDataSize)
368 		return B_IO_ERROR;
369 
370 	return B_OK;
371 }
372 
373 
374 status_t
375 AttributeDescriptor::Close()
376 {
377 	if (fFileFD < 0)
378 		return B_BAD_VALUE;
379 
380 	close(fFileFD);
381 	fFileFD = -1;
382 
383 	free(fData);
384 	fData = NULL;
385 	fDataSize = 0;
386 
387 	return B_OK;
388 }
389 
390 
391 status_t
392 AttributeDescriptor::Dup(Descriptor*& clone)
393 {
394 	return B_NOT_SUPPORTED;
395 }
396 
397 
398 status_t
399 AttributeDescriptor::GetStat(bool traverseLink, struct stat* st)
400 {
401 	return B_NOT_SUPPORTED;
402 }
403 
404 
405 // #pragma mark - AttrDirDescriptor
406 
407 
408 // constructor
409 AttrDirDescriptor::AttrDirDescriptor(DIR *dir, const NodeRef &ref)
410 	: DirectoryDescriptor(dir, ref)
411 {
412 }
413 
414 // destructor
415 AttrDirDescriptor::~AttrDirDescriptor()
416 {
417 	Close();
418 }
419 
420 // Close
421 status_t
422 AttrDirDescriptor::Close()
423 {
424 	if (dir) {
425 		DIR *oldDir = dir;
426 		dir = NULL;
427 		if (fs_close_attr_dir(oldDir) < 0)
428 			return errno;
429 	}
430 
431 	return B_OK;
432 }
433 
434 // Dup
435 status_t
436 AttrDirDescriptor::Dup(Descriptor *&clone)
437 {
438 	// we don't allow dup()int attr dir descriptors
439 	return B_FILE_ERROR;
440 }
441 
442 // GetStat
443 status_t
444 AttrDirDescriptor::GetStat(bool traverseLink, struct stat *st)
445 {
446 	// we don't allow stat()int attr dir descriptors
447 	return B_FILE_ERROR;
448 }
449 
450 // GetNodeRef
451 status_t
452 AttrDirDescriptor::GetNodeRef(NodeRef &ref)
453 {
454 	ref = this->ref;
455 
456 	return B_OK;
457 }
458 
459 
460 // get_descriptor
461 Descriptor *
462 get_descriptor(int fd)
463 {
464 	if (!sDescriptors)
465 		return NULL;
466 	DescriptorMap::iterator it = sDescriptors->find(fd);
467 	if (it == sDescriptors->end())
468 		return NULL;
469 	return it->second;
470 }
471 
472 // add_descriptor
473 int
474 add_descriptor(Descriptor *descriptor)
475 {
476 	if (!sDescriptors)
477 		sDescriptors = new DescriptorMap;
478 
479 	int fd = -1;
480 	if (FileDescriptor *file = dynamic_cast<FileDescriptor*>(descriptor)) {
481 		fd = file->fd;
482 	} else {
483 		// find a free slot
484 		for (fd = kVirtualDescriptorStart;
485 			sDescriptors->find(fd) != sDescriptors->end();
486 			fd++) {
487 		}
488 	}
489 
490 	(*sDescriptors)[fd] = descriptor;
491 	descriptor->fd = fd;
492 
493 	return fd;
494 }
495 
496 // delete_descriptor
497 status_t
498 delete_descriptor(int fd)
499 {
500 	DescriptorMap::iterator it = sDescriptors->find(fd);
501 	if (it == sDescriptors->end())
502 		return B_FILE_ERROR;
503 
504 	status_t error = it->second->Close();
505 	delete it->second;
506 	sDescriptors->erase(it);
507 
508 	if (sDescriptors->size() == 0) {
509 		delete sDescriptors;
510 		sDescriptors = NULL;
511 	}
512 	return error;
513 }
514 
515 
516 bool
517 is_unknown_or_system_descriptor(int fd)
518 {
519 	Descriptor* descriptor = get_descriptor(fd);
520 	return descriptor == NULL || descriptor->IsSystemFD();
521 }
522 
523 
524 } // namespace BPrivate
525