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 30using std::map; 31 32static const int kVirtualDescriptorStart = 10000; 33 34typedef map<int, BPrivate::Descriptor*> DescriptorMap; 35static DescriptorMap *sDescriptors; 36 37namespace BPrivate { 38 39 40static int 41dup_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 51static status_t 52close_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 65Descriptor::~Descriptor() 66{ 67} 68 69// IsSystemFD 70bool 71Descriptor::IsSystemFD() const 72{ 73 return false; 74} 75 76// GetPath 77status_t 78Descriptor::GetPath(string& path) const 79{ 80 return get_path(fd, NULL, path); 81} 82 83// GetNodeRef 84status_t 85Descriptor::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 102FileDescriptor::FileDescriptor(int fd) 103{ 104 this->fd = fd; 105} 106 107// destructor 108FileDescriptor::~FileDescriptor() 109{ 110 Close(); 111} 112 113// Close 114status_t 115FileDescriptor::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 128status_t 129FileDescriptor::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 140status_t 141FileDescriptor::GetStat(bool traverseLink, struct stat *st) 142{ 143 if (fstat(fd, st) < 0) 144 return errno; 145 return B_OK; 146} 147 148// IsSystemFD 149bool 150FileDescriptor::IsSystemFD() const 151{ 152 return true; 153} 154 155 156// #pragma mark - DirectoryDescriptor 157 158 159// constructor 160DirectoryDescriptor::DirectoryDescriptor(DIR *dir, const NodeRef &ref) 161{ 162 this->dir = dir; 163 this->ref = ref; 164} 165 166// destructor 167DirectoryDescriptor::~DirectoryDescriptor() 168{ 169 Close(); 170} 171 172// Close 173status_t 174DirectoryDescriptor::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 187status_t 188DirectoryDescriptor::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 204status_t 205DirectoryDescriptor::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 224status_t 225DirectoryDescriptor::GetNodeRef(NodeRef &ref) 226{ 227 ref = this->ref; 228 229 return B_OK; 230} 231 232 233// #pragma mark - SymlinkDescriptor 234 235 236// constructor 237SymlinkDescriptor::SymlinkDescriptor(const char *path) 238{ 239 this->path = path; 240} 241 242// Close 243status_t 244SymlinkDescriptor::Close() 245{ 246 return B_OK; 247} 248 249// Dup 250status_t 251SymlinkDescriptor::Dup(Descriptor *&clone) 252{ 253 clone = new SymlinkDescriptor(path.c_str()); 254 return B_OK; 255} 256 257// GetStat 258status_t 259SymlinkDescriptor::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 275status_t 276SymlinkDescriptor::GetPath(string& path) const 277{ 278 path = this->path; 279 return B_OK; 280} 281 282 283// #pragma mark - AttributeDescriptor 284 285 286AttributeDescriptor::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 300AttributeDescriptor::~AttributeDescriptor() 301{ 302 Close(); 303} 304 305 306status_t 307AttributeDescriptor::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 355status_t 356AttributeDescriptor::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 397status_t 398AttributeDescriptor::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 414status_t 415AttributeDescriptor::Dup(Descriptor*& clone) 416{ 417 return B_NOT_SUPPORTED; 418} 419 420 421status_t 422AttributeDescriptor::GetStat(bool traverseLink, struct stat* st) 423{ 424 return B_NOT_SUPPORTED; 425} 426 427 428// #pragma mark - AttrDirDescriptor 429 430 431// constructor 432AttrDirDescriptor::AttrDirDescriptor(DIR *dir, const NodeRef &ref) 433 : DirectoryDescriptor(dir, ref) 434{ 435} 436 437// destructor 438AttrDirDescriptor::~AttrDirDescriptor() 439{ 440 Close(); 441} 442 443// Close 444status_t 445AttrDirDescriptor::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 458status_t 459AttrDirDescriptor::Dup(Descriptor *&clone) 460{ 461 // we don't allow dup()int attr dir descriptors 462 return B_FILE_ERROR; 463} 464 465// GetStat 466status_t 467AttrDirDescriptor::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 474status_t 475AttrDirDescriptor::GetNodeRef(NodeRef &ref) 476{ 477 ref = this->ref; 478 479 return B_OK; 480} 481 482 483// get_descriptor 484Descriptor * 485get_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 496int 497add_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 520status_t 521delete_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 539bool 540is_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