Inode.h revision db1b905e
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
25class Inode : public TransactionListener {
26public:
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
120protected:
121	virtual	void		TransactionDone(bool success);
122	virtual	void		RemovedFromTransaction();
123
124
125private:
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
162class Vnode {
163public:
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
248private:
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