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 AttributeIterator; 186 friend InodeAllocator; 187 188 void Initialize(); 189 190 status_t RemoveSmallData(small_data *item, int32 index); 191 192 void AddIterator(AttributeIterator *iterator); 193 void RemoveIterator(AttributeIterator *iterator); 194 195 status_t FreeStaticStreamArray(Transaction *transaction, int32 level, block_run run, 196 off_t size, off_t offset, off_t &max); 197 status_t FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayLength, 198 off_t size, off_t &offset, off_t &max); 199 status_t AllocateBlockArray(Transaction *transaction, block_run &run); 200 status_t GrowStream(Transaction *transaction, off_t size); 201 status_t ShrinkStream(Transaction *transaction, off_t size); 202 203 BPlusTree *fTree; 204 Inode *fAttributes; 205 ReadWriteLock fLock; 206 off_t fOldSize; // we need those values to ensure we will remove 207 off_t fOldLastModified; // the correct keys from the indices 208 209 mutable SimpleLock fSmallDataLock; 210 Chain<AttributeIterator> fIterators; 211 }; 212 213 214 // The Vnode class provides a convenience layer upon get_vnode(), so that 215 // you don't have to call put_vnode() anymore, which may make code more 216 // readable in some cases 217 218 class Vnode { 219 public: 220 Vnode(Volume *volume, vnode_id id) 221 : 222 fVolume(volume), 223 fID(id) 224 { 225 } 226 227 Vnode(Volume *volume, block_run run) 228 : 229 fVolume(volume), 230 fID(volume->ToVnode(run)) 231 { 232 } 233 234 ~Vnode() 235 { 236 Put(); 237 } 238 239 status_t Get(Inode **inode) 240 { 241 // should we check inode against NULL here? it should not be necessary 242 return get_vnode(fVolume->ID(), fID, (void **)inode); 243 } 244 245 void Put() 246 { 247 if (fVolume) 248 put_vnode(fVolume->ID(), fID); 249 fVolume = NULL; 250 } 251 252 void Keep() 253 { 254 fVolume = NULL; 255 } 256 257 private: 258 Volume *fVolume; 259 vnode_id fID; 260 }; 261 262 263 class AttributeIterator { 264 public: 265 AttributeIterator(Inode *inode); 266 ~AttributeIterator(); 267 268 status_t Rewind(); 269 status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id); 270 271 private: 272 int32 fCurrentSmallData; 273 Inode *fInode, *fAttributes; 274 TreeIterator *fIterator; 275 void *fBuffer; 276 277 private: 278 friend Chain<AttributeIterator>; 279 friend Inode; 280 281 void Update(uint16 index, int8 change); 282 AttributeIterator *fNext; 283 }; 284 285 286 //-------------------------------------- 287 // inlines 288 289 290 inline 291 CachedBlock::CachedBlock(Volume *volume) 292 : 293 fVolume(volume), 294 fBlock(NULL) 295 { 296 } 297 298 299 inline 300 CachedBlock::CachedBlock(Volume *volume, off_t block, bool empty = false) 301 : 302 fVolume(volume), 303 fBlock(NULL) 304 { 305 SetTo(block, empty); 306 } 307 308 309 inline 310 CachedBlock::CachedBlock(Volume *volume, block_run run, bool empty = false) 311 : 312 fVolume(volume), 313 fBlock(NULL) 314 { 315 SetTo(volume->ToBlock(run), empty); 316 } 317 318 319 inline 320 CachedBlock::CachedBlock(CachedBlock *cached) 321 : 322 fVolume(cached->fVolume), 323 fBlockNumber(cached->BlockNumber()), 324 fBlock(cached->fBlock) 325 { 326 cached->Keep(); 327 } 328 329 330 inline 331 CachedBlock::~CachedBlock() 332 { 333 Unset(); 334 } 335 336 337 inline void 338 CachedBlock::Keep() 339 { 340 fBlock = NULL; 341 } 342 343 344 inline void 345 CachedBlock::Unset() 346 { 347 if (fBlock != NULL) 348 release_block(fVolume->Device(), fBlockNumber); 349 } 350 351 352 inline uint8 * 353 CachedBlock::SetTo(off_t block, bool empty = false) 354 { 355 Unset(); 356 fBlockNumber = block; 357 return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(), block, BlockSize()) 358 : (uint8 *)get_block(fVolume->Device(), block, BlockSize()); 359 } 360 361 362 inline uint8 * 363 CachedBlock::SetTo(block_run run, bool empty = false) 364 { 365 return SetTo(fVolume->ToBlock(run), empty); 366 } 367 368 369 inline status_t 370 CachedBlock::WriteBack(Transaction *transaction) 371 { 372 if (transaction == NULL || fBlock == NULL) 373 RETURN_ERROR(B_BAD_VALUE); 374 375 return transaction->WriteBlocks(fBlockNumber, fBlock); 376 } 377 378 379 /** Converts the "omode", the open flags given to bfs_open(), into 380 * access modes, e.g. since O_RDONLY requires read access to the 381 * file, it will be converted to R_OK. 382 */ 383 384 inline int 385 oModeToAccess(int omode) 386 { 387 omode &= O_RWMASK; 388 if (omode == O_RDONLY) 389 return R_OK; 390 else if (omode == O_WRONLY) 391 return W_OK; 392 393 return R_OK | W_OK; 394 } 395 396 #endif /* INODE_H */ 397