Inode.h revision a1b0ec30
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
17class Inode : public TransactionListener {
18public:
19						Inode(Volume* volume, ino_t id);
20						~Inode();
21
22			status_t	InitCheck();
23
24			ino_t		ID() const { return fID; }
25
26			rw_lock*	Lock() { return &fLock; }
27			void		WriteLockInTransaction(Transaction& transaction);
28
29			status_t	UpdateNodeFromDisk();
30			status_t	WriteBack(Transaction& transaction);
31
32			bool		IsDirectory() const
33							{ return S_ISDIR(Mode()); }
34			bool		IsFile() const
35							{ return S_ISREG(Mode()); }
36			bool		IsSymLink() const
37							{ return S_ISLNK(Mode()); }
38			status_t	CheckPermissions(int accessMode) const;
39
40			bool		IsDeleted() const { return fUnlinked; }
41
42			mode_t		Mode() const { return fNode.Mode(); }
43			int32		Flags() const { return fNode.Flags(); }
44
45			off_t		Size() const { return fNode.Size(); }
46			time_t		ModificationTime() const
47							{ return fNode.ModificationTime(); }
48			time_t		CreationTime() const
49							{ return fNode.CreationTime(); }
50			time_t		AccessTime() const
51							{ return fNode.AccessTime(); }
52
53			//::Volume* _Volume() const { return fVolume; }
54			Volume*		GetVolume() const { return fVolume; }
55
56			status_t	FindBlock(off_t offset, uint32& block);
57			status_t	ReadAt(off_t pos, uint8 *buffer, size_t *length);
58			status_t	WriteAt(Transaction& transaction, off_t pos,
59							const uint8* buffer, size_t* length);
60			status_t	FillGapWithZeros(off_t start, off_t end);
61
62			status_t	Resize(Transaction& transaction, off_t size);
63
64			status_t	AttributeBlockReadAt(off_t pos, uint8 *buffer,
65							size_t *length);
66
67			ext2_inode&	Node() { return fNode; }
68
69			status_t	InitDirectory(Transaction& transaction, Inode* parent);
70
71			status_t	Unlink(Transaction& transaction);
72
73	static	status_t	Create(Transaction& transaction, Inode* parent,
74							const char* name, int32 mode, int openMode,
75							uint8 type, bool* _created = NULL,
76							ino_t* _id = NULL, Inode** _inode = NULL,
77							fs_vnode_ops* vnodeOps = NULL,
78							uint32 publishFlags = 0);
79
80			void*		FileCache() const { return fCache; }
81			void*		Map() const { return fMap; }
82			status_t	EnableFileCache();
83			status_t	DisableFileCache();
84			bool		IsFileCacheDisabled() const { return !fCached; }
85
86			status_t	Sync();
87
88protected:
89	virtual	void		TransactionDone(bool success);
90	virtual	void		RemovedFromTransaction();
91
92
93private:
94						Inode(Volume* volume);
95						Inode(const Inode&);
96						Inode &operator=(const Inode&);
97							// no implementation
98
99			status_t	_EnlargeDataStream(Transaction& transaction,
100							off_t size);
101			status_t	_ShrinkDataStream(Transaction& transaction, off_t size);
102
103
104			rw_lock		fLock;
105			::Volume*	fVolume;
106			ino_t		fID;
107			void*		fCache;
108			void*		fMap;
109			bool		fCached;
110			bool		fUnlinked;
111			ext2_inode	fNode;
112			uint32		fNodeSize;
113				// Inodes have a varible size, but the important
114				// information is always the same size (except in ext4)
115			ext2_xattr_header* fAttributesBlock;
116			status_t	fInitStatus;
117};
118
119
120// The Vnode class provides a convenience layer upon get_vnode(), so that
121// you don't have to call put_vnode() anymore, which may make code more
122// readable in some cases
123
124class Vnode {
125public:
126	Vnode(Volume* volume, ino_t id)
127		:
128		fInode(NULL)
129	{
130		SetTo(volume, id);
131	}
132
133	Vnode()
134		:
135		fStatus(B_NO_INIT),
136		fInode(NULL)
137	{
138	}
139
140	~Vnode()
141	{
142		Unset();
143	}
144
145	status_t InitCheck()
146	{
147		return fStatus;
148	}
149
150	void Unset()
151	{
152		if (fInode != NULL) {
153			put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
154			fInode = NULL;
155			fStatus = B_NO_INIT;
156		}
157	}
158
159	status_t SetTo(Volume* volume, ino_t id)
160	{
161		Unset();
162
163		return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
164	}
165
166	status_t Get(Inode** _inode)
167	{
168		*_inode = fInode;
169		return fStatus;
170	}
171
172	void Keep()
173	{
174		dprintf("Vnode::Keep()\n");
175		fInode = NULL;
176	}
177
178	status_t Publish(Transaction& transaction, Inode* inode,
179		fs_vnode_ops* vnodeOps, uint32 publishFlags)
180	{
181		dprintf("Vnode::Publish()\n");
182		Volume* volume = transaction.GetVolume();
183
184		status_t status = B_OK;
185
186		if (!inode->IsSymLink() && volume->ID() >= 0) {
187			dprintf("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, "
188				"%x\n", (int)volume->FSVolume(), (int)inode->ID(), inode,
189				vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(),
190				(int)publishFlags);
191			status = publish_vnode(volume->FSVolume(), inode->ID(), inode,
192				vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(),
193				publishFlags);
194			dprintf("Vnode::Publish(): Result: %s\n", strerror(status));
195		}
196
197		if (status == B_OK) {
198			dprintf("Vnode::Publish(): Preparing internal data\n");
199			fInode = inode;
200			fStatus = B_OK;
201
202			cache_add_transaction_listener(volume->BlockCache(),
203				transaction.ID(), TRANSACTION_ABORTED, &_TransactionListener,
204				inode);
205		}
206
207		return status;
208	}
209
210private:
211	status_t	fStatus;
212	Inode*		fInode;
213
214	// TODO: How to apply coding style here?
215	static void _TransactionListener(int32 id, int32 event, void* _inode)
216	{
217		Inode* inode = (Inode*)_inode;
218
219		if (event == TRANSACTION_ABORTED) {
220			// TODO: Unpublish?
221			panic("Transaction %d aborted, inode %p still exists!\n", (int)id,
222				inode);
223		}
224	}
225};
226
227#endif	// INODE_H
228