tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / build / libroot / fs_descriptors.cpp
blob1f9e1c8aa5160f9760e1729de0e13c7dfb973b40
1 /*
2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
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
15 #include "fs_descriptors.h"
17 #include <map>
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
24 #include <fs_attr.h>
26 #include <syscalls.h>
28 #include "fs_impl.h"
30 using std::map;
32 static const int kVirtualDescriptorStart = 10000;
34 typedef map<int, BPrivate::Descriptor*> DescriptorMap;
35 static DescriptorMap *sDescriptors;
37 namespace BPrivate {
40 static int
41 dup_maybe_system(int fd)
43 if (get_descriptor(fd) != NULL)
44 return _kern_dup(fd);
46 int clonedFD = dup(fd);
47 return clonedFD >= 0 ? clonedFD : errno;
51 static status_t
52 close_maybe_system(int fd)
54 if (get_descriptor(fd) != NULL)
55 return _kern_close(fd);
57 return close(fd) == 0 ? B_OK : errno;
61 // #pragma mark - Descriptor
64 // constructor
65 Descriptor::~Descriptor()
69 // IsSystemFD
70 bool
71 Descriptor::IsSystemFD() const
73 return false;
76 // GetPath
77 status_t
78 Descriptor::GetPath(string& path) const
80 return get_path(fd, NULL, path);
83 // GetNodeRef
84 status_t
85 Descriptor::GetNodeRef(NodeRef &ref)
87 struct stat st;
88 status_t error = GetStat(false, &st);
89 if (error != B_OK)
90 return error;
92 ref = NodeRef(st);
94 return B_OK;
98 // #pragma mark - FileDescriptor
101 // constructor
102 FileDescriptor::FileDescriptor(int fd)
104 this->fd = fd;
107 // destructor
108 FileDescriptor::~FileDescriptor()
110 Close();
113 // Close
114 status_t
115 FileDescriptor::Close()
117 if (fd >= 0) {
118 int oldFD = fd;
119 fd = -1;
120 if (close(oldFD) < 0)
121 return errno;
124 return B_OK;
127 // Dup
128 status_t
129 FileDescriptor::Dup(Descriptor *&clone)
131 int dupFD = dup(fd);
132 if (dupFD < 0)
133 return errno;
135 clone = new FileDescriptor(dupFD);
136 return B_OK;
139 // GetStat
140 status_t
141 FileDescriptor::GetStat(bool traverseLink, struct stat *st)
143 if (fstat(fd, st) < 0)
144 return errno;
145 return B_OK;
148 // IsSystemFD
149 bool
150 FileDescriptor::IsSystemFD() const
152 return true;
156 // #pragma mark - DirectoryDescriptor
159 // constructor
160 DirectoryDescriptor::DirectoryDescriptor(DIR *dir, const NodeRef &ref)
162 this->dir = dir;
163 this->ref = ref;
166 // destructor
167 DirectoryDescriptor::~DirectoryDescriptor()
169 Close();
172 // Close
173 status_t
174 DirectoryDescriptor::Close()
176 if (dir) {
177 DIR *oldDir = dir;
178 dir = NULL;
179 if (closedir(oldDir) < 0)
180 return errno;
183 return B_OK;
186 // Dup
187 status_t
188 DirectoryDescriptor::Dup(Descriptor *&clone)
190 string path;
191 status_t error = get_path(fd, NULL, path);
192 if (error != B_OK)
193 return error;
195 DIR *dupDir = opendir(path.c_str());
196 if (!dupDir)
197 return errno;
199 clone = new DirectoryDescriptor(dupDir, ref);
200 return B_OK;
203 // GetStat
204 status_t
205 DirectoryDescriptor::GetStat(bool traverseLink, struct stat *st)
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;
213 // stat
214 int result;
215 result = stat(realPath.c_str(), st);
217 if (result < 0)
218 return errno;
220 return B_OK;
223 // GetNodeRef
224 status_t
225 DirectoryDescriptor::GetNodeRef(NodeRef &ref)
227 ref = this->ref;
229 return B_OK;
233 // #pragma mark - SymlinkDescriptor
236 // constructor
237 SymlinkDescriptor::SymlinkDescriptor(const char *path)
239 this->path = path;
242 // Close
243 status_t
244 SymlinkDescriptor::Close()
246 return B_OK;
249 // Dup
250 status_t
251 SymlinkDescriptor::Dup(Descriptor *&clone)
253 clone = new SymlinkDescriptor(path.c_str());
254 return B_OK;
257 // GetStat
258 status_t
259 SymlinkDescriptor::GetStat(bool traverseLink, struct stat *st)
261 // stat
262 int result;
263 if (traverseLink)
264 result = stat(path.c_str(), st);
265 else
266 result = lstat(path.c_str(), st);
268 if (result < 0)
269 return errno;
271 return B_OK;
274 // GetPath
275 status_t
276 SymlinkDescriptor::GetPath(string& path) const
278 path = this->path;
279 return B_OK;
283 // #pragma mark - AttributeDescriptor
286 AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute,
287 uint32 type, int openMode)
289 fFileFD(dup_maybe_system(fileFD)),
290 fType(type),
291 fOpenMode(openMode),
292 fData(NULL),
293 fDataSize(0)
296 strlcpy(fAttribute, attribute, sizeof(fAttribute));
300 AttributeDescriptor::~AttributeDescriptor()
302 Close();
306 status_t
307 AttributeDescriptor::Init()
309 if (fFileFD < 0)
310 return B_IO_ERROR;
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;
319 // create the attribute
320 if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
321 return errno;
322 return B_OK;
324 return errno;
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;
334 // we have to read in the attribute data
335 if (info.size == 0)
336 return B_OK;
338 fData = (uint8*)malloc(info.size);
339 if (fData == NULL)
340 return B_NO_MEMORY;
342 fDataSize = info.size;
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;
351 return B_OK;
355 status_t
356 AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize)
358 if (offset < 0)
359 return B_BAD_VALUE;
361 if ((fOpenMode & O_ACCMODE) != O_WRONLY
362 && (fOpenMode & O_ACCMODE) != O_RDWR) {
363 return B_NOT_ALLOWED;
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;
373 if ((size_t)offset > fDataSize)
374 memset(data + offset, 0, offset - fDataSize);
376 fData = data;
377 fDataSize = minSize;
380 // copy the data and write all of it
381 if (bufferSize == 0)
382 return B_OK;
384 memcpy((uint8*)fData + offset, buffer, bufferSize);
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;
393 return B_OK;
397 status_t
398 AttributeDescriptor::Close()
400 if (fFileFD < 0)
401 return B_BAD_VALUE;
403 close_maybe_system(fFileFD);
404 fFileFD = -1;
406 free(fData);
407 fData = NULL;
408 fDataSize = 0;
410 return B_OK;
414 status_t
415 AttributeDescriptor::Dup(Descriptor*& clone)
417 return B_NOT_SUPPORTED;
421 status_t
422 AttributeDescriptor::GetStat(bool traverseLink, struct stat* st)
424 return B_NOT_SUPPORTED;
428 // #pragma mark - AttrDirDescriptor
431 // constructor
432 AttrDirDescriptor::AttrDirDescriptor(DIR *dir, const NodeRef &ref)
433 : DirectoryDescriptor(dir, ref)
437 // destructor
438 AttrDirDescriptor::~AttrDirDescriptor()
440 Close();
443 // Close
444 status_t
445 AttrDirDescriptor::Close()
447 if (dir) {
448 DIR *oldDir = dir;
449 dir = NULL;
450 if (fs_close_attr_dir(oldDir) < 0)
451 return errno;
454 return B_OK;
457 // Dup
458 status_t
459 AttrDirDescriptor::Dup(Descriptor *&clone)
461 // we don't allow dup()int attr dir descriptors
462 return B_FILE_ERROR;
465 // GetStat
466 status_t
467 AttrDirDescriptor::GetStat(bool traverseLink, struct stat *st)
469 // we don't allow stat()int attr dir descriptors
470 return B_FILE_ERROR;
473 // GetNodeRef
474 status_t
475 AttrDirDescriptor::GetNodeRef(NodeRef &ref)
477 ref = this->ref;
479 return B_OK;
483 // get_descriptor
484 Descriptor *
485 get_descriptor(int fd)
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;
495 // add_descriptor
497 add_descriptor(Descriptor *descriptor)
499 if (!sDescriptors)
500 sDescriptors = new DescriptorMap;
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++) {
513 (*sDescriptors)[fd] = descriptor;
514 descriptor->fd = fd;
516 return fd;
519 // delete_descriptor
520 status_t
521 delete_descriptor(int fd)
523 DescriptorMap::iterator it = sDescriptors->find(fd);
524 if (it == sDescriptors->end())
525 return B_FILE_ERROR;
527 status_t error = it->second->Close();
528 delete it->second;
529 sDescriptors->erase(it);
531 if (sDescriptors->size() == 0) {
532 delete sDescriptors;
533 sDescriptors = NULL;
535 return error;
539 bool
540 is_unknown_or_system_descriptor(int fd)
542 Descriptor* descriptor = get_descriptor(fd);
543 return descriptor == NULL || descriptor->IsSystemFD();
547 } // namespace BPrivate