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 12 #include <Directory.h> 13 #include <Entry.h> 14 #include <File.h> 15 #include <NodeMonitor.h> 16 17 #include <syscalls.h> 18 19 20 extern mode_t __gUmask; 21 // declared in sys/umask.c 22 23 24 #ifdef USE_OPENBEOS_NAMESPACE 25 namespace OpenBeOS { 26 #endif 27 28 // constructor 29 //! Creates an uninitialized BFile. 30 BFile::BFile() 31 : BNode(), 32 BPositionIO(), 33 fMode(0) 34 { 35 } 36 37 // copy constructor 38 //! Creates a copy of the supplied BFile. 39 /*! If \a file is uninitialized, the newly constructed BFile will be, too. 40 \param file the BFile object to be copied 41 */ 42 BFile::BFile(const BFile &file) 43 : BNode(), 44 BPositionIO(), 45 fMode(0) 46 { 47 *this = file; 48 } 49 50 // constructor 51 /*! \brief Creates a BFile and initializes it to the file referred to by 52 the supplied entry_ref and according to the specified open mode. 53 \param ref the entry_ref referring to the file 54 \param openMode the mode in which the file should be opened 55 \see SetTo() for values for \a openMode 56 */ 57 BFile::BFile(const entry_ref *ref, uint32 openMode) 58 : BNode(), 59 BPositionIO(), 60 fMode(0) 61 { 62 SetTo(ref, openMode); 63 } 64 65 // constructor 66 /*! \brief Creates a BFile and initializes it to the file referred to by 67 the supplied BEntry and according to the specified open mode. 68 \param entry the BEntry referring to the file 69 \param openMode the mode in which the file should be opened 70 \see SetTo() for values for \a openMode 71 */ 72 BFile::BFile(const BEntry *entry, uint32 openMode) 73 : BNode(), 74 BPositionIO(), 75 fMode(0) 76 { 77 SetTo(entry, openMode); 78 } 79 80 // constructor 81 /*! \brief Creates a BFile and initializes it to the file referred to by 82 the supplied path name and according to the specified open mode. 83 \param path the file's path name 84 \param openMode the mode in which the file should be opened 85 \see SetTo() for values for \a openMode 86 */ 87 BFile::BFile(const char *path, uint32 openMode) 88 : BNode(), 89 BPositionIO(), 90 fMode(0) 91 { 92 SetTo(path, openMode); 93 } 94 95 // constructor 96 /*! \brief Creates a BFile and initializes it to the file referred to by 97 the supplied path name relative to the specified BDirectory and 98 according to the specified open mode. 99 \param dir the BDirectory, relative to which the file's path name is 100 given 101 \param path the file's path name relative to \a dir 102 \param openMode the mode in which the file should be opened 103 \see SetTo() for values for \a openMode 104 */ 105 BFile::BFile(const BDirectory *dir, const char *path, uint32 openMode) 106 : BNode(), 107 BPositionIO(), 108 fMode(0) 109 { 110 SetTo(dir, path, openMode); 111 } 112 113 // destructor 114 //! Frees all allocated resources. 115 /*! If the file is properly initialized, the file's file descriptor is closed. 116 */ 117 BFile::~BFile() 118 { 119 // Also called by the BNode destructor, but we rather try to avoid 120 // problems with calling virtual functions in the base class destructor. 121 // Depending on the compiler implementation an object may be degraded to 122 // an object of the base class after the destructor of the derived class 123 // has been executed. 124 close_fd(); 125 } 126 127 // SetTo 128 /*! \brief Re-initializes the BFile to the file referred to by the 129 supplied entry_ref and according to the specified open mode. 130 \param ref the entry_ref referring to the file 131 \param openMode the mode in which the file should be opened 132 \a openMode must be a bitwise or of exactly one of the flags 133 - \c B_READ_ONLY: The file is opened read only. 134 - \c B_WRITE_ONLY: The file is opened write only. 135 - \c B_READ_WRITE: The file is opened for random read/write access. 136 and any number of the flags 137 - \c B_CREATE_FILE: A new file will be created, if it does not already 138 exist. 139 - \c B_FAIL_IF_EXISTS: If the file does already exist and B_CREATE_FILE is 140 set, SetTo() fails. 141 - \c B_ERASE_FILE: An already existing file is truncated to zero size. 142 - \c B_OPEN_AT_END: Seek() to the end of the file after opening. 143 \return 144 - \c B_OK: Everything went fine. 145 - \c B_BAD_VALUE: \c NULL \a ref or bad \a openMode. 146 - \c B_ENTRY_NOT_FOUND: File not found or failed to create file. 147 - \c B_FILE_EXISTS: File exists and \c B_FAIL_IF_EXISTS was passed. 148 - \c B_PERMISSION_DENIED: File permissions didn't allow operation. 149 - \c B_NO_MEMORY: Insufficient memory for operation. 150 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 151 - \c B_BUSY: A node was busy. 152 - \c B_FILE_ERROR: A general file error. 153 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 154 */ 155 status_t 156 BFile::SetTo(const entry_ref *ref, uint32 openMode) 157 { 158 Unset(); 159 160 if (!ref) 161 return (fCStatus = B_BAD_VALUE); 162 163 int fd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 164 openMode, DEFFILEMODE & ~__gUmask); 165 if (fd >= 0) { 166 set_fd(fd); 167 fMode = openMode; 168 fCStatus = B_OK; 169 170 fcntl(fd, F_SETFD, FD_CLOEXEC); 171 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 int fd = _kern_open(entry->fDirFd, entry->fName, openMode, 208 DEFFILEMODE & ~__gUmask); 209 if (fd >= 0) { 210 set_fd(fd); 211 fMode = openMode; 212 fCStatus = B_OK; 213 214 fcntl(fd, F_SETFD, FD_CLOEXEC); 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 int fd = _kern_open(-1, path, openMode, DEFFILEMODE & ~__gUmask); 247 if (fd >= 0) { 248 set_fd(fd); 249 fMode = openMode; 250 fCStatus = B_OK; 251 252 fcntl(fd, F_SETFD, FD_CLOEXEC); 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 int fd = _kern_open(dir->fDirFd, path, openMode, DEFFILEMODE & ~__gUmask); 289 if (fd >= 0) { 290 set_fd(fd); 291 fMode = openMode; 292 fCStatus = B_OK; 293 294 fcntl(fd, F_SETFD, FD_CLOEXEC); 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_ACCMODE) == O_RDONLY 313 || (fMode & O_ACCMODE) == 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_ACCMODE) == O_WRONLY 328 || (fMode & O_ACCMODE) == 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