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 "DirectoryIterator.h"
15#include "exfat.h"
16#include "SplayTree.h"
17#include "Volume.h"
18
19
20//#define TRACE_EXFAT
21#ifdef TRACE_EXFAT
22#	define TRACEI(x...) dprintf("\33[34mexfat:\33[0m " x)
23#else
24#	define TRACEI(x...) ;
25#endif
26
27
28struct InodesTreeDefinition;
29
30
31class Inode : EntryVisitor {
32public:
33						Inode(Volume* volume, cluster_t cluster,
34							uint32 offset);
35						Inode(Volume* volume, ino_t ino);
36						~Inode();
37
38			status_t	InitCheck();
39
40			ino_t		ID() const { return fID; }
41			ino_t		Parent() const { return fParent; }
42			cluster_t	Cluster() const { return fCluster; }
43			uint32		Offset() const { return fOffset; }
44			cluster_t	StartCluster() const
45							{ return fFileInfoEntry.file_info.StartCluster(); }
46			bool		IsContiguous() const
47							{ return fFileInfoEntry.file_info.IsContiguous(); }
48			cluster_t	NextCluster(cluster_t cluster) const;
49
50			rw_lock*	Lock() { return &fLock; }
51
52			status_t	UpdateNodeFromDisk();
53
54			bool		IsDirectory() const
55							{ return S_ISDIR(Mode()); }
56			bool		IsFile() const
57							{ return S_ISREG(Mode()); }
58			bool		IsSymLink() const
59							{ return S_ISLNK(Mode()); }
60			status_t	CheckPermissions(int accessMode) const;
61
62			mode_t		Mode() const;
63			off_t		Size() const { return fFileInfoEntry.file_info.Size(); }
64			uid_t		UserID() const { return 0;/*fNode.UserID();*/ }
65			gid_t		GroupID() const { return 0;/*fNode.GroupID();*/ }
66			void		GetChangeTime(struct timespec &timespec) const
67							{ GetModificationTime(timespec); }
68			void		GetModificationTime(struct timespec &timespec) const
69							{ _GetTimespec(fFileEntry.file.ModificationDate(),
70								fFileEntry.file.ModificationTime(), timespec); }
71			void		GetCreationTime(struct timespec &timespec) const
72							{ _GetTimespec(fFileEntry.file.CreationDate(),
73								fFileEntry.file.CreationTime(), timespec); }
74			void		GetAccessTime(struct timespec &timespec) const
75							{ _GetTimespec(fFileEntry.file.AccessDate(),
76								fFileEntry.file.AccessTime(), timespec); }
77
78			Volume*		GetVolume() const { return fVolume; }
79
80			status_t	FindBlock(off_t logical, off_t& physical,
81							off_t *_length = NULL);
82			status_t	ReadAt(off_t pos, uint8 *buffer, size_t *length);
83			status_t	FillGapWithZeros(off_t start, off_t end);
84
85			void*		FileCache() const { return fCache; }
86			void*		Map() const { return fMap; }
87
88			bool		VisitFile(struct exfat_entry*);
89			bool		VisitFileInfo(struct exfat_entry*);
90
91private:
92			friend struct InodesInoTreeDefinition;
93			friend struct InodesClusterTreeDefinition;
94
95						Inode(Volume* volume);
96						Inode(const Inode&);
97						Inode &operator=(const Inode&);
98							// no implementation
99
100			void		_GetTimespec(uint16 date, uint16 time,
101							struct timespec &timespec) const;
102			void		_Init();
103
104			rw_lock		fLock;
105			::Volume*	fVolume;
106			ino_t		fID;
107			ino_t		fParent;
108			cluster_t 	fCluster;
109			uint32		fOffset;
110			uint32		fFlags;
111			void*		fCache;
112			void*		fMap;
113			status_t	fInitStatus;
114
115			SplayTreeLink<Inode> fInoTreeLink;
116			Inode*				fInoTreeNext;
117			SplayTreeLink<Inode> fClusterTreeLink;
118			Inode*				fClusterTreeNext;
119
120			struct exfat_entry	fFileEntry;
121			struct exfat_entry	fFileInfoEntry;
122};
123
124
125// The Vnode class provides a convenience layer upon get_vnode(), so that
126// you don't have to call put_vnode() anymore, which may make code more
127// readable in some cases
128
129class Vnode {
130public:
131	Vnode(Volume* volume, ino_t id)
132		:
133		fInode(NULL)
134	{
135		SetTo(volume, id);
136	}
137
138	Vnode()
139		:
140		fStatus(B_NO_INIT),
141		fInode(NULL)
142	{
143	}
144
145	~Vnode()
146	{
147		Unset();
148	}
149
150	status_t InitCheck()
151	{
152		return fStatus;
153	}
154
155	void Unset()
156	{
157		if (fInode != NULL) {
158			put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
159			fInode = NULL;
160			fStatus = B_NO_INIT;
161		}
162	}
163
164	status_t SetTo(Volume* volume, ino_t id)
165	{
166		Unset();
167
168		return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
169	}
170
171	status_t Get(Inode** _inode)
172	{
173		*_inode = fInode;
174		return fStatus;
175	}
176
177	void Keep()
178	{
179		TRACEI("Vnode::Keep()\n");
180		fInode = NULL;
181	}
182
183private:
184	status_t	fStatus;
185	Inode*		fInode;
186};
187
188
189struct InodesInoTreeDefinition {
190	typedef ino_t KeyType;
191	typedef	Inode NodeType;
192
193	static KeyType GetKey(const NodeType* node)
194	{
195		return node->ID();
196	}
197
198	static SplayTreeLink<NodeType>* GetLink(NodeType* node)
199	{
200		return &node->fInoTreeLink;
201	}
202
203	static int Compare(KeyType key, const NodeType* node)
204	{
205		return key == node->ID() ? 0
206			: (key < node->ID() ? -1 : 1);
207	}
208
209	static NodeType** GetListLink(NodeType* node)
210	{
211		return &node->fInoTreeNext;
212	}
213};
214
215typedef IteratableSplayTree<InodesInoTreeDefinition> InodesInoTree;
216
217struct InodesClusterTreeDefinition {
218	typedef cluster_t KeyType;
219	typedef	Inode NodeType;
220
221	static KeyType GetKey(const NodeType* node)
222	{
223		return node->Cluster();
224	}
225
226	static SplayTreeLink<NodeType>* GetLink(NodeType* node)
227	{
228		return &node->fClusterTreeLink;
229	}
230
231	static int Compare(KeyType key, const NodeType* node)
232	{
233		return key == node->Cluster() ? 0
234			: (key < node->Cluster() ? -1 : 1);
235	}
236
237	static NodeType** GetListLink(NodeType* node)
238	{
239		return &node->fClusterTreeNext;
240	}
241};
242
243typedef IteratableSplayTree<InodesClusterTreeDefinition> InodesClusterTree;
244
245#endif	// INODE_H
246