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