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 openMode |= O_CLOEXEC; 165 166 int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 167 openMode, DEFFILEMODE & ~__gUmask); 168 if (fd >= 0) { 169 set_fd(fd); 170 fMode = openMode; 171 fCStatus = B_OK; 172 } else 173 fCStatus = fd; 174 175 return fCStatus; 176 } 177 178 // SetTo 179 /*! \brief Re-initializes the BFile to the file referred to by the 180 supplied BEntry and according to the specified open mode. 181 \param entry the BEntry referring to the file 182 \param openMode the mode in which the file should be opened 183 \return 184 - \c B_OK: Everything went fine. 185 - \c B_BAD_VALUE: \c NULL \a entry or bad \a openMode. 186 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 187 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 188 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 189 - \c B_NO_MEMORY: Insufficient memory for operation. 190 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 191 - \c B_BUSY: A node was busy. 192 - \c B_FILE_ERROR: A general file error. 193 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 194 \todo Implemented using SetTo(entry_ref*, uint32). Check, if necessary 195 to reimplement! 196 */ 197 status_t 198 BFile::SetTo(const BEntry *entry, uint32 openMode) 199 { 200 Unset(); 201 202 if (!entry) 203 return (fCStatus = B_BAD_VALUE); 204 if (entry->InitCheck() != B_OK) 205 return (fCStatus = entry->InitCheck()); 206 207 openMode |= O_CLOEXEC; 208 209 int fd = _kern_open(entry->fDirFd, entry->fName, openMode | O_CLOEXEC, 210 DEFFILEMODE & ~__gUmask); 211 if (fd >= 0) { 212 set_fd(fd); 213 fMode = openMode; 214 fCStatus = B_OK; 215 } else 216 fCStatus = fd; 217 218 return fCStatus; 219 } 220 221 // SetTo 222 /*! \brief Re-initializes the BFile to the file referred to by the 223 supplied path name and according to the specified open mode. 224 \param path the file's path name 225 \param openMode the mode in which the file should be opened 226 \return 227 - \c B_OK: Everything went fine. 228 - \c B_BAD_VALUE: \c NULL \a path or bad \a openMode. 229 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 230 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 231 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 232 - \c B_NO_MEMORY: Insufficient memory for operation. 233 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 234 - \c B_BUSY: A node was busy. 235 - \c B_FILE_ERROR: A general file error. 236 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 237 */ 238 status_t 239 BFile::SetTo(const char *path, uint32 openMode) 240 { 241 Unset(); 242 243 if (!path) 244 return (fCStatus = B_BAD_VALUE); 245 246 openMode |= O_CLOEXEC; 247 248 int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask); 249 if (fd >= 0) { 250 set_fd(fd); 251 fMode = openMode; 252 fCStatus = B_OK; 253 } else 254 fCStatus = fd; 255 256 return fCStatus; 257 } 258 259 // SetTo 260 /*! \brief Re-initializes the BFile to the file referred to by the 261 supplied path name relative to the specified BDirectory and 262 according to the specified open mode. 263 \param dir the BDirectory, relative to which the file's path name is 264 given 265 \param path the file's path name relative to \a dir 266 \param openMode the mode in which the file should be opened 267 - \c B_OK: Everything went fine. 268 - \c B_BAD_VALUE: \c NULL \a dir or \a path or bad \a openMode. 269 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 270 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 271 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 272 - \c B_NO_MEMORY: Insufficient memory for operation. 273 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 274 - \c B_BUSY: A node was busy. 275 - \c B_FILE_ERROR: A general file error. 276 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 277 \todo Implemented using SetTo(BEntry*, uint32). Check, if necessary 278 to reimplement! 279 */ 280 status_t 281 BFile::SetTo(const BDirectory *dir, const char *path, uint32 openMode) 282 { 283 Unset(); 284 285 if (!dir) 286 return (fCStatus = B_BAD_VALUE); 287 288 openMode |= O_CLOEXEC; 289 290 int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask); 291 if (fd >= 0) { 292 set_fd(fd); 293 fMode = openMode; 294 fCStatus = B_OK; 295 } else 296 fCStatus = fd; 297 298 return fCStatus; 299 } 300 301 // IsReadable 302 //! Returns whether the file is readable. 303 /*! \return 304 - \c true, if the BFile has been initialized properly and the file has 305 been been opened for reading, 306 - \c false, otherwise. 307 */ 308 bool 309 BFile::IsReadable() const 310 { 311 return (InitCheck() == B_OK 312 && ((fMode & O_RWMASK) == O_RDONLY 313 || (fMode & O_RWMASK) == O_RDWR)); 314 } 315 316 // IsWritable 317 //! Returns whether the file is writable. 318 /*! \return 319 - \c true, if the BFile has been initialized properly and the file has 320 been opened for writing, 321 - \c false, otherwise. 322 */ 323 bool 324 BFile::IsWritable() const 325 { 326 return (InitCheck() == B_OK 327 && ((fMode & O_RWMASK) == O_WRONLY 328 || (fMode & O_RWMASK) == O_RDWR)); 329 } 330 331 // Read 332 //! Reads a number of bytes from the file into a buffer. 333 /*! \param buffer the buffer the data from the file shall be written to 334 \param size the number of bytes that shall be read 335 \return the number of bytes actually read or an error code 336 */ 337 ssize_t 338 BFile::Read(void *buffer, size_t size) 339 { 340 if (InitCheck() != B_OK) 341 return InitCheck(); 342 return _kern_read(get_fd(), -1, buffer, size); 343 } 344 345 // ReadAt 346 /*! \brief Reads a number of bytes from a certain position within the file 347 into a buffer. 348 \param location the position (in bytes) within the file from which the 349 data shall be read 350 \param buffer the buffer the data from the file shall be written to 351 \param size the number of bytes that shall be read 352 \return the number of bytes actually read or an error code 353 */ 354 ssize_t 355 BFile::ReadAt(off_t location, void *buffer, size_t size) 356 { 357 if (InitCheck() != B_OK) 358 return InitCheck(); 359 if (location < 0) 360 return B_BAD_VALUE; 361 return _kern_read(get_fd(), location, buffer, size); 362 } 363 364 // Write 365 //! Writes a number of bytes from a buffer into the file. 366 /*! \param buffer the buffer containing the data to be written to the file 367 \param size the number of bytes that shall be written 368 \return the number of bytes actually written or an error code 369 */ 370 ssize_t 371 BFile::Write(const void *buffer, size_t size) 372 { 373 if (InitCheck() != B_OK) 374 return InitCheck(); 375 return _kern_write(get_fd(), -1, buffer, size); 376 } 377 378 // WriteAt 379 /*! \brief Writes a number of bytes from a buffer at a certain position 380 into the file. 381 \param location the position (in bytes) within the file at which the data 382 shall be written 383 \param buffer the buffer containing the data to be written to the file 384 \param size the number of bytes that shall be written 385 \return the number of bytes actually written or an error code 386 */ 387 ssize_t 388 BFile::WriteAt(off_t location, const void *buffer, size_t size) 389 { 390 if (InitCheck() != B_OK) 391 return InitCheck(); 392 if (location < 0) 393 return B_BAD_VALUE; 394 return _kern_write(get_fd(), location, buffer, size); 395 } 396 397 // Seek 398 //! Seeks to another read/write position within the file. 399 /*! It is allowed to seek past the end of the file. A subsequent call to 400 Write() will pad the file with undefined data. Seeking before the 401 beginning of the file will fail and the behavior of subsequent Read() 402 or Write() invocations will be undefined. 403 \param offset new read/write position, depending on \a seekMode relative 404 to the beginning or the end of the file or the current position 405 \param seekMode: 406 - \c SEEK_SET: move relative to the beginning of the file 407 - \c SEEK_CUR: move relative to the current position 408 - \c SEEK_END: move relative to the end of the file 409 \return 410 - the new read/write position relative to the beginning of the file 411 - \c B_ERROR when trying to seek before the beginning of the file 412 - \c B_FILE_ERROR, if the file is not properly initialized 413 */ 414 off_t 415 BFile::Seek(off_t offset, uint32 seekMode) 416 { 417 if (InitCheck() != B_OK) 418 return B_FILE_ERROR; 419 return _kern_seek(get_fd(), offset, seekMode); 420 } 421 422 // Position 423 //! Returns the current read/write position within the file. 424 /*! \return 425 - the current read/write position relative to the beginning of the file 426 - \c B_ERROR, after a Seek() before the beginning of the file 427 - \c B_FILE_ERROR, if the file has not been initialized 428 */ 429 off_t 430 BFile::Position() const 431 { 432 if (InitCheck() != B_OK) 433 return B_FILE_ERROR; 434 return _kern_seek(get_fd(), 0, SEEK_CUR); 435 } 436 437 // SetSize 438 //! Sets the size of the file. 439 /*! If the file is shorter than \a size bytes it will be padded with 440 unspecified data to the requested size. If it is larger, it will be 441 truncated. 442 Note: There's no problem with setting the size of a BFile opened in 443 \c B_READ_ONLY mode, unless the file resides on a read only volume. 444 \param size the new file size 445 \return 446 - \c B_OK, if everything went fine 447 - \c B_NOT_ALLOWED, if trying to set the size of a file on a read only 448 volume 449 - \c B_DEVICE_FULL, if there's not enough space left on the volume 450 */ 451 status_t 452 BFile::SetSize(off_t size) 453 { 454 if (InitCheck() != B_OK) 455 return InitCheck(); 456 if (size < 0) 457 return B_BAD_VALUE; 458 struct stat statData; 459 statData.st_size = size; 460 return set_stat(statData, B_STAT_SIZE); 461 } 462 463 // = 464 //! Assigns another BFile to this BFile. 465 /*! If the other BFile is uninitialized, this one will be too. Otherwise it 466 will refer to the same file using the same mode, unless an error occurs. 467 \param file the original BFile 468 \return a reference to this BFile 469 */ 470 BFile & 471 BFile::operator=(const BFile &file) 472 { 473 if (&file != this) { // no need to assign us to ourselves 474 Unset(); 475 if (file.InitCheck() == B_OK) { 476 // duplicate the file descriptor 477 int fd = _kern_dup(file.get_fd()); 478 // set it 479 if (fd >= 0) { 480 fFd = fd; 481 fMode = file.fMode; 482 fCStatus = B_OK; 483 } else 484 fCStatus = fd; 485 } 486 } 487 return *this; 488 } 489 490 491 // FBC 492 void BFile::_PhiloFile1() {} 493 void BFile::_PhiloFile2() {} 494 void BFile::_PhiloFile3() {} 495 void BFile::_PhiloFile4() {} 496 void BFile::_PhiloFile5() {} 497 void BFile::_PhiloFile6() {} 498 499 500 // get_fd 501 /*! Returns the file descriptor. 502 To be used instead of accessing the BNode's private \c fFd member directly. 503 \return the file descriptor, or -1, if not properly initialized. 504 */ 505 int 506 BFile::get_fd() const 507 { 508 return fFd; 509 } 510 511 // close_fd 512 /*! Overrides BNode::close_fd() solely for R5 binary compatibility. 513 */ 514 void 515 BFile::close_fd() 516 { 517 BNode::close_fd(); 518 } 519 520 521 #ifdef USE_OPENBEOS_NAMESPACE 522 }; // namespace OpenBeOS 523 #endif 524 525