1 /* 2 * Copyright 2008, 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 <fs_cache.h> 10 #include <lock.h> 11 #include <string.h> 12 13 #include "ext2.h" 14 #include "Volume.h" 15 16 17 //#define TRACE_EXT2 18 #ifdef TRACE_EXT2 19 # define TRACEI(x...) dprintf("\33[34mext2:\33[0m " x) 20 #else 21 # define TRACEI(x...) ; 22 #endif 23 24 25 class Inode : public TransactionListener { 26 public: 27 Inode(Volume* volume, ino_t id); 28 ~Inode(); 29 30 status_t InitCheck(); 31 32 ino_t ID() const { return fID; } 33 34 rw_lock* Lock() { return &fLock; } 35 void WriteLockInTransaction(Transaction& transaction); 36 37 status_t UpdateNodeFromDisk(); 38 status_t WriteBack(Transaction& transaction); 39 40 recursive_lock& SmallDataLock() { return fSmallDataLock; } 41 42 bool IsDirectory() const 43 { return S_ISDIR(Mode()); } 44 bool IsFile() const 45 { return S_ISREG(Mode()); } 46 bool IsSymLink() const 47 { return S_ISLNK(Mode()); } 48 status_t CheckPermissions(int accessMode) const; 49 50 bool IsDeleted() const { return fUnlinked; } 51 bool HasExtraAttributes() const 52 { return fHasExtraAttributes; } 53 54 mode_t Mode() const { return fNode.Mode(); } 55 int32 Flags() const { return fNode.Flags(); } 56 57 off_t Size() const { return fNode.Size(); } 58 void GetChangeTime(struct timespec *timespec) const 59 { fNode.GetChangeTime(timespec, fHasExtraAttributes); } 60 void GetModificationTime(struct timespec *timespec) const 61 { fNode.GetModificationTime(timespec, 62 fHasExtraAttributes); } 63 void GetCreationTime(struct timespec *timespec) const 64 { fNode.GetCreationTime(timespec, 65 fHasExtraAttributes); } 66 void GetAccessTime(struct timespec *timespec) const 67 { fNode.GetAccessTime(timespec, fHasExtraAttributes); } 68 void SetChangeTime(const struct timespec *timespec) 69 { fNode.SetChangeTime(timespec, fHasExtraAttributes); } 70 void SetModificationTime(const struct timespec *timespec) 71 { fNode.SetModificationTime(timespec, 72 fHasExtraAttributes); } 73 void SetCreationTime(const struct timespec *timespec) 74 { fNode.SetCreationTime(timespec, 75 fHasExtraAttributes); } 76 void SetAccessTime(const struct timespec *timespec) 77 { fNode.SetAccessTime(timespec, fHasExtraAttributes); } 78 79 //::Volume* _Volume() const { return fVolume; } 80 Volume* GetVolume() const { return fVolume; } 81 82 status_t FindBlock(off_t offset, uint32& block); 83 status_t ReadAt(off_t pos, uint8 *buffer, size_t *length); 84 status_t WriteAt(Transaction& transaction, off_t pos, 85 const uint8* buffer, size_t* length); 86 status_t FillGapWithZeros(off_t start, off_t end); 87 88 status_t Resize(Transaction& transaction, off_t size); 89 90 status_t AttributeBlockReadAt(off_t pos, uint8 *buffer, 91 size_t *length); 92 93 ext2_inode& Node() { return fNode; } 94 95 status_t InitDirectory(Transaction& transaction, Inode* parent); 96 97 status_t Unlink(Transaction& transaction); 98 99 static status_t Create(Transaction& transaction, Inode* parent, 100 const char* name, int32 mode, int openMode, 101 uint8 type, bool* _created = NULL, 102 ino_t* _id = NULL, Inode** _inode = NULL, 103 fs_vnode_ops* vnodeOps = NULL, 104 uint32 publishFlags = 0); 105 static void _BigtimeToTimespec(bigtime_t time, 106 struct timespec *timespec) 107 { timespec->tv_sec = time / 1000000LL; 108 timespec->tv_nsec = (time % 1000000LL) * 1000; } 109 110 void* FileCache() const { return fCache; } 111 void* Map() const { return fMap; } 112 status_t EnableFileCache(); 113 status_t DisableFileCache(); 114 bool IsFileCacheDisabled() const { return !fCached; } 115 116 status_t Sync(); 117 118 119 120 protected: 121 virtual void TransactionDone(bool success); 122 virtual void RemovedFromTransaction(); 123 124 125 private: 126 Inode(Volume* volume); 127 Inode(const Inode&); 128 Inode &operator=(const Inode&); 129 // no implementation 130 131 status_t _EnlargeDataStream(Transaction& transaction, 132 off_t size); 133 status_t _ShrinkDataStream(Transaction& transaction, 134 off_t size); 135 136 uint64 _NumBlocks(); 137 status_t _SetNumBlocks(uint64 numBlocks); 138 139 rw_lock fLock; 140 ::Volume* fVolume; 141 ino_t fID; 142 void* fCache; 143 void* fMap; 144 bool fCached; 145 bool fUnlinked; 146 bool fHasExtraAttributes; 147 ext2_inode fNode; 148 uint32 fNodeSize; 149 // Inodes have a variable size, but the important 150 // information is always the same size (except in ext4) 151 ext2_xattr_header* fAttributesBlock; 152 status_t fInitStatus; 153 154 mutable recursive_lock fSmallDataLock; 155 }; 156 157 158 // The Vnode class provides a convenience layer upon get_vnode(), so that 159 // you don't have to call put_vnode() anymore, which may make code more 160 // readable in some cases 161 162 class Vnode { 163 public: 164 Vnode(Volume* volume, ino_t id) 165 : 166 fInode(NULL) 167 { 168 SetTo(volume, id); 169 } 170 171 Vnode() 172 : 173 fStatus(B_NO_INIT), 174 fInode(NULL) 175 { 176 } 177 178 ~Vnode() 179 { 180 Unset(); 181 } 182 183 status_t InitCheck() 184 { 185 return fStatus; 186 } 187 188 void Unset() 189 { 190 if (fInode != NULL) { 191 put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID()); 192 fInode = NULL; 193 fStatus = B_NO_INIT; 194 } 195 } 196 197 status_t SetTo(Volume* volume, ino_t id) 198 { 199 Unset(); 200 201 return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode); 202 } 203 204 status_t Get(Inode** _inode) 205 { 206 *_inode = fInode; 207 return fStatus; 208 } 209 210 void Keep() 211 { 212 TRACEI("Vnode::Keep()\n"); 213 fInode = NULL; 214 } 215 216 status_t Publish(Transaction& transaction, Inode* inode, 217 fs_vnode_ops* vnodeOps, uint32 publishFlags) 218 { 219 TRACEI("Vnode::Publish()\n"); 220 Volume* volume = transaction.GetVolume(); 221 222 status_t status = B_OK; 223 224 if (!inode->IsSymLink() && volume->ID() >= 0) { 225 TRACEI("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, " 226 "%x\n", (int)volume->FSVolume(), (int)inode->ID(), inode, 227 vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(), 228 (int)publishFlags); 229 status = publish_vnode(volume->FSVolume(), inode->ID(), inode, 230 vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(), 231 publishFlags); 232 TRACEI("Vnode::Publish(): Result: %s\n", strerror(status)); 233 } 234 235 if (status == B_OK) { 236 TRACEI("Vnode::Publish(): Preparing internal data\n"); 237 fInode = inode; 238 fStatus = B_OK; 239 240 cache_add_transaction_listener(volume->BlockCache(), 241 transaction.ID(), TRANSACTION_ABORTED, &_TransactionListener, 242 inode); 243 } 244 245 return status; 246 } 247 248 private: 249 status_t fStatus; 250 Inode* fInode; 251 252 // TODO: How to apply coding style here? 253 static void _TransactionListener(int32 id, int32 event, void* _inode) 254 { 255 Inode* inode = (Inode*)_inode; 256 257 if (event == TRANSACTION_ABORTED) { 258 // TODO: Unpublish? 259 panic("Transaction %d aborted, inode %p still exists!\n", (int)id, 260 inode); 261 } 262 } 263 }; 264 265 #endif // INODE_H 266