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