1 /* 2 * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 #ifndef INODE_H 6 #define INODE_H 7 8 9 #include "system_dependencies.h" 10 11 #include "CachedBlock.h" 12 #include "Debug.h" 13 #include "Journal.h" 14 #include "Volume.h" 15 16 17 class BPlusTree; 18 class TreeIterator; 19 class AttributeIterator; 20 class Index; 21 class InodeAllocator; 22 class NodeGetter; 23 class Transaction; 24 25 26 // To be used in Inode::Create() as publishFlags 27 #define BFS_DO_NOT_PUBLISH_VNODE 0x80000000 28 29 30 class Inode : public TransactionListener { 31 typedef DoublyLinkedListLink<Inode> Link; 32 33 public: 34 Inode(Volume* volume, ino_t id); 35 Inode(Volume* volume, Transaction& transaction, 36 ino_t id, mode_t mode, block_run& run); 37 ~Inode(); 38 39 status_t InitCheck(bool checkNode = true) const; 40 41 ino_t ID() const { return fID; } 42 off_t BlockNumber() const 43 { return fVolume->VnodeToBlock(fID); } 44 45 rw_lock& Lock() { return fLock; } 46 ReadLocker ReadLock() { return ReadLocker(fLock); } 47 void WriteLockInTransaction(Transaction& transaction); 48 49 recursive_lock& SmallDataLock() { return fSmallDataLock; } 50 51 status_t WriteBack(Transaction& transaction); 52 status_t UpdateNodeFromDisk(); 53 54 bool IsContainer() const 55 { return S_ISDIR(Mode()); } 56 bool IsDirectory() const 57 { return is_directory(Mode()); } 58 bool IsIndex() const 59 { return is_index(Mode()); } 60 61 bool IsAttributeDirectory() const 62 { return (Mode() & S_EXTENDED_TYPES) 63 == S_ATTR_DIR; } 64 bool IsAttribute() const 65 { return (Mode() & S_EXTENDED_TYPES) 66 == S_ATTR; } 67 bool IsFile() const 68 { return (Mode() & (S_IFMT 69 | S_EXTENDED_TYPES)) == S_FILE; } 70 bool IsRegularNode() const 71 { return (Mode() & S_EXTENDED_TYPES) == 0; } 72 // a regular node in the standard namespace 73 // (i.e. not an index or attribute) 74 bool IsSymLink() const { return S_ISLNK(Mode()); } 75 bool IsLongSymLink() const 76 { return (Flags() & INODE_LONG_SYMLINK) 77 != 0; } 78 79 bool HasUserAccessableStream() const 80 { return IsFile(); } 81 // currently only files can be accessed with 82 // bfs_read()/bfs_write() 83 bool NeedsFileCache() const 84 { return IsFile() || IsAttribute() 85 || IsLongSymLink(); } 86 87 bool IsDeleted() const 88 { return (Flags() & INODE_DELETED) != 0; } 89 90 mode_t Mode() const { return fNode.Mode(); } 91 uint32 Type() const { return fNode.Type(); } 92 int32 Flags() const { return fNode.Flags(); } 93 94 off_t Size() const { return fNode.data.Size(); } 95 off_t AllocatedSize() const; 96 off_t LastModified() const 97 { return fNode.LastModifiedTime(); } 98 99 const block_run& BlockRun() const 100 { return fNode.inode_num; } 101 block_run& Parent() { return fNode.parent; } 102 const block_run& Parent() const { return fNode.parent; } 103 ino_t ParentID() const 104 { return fVolume->ToVnode(Parent()); } 105 block_run& Attributes() { return fNode.attributes; } 106 107 Volume* GetVolume() const { return fVolume; } 108 109 status_t CheckPermissions(int accessMode) const; 110 111 // small_data access methods 112 small_data* FindSmallData(const bfs_inode* node, 113 const char* name) const; 114 const char* Name(const bfs_inode* node) const; 115 status_t GetName(char* buffer, size_t bufferSize 116 = B_FILE_NAME_LENGTH) const; 117 status_t SetName(Transaction& transaction, 118 const char* name); 119 120 // high-level attribute methods 121 status_t ReadAttribute(const char* name, int32 type, 122 off_t pos, uint8* buffer, size_t* _length); 123 status_t WriteAttribute(Transaction& transaction, 124 const char* name, int32 type, off_t pos, 125 const uint8* buffer, size_t* _length, 126 bool* _created); 127 status_t RemoveAttribute(Transaction& transaction, 128 const char* name); 129 130 // attribute methods 131 status_t GetAttribute(const char* name, 132 Inode** _attribute); 133 void ReleaseAttribute(Inode* attribute); 134 status_t CreateAttribute(Transaction& transaction, 135 const char* name, uint32 type, 136 Inode** attribute); 137 138 // for directories only: 139 BPlusTree* Tree() const { return fTree; } 140 bool IsEmpty(); 141 status_t ContainerContentsChanged( 142 Transaction& transaction); 143 144 // manipulating the data stream 145 status_t FindBlockRun(off_t pos, block_run& run, 146 off_t& offset); 147 148 status_t ReadAt(off_t pos, uint8* buffer, size_t* length); 149 status_t WriteAt(Transaction& transaction, off_t pos, 150 const uint8* buffer, size_t* length); 151 status_t FillGapWithZeros(off_t oldSize, off_t newSize); 152 153 status_t SetFileSize(Transaction& transaction, 154 off_t size); 155 status_t Append(Transaction& transaction, off_t bytes); 156 status_t TrimPreallocation(Transaction& transaction); 157 bool NeedsTrimming() const; 158 159 status_t Free(Transaction& transaction); 160 status_t Sync(); 161 162 bfs_inode& Node() { return fNode; } 163 const bfs_inode& Node() const { return fNode; } 164 165 // create/remove inodes 166 status_t Remove(Transaction& transaction, 167 const char* name, ino_t* _id = NULL, 168 bool isDirectory = false, 169 bool force = false); 170 static status_t Create(Transaction& transaction, Inode* parent, 171 const char* name, int32 mode, int openMode, 172 uint32 type, bool* _created = NULL, 173 ino_t* _id = NULL, Inode** _inode = NULL, 174 fs_vnode_ops* vnodeOps = NULL, 175 uint32 publishFlags = 0); 176 177 // index maintaining helper 178 void UpdateOldSize() { fOldSize = Size(); } 179 void UpdateOldLastModified() 180 { fOldLastModified 181 = Node().LastModifiedTime(); } 182 off_t OldSize() { return fOldSize; } 183 off_t OldLastModified() { return fOldLastModified; } 184 185 bool InNameIndex() const; 186 bool InSizeIndex() const; 187 bool InLastModifiedIndex() const; 188 189 // file cache 190 void* FileCache() const { return fCache; } 191 void SetFileCache(void* cache) { fCache = cache; } 192 void* Map() const { return fMap; } 193 void SetMap(void* map) { fMap = map; } 194 195 #if _KERNEL_MODE && KDEBUG 196 void AssertReadLocked() 197 { ASSERT_READ_LOCKED_RW_LOCK(&fLock); } 198 void AssertWriteLocked() 199 { ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); } 200 #endif 201 202 Link* GetDoublyLinkedListLink() 203 { return (Link*)TransactionListener 204 ::GetDoublyLinkedListLink(); } 205 const Link* GetDoublyLinkedListLink() const 206 { return (Link*)TransactionListener 207 ::GetDoublyLinkedListLink(); } 208 209 protected: 210 virtual void TransactionDone(bool success); 211 virtual void RemovedFromTransaction(); 212 213 private: 214 Inode(const Inode& other); 215 Inode& operator=(const Inode& other); 216 // no implementation 217 218 friend class AttributeIterator; 219 friend class InodeAllocator; 220 221 // small_data access methods 222 status_t _MakeSpaceForSmallData(Transaction& transaction, 223 bfs_inode* node, const char* name, 224 int32 length); 225 status_t _RemoveSmallData(Transaction& transaction, 226 NodeGetter& node, const char* name); 227 status_t _AddSmallData(Transaction& transaction, 228 NodeGetter& node, const char* name, 229 uint32 type, off_t pos, const uint8* data, 230 size_t length, bool force = false); 231 status_t _GetNextSmallData(bfs_inode* node, 232 small_data** _smallData) const; 233 status_t _RemoveSmallData(bfs_inode* node, 234 small_data* item, int32 index); 235 status_t _RemoveAttribute(Transaction& transaction, 236 const char* name, bool hasIndex, 237 Index* index); 238 239 void _AddIterator(AttributeIterator* iterator); 240 void _RemoveIterator(AttributeIterator* iterator); 241 242 size_t _DoubleIndirectBlockLength() const; 243 status_t _FreeStaticStreamArray(Transaction& transaction, 244 int32 level, block_run run, off_t size, 245 off_t offset, off_t& max); 246 status_t _FreeStreamArray(Transaction& transaction, 247 block_run* array, uint32 arrayLength, 248 off_t size, off_t& offset, off_t& max); 249 status_t _AllocateBlockArray(Transaction& transaction, 250 block_run& run, size_t length, 251 bool variableSize = false); 252 status_t _GrowStream(Transaction& transaction, 253 off_t size); 254 status_t _ShrinkStream(Transaction& transaction, 255 off_t size); 256 257 private: 258 rw_lock fLock; 259 Volume* fVolume; 260 ino_t fID; 261 BPlusTree* fTree; 262 Inode* fAttributes; 263 void* fCache; 264 void* fMap; 265 bfs_inode fNode; 266 267 off_t fOldSize; 268 off_t fOldLastModified; 269 // we need those values to ensure we will remove 270 // the correct keys from the indices 271 272 mutable recursive_lock fSmallDataLock; 273 SinglyLinkedList<AttributeIterator> fIterators; 274 }; 275 276 277 /*! Checks whether or not this node should be part of the name index */ 278 inline bool 279 Inode::InNameIndex() const 280 { 281 return IsRegularNode(); 282 } 283 284 285 /*! Checks whether or not this node should be part of the size index */ 286 inline bool 287 Inode::InSizeIndex() const 288 { 289 return IsFile(); 290 } 291 292 293 /*! Checks whether or not this node should be part of the last modified index */ 294 inline bool 295 Inode::InLastModifiedIndex() const 296 { 297 return IsFile() || IsSymLink(); 298 } 299 300 301 #if _KERNEL_MODE && KDEBUG 302 # define ASSERT_READ_LOCKED_INODE(inode) inode->AssertReadLocked() 303 # define ASSERT_WRITE_LOCKED_INODE(inode) inode->AssertWriteLocked() 304 #else 305 # define ASSERT_READ_LOCKED_INODE(inode) 306 # define ASSERT_WRITE_LOCKED_INODE(inode) 307 #endif 308 309 310 class InodeReadLocker { 311 public: 312 InodeReadLocker(Inode* inode) 313 : 314 fLock(&inode->Lock()) 315 { 316 rw_lock_read_lock(fLock); 317 } 318 319 ~InodeReadLocker() 320 { 321 if (fLock != NULL) 322 rw_lock_read_unlock(fLock); 323 } 324 325 void Unlock() 326 { 327 if (fLock != NULL) { 328 rw_lock_read_unlock(fLock); 329 fLock = NULL; 330 } 331 } 332 333 private: 334 rw_lock* fLock; 335 }; 336 337 338 class NodeGetter : public CachedBlock { 339 public: 340 NodeGetter(Volume* volume = NULL) 341 : 342 CachedBlock(volume) 343 { 344 } 345 346 ~NodeGetter() 347 { 348 } 349 350 status_t SetTo(const Inode* inode) 351 { 352 Unset(); 353 fVolume = inode->GetVolume(); 354 return CachedBlock::SetTo(fVolume->VnodeToBlock(inode->ID())); 355 } 356 357 status_t SetToWritable(Transaction& transaction, const Inode* inode, 358 bool empty = false) 359 { 360 return CachedBlock::SetToWritable(transaction, 361 fVolume->VnodeToBlock(inode->ID()), empty); 362 } 363 364 const bfs_inode* Node() const { return (const bfs_inode*)Block(); } 365 bfs_inode* WritableNode() const { return (bfs_inode*)Block(); } 366 }; 367 368 369 // The Vnode class provides a convenience layer upon get_vnode(), so that 370 // you don't have to call put_vnode() anymore, which may make code more 371 // readable in some cases 372 373 class Vnode { 374 public: 375 Vnode(Volume* volume, ino_t id) 376 : 377 fInode(NULL) 378 { 379 SetTo(volume, id); 380 } 381 382 Vnode(Volume* volume, block_run run) 383 : 384 fInode(NULL) 385 { 386 SetTo(volume, run); 387 } 388 389 Vnode() 390 : 391 fStatus(B_NO_INIT), 392 fInode(NULL) 393 { 394 } 395 396 ~Vnode() 397 { 398 Unset(); 399 } 400 401 status_t InitCheck() 402 { 403 return fStatus; 404 } 405 406 void Unset() 407 { 408 if (fInode != NULL) { 409 put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID()); 410 fInode = NULL; 411 fStatus = B_NO_INIT; 412 } 413 } 414 415 status_t SetTo(Volume* volume, ino_t id) 416 { 417 Unset(); 418 419 return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode); 420 } 421 422 status_t SetTo(Volume* volume, block_run run) 423 { 424 return SetTo(volume, volume->ToVnode(run)); 425 } 426 427 status_t Get(Inode** _inode) 428 { 429 *_inode = fInode; 430 return fStatus; 431 } 432 433 void Keep() 434 { 435 fInode = NULL; 436 } 437 438 private: 439 status_t fStatus; 440 Inode* fInode; 441 }; 442 443 444 class AttributeIterator : public SinglyLinkedListLinkImpl<AttributeIterator> { 445 public: 446 AttributeIterator(Inode* inode); 447 ~AttributeIterator(); 448 449 status_t Rewind(); 450 status_t GetNext(char* name, size_t* length, uint32* type, 451 ino_t* id); 452 453 private: 454 friend class Inode; 455 456 void Update(uint16 index, int8 change); 457 458 private: 459 int32 fCurrentSmallData; 460 Inode* fInode; 461 Inode* fAttributes; 462 TreeIterator* fIterator; 463 void* fBuffer; 464 }; 465 466 #endif // INODE_H 467