1 #ifndef INODE_H 2 #define INODE_H 3 /* Inode - inode access functions 4 ** 5 ** Initial version by Axel Dörfler, axeld@pinc-software.de 6 ** This file may be used under the terms of the OpenBeOS License. 7 */ 8 9 10 #include <KernelExport.h> 11 #ifdef USER 12 # include "myfs.h" 13 # include <stdio.h> 14 #endif 15 16 #ifndef _IMPEXP_KERNEL 17 # define _IMPEXP_KERNEL 18 #endif 19 20 extern "C" { 21 #include <lock.h> 22 #include <cache.h> 23 } 24 25 #include <string.h> 26 27 #include "Volume.h" 28 #include "Journal.h" 29 #include "Lock.h" 30 #include "Chain.h" 31 #include "Debug.h" 32 33 34 class BPlusTree; 35 class TreeIterator; 36 class AttributeIterator; 37 class InodeAllocator; 38 39 40 enum inode_type { 41 S_DIRECTORY = S_IFDIR, 42 S_FILE = S_IFREG, 43 S_SYMLINK = S_IFLNK, 44 45 S_REGULAR = (S_DIRECTORY | S_FILE | S_SYMLINK), 46 S_INDEX_TYPES = (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX 47 | S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX) 48 }; 49 50 51 // The CachedBlock class is completely implemented as inlines. 52 // It should be used when cache single blocks to make sure they 53 // will be properly released after use (and it's also very 54 // convenient to use them). 55 56 class CachedBlock { 57 public: 58 CachedBlock(Volume *volume); 59 CachedBlock(Volume *volume, off_t block, bool empty = false); 60 CachedBlock(Volume *volume, block_run run, bool empty = false); 61 CachedBlock(CachedBlock *cached); 62 ~CachedBlock(); 63 64 inline void Keep(); 65 inline void Unset(); 66 inline uint8 *SetTo(off_t block, bool empty = false); 67 inline uint8 *SetTo(block_run run, bool empty = false); 68 inline status_t WriteBack(Transaction *transaction); 69 70 uint8 *Block() const { return fBlock; } 71 off_t BlockNumber() const { return fBlockNumber; } 72 uint32 BlockSize() const { return fVolume->BlockSize(); } 73 uint32 BlockShift() const { return fVolume->BlockShift(); } 74 75 private: 76 CachedBlock(const CachedBlock &); 77 CachedBlock &operator=(const CachedBlock &); 78 // no implementation 79 80 protected: 81 Volume *fVolume; 82 off_t fBlockNumber; 83 uint8 *fBlock; 84 }; 85 86 //-------------------------------------- 87 88 class Inode : public CachedBlock { 89 public: 90 Inode(Volume *volume, vnode_id id, bool empty = false, uint8 reenter = 0); 91 Inode(CachedBlock *cached); 92 ~Inode(); 93 94 bfs_inode *Node() const { return (bfs_inode *)fBlock; } 95 vnode_id ID() const { return fVolume->ToVnode(fBlockNumber); } 96 97 ReadWriteLock &Lock() { return fLock; } 98 SimpleLock &SmallDataLock() { return fSmallDataLock; } 99 100 mode_t Mode() const { return Node()->Mode(); } 101 uint32 Type() const { return Node()->Type(); } 102 int32 Flags() const { return Node()->Flags(); } 103 bool IsContainer() const { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); } 104 // note, that this test will also be true for S_IFBLK (not that it's used in the fs :) 105 bool IsDirectory() const { return (Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY; } 106 bool IsIndex() const { return (Mode() & (S_INDEX_DIR | 0777)) == S_INDEX_DIR; } 107 // that's a stupid check, but AFAIK the only possible method... 108 109 bool IsAttribute() const { return Mode() & S_ATTR; } 110 bool IsFile() const { return Mode() & S_IFREG; } 111 bool IsRegularNode() const { return (Mode() & (S_ATTR_DIR | S_INDEX_DIR | S_ATTR)) == 0; } 112 // a regular node in the standard namespace (i.e. not an index or attribute) 113 bool IsSymLink() const { return S_ISLNK(Mode()); } 114 bool HasUserAccessableStream() const { return S_ISREG(Mode()); } 115 // currently only files can be accessed with bfs_read()/bfs_write() 116 117 off_t Size() const { return Node()->data.Size(); } 118 off_t LastModified() const { return Node()->last_modified_time; } 119 120 block_run &BlockRun() const { return Node()->inode_num; } 121 block_run &Parent() const { return Node()->parent; } 122 block_run &Attributes() const { return Node()->attributes; } 123 Volume *GetVolume() const { return fVolume; } 124 125 status_t InitCheck(bool checkNode = true); 126 127 status_t CheckPermissions(int accessMode) const; 128 129 // small_data access methods 130 status_t MakeSpaceForSmallData(Transaction *transaction, const char *name, int32 length); 131 status_t RemoveSmallData(Transaction *transaction, const char *name); 132 status_t AddSmallData(Transaction *transaction, const char *name, uint32 type, 133 const uint8 *data, size_t length, bool force = false); 134 status_t GetNextSmallData(small_data **_smallData) const; 135 small_data *FindSmallData(const char *name) const; 136 const char *Name() const; 137 status_t GetName(char *buffer) const; 138 status_t SetName(Transaction *transaction, const char *name); 139 140 // high-level attribute methods 141 status_t ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer, size_t *_length); 142 status_t WriteAttribute(Transaction *transaction, const char *name, int32 type, off_t pos, const uint8 *buffer, size_t *_length); 143 status_t RemoveAttribute(Transaction *transaction, const char *name); 144 145 // attribute methods 146 status_t GetAttribute(const char *name, Inode **attribute); 147 void ReleaseAttribute(Inode *attribute); 148 status_t CreateAttribute(Transaction *transaction, const char *name, uint32 type, Inode **attribute); 149 150 // for directories only: 151 status_t GetTree(BPlusTree **); 152 bool IsEmpty(); 153 154 // manipulating the data stream 155 status_t FindBlockRun(off_t pos, block_run &run, off_t &offset); 156 157 status_t ReadAt(off_t pos, uint8 *buffer, size_t *length); 158 status_t WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer, size_t *length); 159 status_t FillGapWithZeros(off_t oldSize, off_t newSize); 160 161 status_t SetFileSize(Transaction *transaction, off_t size); 162 status_t Append(Transaction *transaction, off_t bytes); 163 status_t Trim(Transaction *transaction); 164 165 status_t Free(Transaction *transaction); 166 status_t Sync(); 167 168 // create/remove inodes 169 status_t Remove(Transaction *transaction, const char *name, off_t *_id = NULL, 170 bool isDirectory = false); 171 static status_t Create(Transaction *transaction, Inode *parent, const char *name, 172 int32 mode, int omode, uint32 type, off_t *_id = NULL, Inode **_inode = NULL); 173 174 // index maintaining helper 175 void UpdateOldSize() { fOldSize = Size(); } 176 void UpdateOldLastModified() { fOldLastModified = Node()->LastModifiedTime(); } 177 off_t OldSize() { return fOldSize; } 178 off_t OldLastModified() { return fOldLastModified; } 179 180 private: 181 Inode(const Inode &); 182 Inode &operator=(const Inode &); 183 // no implementation 184 185 friend void dump_inode(Inode &inode); 186 friend AttributeIterator; 187 friend InodeAllocator; 188 189 void Initialize(); 190 191 status_t RemoveSmallData(small_data *item, int32 index); 192 193 void AddIterator(AttributeIterator *iterator); 194 void RemoveIterator(AttributeIterator *iterator); 195 196 status_t FreeStaticStreamArray(Transaction *transaction, int32 level, block_run run, 197 off_t size, off_t offset, off_t &max); 198 status_t FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayLength, 199 off_t size, off_t &offset, off_t &max); 200 status_t AllocateBlockArray(Transaction *transaction, block_run &run); 201 status_t GrowStream(Transaction *transaction, off_t size); 202 status_t ShrinkStream(Transaction *transaction, off_t size); 203 204 BPlusTree *fTree; 205 Inode *fAttributes; 206 ReadWriteLock fLock; 207 off_t fOldSize; // we need those values to ensure we will remove 208 off_t fOldLastModified; // the correct keys from the indices 209 210 mutable SimpleLock fSmallDataLock; 211 Chain<AttributeIterator> fIterators; 212 }; 213 214 215 // The Vnode class provides a convenience layer upon get_vnode(), so that 216 // you don't have to call put_vnode() anymore, which may make code more 217 // readable in some cases 218 219 class Vnode { 220 public: 221 Vnode(Volume *volume, vnode_id id) 222 : 223 fVolume(volume), 224 fID(id) 225 { 226 } 227 228 Vnode(Volume *volume, block_run run) 229 : 230 fVolume(volume), 231 fID(volume->ToVnode(run)) 232 { 233 } 234 235 ~Vnode() 236 { 237 Put(); 238 } 239 240 status_t Get(Inode **inode) 241 { 242 // should we check inode against NULL here? it should not be necessary 243 #ifdef UNSAFE_GET_VNODE 244 RecursiveLocker locker(fVolume->Lock()); 245 #endif 246 return get_vnode(fVolume->ID(), fID, (void **)inode); 247 } 248 249 void Put() 250 { 251 if (fVolume) 252 put_vnode(fVolume->ID(), fID); 253 fVolume = NULL; 254 } 255 256 void Keep() 257 { 258 fVolume = NULL; 259 } 260 261 private: 262 Volume *fVolume; 263 vnode_id fID; 264 }; 265 266 267 class AttributeIterator { 268 public: 269 AttributeIterator(Inode *inode); 270 ~AttributeIterator(); 271 272 status_t Rewind(); 273 status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id); 274 275 private: 276 int32 fCurrentSmallData; 277 Inode *fInode, *fAttributes; 278 TreeIterator *fIterator; 279 void *fBuffer; 280 281 private: 282 friend Chain<AttributeIterator>; 283 friend Inode; 284 285 void Update(uint16 index, int8 change); 286 AttributeIterator *fNext; 287 }; 288 289 290 //-------------------------------------- 291 // inlines 292 293 294 inline 295 CachedBlock::CachedBlock(Volume *volume) 296 : 297 fVolume(volume), 298 fBlock(NULL) 299 { 300 } 301 302 303 inline 304 CachedBlock::CachedBlock(Volume *volume, off_t block, bool empty) 305 : 306 fVolume(volume), 307 fBlock(NULL) 308 { 309 SetTo(block, empty); 310 } 311 312 313 inline 314 CachedBlock::CachedBlock(Volume *volume, block_run run, bool empty) 315 : 316 fVolume(volume), 317 fBlock(NULL) 318 { 319 SetTo(volume->ToBlock(run), empty); 320 } 321 322 323 inline 324 CachedBlock::CachedBlock(CachedBlock *cached) 325 : 326 fVolume(cached->fVolume), 327 fBlockNumber(cached->BlockNumber()), 328 fBlock(cached->fBlock) 329 { 330 cached->Keep(); 331 } 332 333 334 inline 335 CachedBlock::~CachedBlock() 336 { 337 Unset(); 338 } 339 340 341 inline void 342 CachedBlock::Keep() 343 { 344 fBlock = NULL; 345 } 346 347 348 inline void 349 CachedBlock::Unset() 350 { 351 if (fBlock != NULL) 352 release_block(fVolume->Device(), fBlockNumber); 353 } 354 355 356 inline uint8 * 357 CachedBlock::SetTo(off_t block, bool empty) 358 { 359 Unset(); 360 fBlockNumber = block; 361 return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(), block, BlockSize()) 362 : (uint8 *)get_block(fVolume->Device(), block, BlockSize()); 363 } 364 365 366 inline uint8 * 367 CachedBlock::SetTo(block_run run, bool empty) 368 { 369 return SetTo(fVolume->ToBlock(run), empty); 370 } 371 372 373 inline status_t 374 CachedBlock::WriteBack(Transaction *transaction) 375 { 376 if (transaction == NULL || fBlock == NULL) 377 RETURN_ERROR(B_BAD_VALUE); 378 379 return transaction->WriteBlocks(fBlockNumber, fBlock); 380 } 381 382 383 /** Converts the "omode", the open flags given to bfs_open(), into 384 * access modes, e.g. since O_RDONLY requires read access to the 385 * file, it will be converted to R_OK. 386 */ 387 388 inline int 389 oModeToAccess(int omode) 390 { 391 omode &= O_RWMASK; 392 if (omode == O_RDONLY) 393 return R_OK; 394 else if (omode == O_WRONLY) 395 return W_OK; 396 397 return R_OK | W_OK; 398 } 399 400 #endif /* INODE_H */ 401