Inode.h revision d482c34e
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
26class Inode : public TransactionListener {
27public:
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	EnableFileCache();
116			status_t	DisableFileCache();
117			bool		IsFileCacheDisabled() const { return !fCached; }
118
119			status_t	Sync();
120
121
122
123protected:
124	virtual	void		TransactionDone(bool success);
125	virtual	void		RemovedFromTransaction();
126
127
128private:
129						Inode(Volume* volume);
130						Inode(const Inode&);
131						Inode &operator=(const Inode&);
132							// no implementation
133
134			status_t	_EnlargeDataStream(Transaction& transaction,
135							off_t size);
136			status_t	_ShrinkDataStream(Transaction& transaction,
137							off_t size);
138
139			uint64		_NumBlocks();
140			status_t	_SetNumBlocks(uint64 numBlocks);
141
142			rw_lock		fLock;
143			::Volume*	fVolume;
144			ino_t		fID;
145			void*		fCache;
146			void*		fMap;
147			bool		fCached;
148			bool		fUnlinked;
149			bool		fHasExtraAttributes;
150			ext2_inode	fNode;
151			uint32		fNodeSize;
152				// Inodes have a variable size, but the important
153				// information is always the same size (except in ext4)
154			status_t	fInitStatus;
155
156			mutable recursive_lock fSmallDataLock;
157};
158
159
160// The Vnode class provides a convenience layer upon get_vnode(), so that
161// you don't have to call put_vnode() anymore, which may make code more
162// readable in some cases
163
164class Vnode {
165public:
166	Vnode(Volume* volume, ino_t id)
167		:
168		fInode(NULL)
169	{
170		SetTo(volume, id);
171	}
172
173	Vnode()
174		:
175		fStatus(B_NO_INIT),
176		fInode(NULL)
177	{
178	}
179
180	~Vnode()
181	{
182		Unset();
183	}
184
185	status_t InitCheck()
186	{
187		return fStatus;
188	}
189
190	void Unset()
191	{
192		if (fInode != NULL) {
193			put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
194			fInode = NULL;
195			fStatus = B_NO_INIT;
196		}
197	}
198
199	status_t SetTo(Volume* volume, ino_t id)
200	{
201		Unset();
202
203		return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
204	}
205
206	status_t Get(Inode** _inode)
207	{
208		*_inode = fInode;
209		return fStatus;
210	}
211
212	void Keep()
213	{
214		TRACEI("Vnode::Keep()\n");
215		fInode = NULL;
216	}
217
218	status_t Publish(Transaction& transaction, Inode* inode,
219		fs_vnode_ops* vnodeOps, uint32 publishFlags)
220	{
221		TRACEI("Vnode::Publish()\n");
222		Volume* volume = transaction.GetVolume();
223
224		status_t status = B_OK;
225
226		if (!inode->IsSymLink() && volume->ID() >= 0) {
227			TRACEI("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, "
228				"%x\n", (int)volume->FSVolume(), (int)inode->ID(), inode,
229				vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(),
230				(int)publishFlags);
231			status = publish_vnode(volume->FSVolume(), inode->ID(), inode,
232				vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(),
233				publishFlags);
234			TRACEI("Vnode::Publish(): Result: %s\n", strerror(status));
235		}
236
237		if (status == B_OK) {
238			TRACEI("Vnode::Publish(): Preparing internal data\n");
239			fInode = inode;
240			fStatus = B_OK;
241
242			cache_add_transaction_listener(volume->BlockCache(),
243				transaction.ID(), TRANSACTION_ABORTED, &_TransactionListener,
244				inode);
245		}
246
247		return status;
248	}
249
250private:
251	status_t	fStatus;
252	Inode*		fInode;
253
254	// TODO: How to apply coding style here?
255	static void _TransactionListener(int32 id, int32 event, void* _inode)
256	{
257		Inode* inode = (Inode*)_inode;
258
259		if (event == TRANSACTION_ABORTED) {
260			// TODO: Unpublish?
261			panic("Transaction %d aborted, inode %p still exists!\n", (int)id,
262				inode);
263		}
264	}
265};
266
267#endif	// INODE_H
268