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