1 /* 2 * Copyright 2002-2011, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Ingo Weinhold, bonefish@users.sf.net 8 */ 9 10 11 #include <Node.h> 12 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <new> 16 #include <string.h> 17 #include <unistd.h> 18 19 #include <compat/sys/stat.h> 20 21 #include <Directory.h> 22 #include <Entry.h> 23 #include <fs_attr.h> 24 #include <String.h> 25 #include <TypeConstants.h> 26 27 #include <syscalls.h> 28 29 #include "storage_support.h" 30 31 32 // #pragma mark - node_ref 33 34 35 node_ref::node_ref() 36 : device((dev_t)-1), 37 node((ino_t)-1) 38 { 39 } 40 41 42 node_ref::node_ref(dev_t device, ino_t node) 43 : 44 device(device), 45 node(node) 46 { 47 } 48 49 50 node_ref::node_ref(const node_ref &ref) 51 : device((dev_t)-1), 52 node((ino_t)-1) 53 { 54 *this = ref; 55 } 56 57 // == 58 bool 59 node_ref::operator==(const node_ref &ref) const 60 { 61 return (device == ref.device && node == ref.node); 62 } 63 64 // != 65 bool 66 node_ref::operator!=(const node_ref &ref) const 67 { 68 return !(*this == ref); 69 } 70 71 72 bool 73 node_ref::operator<(const node_ref& other) const 74 { 75 if (this->device != other.device) 76 return this->device < other.device; 77 return this->node < other.node; 78 } 79 80 81 // = 82 node_ref& 83 node_ref::operator=(const node_ref &ref) 84 { 85 device = ref.device; 86 node = ref.node; 87 return *this; 88 } 89 90 91 // #pragma mark - BNode 92 93 94 BNode::BNode() 95 : fFd(-1), 96 fAttrFd(-1), 97 fCStatus(B_NO_INIT) 98 { 99 } 100 101 102 BNode::BNode(const entry_ref *ref) 103 : fFd(-1), 104 fAttrFd(-1), 105 fCStatus(B_NO_INIT) 106 { 107 SetTo(ref); 108 } 109 110 111 BNode::BNode(const BEntry *entry) 112 : fFd(-1), 113 fAttrFd(-1), 114 fCStatus(B_NO_INIT) 115 { 116 SetTo(entry); 117 } 118 119 120 BNode::BNode(const char *path) 121 : fFd(-1), 122 fAttrFd(-1), 123 fCStatus(B_NO_INIT) 124 { 125 SetTo(path); 126 } 127 128 129 BNode::BNode(const BDirectory *dir, const char *path) 130 : fFd(-1), 131 fAttrFd(-1), 132 fCStatus(B_NO_INIT) 133 { 134 SetTo(dir, path); 135 } 136 137 138 BNode::BNode(const BNode &node) 139 : fFd(-1), 140 fAttrFd(-1), 141 fCStatus(B_NO_INIT) 142 { 143 *this = node; 144 } 145 146 147 BNode::~BNode() 148 { 149 Unset(); 150 } 151 152 153 status_t 154 BNode::InitCheck() const 155 { 156 return fCStatus; 157 } 158 159 160 status_t 161 BNode::SetTo(const entry_ref *ref) 162 { 163 return _SetTo(ref, false); 164 } 165 166 167 status_t 168 BNode::SetTo(const BEntry *entry) 169 { 170 if (!entry) { 171 Unset(); 172 return (fCStatus = B_BAD_VALUE); 173 } 174 return _SetTo(entry->fDirFd, entry->fName, false); 175 } 176 177 178 status_t 179 BNode::SetTo(const char *path) 180 { 181 return _SetTo(-1, path, false); 182 } 183 184 185 status_t 186 BNode::SetTo(const BDirectory *dir, const char *path) 187 { 188 if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { 189 Unset(); 190 return (fCStatus = B_BAD_VALUE); 191 } 192 return _SetTo(dir->fDirFd, path, false); 193 } 194 195 196 void 197 BNode::Unset() 198 { 199 close_fd(); 200 fCStatus = B_NO_INIT; 201 } 202 203 204 status_t 205 BNode::Lock() 206 { 207 if (fCStatus != B_OK) 208 return fCStatus; 209 return _kern_lock_node(fFd); 210 } 211 212 213 status_t 214 BNode::Unlock() 215 { 216 if (fCStatus != B_OK) 217 return fCStatus; 218 return _kern_unlock_node(fFd); 219 } 220 221 222 status_t 223 BNode::Sync() 224 { 225 return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_fsync(fFd); 226 } 227 228 229 ssize_t 230 BNode::WriteAttr(const char *attr, type_code type, off_t offset, 231 const void *buffer, size_t len) 232 { 233 if (fCStatus != B_OK) 234 return B_FILE_ERROR; 235 if (!attr || !buffer) 236 return B_BAD_VALUE; 237 238 ssize_t result = fs_write_attr(fFd, attr, type, offset, buffer, len); 239 return result < 0 ? errno : result; 240 } 241 242 243 ssize_t 244 BNode::ReadAttr(const char *attr, type_code type, off_t offset, 245 void *buffer, size_t len) const 246 { 247 if (fCStatus != B_OK) 248 return B_FILE_ERROR; 249 if (!attr || !buffer) 250 return B_BAD_VALUE; 251 252 ssize_t result = fs_read_attr(fFd, attr, type, offset, buffer, len ); 253 return result == -1 ? errno : result; 254 } 255 256 257 status_t 258 BNode::RemoveAttr(const char *name) 259 { 260 return fCStatus != B_OK ? B_FILE_ERROR : _kern_remove_attr(fFd, name); 261 } 262 263 264 status_t 265 BNode::RenameAttr(const char *oldname, const char *newname) 266 { 267 if (fCStatus != B_OK) 268 return B_FILE_ERROR; 269 270 return _kern_rename_attr(fFd, oldname, fFd, newname); 271 } 272 273 274 status_t 275 BNode::GetAttrInfo(const char *name, struct attr_info *info) const 276 { 277 if (fCStatus != B_OK) 278 return B_FILE_ERROR; 279 if (!name || !info) 280 return B_BAD_VALUE; 281 282 return fs_stat_attr(fFd, name, info) < 0 ? errno : B_OK ; 283 } 284 285 286 status_t 287 BNode::GetNextAttrName(char *buffer) 288 { 289 // We're allowed to assume buffer is at least 290 // B_ATTR_NAME_LENGTH chars long, but NULLs 291 // are not acceptable. 292 if (buffer == NULL) 293 return B_BAD_VALUE; // /new R5 crashed when passed NULL 294 if (InitAttrDir() != B_OK) 295 return B_FILE_ERROR; 296 297 BPrivate::Storage::LongDirEntry entry; 298 ssize_t result = _kern_read_dir(fAttrFd, &entry, sizeof(entry), 1); 299 if (result < 0) 300 return result; 301 if (result == 0) 302 return B_ENTRY_NOT_FOUND; 303 strlcpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH); 304 return B_OK; 305 } 306 307 308 status_t 309 BNode::RewindAttrs() 310 { 311 if (InitAttrDir() != B_OK) 312 return B_FILE_ERROR; 313 314 return _kern_rewind_dir(fAttrFd); 315 } 316 317 318 status_t 319 BNode::WriteAttrString(const char *name, const BString *data) 320 { 321 status_t error = (!name || !data) ? B_BAD_VALUE : B_OK; 322 if (error == B_OK) { 323 int32 len = data->Length() + 1; 324 ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(), 325 len); 326 if (sizeWritten != len) 327 error = sizeWritten; 328 } 329 return error; 330 } 331 332 333 status_t 334 BNode::ReadAttrString(const char *name, BString *result) const 335 { 336 if (!name || !result) 337 return B_BAD_VALUE; 338 339 attr_info info; 340 status_t error; 341 342 error = GetAttrInfo(name, &info); 343 if (error != B_OK) 344 return error; 345 346 // Lock the string's buffer so we can meddle with it 347 char *data = result->LockBuffer(info.size + 1); 348 if (!data) 349 return B_NO_MEMORY; 350 351 // Read the attribute 352 ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size); 353 // Check for failure 354 if (bytes < 0) { 355 error = bytes; 356 bytes = 0; // In this instance, we simply clear the string 357 } else 358 error = B_OK; 359 360 // Null terminate the new string just to be sure (since it *is* 361 // possible to read and write non-NULL-terminated strings) 362 data[bytes] = 0; 363 result->UnlockBuffer(); 364 return error; 365 } 366 367 368 BNode& 369 BNode::operator=(const BNode &node) 370 { 371 // No need to do any assignment if already equal 372 if (*this == node) 373 return *this; 374 375 // Close down out current state 376 Unset(); 377 // We have to manually dup the node, because R5::BNode::Dup() 378 // is not declared to be const (which IMO is retarded). 379 fFd = _kern_dup(node.fFd); 380 fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ; 381 return *this; 382 } 383 384 385 bool 386 BNode::operator==(const BNode &node) const 387 { 388 if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT) 389 return true; 390 if (fCStatus == B_OK && node.InitCheck() == B_OK) { 391 // compare the node_refs 392 node_ref ref1, ref2; 393 if (GetNodeRef(&ref1) != B_OK) 394 return false; 395 if (node.GetNodeRef(&ref2) != B_OK) 396 return false; 397 return (ref1 == ref2); 398 } 399 return false; 400 } 401 402 403 bool 404 BNode::operator!=(const BNode &node) const 405 { 406 return !(*this == node); 407 } 408 409 410 int 411 BNode::Dup() 412 { 413 int fd = _kern_dup(fFd); 414 return (fd >= 0 ? fd : -1); // comply with R5 return value 415 } 416 417 418 /*! (currently unused) */ 419 void BNode::_RudeNode1() { } 420 void BNode::_RudeNode2() { } 421 void BNode::_RudeNode3() { } 422 void BNode::_RudeNode4() { } 423 void BNode::_RudeNode5() { } 424 void BNode::_RudeNode6() { } 425 426 427 status_t 428 BNode::set_fd(int fd) 429 { 430 if (fFd != -1) 431 close_fd(); 432 fFd = fd; 433 return B_OK; 434 } 435 436 437 void 438 BNode::close_fd() 439 { 440 if (fAttrFd >= 0) { 441 _kern_close(fAttrFd); 442 fAttrFd = -1; 443 } 444 if (fFd >= 0) { 445 _kern_close(fFd); 446 fFd = -1; 447 } 448 } 449 450 451 void 452 BNode::set_status(status_t newStatus) 453 { 454 fCStatus = newStatus; 455 } 456 457 458 status_t 459 BNode::_SetTo(int fd, const char *path, bool traverse) 460 { 461 Unset(); 462 status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE); 463 if (error == B_OK) { 464 int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); 465 fFd = _kern_open(fd, path, O_RDWR | O_CLOEXEC | traverseFlag, 0); 466 if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) { 467 // opening read-write failed, re-try read-only 468 fFd = _kern_open(fd, path, O_RDONLY | O_CLOEXEC | traverseFlag, 0); 469 } 470 if (fFd < 0) 471 error = fFd; 472 } 473 return fCStatus = error; 474 } 475 476 477 status_t 478 BNode::_SetTo(const entry_ref *ref, bool traverse) 479 { 480 Unset(); 481 status_t error = (ref ? B_OK : B_BAD_VALUE); 482 if (error == B_OK) { 483 int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); 484 fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 485 O_RDWR | O_CLOEXEC | traverseFlag, 0); 486 if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) { 487 // opening read-write failed, re-try read-only 488 fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 489 O_RDONLY | O_CLOEXEC | traverseFlag, 0); 490 } 491 if (fFd < 0) 492 error = fFd; 493 } 494 return fCStatus = error; 495 } 496 497 498 status_t 499 BNode::set_stat(struct stat &st, uint32 what) 500 { 501 if (fCStatus != B_OK) 502 return B_FILE_ERROR; 503 504 return _kern_write_stat(fFd, NULL, false, &st, sizeof(struct stat), 505 what); 506 } 507 508 509 status_t 510 BNode::InitAttrDir() 511 { 512 if (fCStatus == B_OK && fAttrFd < 0) { 513 fAttrFd = _kern_open_attr_dir(fFd, NULL, false); 514 if (fAttrFd < 0) 515 return fAttrFd; 516 517 // set close on exec flag 518 fcntl(fAttrFd, F_SETFD, FD_CLOEXEC); 519 } 520 return fCStatus; 521 } 522 523 524 status_t 525 BNode::_GetStat(struct stat *st) const 526 { 527 return fCStatus != B_OK 528 ? fCStatus 529 : _kern_read_stat(fFd, NULL, false, st, sizeof(struct stat)); 530 } 531 532 533 status_t 534 BNode::_GetStat(struct stat_beos *st) const 535 { 536 struct stat newStat; 537 status_t error = _GetStat(&newStat); 538 if (error != B_OK) 539 return error; 540 541 convert_to_stat_beos(&newStat, st); 542 return B_OK; 543 } 544 545 546 // #pragma mark - symbol versions 547 548 549 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST 550 # if __GNUC__ == 2 // gcc 2 551 552 B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP4stat", 553 "GetStat__C5BNodeP4stat@@LIBBE_TEST"); 554 555 # else // gcc 4 556 557 B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP4stat", 558 "_ZNK5BNode7GetStatEP4stat@@LIBBE_TEST"); 559 560 # endif // gcc 4 561 #else // !HAIKU_TARGET_PLATFORM_LIBBE_TEST 562 # if __GNUC__ == 2 // gcc 2 563 564 // BeOS compatible GetStat() 565 B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP9stat_beos", 566 "GetStat__C5BNodeP4stat@LIBBE_BASE"); 567 568 // Haiku GetStat() 569 B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP4stat", 570 "GetStat__C5BNodeP4stat@@LIBBE_1_ALPHA1"); 571 572 # else // gcc 4 573 574 // BeOS compatible GetStat() 575 B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP9stat_beos", 576 "_ZNK5BNode7GetStatEP4stat@LIBBE_BASE"); 577 578 // Haiku GetStat() 579 B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP4stat", 580 "_ZNK5BNode7GetStatEP4stat@@LIBBE_1_ALPHA1"); 581 582 # endif // gcc 4 583 #endif // !HAIKU_TARGET_PLATFORM_LIBBE_TEST 584