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