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