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