1 /* 2 * Copyright 2001-2017, 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) 341 : CachedBlock(volume) 342 { 343 } 344 345 NodeGetter(Volume* volume, const Inode* inode) 346 : CachedBlock(volume) 347 { 348 SetTo(volume->VnodeToBlock(inode->ID())); 349 } 350 351 NodeGetter(Volume* volume, Transaction& transaction, 352 const Inode* inode, bool empty = false) 353 : CachedBlock(volume) 354 { 355 SetToWritable(transaction, volume->VnodeToBlock(inode->ID()), empty); 356 } 357 358 ~NodeGetter() 359 { 360 } 361 362 const bfs_inode* SetToNode(const Inode* inode) 363 { 364 return (const bfs_inode*)SetTo(fVolume->VnodeToBlock(inode->ID())); 365 } 366 367 const bfs_inode* Node() const { return (const bfs_inode*)Block(); } 368 bfs_inode* WritableNode() const { return (bfs_inode*)Block(); } 369 }; 370 371 372 // The Vnode class provides a convenience layer upon get_vnode(), so that 373 // you don't have to call put_vnode() anymore, which may make code more 374 // readable in some cases 375 376 class Vnode { 377 public: 378 Vnode(Volume* volume, ino_t id) 379 : 380 fInode(NULL) 381 { 382 SetTo(volume, id); 383 } 384 385 Vnode(Volume* volume, block_run run) 386 : 387 fInode(NULL) 388 { 389 SetTo(volume, run); 390 } 391 392 Vnode() 393 : 394 fStatus(B_NO_INIT), 395 fInode(NULL) 396 { 397 } 398 399 ~Vnode() 400 { 401 Unset(); 402 } 403 404 status_t InitCheck() 405 { 406 return fStatus; 407 } 408 409 void Unset() 410 { 411 if (fInode != NULL) { 412 put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID()); 413 fInode = NULL; 414 fStatus = B_NO_INIT; 415 } 416 } 417 418 status_t SetTo(Volume* volume, ino_t id) 419 { 420 Unset(); 421 422 return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode); 423 } 424 425 status_t SetTo(Volume* volume, block_run run) 426 { 427 return SetTo(volume, volume->ToVnode(run)); 428 } 429 430 status_t Get(Inode** _inode) 431 { 432 *_inode = fInode; 433 return fStatus; 434 } 435 436 void Keep() 437 { 438 fInode = NULL; 439 } 440 441 private: 442 status_t fStatus; 443 Inode* fInode; 444 }; 445 446 447 class AttributeIterator : public SinglyLinkedListLinkImpl<AttributeIterator> { 448 public: 449 AttributeIterator(Inode* inode); 450 ~AttributeIterator(); 451 452 status_t Rewind(); 453 status_t GetNext(char* name, size_t* length, uint32* type, 454 ino_t* id); 455 456 private: 457 friend class Inode; 458 459 void Update(uint16 index, int8 change); 460 461 private: 462 int32 fCurrentSmallData; 463 Inode* fInode; 464 Inode* fAttributes; 465 TreeIterator* fIterator; 466 void* fBuffer; 467 }; 468 469 #endif // INODE_H 470