1 /* 2 * Copyright 2001-2007, 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 "Volume.h" 12 #include "Journal.h" 13 #include "Lock.h" 14 #include "Chain.h" 15 #include "Debug.h" 16 #include "CachedBlock.h" 17 18 19 class BPlusTree; 20 class TreeIterator; 21 class AttributeIterator; 22 class Index; 23 class InodeAllocator; 24 class NodeGetter; 25 26 27 enum inode_type { 28 S_DIRECTORY = S_IFDIR, 29 S_FILE = S_IFREG, 30 S_SYMLINK = S_IFLNK, 31 32 S_INDEX_TYPES = (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX 33 | S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX) 34 }; 35 36 class Inode { 37 public: 38 Inode(Volume *volume, ino_t id); 39 Inode(Volume *volume, Transaction &transaction, ino_t id, 40 mode_t mode, block_run &run); 41 //Inode(CachedBlock *cached); 42 ~Inode(); 43 44 //bfs_inode *Node() const { return (bfs_inode *)fBlock; } 45 ino_t ID() const { return fID; } 46 off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); } 47 48 ReadWriteLock &Lock() { return fLock; } 49 SimpleLock &SmallDataLock() { return fSmallDataLock; } 50 status_t WriteBack(Transaction &transaction); 51 52 bool IsContainer() const 53 { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); } 54 // note, that this test will also be true for S_IFBLK 55 // (not that it's used in the fs :) 56 bool IsDirectory() const 57 { return (Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) 58 == S_DIRECTORY; } 59 bool IsIndex() const 60 { return (Mode() & (S_INDEX_DIR | 0777)) == S_INDEX_DIR; } 61 // that's a stupid check, but AFAIK the only possible method... 62 63 bool IsAttributeDirectory() const 64 { return (Mode() & S_ATTR_DIR) != 0; } 65 bool IsAttribute() const 66 { return (Mode() & S_ATTR) != 0; } 67 bool IsFile() const 68 { return (Mode() & (S_IFMT | S_ATTR)) == S_FILE; } 69 bool IsRegularNode() const 70 { return (Mode() & (S_ATTR_DIR | S_INDEX_DIR | S_ATTR)) == 0; } 71 // a regular node in the standard namespace 72 // (i.e. not an index or attribute) 73 bool IsSymLink() const { return S_ISLNK(Mode()); } 74 bool HasUserAccessableStream() const { return IsFile(); } 75 // currently only files can be accessed with bfs_read()/bfs_write() 76 77 bool IsDeleted() const { return (Flags() & INODE_DELETED) != 0; } 78 79 mode_t Mode() const { return fNode.Mode(); } 80 uint32 Type() const { return fNode.Type(); } 81 int32 Flags() const { return fNode.Flags(); } 82 83 off_t Size() const { return fNode.data.Size(); } 84 off_t LastModified() const { return fNode.last_modified_time; } 85 86 const block_run &BlockRun() const { return fNode.inode_num; } 87 block_run &Parent() { return fNode.parent; } 88 block_run &Attributes() { return fNode.attributes; } 89 90 Volume *GetVolume() const { return fVolume; } 91 92 status_t InitCheck(bool checkNode = true); 93 94 status_t CheckPermissions(int accessMode) const; 95 96 // small_data access methods 97 small_data *FindSmallData(const bfs_inode *node, 98 const char *name) const; 99 const char *Name(const bfs_inode *node) const; 100 status_t GetName(char *buffer, 101 size_t bufferSize = B_FILE_NAME_LENGTH) const; 102 status_t SetName(Transaction &transaction, const char *name); 103 104 // high-level attribute methods 105 status_t ReadAttribute(const char *name, int32 type, off_t pos, 106 uint8 *buffer, size_t *_length); 107 status_t WriteAttribute(Transaction &transaction, const char *name, 108 int32 type, off_t pos, const uint8 *buffer, size_t *_length); 109 status_t RemoveAttribute(Transaction &transaction, const char *name); 110 111 // attribute methods 112 status_t GetAttribute(const char *name, Inode **attribute); 113 void ReleaseAttribute(Inode *attribute); 114 status_t CreateAttribute(Transaction &transaction, const char *name, 115 uint32 type, Inode **attribute); 116 117 // for directories only: 118 status_t GetTree(BPlusTree **_tree); 119 bool IsEmpty(); 120 121 // manipulating the data stream 122 status_t FindBlockRun(off_t pos, block_run &run, off_t &offset); 123 124 status_t ReadAt(off_t pos, uint8 *buffer, size_t *length); 125 status_t WriteAt(Transaction &transaction, off_t pos, 126 const uint8 *buffer, size_t *length); 127 status_t FillGapWithZeros(off_t oldSize, off_t newSize); 128 129 status_t SetFileSize(Transaction &transaction, off_t size); 130 status_t Append(Transaction &transaction, off_t bytes); 131 status_t TrimPreallocation(Transaction &transaction); 132 bool NeedsTrimming(); 133 134 status_t Free(Transaction &transaction); 135 status_t Sync(); 136 137 bfs_inode &Node() { return fNode; } 138 139 // create/remove inodes 140 status_t Remove(Transaction &transaction, const char *name, 141 ino_t *_id = NULL, bool isDirectory = false); 142 static status_t Create(Transaction &transaction, Inode *parent, 143 const char *name, int32 mode, int openMode, uint32 type, 144 bool *_created = NULL, ino_t *_id = NULL, Inode **_inode = NULL); 145 146 // index maintaining helper 147 void UpdateOldSize() 148 { fOldSize = Size(); } 149 void UpdateOldLastModified() 150 { fOldLastModified = Node().LastModifiedTime(); } 151 off_t OldSize() 152 { return fOldSize; } 153 off_t OldLastModified() 154 { return fOldLastModified; } 155 156 // file cache 157 void *FileCache() const { return fCache; } 158 void SetFileCache(void *cache) { fCache = cache; } 159 160 private: 161 Inode(const Inode &); 162 Inode &operator=(const Inode &); 163 // no implementation 164 165 friend class AttributeIterator; 166 friend class InodeAllocator; 167 168 // small_data access methods 169 status_t _MakeSpaceForSmallData(Transaction &transaction, 170 bfs_inode *node, const char *name, int32 length); 171 status_t _RemoveSmallData(Transaction &transaction, NodeGetter &node, 172 const char *name); 173 status_t _AddSmallData(Transaction &transaction, NodeGetter &node, 174 const char *name, uint32 type, const uint8 *data, size_t length, 175 bool force = false); 176 status_t _GetNextSmallData(bfs_inode *node, 177 small_data **_smallData) const; 178 status_t _RemoveSmallData(bfs_inode *node, small_data *item, 179 int32 index); 180 status_t _RemoveAttribute(Transaction &transaction, const char *name, 181 bool hasIndex, Index *index); 182 183 void _AddIterator(AttributeIterator *iterator); 184 void _RemoveIterator(AttributeIterator *iterator); 185 186 status_t _FreeStaticStreamArray(Transaction &transaction, int32 level, 187 block_run run, off_t size, off_t offset, off_t &max); 188 status_t _FreeStreamArray(Transaction &transaction, block_run *array, 189 uint32 arrayLength, off_t size, off_t &offset, off_t &max); 190 status_t _AllocateBlockArray(Transaction &transaction, block_run &run); 191 status_t _GrowStream(Transaction &transaction, off_t size); 192 status_t _ShrinkStream(Transaction &transaction, off_t size); 193 194 private: 195 ReadWriteLock fLock; 196 Volume *fVolume; 197 ino_t fID; 198 BPlusTree *fTree; 199 Inode *fAttributes; 200 void *fCache; 201 bfs_inode fNode; 202 203 off_t fOldSize; 204 off_t fOldLastModified; 205 // we need those values to ensure we will remove 206 // the correct keys from the indices 207 208 mutable SimpleLock fSmallDataLock; 209 Chain<AttributeIterator> fIterators; 210 }; 211 212 213 class NodeGetter : public CachedBlock { 214 public: 215 NodeGetter(Volume *volume) 216 : CachedBlock(volume) 217 { 218 } 219 220 NodeGetter(Volume *volume, const Inode *inode) 221 : CachedBlock(volume) 222 { 223 SetTo(volume->VnodeToBlock(inode->ID())); 224 } 225 226 NodeGetter(Volume *volume, Transaction &transaction, 227 const Inode *inode, bool empty = false) 228 : CachedBlock(volume) 229 { 230 SetToWritable(transaction, volume->VnodeToBlock(inode->ID()), empty); 231 } 232 233 ~NodeGetter() 234 { 235 } 236 237 const bfs_inode * 238 SetToNode(const Inode *inode) 239 { 240 return (const bfs_inode *)SetTo(fVolume->VnodeToBlock(inode->ID())); 241 } 242 243 const bfs_inode *Node() const { return (const bfs_inode *)Block(); } 244 bfs_inode *WritableNode() const { return (bfs_inode *)Block(); } 245 }; 246 247 248 // The Vnode class provides a convenience layer upon get_vnode(), so that 249 // you don't have to call put_vnode() anymore, which may make code more 250 // readable in some cases 251 252 class Vnode { 253 public: 254 Vnode(Volume *volume, ino_t id) 255 : 256 fVolume(volume), 257 fID(id) 258 { 259 } 260 261 Vnode(Volume *volume, block_run run) 262 : 263 fVolume(volume), 264 fID(volume->ToVnode(run)) 265 { 266 } 267 268 ~Vnode() 269 { 270 Put(); 271 } 272 273 status_t Get(Inode **_inode) 274 { 275 // should we check inode against NULL here? it should not be necessary 276 return get_vnode(fVolume->ID(), fID, (void **)_inode); 277 } 278 279 void Put() 280 { 281 if (fVolume) 282 put_vnode(fVolume->ID(), fID); 283 fVolume = NULL; 284 } 285 286 void Keep() 287 { 288 fVolume = NULL; 289 } 290 291 private: 292 Volume *fVolume; 293 ino_t fID; 294 }; 295 296 297 class AttributeIterator { 298 public: 299 AttributeIterator(Inode *inode); 300 ~AttributeIterator(); 301 302 status_t Rewind(); 303 status_t GetNext(char *name, size_t *length, uint32 *type, ino_t *id); 304 305 private: 306 friend class Chain<AttributeIterator>; 307 friend class Inode; 308 309 void Update(uint16 index, int8 change); 310 AttributeIterator *fNext; 311 312 private: 313 int32 fCurrentSmallData; 314 Inode *fInode, *fAttributes; 315 TreeIterator *fIterator; 316 void *fBuffer; 317 }; 318 319 320 /*! 321 Converts the open mode, the open flags given to bfs_open(), into 322 access modes, e.g. since O_RDONLY requires read access to the 323 file, it will be converted to R_OK. 324 */ 325 inline int 326 openModeToAccess(int openMode) 327 { 328 openMode &= O_RWMASK; 329 if (openMode == O_RDONLY) 330 return R_OK; 331 else if (openMode == O_WRONLY) 332 return W_OK; 333 334 return R_OK | W_OK; 335 } 336 337 #endif /* INODE_H */ 338