163db34c8SAxel Dörfler/*
2d482c34eSJérôme Duval * Copyright 2011, J��r��me Duval, korli@users.berlios.de.
363db34c8SAxel Dörfler * Copyright 2008, Axel D��rfler, axeld@pinc-software.de.
463db34c8SAxel Dörfler * This file may be used under the terms of the MIT License.
563db34c8SAxel Dörfler */
663db34c8SAxel Dörfler#ifndef INODE_H
763db34c8SAxel Dörfler#define INODE_H
863db34c8SAxel Dörfler
963db34c8SAxel Dörfler
10a1b0ec30SJérôme Duval#include <fs_cache.h>
1163db34c8SAxel Dörfler#include <lock.h>
12a1b0ec30SJérôme Duval#include <string.h>
1363db34c8SAxel Dörfler
1463db34c8SAxel Dörfler#include "ext2.h"
1563db34c8SAxel Dörfler#include "Volume.h"
1663db34c8SAxel Dörfler
1763db34c8SAxel Dörfler
186bfb10d3SJérôme Duval//#define TRACE_EXT2
196bfb10d3SJérôme Duval#ifdef TRACE_EXT2
206bfb10d3SJérôme Duval#	define TRACEI(x...) dprintf("\33[34mext2:\33[0m " x)
216bfb10d3SJérôme Duval#else
226bfb10d3SJérôme Duval#	define TRACEI(x...) ;
236bfb10d3SJérôme Duval#endif
246bfb10d3SJérôme Duval
256bfb10d3SJérôme Duval
26a1b0ec30SJérôme Duvalclass Inode : public TransactionListener {
2763db34c8SAxel Dörflerpublic:
2863db34c8SAxel Dörfler						Inode(Volume* volume, ino_t id);
2963db34c8SAxel Dörfler						~Inode();
3063db34c8SAxel Dörfler
3163db34c8SAxel Dörfler			status_t	InitCheck();
3263db34c8SAxel Dörfler
3363db34c8SAxel Dörfler			ino_t		ID() const { return fID; }
3463db34c8SAxel Dörfler
3563db34c8SAxel Dörfler			rw_lock*	Lock() { return &fLock; }
36a1b0ec30SJérôme Duval			void		WriteLockInTransaction(Transaction& transaction);
37a1b0ec30SJérôme Duval
38a1b0ec30SJérôme Duval			status_t	UpdateNodeFromDisk();
39a1b0ec30SJérôme Duval			status_t	WriteBack(Transaction& transaction);
4063db34c8SAxel Dörfler
41db1b905eSJérôme Duval			recursive_lock&	SmallDataLock() { return fSmallDataLock; }
42db1b905eSJérôme Duval
4363db34c8SAxel Dörfler			bool		IsDirectory() const
4463db34c8SAxel Dörfler							{ return S_ISDIR(Mode()); }
4563db34c8SAxel Dörfler			bool		IsFile() const
4663db34c8SAxel Dörfler							{ return S_ISREG(Mode()); }
4763db34c8SAxel Dörfler			bool		IsSymLink() const
4863db34c8SAxel Dörfler							{ return S_ISLNK(Mode()); }
4963db34c8SAxel Dörfler			status_t	CheckPermissions(int accessMode) const;
5063db34c8SAxel Dörfler
51a1b0ec30SJérôme Duval			bool		IsDeleted() const { return fUnlinked; }
526bfb10d3SJérôme Duval			bool		HasExtraAttributes() const
536bfb10d3SJérôme Duval							{ return fHasExtraAttributes; }
54d482c34eSJérôme Duval			bool		IsIndexed() const
55d482c34eSJérôme Duval						{ return fVolume->IndexedDirectories()
56d482c34eSJérôme Duval							&& (Flags() & EXT2_INODE_INDEXED) != 0; }
5763db34c8SAxel Dörfler
58a1b0ec30SJérôme Duval			mode_t		Mode() const { return fNode.Mode(); }
59a1b0ec30SJérôme Duval			int32		Flags() const { return fNode.Flags(); }
60a1b0ec30SJérôme Duval
61a1b0ec30SJérôme Duval			off_t		Size() const { return fNode.Size(); }
626bfb10d3SJérôme Duval			void		GetChangeTime(struct timespec *timespec) const
636bfb10d3SJérôme Duval						{ fNode.GetChangeTime(timespec, fHasExtraAttributes); }
646bfb10d3SJérôme Duval			void		GetModificationTime(struct timespec *timespec) const
656bfb10d3SJérôme Duval						{ fNode.GetModificationTime(timespec,
666bfb10d3SJérôme Duval							fHasExtraAttributes); }
676bfb10d3SJérôme Duval			void		GetCreationTime(struct timespec *timespec) const
686bfb10d3SJérôme Duval						{ fNode.GetCreationTime(timespec,
696bfb10d3SJérôme Duval							fHasExtraAttributes); }
706bfb10d3SJérôme Duval			void		GetAccessTime(struct timespec *timespec) const
716bfb10d3SJérôme Duval						{ fNode.GetAccessTime(timespec, fHasExtraAttributes); }
726bfb10d3SJérôme Duval			void		SetChangeTime(const struct timespec *timespec)
736bfb10d3SJérôme Duval						{ fNode.SetChangeTime(timespec, fHasExtraAttributes); }
746bfb10d3SJérôme Duval			void		SetModificationTime(const struct timespec *timespec)
756bfb10d3SJérôme Duval						{ fNode.SetModificationTime(timespec,
766bfb10d3SJérôme Duval							fHasExtraAttributes); }
776bfb10d3SJérôme Duval			void		SetCreationTime(const struct timespec *timespec)
786bfb10d3SJérôme Duval						{ fNode.SetCreationTime(timespec,
796bfb10d3SJérôme Duval							fHasExtraAttributes); }
806bfb10d3SJérôme Duval			void		SetAccessTime(const struct timespec *timespec)
816bfb10d3SJérôme Duval						{ fNode.SetAccessTime(timespec, fHasExtraAttributes); }
82d482c34eSJérôme Duval			void		IncrementNumLinks(Transaction& transaction);
8363db34c8SAxel Dörfler
8463db34c8SAxel Dörfler			//::Volume* _Volume() const { return fVolume; }
8563db34c8SAxel Dörfler			Volume*		GetVolume() const { return fVolume; }
8663db34c8SAxel Dörfler
8745af882dSJérôme Duval			status_t	FindBlock(off_t offset, fsblock_t& block,
88583f39e9SJérôme Duval							uint32 *_count = NULL);
8963db34c8SAxel Dörfler			status_t	ReadAt(off_t pos, uint8 *buffer, size_t *length);
90a1b0ec30SJérôme Duval			status_t	WriteAt(Transaction& transaction, off_t pos,
91a1b0ec30SJérôme Duval							const uint8* buffer, size_t* length);
92a1b0ec30SJérôme Duval			status_t	FillGapWithZeros(off_t start, off_t end);
93a1b0ec30SJérôme Duval
94a1b0ec30SJérôme Duval			status_t	Resize(Transaction& transaction, off_t size);
9563db34c8SAxel Dörfler
96a1b0ec30SJérôme Duval			ext2_inode&	Node() { return fNode; }
97a1b0ec30SJérôme Duval
98a1b0ec30SJérôme Duval			status_t	InitDirectory(Transaction& transaction, Inode* parent);
99a1b0ec30SJérôme Duval
100a1b0ec30SJérôme Duval			status_t	Unlink(Transaction& transaction);
101a1b0ec30SJérôme Duval
102a1b0ec30SJérôme Duval	static	status_t	Create(Transaction& transaction, Inode* parent,
103a1b0ec30SJérôme Duval							const char* name, int32 mode, int openMode,
104a1b0ec30SJérôme Duval							uint8 type, bool* _created = NULL,
105a1b0ec30SJérôme Duval							ino_t* _id = NULL, Inode** _inode = NULL,
106a1b0ec30SJérôme Duval							fs_vnode_ops* vnodeOps = NULL,
107a1b0ec30SJérôme Duval							uint32 publishFlags = 0);
1086bfb10d3SJérôme Duval	static 	void		_BigtimeToTimespec(bigtime_t time,
1096bfb10d3SJérôme Duval							struct timespec *timespec)
1106bfb10d3SJérôme Duval						{ timespec->tv_sec = time / 1000000LL;
1116bfb10d3SJérôme Duval							timespec->tv_nsec = (time % 1000000LL) * 1000; }
1126bfb10d3SJérôme Duval
11363db34c8SAxel Dörfler			void*		FileCache() const { return fCache; }
11463db34c8SAxel Dörfler			void*		Map() const { return fMap; }
11526aef3acSIngo Weinhold			status_t	CreateFileCache();
11626aef3acSIngo Weinhold			void		DeleteFileCache();
11726aef3acSIngo Weinhold			bool		HasFileCache() { return fCache != NULL; }
118a1b0ec30SJérôme Duval			status_t	EnableFileCache();
119a1b0ec30SJérôme Duval			status_t	DisableFileCache();
120a1b0ec30SJérôme Duval
121a1b0ec30SJérôme Duval			status_t	Sync();
122a1b0ec30SJérôme Duval
123ce4e12caSJérôme Duval			void		SetDirEntryChecksum(uint8* block, uint32 id, uint32 gen);
124ce4e12caSJérôme Duval			void		SetDirEntryChecksum(uint8* block);
1256bfb10d3SJérôme Duval
126ce4e12caSJérôme Duval			void		SetExtentChecksum(ext2_extent_stream* stream);
127ce4e12caSJérôme Duval			bool		VerifyExtentChecksum(ext2_extent_stream* stream);
1286bfb10d3SJérôme Duval
129a1b0ec30SJérôme Duvalprotected:
130a1b0ec30SJérôme Duval	virtual	void		TransactionDone(bool success);
131a1b0ec30SJérôme Duval	virtual	void		RemovedFromTransaction();
132a1b0ec30SJérôme Duval
13363db34c8SAxel Dörfler
13463db34c8SAxel Dörflerprivate:
135a1b0ec30SJérôme Duval						Inode(Volume* volume);
13663db34c8SAxel Dörfler						Inode(const Inode&);
13763db34c8SAxel Dörfler						Inode &operator=(const Inode&);
13863db34c8SAxel Dörfler							// no implementation
13963db34c8SAxel Dörfler
140a1b0ec30SJérôme Duval			status_t	_EnlargeDataStream(Transaction& transaction,
141a1b0ec30SJérôme Duval							off_t size);
1426bfb10d3SJérôme Duval			status_t	_ShrinkDataStream(Transaction& transaction,
1436bfb10d3SJérôme Duval							off_t size);
1446bfb10d3SJérôme Duval
145de66992bSJérôme Duval			uint64		_NumBlocks();
146de66992bSJérôme Duval			status_t	_SetNumBlocks(uint64 numBlocks);
147a1b0ec30SJérôme Duval
148ce4e12caSJérôme Duval			uint32		_InodeChecksum();
149ce4e12caSJérôme Duval
150ce4e12caSJérôme Duval			ext2_dir_entry_tail*	_DirEntryTail(uint8* block) const;
151ce4e12caSJérôme Duval			uint32		_DirEntryChecksum(uint8* block, uint32 id,
152ce4e12caSJérôme Duval							uint32 gen) const;
153ce4e12caSJérôme Duval
154ce4e12caSJérôme Duval			uint32		_ExtentLength(ext2_extent_stream* stream) const;
155ce4e12caSJérôme Duval			uint32		_ExtentChecksum(ext2_extent_stream* stream) const;
156ce4e12caSJérôme Duval
157a1b0ec30SJérôme Duval			rw_lock		fLock;
158a1b0ec30SJérôme Duval			::Volume*	fVolume;
159a1b0ec30SJérôme Duval			ino_t		fID;
160a1b0ec30SJérôme Duval			void*		fCache;
161a1b0ec30SJérôme Duval			void*		fMap;
162a1b0ec30SJérôme Duval			bool		fUnlinked;
1636bfb10d3SJérôme Duval			bool		fHasExtraAttributes;
164a1b0ec30SJérôme Duval			ext2_inode	fNode;
165a1b0ec30SJérôme Duval			uint32		fNodeSize;
1666bfb10d3SJérôme Duval				// Inodes have a variable size, but the important
167a1b0ec30SJérôme Duval				// information is always the same size (except in ext4)
168a1b0ec30SJérôme Duval			status_t	fInitStatus;
169db1b905eSJérôme Duval
170db1b905eSJérôme Duval			mutable recursive_lock fSmallDataLock;
171a1b0ec30SJérôme Duval};
172a1b0ec30SJérôme Duval
173a1b0ec30SJérôme Duval
174a1b0ec30SJérôme Duval// The Vnode class provides a convenience layer upon get_vnode(), so that
175a1b0ec30SJérôme Duval// you don't have to call put_vnode() anymore, which may make code more
176a1b0ec30SJérôme Duval// readable in some cases
177a1b0ec30SJérôme Duval
178a1b0ec30SJérôme Duvalclass Vnode {
179a1b0ec30SJérôme Duvalpublic:
180a1b0ec30SJérôme Duval	Vnode(Volume* volume, ino_t id)
181a1b0ec30SJérôme Duval		:
182a1b0ec30SJérôme Duval		fInode(NULL)
183a1b0ec30SJérôme Duval	{
184a1b0ec30SJérôme Duval		SetTo(volume, id);
185a1b0ec30SJérôme Duval	}
186a1b0ec30SJérôme Duval
187a1b0ec30SJérôme Duval	Vnode()
188a1b0ec30SJérôme Duval		:
189a1b0ec30SJérôme Duval		fStatus(B_NO_INIT),
190a1b0ec30SJérôme Duval		fInode(NULL)
191a1b0ec30SJérôme Duval	{
192a1b0ec30SJérôme Duval	}
193a1b0ec30SJérôme Duval
194a1b0ec30SJérôme Duval	~Vnode()
195a1b0ec30SJérôme Duval	{
196a1b0ec30SJérôme Duval		Unset();
197a1b0ec30SJérôme Duval	}
198a1b0ec30SJérôme Duval
199a1b0ec30SJérôme Duval	status_t InitCheck()
200a1b0ec30SJérôme Duval	{
201a1b0ec30SJérôme Duval		return fStatus;
202a1b0ec30SJérôme Duval	}
203a1b0ec30SJérôme Duval
204a1b0ec30SJérôme Duval	void Unset()
205a1b0ec30SJérôme Duval	{
206a1b0ec30SJérôme Duval		if (fInode != NULL) {
207a1b0ec30SJérôme Duval			put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
208a1b0ec30SJérôme Duval			fInode = NULL;
209a1b0ec30SJérôme Duval			fStatus = B_NO_INIT;
210a1b0ec30SJérôme Duval		}
211a1b0ec30SJérôme Duval	}
212a1b0ec30SJérôme Duval
213a1b0ec30SJérôme Duval	status_t SetTo(Volume* volume, ino_t id)
214a1b0ec30SJérôme Duval	{
215a1b0ec30SJérôme Duval		Unset();
216a1b0ec30SJérôme Duval
217a1b0ec30SJérôme Duval		return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
218a1b0ec30SJérôme Duval	}
219a1b0ec30SJérôme Duval
220a1b0ec30SJérôme Duval	status_t Get(Inode** _inode)
221a1b0ec30SJérôme Duval	{
222a1b0ec30SJérôme Duval		*_inode = fInode;
223a1b0ec30SJérôme Duval		return fStatus;
224a1b0ec30SJérôme Duval	}
225a1b0ec30SJérôme Duval
226a1b0ec30SJérôme Duval	void Keep()
227a1b0ec30SJérôme Duval	{
2286bfb10d3SJérôme Duval		TRACEI("Vnode::Keep()\n");
229a1b0ec30SJérôme Duval		fInode = NULL;
230a1b0ec30SJérôme Duval	}
231a1b0ec30SJérôme Duval
232a1b0ec30SJérôme Duval	status_t Publish(Transaction& transaction, Inode* inode,
233a1b0ec30SJérôme Duval		fs_vnode_ops* vnodeOps, uint32 publishFlags)
234a1b0ec30SJérôme Duval	{
2356bfb10d3SJérôme Duval		TRACEI("Vnode::Publish()\n");
236a1b0ec30SJérôme Duval		Volume* volume = transaction.GetVolume();
237a1b0ec30SJérôme Duval
238a1b0ec30SJérôme Duval		status_t status = B_OK;
239a1b0ec30SJérôme Duval
240a1b0ec30SJérôme Duval		if (!inode->IsSymLink() && volume->ID() >= 0) {
241a130bab3SJérôme Duval			TRACEI("Vnode::Publish(): Publishing volume: %p, %" B_PRIdINO
242a130bab3SJérôme Duval				", %p, %p, %" B_PRIu16 ", %" B_PRIx32 "\n", volume->FSVolume(),
243a130bab3SJérôme Duval				inode->ID(), inode, vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps,
244a130bab3SJérôme Duval				inode->Mode(), publishFlags);
245a1b0ec30SJérôme Duval			status = publish_vnode(volume->FSVolume(), inode->ID(), inode,
246a1b0ec30SJérôme Duval				vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(),
247a1b0ec30SJérôme Duval				publishFlags);
2486bfb10d3SJérôme Duval			TRACEI("Vnode::Publish(): Result: %s\n", strerror(status));
249a1b0ec30SJérôme Duval		}
250a1b0ec30SJérôme Duval
251a1b0ec30SJérôme Duval		if (status == B_OK) {
2526bfb10d3SJérôme Duval			TRACEI("Vnode::Publish(): Preparing internal data\n");
253a1b0ec30SJérôme Duval			fInode = inode;
254a1b0ec30SJérôme Duval			fStatus = B_OK;
255a1b0ec30SJérôme Duval
256a1b0ec30SJérôme Duval			cache_add_transaction_listener(volume->BlockCache(),
257a1b0ec30SJérôme Duval				transaction.ID(), TRANSACTION_ABORTED, &_TransactionListener,
258a1b0ec30SJérôme Duval				inode);
259a1b0ec30SJérôme Duval		}
260a1b0ec30SJérôme Duval
261a1b0ec30SJérôme Duval		return status;
262a1b0ec30SJérôme Duval	}
263a1b0ec30SJérôme Duval
26463db34c8SAxel Dörflerprivate:
265a1b0ec30SJérôme Duval	status_t	fStatus;
266a1b0ec30SJérôme Duval	Inode*		fInode;
267a1b0ec30SJérôme Duval
268a1b0ec30SJérôme Duval	// TODO: How to apply coding style here?
269a1b0ec30SJérôme Duval	static void _TransactionListener(int32 id, int32 event, void* _inode)
270a1b0ec30SJérôme Duval	{
271a1b0ec30SJérôme Duval		Inode* inode = (Inode*)_inode;
272a1b0ec30SJérôme Duval
273a1b0ec30SJérôme Duval		if (event == TRANSACTION_ABORTED) {
274a1b0ec30SJérôme Duval			// TODO: Unpublish?
275a1b0ec30SJérôme Duval			panic("Transaction %d aborted, inode %p still exists!\n", (int)id,
276a1b0ec30SJérôme Duval				inode);
277a1b0ec30SJérôme Duval		}
278a1b0ec30SJérôme Duval	}
27963db34c8SAxel Dörfler};
28063db34c8SAxel Dörfler
28163db34c8SAxel Dörfler#endif	// INODE_H