1 //---------------------------------------------------------------------- 2 // This software is part of the Haiku distribution and is covered 3 // by the MIT license. 4 //--------------------------------------------------------------------- 5 /*! 6 \file File.cpp 7 BFile implementation. 8 */ 9 10 #include <fcntl.h> 11 #include <unistd.h> 12 13 #include <Directory.h> 14 #include <Entry.h> 15 #include <File.h> 16 #include <NodeMonitor.h> 17 18 #include <syscalls.h> 19 20 21 extern mode_t __gUmask; 22 // declared in sys/umask.c 23 24 25 #ifdef USE_OPENBEOS_NAMESPACE 26 namespace OpenBeOS { 27 #endif 28 29 // constructor 30 //! Creates an uninitialized BFile. 31 BFile::BFile() 32 : BNode(), 33 BPositionIO(), 34 fMode(0) 35 { 36 } 37 38 // copy constructor 39 //! Creates a copy of the supplied BFile. 40 /*! If \a file is uninitialized, the newly constructed BFile will be, too. 41 \param file the BFile object to be copied 42 */ 43 BFile::BFile(const BFile &file) 44 : BNode(), 45 BPositionIO(), 46 fMode(0) 47 { 48 *this = file; 49 } 50 51 // constructor 52 /*! \brief Creates a BFile and initializes it to the file referred to by 53 the supplied entry_ref and according to the specified open mode. 54 \param ref the entry_ref referring to the file 55 \param openMode the mode in which the file should be opened 56 \see SetTo() for values for \a openMode 57 */ 58 BFile::BFile(const entry_ref *ref, uint32 openMode) 59 : BNode(), 60 BPositionIO(), 61 fMode(0) 62 { 63 SetTo(ref, openMode); 64 } 65 66 // constructor 67 /*! \brief Creates a BFile and initializes it to the file referred to by 68 the supplied BEntry and according to the specified open mode. 69 \param entry the BEntry referring to the file 70 \param openMode the mode in which the file should be opened 71 \see SetTo() for values for \a openMode 72 */ 73 BFile::BFile(const BEntry *entry, uint32 openMode) 74 : BNode(), 75 BPositionIO(), 76 fMode(0) 77 { 78 SetTo(entry, openMode); 79 } 80 81 // constructor 82 /*! \brief Creates a BFile and initializes it to the file referred to by 83 the supplied path name and according to the specified open mode. 84 \param path the file's path name 85 \param openMode the mode in which the file should be opened 86 \see SetTo() for values for \a openMode 87 */ 88 BFile::BFile(const char *path, uint32 openMode) 89 : BNode(), 90 BPositionIO(), 91 fMode(0) 92 { 93 SetTo(path, openMode); 94 } 95 96 // constructor 97 /*! \brief Creates a BFile and initializes it to the file referred to by 98 the supplied path name relative to the specified BDirectory and 99 according to the specified open mode. 100 \param dir the BDirectory, relative to which the file's path name is 101 given 102 \param path the file's path name relative to \a dir 103 \param openMode the mode in which the file should be opened 104 \see SetTo() for values for \a openMode 105 */ 106 BFile::BFile(const BDirectory *dir, const char *path, uint32 openMode) 107 : BNode(), 108 BPositionIO(), 109 fMode(0) 110 { 111 SetTo(dir, path, openMode); 112 } 113 114 // destructor 115 //! Frees all allocated resources. 116 /*! If the file is properly initialized, the file's file descriptor is closed. 117 */ 118 BFile::~BFile() 119 { 120 // Also called by the BNode destructor, but we rather try to avoid 121 // problems with calling virtual functions in the base class destructor. 122 // Depending on the compiler implementation an object may be degraded to 123 // an object of the base class after the destructor of the derived class 124 // has been executed. 125 close_fd(); 126 } 127 128 // SetTo 129 /*! \brief Re-initializes the BFile to the file referred to by the 130 supplied entry_ref and according to the specified open mode. 131 \param ref the entry_ref referring to the file 132 \param openMode the mode in which the file should be opened 133 \a openMode must be a bitwise or of exactly one of the flags 134 - \c B_READ_ONLY: The file is opened read only. 135 - \c B_WRITE_ONLY: The file is opened write only. 136 - \c B_READ_WRITE: The file is opened for random read/write access. 137 and any number of the flags 138 - \c B_CREATE_FILE: A new file will be created, if it does not already 139 exist. 140 - \c B_FAIL_IF_EXISTS: If the file does already exist and B_CREATE_FILE is 141 set, SetTo() fails. 142 - \c B_ERASE_FILE: An already existing file is truncated to zero size. 143 - \c B_OPEN_AT_END: Seek() to the end of the file after opening. 144 \return 145 - \c B_OK: Everything went fine. 146 - \c B_BAD_VALUE: \c NULL \a ref or bad \a openMode. 147 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 148 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 149 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 150 - \c B_NO_MEMORY: Insufficient memory for operation. 151 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 152 - \c B_BUSY: A node was busy. 153 - \c B_FILE_ERROR: A general file error. 154 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 155 */ 156 status_t 157 BFile::SetTo(const entry_ref *ref, uint32 openMode) 158 { 159 Unset(); 160 161 if (!ref) 162 return (fCStatus = B_BAD_VALUE); 163 164 int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 165 openMode, DEFFILEMODE & ~__gUmask); 166 if (fd >= 0) { 167 set_fd(fd); 168 fMode = openMode; 169 fCStatus = B_OK; 170 171 fcntl(fd, F_SETFD, FD_CLOEXEC); 172 173 } else 174 fCStatus = fd; 175 176 return fCStatus; 177 } 178 179 // SetTo 180 /*! \brief Re-initializes the BFile to the file referred to by the 181 supplied BEntry and according to the specified open mode. 182 \param entry the BEntry referring to the file 183 \param openMode the mode in which the file should be opened 184 \return 185 - \c B_OK: Everything went fine. 186 - \c B_BAD_VALUE: \c NULL \a entry or bad \a openMode. 187 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 188 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 189 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 190 - \c B_NO_MEMORY: Insufficient memory for operation. 191 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 192 - \c B_BUSY: A node was busy. 193 - \c B_FILE_ERROR: A general file error. 194 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 195 \todo Implemented using SetTo(entry_ref*, uint32). Check, if necessary 196 to reimplement! 197 */ 198 status_t 199 BFile::SetTo(const BEntry *entry, uint32 openMode) 200 { 201 Unset(); 202 203 if (!entry) 204 return (fCStatus = B_BAD_VALUE); 205 if (entry->InitCheck() != B_OK) 206 return (fCStatus = entry->InitCheck()); 207 208 int fd = _kern_open(entry->fDirFd, entry->fName, openMode, 209 DEFFILEMODE & ~__gUmask); 210 if (fd >= 0) { 211 set_fd(fd); 212 fMode = openMode; 213 fCStatus = B_OK; 214 215 fcntl(fd, F_SETFD, FD_CLOEXEC); 216 } else 217 fCStatus = fd; 218 219 return fCStatus; 220 } 221 222 // SetTo 223 /*! \brief Re-initializes the BFile to the file referred to by the 224 supplied path name and according to the specified open mode. 225 \param path the file's path name 226 \param openMode the mode in which the file should be opened 227 \return 228 - \c B_OK: Everything went fine. 229 - \c B_BAD_VALUE: \c NULL \a path or bad \a openMode. 230 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 231 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 232 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 233 - \c B_NO_MEMORY: Insufficient memory for operation. 234 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 235 - \c B_BUSY: A node was busy. 236 - \c B_FILE_ERROR: A general file error. 237 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 238 */ 239 status_t 240 BFile::SetTo(const char *path, uint32 openMode) 241 { 242 Unset(); 243 244 if (!path) 245 return (fCStatus = B_BAD_VALUE); 246 247 int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask); 248 if (fd >= 0) { 249 set_fd(fd); 250 fMode = openMode; 251 fCStatus = B_OK; 252 253 fcntl(fd, F_SETFD, FD_CLOEXEC); 254 } else 255 fCStatus = fd; 256 257 return fCStatus; 258 } 259 260 // SetTo 261 /*! \brief Re-initializes the BFile to the file referred to by the 262 supplied path name relative to the specified BDirectory and 263 according to the specified open mode. 264 \param dir the BDirectory, relative to which the file's path name is 265 given 266 \param path the file's path name relative to \a dir 267 \param openMode the mode in which the file should be opened 268 - \c B_OK: Everything went fine. 269 - \c B_BAD_VALUE: \c NULL \a dir or \a path or bad \a openMode. 270 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 271 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 272 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 273 - \c B_NO_MEMORY: Insufficient memory for operation. 274 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 275 - \c B_BUSY: A node was busy. 276 - \c B_FILE_ERROR: A general file error. 277 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 278 \todo Implemented using SetTo(BEntry*, uint32). Check, if necessary 279 to reimplement! 280 */ 281 status_t 282 BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode) 283 { 284 Unset(); 285 286 if (!dir) 287 return (fCStatus = B_BAD_VALUE); 288 289 int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask); 290 if (fd >= 0) { 291 set_fd(fd); 292 fMode = openMode; 293 fCStatus = B_OK; 294 295 fcntl(fd, F_SETFD, FD_CLOEXEC); 296 } else 297 fCStatus = fd; 298 299 return fCStatus; 300 } 301 302 // IsReadable 303 //! Returns whether the file is readable. 304 /*! \return 305 - \c true, if the BFile has been initialized properly and the file has 306 been been opened for reading, 307 - \c false, otherwise. 308 */ 309 bool 310 BFile::IsReadable() const 311 { 312 return (InitCheck() == B_OK 313 && ((fMode & O_ACCMODE) == O_RDONLY 314 || (fMode & O_ACCMODE) == O_RDWR)); 315 } 316 317 // IsWritable 318 //! Returns whether the file is writable. 319 /*! \return 320 - \c true, if the BFile has been initialized properly and the file has 321 been opened for writing, 322 - \c false, otherwise. 323 */ 324 bool 325 BFile::IsWritable() const 326 { 327 return (InitCheck() == B_OK 328 && ((fMode & O_ACCMODE) == O_WRONLY 329 || (fMode & O_ACCMODE) == O_RDWR)); 330 } 331 332 // Read 333 //! Reads a number of bytes from the file into a buffer. 334 /*! \param buffer the buffer the data from the file shall be written to 335 \param size the number of bytes that shall be read 336 \return the number of bytes actually read or an error code 337 */ 338 ssize_t 339 BFile::Read(void *buffer, size_t size) 340 { 341 if (InitCheck() != B_OK) 342 return InitCheck(); 343 return _kern_read(get_fd(), -1, buffer, size); 344 } 345 346 // ReadAt 347 /*! \brief Reads a number of bytes from a certain position within the file 348 into a buffer. 349 \param location the position (in bytes) within the file from which the 350 data shall be read 351 \param buffer the buffer the data from the file shall be written to 352 \param size the number of bytes that shall be read 353 \return the number of bytes actually read or an error code 354 */ 355 ssize_t 356 BFile::ReadAt(off_t location, void *buffer, size_t size) 357 { 358 if (InitCheck() != B_OK) 359 return InitCheck(); 360 if (location < 0) 361 return B_BAD_VALUE; 362 return _kern_read(get_fd(), location, buffer, size); 363 } 364 365 // Write 366 //! Writes a number of bytes from a buffer into the file. 367 /*! \param buffer the buffer containing the data to be written to the file 368 \param size the number of bytes that shall be written 369 \return the number of bytes actually written or an error code 370 */ 371 ssize_t 372 BFile::Write(const void *buffer, size_t size) 373 { 374 if (InitCheck() != B_OK) 375 return InitCheck(); 376 return _kern_write(get_fd(), -1, buffer, size); 377 } 378 379 // WriteAt 380 /*! \brief Writes a number of bytes from a buffer at a certain position 381 into the file. 382 \param location the position (in bytes) within the file at which the data 383 shall be written 384 \param buffer the buffer containing the data to be written to the file 385 \param size the number of bytes that shall be written 386 \return the number of bytes actually written or an error code 387 */ 388 ssize_t 389 BFile::WriteAt(off_t location, const void *buffer, size_t size) 390 { 391 if (InitCheck() != B_OK) 392 return InitCheck(); 393 if (location < 0) 394 return B_BAD_VALUE; 395 return _kern_write(get_fd(), location, buffer, size); 396 } 397 398 // Seek 399 //! Seeks to another read/write position within the file. 400 /*! It is allowed to seek past the end of the file. A subsequent call to 401 Write() will pad the file with undefined data. Seeking before the 402 beginning of the file will fail and the behavior of subsequent Read() 403 or Write() invocations will be undefined. 404 \param offset new read/write position, depending on \a seekMode relative 405 to the beginning or the end of the file or the current position 406 \param seekMode: 407 - \c SEEK_SET: move relative to the beginning of the file 408 - \c SEEK_CUR: move relative to the current position 409 - \c SEEK_END: move relative to the end of the file 410 \return 411 - the new read/write position relative to the beginning of the file 412 - \c B_ERROR when trying to seek before the beginning of the file 413 - \c B_FILE_ERROR, if the file is not properly initialized 414 */ 415 off_t 416 BFile::Seek(off_t offset, uint32 seekMode) 417 { 418 if (InitCheck() != B_OK) 419 return B_FILE_ERROR; 420 return _kern_seek(get_fd(), offset, seekMode); 421 } 422 423 // Position 424 //! Returns the current read/write position within the file. 425 /*! \return 426 - the current read/write position relative to the beginning of the file 427 - \c B_ERROR, after a Seek() before the beginning of the file 428 - \c B_FILE_ERROR, if the file has not been initialized 429 */ 430 off_t 431 BFile::Position() const 432 { 433 if (InitCheck() != B_OK) 434 return B_FILE_ERROR; 435 return _kern_seek(get_fd(), 0, SEEK_CUR); 436 } 437 438 // SetSize 439 //! Sets the size of the file. 440 /*! If the file is shorter than \a size bytes it will be padded with 441 unspecified data to the requested size. If it is larger, it will be 442 truncated. 443 Note: There's no problem with setting the size of a BFile opened in 444 \c B_READ_ONLY mode, unless the file resides on a read only volume. 445 \param size the new file size 446 \return 447 - \c B_OK, if everything went fine 448 - \c B_NOT_ALLOWED, if trying to set the size of a file on a read only 449 volume 450 - \c B_DEVICE_FULL, if there's not enough space left on the volume 451 */ 452 status_t 453 BFile::SetSize(off_t size) 454 { 455 if (InitCheck() != B_OK) 456 return InitCheck(); 457 if (size < 0) 458 return B_BAD_VALUE; 459 struct stat statData; 460 statData.st_size = size; 461 return set_stat(statData, B_STAT_SIZE); 462 } 463 464 465 status_t 466 BFile::GetSize(off_t* size) const 467 { 468 return BStatable::GetSize(size); 469 } 470 471 472 // = 473 //! Assigns another BFile to this BFile. 474 /*! If the other BFile is uninitialized, this one will be too. Otherwise it 475 will refer to the same file using the same mode, unless an error occurs. 476 \param file the original BFile 477 \return a reference to this BFile 478 */ 479 BFile & 480 BFile::operator=(const BFile &file) 481 { 482 if (&file != this) { // no need to assign us to ourselves 483 Unset(); 484 if (file.InitCheck() == B_OK) { 485 // duplicate the file descriptor 486 int fd = _kern_dup(file.get_fd()); 487 // set it 488 if (fd >= 0) { 489 fFd = fd; 490 fMode = file.fMode; 491 fCStatus = B_OK; 492 } else 493 fCStatus = fd; 494 } 495 } 496 return *this; 497 } 498 499 500 // FBC 501 void BFile::_PhiloFile1() {} 502 void BFile::_PhiloFile2() {} 503 void BFile::_PhiloFile3() {} 504 void BFile::_PhiloFile4() {} 505 void BFile::_PhiloFile5() {} 506 void BFile::_PhiloFile6() {} 507 508 509 // get_fd 510 /*! Returns the file descriptor. 511 To be used instead of accessing the BNode's private \c fFd member directly. 512 \return the file descriptor, or -1, if not properly initialized. 513 */ 514 int 515 BFile::get_fd() const 516 { 517 return fFd; 518 } 519 520 // close_fd 521 /*! Overrides BNode::close_fd() solely for R5 binary compatibility. 522 */ 523 void 524 BFile::close_fd() 525 { 526 BNode::close_fd(); 527 } 528 529 530 #ifdef USE_OPENBEOS_NAMESPACE 531 }; // namespace OpenBeOS 532 #endif 533 534