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