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