1/*
2 * Copyright 2001-2020, 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 "system_dependencies.h"
10
11#include "CachedBlock.h"
12#include "Debug.h"
13#include "Journal.h"
14#include "Volume.h"
15
16
17class BPlusTree;
18class TreeIterator;
19class AttributeIterator;
20class Index;
21class InodeAllocator;
22class NodeGetter;
23class Transaction;
24
25
26// To be used in Inode::Create() as publishFlags
27#define BFS_DO_NOT_PUBLISH_VNODE	0x80000000
28
29
30class Inode : public TransactionListener {
31	typedef DoublyLinkedListLink<Inode> Link;
32
33public:
34								Inode(Volume* volume, ino_t id);
35								Inode(Volume* volume, Transaction& transaction,
36									ino_t id, mode_t mode, block_run& run);
37								~Inode();
38
39			status_t			InitCheck(bool checkNode = true) const;
40
41			ino_t				ID() const { return fID; }
42			off_t				BlockNumber() const
43									{ return fVolume->VnodeToBlock(fID); }
44
45			rw_lock&			Lock() { return fLock; }
46			ReadLocker			ReadLock() { return ReadLocker(fLock); }
47			void				WriteLockInTransaction(Transaction& transaction);
48
49			recursive_lock&		SmallDataLock() { return fSmallDataLock; }
50
51			status_t			WriteBack(Transaction& transaction);
52			status_t			UpdateNodeFromDisk();
53
54			bool				IsContainer() const
55									{ return S_ISDIR(Mode()); }
56			bool				IsDirectory() const
57									{ return is_directory(Mode()); }
58			bool				IsIndex() const
59									{ return is_index(Mode()); }
60
61			bool				IsAttributeDirectory() const
62									{ return (Mode() & S_EXTENDED_TYPES)
63										== S_ATTR_DIR; }
64			bool				IsAttribute() const
65									{ return (Mode() & S_EXTENDED_TYPES)
66										== S_ATTR; }
67			bool				IsFile() const
68									{ return (Mode() & (S_IFMT
69											| S_EXTENDED_TYPES)) == S_FILE; }
70			bool				IsRegularNode() const
71									{ return (Mode() & S_EXTENDED_TYPES) == 0; }
72									// a regular node in the standard namespace
73									// (i.e. not an index or attribute)
74			bool				IsSymLink() const { return S_ISLNK(Mode()); }
75			bool				IsLongSymLink() const
76									{ return (Flags() & INODE_LONG_SYMLINK)
77										!= 0; }
78
79			bool				HasUserAccessableStream() const
80									{ return IsFile(); }
81									// currently only files can be accessed with
82									// bfs_read()/bfs_write()
83			bool				NeedsFileCache() const
84									{ return IsFile() || IsAttribute()
85										|| IsLongSymLink(); }
86
87			bool				IsDeleted() const
88									{ return (Flags() & INODE_DELETED) != 0; }
89
90			mode_t				Mode() const { return fNode.Mode(); }
91			uint32				Type() const { return fNode.Type(); }
92			int32				Flags() const { return fNode.Flags(); }
93
94			off_t				Size() const { return fNode.data.Size(); }
95			off_t				AllocatedSize() const;
96			off_t				LastModified() const
97									{ return fNode.LastModifiedTime(); }
98
99			const block_run&	BlockRun() const
100									{ return fNode.inode_num; }
101			block_run&			Parent() { return fNode.parent; }
102			const block_run&	Parent() const { return fNode.parent; }
103			ino_t				ParentID() const
104									{ return fVolume->ToVnode(Parent()); }
105			block_run&			Attributes() { return fNode.attributes; }
106
107			Volume*				GetVolume() const { return fVolume; }
108
109			status_t			CheckPermissions(int accessMode) const;
110
111			// small_data access methods
112			small_data*			FindSmallData(const bfs_inode* node,
113									const char* name) const;
114			const char*			Name(const bfs_inode* node) const;
115			status_t			GetName(char* buffer, size_t bufferSize
116										= B_FILE_NAME_LENGTH) const;
117			status_t			SetName(Transaction& transaction,
118									const char* name);
119
120			// high-level attribute methods
121			status_t			ReadAttribute(const char* name, int32 type,
122									off_t pos, uint8* buffer, size_t* _length);
123			status_t			WriteAttribute(Transaction& transaction,
124									const char* name, int32 type, off_t pos,
125									const uint8* buffer, size_t* _length,
126									bool* _created);
127			status_t			RemoveAttribute(Transaction& transaction,
128									const char* name);
129
130			// attribute methods
131			status_t			GetAttribute(const char* name,
132									Inode** _attribute);
133			void				ReleaseAttribute(Inode* attribute);
134			status_t			CreateAttribute(Transaction& transaction,
135									const char* name, uint32 type,
136									Inode** attribute);
137
138			// for directories only:
139			BPlusTree*			Tree() const { return fTree; }
140			bool				IsEmpty();
141			status_t			ContainerContentsChanged(
142									Transaction& transaction);
143
144			// manipulating the data stream
145			status_t			FindBlockRun(off_t pos, block_run& run,
146									off_t& offset);
147
148			status_t			ReadAt(off_t pos, uint8* buffer, size_t* length);
149			status_t			WriteAt(Transaction& transaction, off_t pos,
150									const uint8* buffer, size_t* length);
151			status_t			FillGapWithZeros(off_t oldSize, off_t newSize);
152
153			status_t			SetFileSize(Transaction& transaction,
154									off_t size);
155			status_t			Append(Transaction& transaction, off_t bytes);
156			status_t			TrimPreallocation(Transaction& transaction);
157			bool				NeedsTrimming() const;
158
159			status_t			Free(Transaction& transaction);
160			status_t			Sync();
161
162			bfs_inode&			Node() { return fNode; }
163			const bfs_inode&	Node() const { return fNode; }
164
165			// create/remove inodes
166			status_t			Remove(Transaction& transaction,
167									const char* name, ino_t* _id = NULL,
168									bool isDirectory = false,
169									bool force = false);
170	static	status_t			Create(Transaction& transaction, Inode* parent,
171									const char* name, int32 mode, int openMode,
172									uint32 type, bool* _created = NULL,
173									ino_t* _id = NULL, Inode** _inode = NULL,
174									fs_vnode_ops* vnodeOps = NULL,
175									uint32 publishFlags = 0);
176
177			// index maintaining helper
178			void				UpdateOldSize() { fOldSize = Size(); }
179			void				UpdateOldLastModified()
180									{ fOldLastModified
181										= Node().LastModifiedTime(); }
182			off_t				OldSize() { return fOldSize; }
183			off_t				OldLastModified() { return fOldLastModified; }
184
185			bool				InNameIndex() const;
186			bool				InSizeIndex() const;
187			bool				InLastModifiedIndex() const;
188
189			// file cache
190			void*				FileCache() const { return fCache; }
191			void				SetFileCache(void* cache) { fCache = cache; }
192			void*				Map() const { return fMap; }
193			void				SetMap(void* map) { fMap = map; }
194
195#if _KERNEL_MODE && KDEBUG
196			void				AssertReadLocked()
197									{ ASSERT_READ_LOCKED_RW_LOCK(&fLock); }
198			void				AssertWriteLocked()
199									{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
200#endif
201
202			Link*				GetDoublyLinkedListLink()
203									{ return (Link*)TransactionListener
204										::GetDoublyLinkedListLink(); }
205			const Link*			GetDoublyLinkedListLink() const
206									{ return (Link*)TransactionListener
207										::GetDoublyLinkedListLink(); }
208
209protected:
210	virtual void				TransactionDone(bool success);
211	virtual void				RemovedFromTransaction();
212
213private:
214								Inode(const Inode& other);
215								Inode& operator=(const Inode& other);
216									// no implementation
217
218	friend class AttributeIterator;
219	friend class InodeAllocator;
220
221			// small_data access methods
222			status_t			_MakeSpaceForSmallData(Transaction& transaction,
223									bfs_inode* node, const char* name,
224									int32 length);
225			status_t			_RemoveSmallData(Transaction& transaction,
226									NodeGetter& node, const char* name);
227			status_t			_AddSmallData(Transaction& transaction,
228									NodeGetter& node, const char* name,
229									uint32 type, off_t pos, const uint8* data,
230									size_t length, bool force = false);
231			status_t			_GetNextSmallData(bfs_inode* node,
232									small_data** _smallData) const;
233			status_t			_RemoveSmallData(bfs_inode* node,
234									small_data* item, int32 index);
235			status_t			_RemoveAttribute(Transaction& transaction,
236									const char* name, bool hasIndex,
237									Index* index);
238
239			void				_AddIterator(AttributeIterator* iterator);
240			void				_RemoveIterator(AttributeIterator* iterator);
241
242			size_t				_DoubleIndirectBlockLength() const;
243			status_t			_FreeStaticStreamArray(Transaction& transaction,
244									int32 level, block_run run, off_t size,
245									off_t offset, off_t& max);
246			status_t			_FreeStreamArray(Transaction& transaction,
247									block_run* array, uint32 arrayLength,
248									off_t size, off_t& offset, off_t& max);
249			status_t			_AllocateBlockArray(Transaction& transaction,
250									block_run& run, size_t length,
251									bool variableSize = false);
252			status_t			_GrowStream(Transaction& transaction,
253									off_t size);
254			status_t			_ShrinkStream(Transaction& transaction,
255									off_t size);
256
257private:
258			rw_lock				fLock;
259			Volume*				fVolume;
260			ino_t				fID;
261			BPlusTree*			fTree;
262			Inode*				fAttributes;
263			void*				fCache;
264			void*				fMap;
265			bfs_inode			fNode;
266
267			off_t				fOldSize;
268			off_t				fOldLastModified;
269				// we need those values to ensure we will remove
270				// the correct keys from the indices
271
272			mutable recursive_lock fSmallDataLock;
273			SinglyLinkedList<AttributeIterator> fIterators;
274};
275
276
277/*!	Checks whether or not this node should be part of the name index */
278inline bool
279Inode::InNameIndex() const
280{
281	return IsRegularNode();
282}
283
284
285/*!	Checks whether or not this node should be part of the size index */
286inline bool
287Inode::InSizeIndex() const
288{
289	return IsFile();
290}
291
292
293/*!	Checks whether or not this node should be part of the last modified index */
294inline bool
295Inode::InLastModifiedIndex() const
296{
297	return IsFile() || IsSymLink();
298}
299
300
301#if _KERNEL_MODE && KDEBUG
302#	define ASSERT_READ_LOCKED_INODE(inode) inode->AssertReadLocked()
303#	define ASSERT_WRITE_LOCKED_INODE(inode) inode->AssertWriteLocked()
304#else
305#	define ASSERT_READ_LOCKED_INODE(inode)
306#	define ASSERT_WRITE_LOCKED_INODE(inode)
307#endif
308
309
310class InodeReadLocker {
311public:
312	InodeReadLocker(Inode* inode)
313		:
314		fLock(&inode->Lock())
315	{
316		rw_lock_read_lock(fLock);
317	}
318
319	~InodeReadLocker()
320	{
321		if (fLock != NULL)
322			rw_lock_read_unlock(fLock);
323	}
324
325	void Unlock()
326	{
327		if (fLock != NULL) {
328			rw_lock_read_unlock(fLock);
329			fLock = NULL;
330		}
331	}
332
333private:
334	rw_lock*	fLock;
335};
336
337
338class NodeGetter : public CachedBlock {
339public:
340	NodeGetter(Volume* volume)
341		:
342		CachedBlock(volume)
343	{
344	}
345
346	~NodeGetter()
347	{
348	}
349
350	status_t SetTo(const Inode* inode)
351	{
352		return CachedBlock::SetTo(fVolume->VnodeToBlock(inode->ID()));
353	}
354
355	status_t SetToWritable(Transaction& transaction, const Inode* inode,
356		bool empty = false)
357	{
358		return CachedBlock::SetToWritable(transaction,
359			fVolume->VnodeToBlock(inode->ID()), empty);
360	}
361
362	const bfs_inode* Node() const { return (const bfs_inode*)Block(); }
363	bfs_inode* WritableNode() const { return (bfs_inode*)Block();  }
364};
365
366
367// The Vnode class provides a convenience layer upon get_vnode(), so that
368// you don't have to call put_vnode() anymore, which may make code more
369// readable in some cases
370
371class Vnode {
372public:
373	Vnode(Volume* volume, ino_t id)
374		:
375		fInode(NULL)
376	{
377		SetTo(volume, id);
378	}
379
380	Vnode(Volume* volume, block_run run)
381		:
382		fInode(NULL)
383	{
384		SetTo(volume, run);
385	}
386
387	Vnode()
388		:
389		fStatus(B_NO_INIT),
390		fInode(NULL)
391	{
392	}
393
394	~Vnode()
395	{
396		Unset();
397	}
398
399	status_t InitCheck()
400	{
401		return fStatus;
402	}
403
404	void Unset()
405	{
406		if (fInode != NULL) {
407			put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
408			fInode = NULL;
409			fStatus = B_NO_INIT;
410		}
411	}
412
413	status_t SetTo(Volume* volume, ino_t id)
414	{
415		Unset();
416
417		return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
418	}
419
420	status_t SetTo(Volume* volume, block_run run)
421	{
422		return SetTo(volume, volume->ToVnode(run));
423	}
424
425	status_t Get(Inode** _inode)
426	{
427		*_inode = fInode;
428		return fStatus;
429	}
430
431	void Keep()
432	{
433		fInode = NULL;
434	}
435
436private:
437	status_t	fStatus;
438	Inode*		fInode;
439};
440
441
442class AttributeIterator : public SinglyLinkedListLinkImpl<AttributeIterator> {
443public:
444							AttributeIterator(Inode* inode);
445							~AttributeIterator();
446
447			status_t		Rewind();
448			status_t		GetNext(char* name, size_t* length, uint32* type,
449								ino_t* id);
450
451private:
452	friend class Inode;
453
454			void			Update(uint16 index, int8 change);
455
456private:
457			int32			fCurrentSmallData;
458			Inode*			fInode;
459			Inode*			fAttributes;
460			TreeIterator*	fIterator;
461			void*			fBuffer;
462};
463
464#endif	// INODE_H
465