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