xref: /haiku/src/add-ons/kernel/file_systems/ext2/Inode.h (revision 56187df6ebd9d1fb16bf954fce8df0999e9e3048)
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