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