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