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