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