xref: /haiku/src/add-ons/kernel/file_systems/ext2/Inode.h (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
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 			uint64		NumBlocks();
63 			void		GetChangeTime(struct timespec *timespec) const
64 						{ fNode.GetChangeTime(timespec, fHasExtraAttributes); }
65 			void		GetModificationTime(struct timespec *timespec) const
66 						{ fNode.GetModificationTime(timespec,
67 							fHasExtraAttributes); }
68 			void		GetCreationTime(struct timespec *timespec) const
69 						{ fNode.GetCreationTime(timespec,
70 							fHasExtraAttributes); }
71 			void		GetAccessTime(struct timespec *timespec) const
72 						{ fNode.GetAccessTime(timespec, fHasExtraAttributes); }
73 			void		SetChangeTime(const struct timespec *timespec)
74 						{ fNode.SetChangeTime(timespec, fHasExtraAttributes); }
75 			void		SetModificationTime(const struct timespec *timespec)
76 						{ fNode.SetModificationTime(timespec,
77 							fHasExtraAttributes); }
78 			void		SetCreationTime(const struct timespec *timespec)
79 						{ fNode.SetCreationTime(timespec,
80 							fHasExtraAttributes); }
81 			void		SetAccessTime(const struct timespec *timespec)
82 						{ fNode.SetAccessTime(timespec, fHasExtraAttributes); }
83 			void		IncrementNumLinks(Transaction& transaction);
84 
85 			//::Volume* _Volume() const { return fVolume; }
86 			Volume*		GetVolume() const { return fVolume; }
87 
88 			status_t	FindBlock(off_t offset, fsblock_t& block,
89 							uint32 *_count = NULL);
90 			status_t	ReadAt(off_t pos, uint8 *buffer, size_t *length);
91 			status_t	WriteAt(Transaction& transaction, off_t pos,
92 							const uint8* buffer, size_t* length);
93 			status_t	FillGapWithZeros(off_t start, off_t end);
94 
95 			status_t	Resize(Transaction& transaction, off_t size);
96 
97 			ext2_inode&	Node() { return fNode; }
98 
99 			status_t	InitDirectory(Transaction& transaction, Inode* parent);
100 
101 			status_t	Unlink(Transaction& transaction);
102 
103 	static	status_t	Create(Transaction& transaction, Inode* parent,
104 							const char* name, int32 mode, int openMode,
105 							uint8 type, bool* _created = NULL,
106 							ino_t* _id = NULL, Inode** _inode = NULL,
107 							fs_vnode_ops* vnodeOps = NULL,
108 							uint32 publishFlags = 0);
109 	static 	void		_BigtimeToTimespec(bigtime_t time,
110 							struct timespec *timespec)
111 						{ timespec->tv_sec = time / 1000000LL;
112 							timespec->tv_nsec = (time % 1000000LL) * 1000; }
113 
114 			void*		FileCache() const { return fCache; }
115 			void*		Map() const { return fMap; }
116 			status_t	CreateFileCache();
117 			void		DeleteFileCache();
118 			bool		HasFileCache() { return fCache != NULL; }
119 			status_t	EnableFileCache();
120 			status_t	DisableFileCache();
121 
122 			status_t	Sync();
123 
124 			void		SetDirEntryChecksum(uint8* block, uint32 id, uint32 gen);
125 			void		SetDirEntryChecksum(uint8* block);
126 
127 			void		SetExtentChecksum(ext2_extent_stream* stream);
128 			bool		VerifyExtentChecksum(ext2_extent_stream* stream);
129 
130 protected:
131 	virtual	void		TransactionDone(bool success);
132 	virtual	void		RemovedFromTransaction();
133 
134 
135 private:
136 						Inode(Volume* volume);
137 						Inode(const Inode&);
138 						Inode &operator=(const Inode&);
139 							// no implementation
140 
141 			status_t	_EnlargeDataStream(Transaction& transaction,
142 							off_t size);
143 			status_t	_ShrinkDataStream(Transaction& transaction,
144 							off_t size);
145 
146 			status_t	_SetNumBlocks(uint64 numBlocks);
147 
148 			uint32		_InodeChecksum(ext2_inode* inode);
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