xref: /haiku/src/add-ons/kernel/file_systems/bfs/Inode.h (revision b8a45b3a2df2379b4301bf3bd5949b9a105be4ba)
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 
17 class BPlusTree;
18 class TreeIterator;
19 class AttributeIterator;
20 class Index;
21 class InodeAllocator;
22 class NodeGetter;
23 class Transaction;
24 
25 
26 // To be used in Inode::Create() as publishFlags
27 #define BFS_DO_NOT_PUBLISH_VNODE	0x80000000
28 
29 
30 class Inode : public TransactionListener {
31 	typedef DoublyLinkedListLink<Inode> Link;
32 
33 public:
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 
209 protected:
210 	virtual void				TransactionDone(bool success);
211 	virtual void				RemovedFromTransaction();
212 
213 private:
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 
257 private:
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 */
278 inline bool
279 Inode::InNameIndex() const
280 {
281 	return IsRegularNode();
282 }
283 
284 
285 /*!	Checks whether or not this node should be part of the size index */
286 inline bool
287 Inode::InSizeIndex() const
288 {
289 	return IsFile();
290 }
291 
292 
293 /*!	Checks whether or not this node should be part of the last modified index */
294 inline bool
295 Inode::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 
310 class InodeReadLocker {
311 public:
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 
333 private:
334 	rw_lock*	fLock;
335 };
336 
337 
338 class NodeGetter : public CachedBlock {
339 public:
340 	NodeGetter(Volume* volume = NULL)
341 		:
342 		CachedBlock(volume)
343 	{
344 	}
345 
346 	~NodeGetter()
347 	{
348 	}
349 
350 	status_t SetTo(const Inode* inode)
351 	{
352 		Unset();
353 		fVolume = inode->GetVolume();
354 		return CachedBlock::SetTo(fVolume->VnodeToBlock(inode->ID()));
355 	}
356 
357 	status_t SetToWritable(Transaction& transaction, const Inode* inode,
358 		bool empty = false)
359 	{
360 		return CachedBlock::SetToWritable(transaction,
361 			fVolume->VnodeToBlock(inode->ID()), empty);
362 	}
363 
364 	const bfs_inode* Node() const { return (const bfs_inode*)Block(); }
365 	bfs_inode* WritableNode() const { return (bfs_inode*)Block();  }
366 };
367 
368 
369 // The Vnode class provides a convenience layer upon get_vnode(), so that
370 // you don't have to call put_vnode() anymore, which may make code more
371 // readable in some cases
372 
373 class Vnode {
374 public:
375 	Vnode(Volume* volume, ino_t id)
376 		:
377 		fInode(NULL)
378 	{
379 		SetTo(volume, id);
380 	}
381 
382 	Vnode(Volume* volume, block_run run)
383 		:
384 		fInode(NULL)
385 	{
386 		SetTo(volume, run);
387 	}
388 
389 	Vnode()
390 		:
391 		fStatus(B_NO_INIT),
392 		fInode(NULL)
393 	{
394 	}
395 
396 	~Vnode()
397 	{
398 		Unset();
399 	}
400 
401 	status_t InitCheck()
402 	{
403 		return fStatus;
404 	}
405 
406 	void Unset()
407 	{
408 		if (fInode != NULL) {
409 			put_vnode(fInode->GetVolume()->FSVolume(), fInode->ID());
410 			fInode = NULL;
411 			fStatus = B_NO_INIT;
412 		}
413 	}
414 
415 	status_t SetTo(Volume* volume, ino_t id)
416 	{
417 		Unset();
418 
419 		return fStatus = get_vnode(volume->FSVolume(), id, (void**)&fInode);
420 	}
421 
422 	status_t SetTo(Volume* volume, block_run run)
423 	{
424 		return SetTo(volume, volume->ToVnode(run));
425 	}
426 
427 	status_t Get(Inode** _inode)
428 	{
429 		*_inode = fInode;
430 		return fStatus;
431 	}
432 
433 	void Keep()
434 	{
435 		fInode = NULL;
436 	}
437 
438 private:
439 	status_t	fStatus;
440 	Inode*		fInode;
441 };
442 
443 
444 class AttributeIterator : public SinglyLinkedListLinkImpl<AttributeIterator> {
445 public:
446 							AttributeIterator(Inode* inode);
447 							~AttributeIterator();
448 
449 			status_t		Rewind();
450 			status_t		GetNext(char* name, size_t* length, uint32* type,
451 								ino_t* id);
452 
453 private:
454 	friend class Inode;
455 
456 			void			Update(uint16 index, int8 change);
457 
458 private:
459 			int32			fCurrentSmallData;
460 			Inode*			fInode;
461 			Inode*			fAttributes;
462 			TreeIterator*	fIterator;
463 			void*			fBuffer;
464 };
465 
466 #endif	// INODE_H
467