2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #ifdef BUILDING_FS_SHELL
10 # define B_FILE_ERROR EBADF
12 # include <BeOSBuildCompatibility.h>
15 #include "fs_descriptors.h"
32 static const int kVirtualDescriptorStart
= 10000;
34 typedef map
<int, BPrivate::Descriptor
*> DescriptorMap
;
35 static DescriptorMap
*sDescriptors
;
41 dup_maybe_system(int fd
)
43 if (get_descriptor(fd
) != NULL
)
46 int clonedFD
= dup(fd
);
47 return clonedFD
>= 0 ? clonedFD
: errno
;
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
65 Descriptor::~Descriptor()
71 Descriptor::IsSystemFD() const
78 Descriptor::GetPath(string
& path
) const
80 return get_path(fd
, NULL
, path
);
85 Descriptor::GetNodeRef(NodeRef
&ref
)
88 status_t error
= GetStat(false, &st
);
98 // #pragma mark - FileDescriptor
102 FileDescriptor::FileDescriptor(int fd
)
108 FileDescriptor::~FileDescriptor()
115 FileDescriptor::Close()
120 if (close(oldFD
) < 0)
129 FileDescriptor::Dup(Descriptor
*&clone
)
135 clone
= new FileDescriptor(dupFD
);
141 FileDescriptor::GetStat(bool traverseLink
, struct stat
*st
)
143 if (fstat(fd
, st
) < 0)
150 FileDescriptor::IsSystemFD() const
156 // #pragma mark - DirectoryDescriptor
160 DirectoryDescriptor::DirectoryDescriptor(DIR *dir
, const NodeRef
&ref
)
167 DirectoryDescriptor::~DirectoryDescriptor()
174 DirectoryDescriptor::Close()
179 if (closedir(oldDir
) < 0)
188 DirectoryDescriptor::Dup(Descriptor
*&clone
)
191 status_t error
= get_path(fd
, NULL
, path
);
195 DIR *dupDir
= opendir(path
.c_str());
199 clone
= new DirectoryDescriptor(dupDir
, ref
);
205 DirectoryDescriptor::GetStat(bool traverseLink
, struct stat
*st
)
209 status_t error
= get_path(fd
, NULL
, realPath
);
215 result
= stat(realPath
.c_str(), st
);
225 DirectoryDescriptor::GetNodeRef(NodeRef
&ref
)
233 // #pragma mark - SymlinkDescriptor
237 SymlinkDescriptor::SymlinkDescriptor(const char *path
)
244 SymlinkDescriptor::Close()
251 SymlinkDescriptor::Dup(Descriptor
*&clone
)
253 clone
= new SymlinkDescriptor(path
.c_str());
259 SymlinkDescriptor::GetStat(bool traverseLink
, struct stat
*st
)
264 result
= stat(path
.c_str(), st
);
266 result
= lstat(path
.c_str(), st
);
276 SymlinkDescriptor::GetPath(string
& path
) const
283 // #pragma mark - AttributeDescriptor
286 AttributeDescriptor::AttributeDescriptor(int fileFD
, const char* attribute
,
287 uint32 type
, int openMode
)
289 fFileFD(dup_maybe_system(fileFD
)),
296 strlcpy(fAttribute
, attribute
, sizeof(fAttribute
));
300 AttributeDescriptor::~AttributeDescriptor()
307 AttributeDescriptor::Init()
312 // stat the attribute
314 if (fs_stat_attr(fFileFD
, fAttribute
, &info
) < 0) {
315 if (errno
== B_ENTRY_NOT_FOUND
) {
316 if ((fOpenMode
& O_CREAT
) == 0)
319 // create the attribute
320 if (fs_write_attr(fFileFD
, fAttribute
, fType
, 0, NULL
, 0) < 0)
327 if ((fOpenMode
& O_TRUNC
) == 0) {
328 // truncate the attribute
329 if (fs_write_attr(fFileFD
, fAttribute
, fType
, 0, NULL
, 0) < 0)
334 // we have to read in the attribute data
338 fData
= (uint8
*)malloc(info
.size
);
342 fDataSize
= info
.size
;
344 ssize_t bytesRead
= fs_read_attr(fFileFD
, fAttribute
, fType
, 0, fData
,
348 if ((size_t)bytesRead
!= fDataSize
)
356 AttributeDescriptor::Write(off_t offset
, const void* buffer
, size_t bufferSize
)
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
);
373 if ((size_t)offset
> fDataSize
)
374 memset(data
+ offset
, 0, offset
- fDataSize
);
380 // copy the data and write all of it
384 memcpy((uint8
*)fData
+ offset
, buffer
, bufferSize
);
386 ssize_t bytesWritten
= fs_write_attr(fFileFD
, fAttribute
, fType
, 0,
388 if (bytesWritten
< 0)
390 if ((size_t)bytesWritten
!= fDataSize
)
398 AttributeDescriptor::Close()
403 close_maybe_system(fFileFD
);
415 AttributeDescriptor::Dup(Descriptor
*& clone
)
417 return B_NOT_SUPPORTED
;
422 AttributeDescriptor::GetStat(bool traverseLink
, struct stat
* st
)
424 return B_NOT_SUPPORTED
;
428 // #pragma mark - AttrDirDescriptor
432 AttrDirDescriptor::AttrDirDescriptor(DIR *dir
, const NodeRef
&ref
)
433 : DirectoryDescriptor(dir
, ref
)
438 AttrDirDescriptor::~AttrDirDescriptor()
445 AttrDirDescriptor::Close()
450 if (fs_close_attr_dir(oldDir
) < 0)
459 AttrDirDescriptor::Dup(Descriptor
*&clone
)
461 // we don't allow dup()int attr dir descriptors
467 AttrDirDescriptor::GetStat(bool traverseLink
, struct stat
*st
)
469 // we don't allow stat()int attr dir descriptors
475 AttrDirDescriptor::GetNodeRef(NodeRef
&ref
)
485 get_descriptor(int fd
)
489 DescriptorMap::iterator it
= sDescriptors
->find(fd
);
490 if (it
== sDescriptors
->end())
497 add_descriptor(Descriptor
*descriptor
)
500 sDescriptors
= new DescriptorMap
;
503 if (FileDescriptor
*file
= dynamic_cast<FileDescriptor
*>(descriptor
)) {
507 for (fd
= kVirtualDescriptorStart
;
508 sDescriptors
->find(fd
) != sDescriptors
->end();
513 (*sDescriptors
)[fd
] = descriptor
;
521 delete_descriptor(int fd
)
523 DescriptorMap::iterator it
= sDescriptors
->find(fd
);
524 if (it
== sDescriptors
->end())
527 status_t error
= it
->second
->Close();
529 sDescriptors
->erase(it
);
531 if (sDescriptors
->size() == 0) {
540 is_unknown_or_system_descriptor(int fd
)
542 Descriptor
* descriptor
= get_descriptor(fd
);
543 return descriptor
== NULL
|| descriptor
->IsSystemFD();
547 } // namespace BPrivate