xref: /haiku/src/add-ons/kernel/file_systems/bfs/Inode.h (revision 5d9e40fe9252c8f9c5e5e41594545bfa4419fcc7)
1 #ifndef INODE_H
2 #define INODE_H
3 /* Inode - inode access functions
4 **
5 ** Initial version by Axel Dörfler, axeld@pinc-software.de
6 ** This file may be used under the terms of the OpenBeOS License.
7 */
8 
9 
10 #include <KernelExport.h>
11 #ifdef USER
12 #	include "myfs.h"
13 #	include <stdio.h>
14 #endif
15 
16 #ifndef _IMPEXP_KERNEL
17 #	define _IMPEXP_KERNEL
18 #endif
19 
20 extern "C" {
21 	#include <lock.h>
22 	#include <cache.h>
23 }
24 
25 #include <string.h>
26 
27 #include "Volume.h"
28 #include "Journal.h"
29 #include "Lock.h"
30 #include "Chain.h"
31 #include "Debug.h"
32 
33 
34 class BPlusTree;
35 class TreeIterator;
36 class AttributeIterator;
37 class InodeAllocator;
38 
39 
40 enum inode_type {
41 	S_DIRECTORY		= S_IFDIR,
42 	S_FILE			= S_IFREG,
43 	S_SYMLINK		= S_IFLNK,
44 
45 	S_REGULAR		= (S_DIRECTORY | S_FILE | S_SYMLINK),
46 	S_INDEX_TYPES	= (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX
47 						| S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX)
48 };
49 
50 
51 // The CachedBlock class is completely implemented as inlines.
52 // It should be used when cache single blocks to make sure they
53 // will be properly released after use (and it's also very
54 // convenient to use them).
55 
56 class CachedBlock {
57 	public:
58 		CachedBlock(Volume *volume);
59 		CachedBlock(Volume *volume, off_t block, bool empty = false);
60 		CachedBlock(Volume *volume, block_run run, bool empty = false);
61 		CachedBlock(CachedBlock *cached);
62 		~CachedBlock();
63 
64 		inline void Keep();
65 		inline void Unset();
66 		inline uint8 *SetTo(off_t block, bool empty = false);
67 		inline uint8 *SetTo(block_run run, bool empty = false);
68 		inline status_t WriteBack(Transaction *transaction);
69 
70 		uint8 *Block() const { return fBlock; }
71 		off_t BlockNumber() const { return fBlockNumber; }
72 		uint32 BlockSize() const { return fVolume->BlockSize(); }
73 		uint32 BlockShift() const { return fVolume->BlockShift(); }
74 
75 	private:
76 		CachedBlock(const CachedBlock &);
77 		CachedBlock &operator=(const CachedBlock &);
78 			// no implementation
79 
80 	protected:
81 		Volume	*fVolume;
82 		off_t	fBlockNumber;
83 		uint8	*fBlock;
84 };
85 
86 //--------------------------------------
87 
88 class Inode : public CachedBlock {
89 	public:
90 		Inode(Volume *volume, vnode_id id, bool empty = false, uint8 reenter = 0);
91 		Inode(CachedBlock *cached);
92 		~Inode();
93 
94 		bfs_inode *Node() const { return (bfs_inode *)fBlock; }
95 		vnode_id ID() const { return fVolume->ToVnode(fBlockNumber); }
96 
97 		ReadWriteLock &Lock() { return fLock; }
98 		SimpleLock &SmallDataLock() { return fSmallDataLock; }
99 
100 		mode_t Mode() const { return Node()->Mode(); }
101 		uint32 Type() const { return Node()->Type(); }
102 		int32 Flags() const { return Node()->Flags(); }
103 		bool IsContainer() const { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); }
104 			// note, that this test will also be true for S_IFBLK (not that it's used in the fs :)
105 		bool IsDirectory() const { return (Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY; }
106 		bool IsIndex() const { return (Mode() & (S_INDEX_DIR | 0777)) == S_INDEX_DIR; }
107 			// that's a stupid check, but AFAIK the only possible method...
108 
109 		bool IsAttribute() const { return Mode() & S_ATTR; }
110 		bool IsFile() const { return Mode() & S_IFREG; }
111 		bool IsRegularNode() const { return (Mode() & (S_ATTR_DIR | S_INDEX_DIR | S_ATTR)) == 0; }
112 			// a regular node in the standard namespace (i.e. not an index or attribute)
113 		bool IsSymLink() const { return S_ISLNK(Mode()); }
114 		bool HasUserAccessableStream() const { return S_ISREG(Mode()); }
115 			// currently only files can be accessed with bfs_read()/bfs_write()
116 
117 		off_t Size() const { return Node()->data.Size(); }
118 		off_t LastModified() const { return Node()->last_modified_time; }
119 
120 		block_run &BlockRun() const { return Node()->inode_num; }
121 		block_run &Parent() const { return Node()->parent; }
122 		block_run &Attributes() const { return Node()->attributes; }
123 		Volume *GetVolume() const { return fVolume; }
124 
125 		status_t InitCheck(bool checkNode = true);
126 
127 		status_t CheckPermissions(int accessMode) const;
128 
129 		// small_data access methods
130 		status_t MakeSpaceForSmallData(Transaction *transaction, const char *name, int32 length);
131 		status_t RemoveSmallData(Transaction *transaction, const char *name);
132 		status_t AddSmallData(Transaction *transaction, const char *name, uint32 type,
133 					const uint8 *data, size_t length, bool force = false);
134 		status_t GetNextSmallData(small_data **_smallData) const;
135 		small_data *FindSmallData(const char *name) const;
136 		const char *Name() const;
137 		status_t GetName(char *buffer) const;
138 		status_t SetName(Transaction *transaction, const char *name);
139 
140 		// high-level attribute methods
141 		status_t ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer, size_t *_length);
142 		status_t WriteAttribute(Transaction *transaction, const char *name, int32 type, off_t pos, const uint8 *buffer, size_t *_length);
143 		status_t RemoveAttribute(Transaction *transaction, const char *name);
144 
145 		// attribute methods
146 		status_t GetAttribute(const char *name, Inode **attribute);
147 		void ReleaseAttribute(Inode *attribute);
148 		status_t CreateAttribute(Transaction *transaction, const char *name, uint32 type, Inode **attribute);
149 
150 		// for directories only:
151 		status_t GetTree(BPlusTree **);
152 		bool IsEmpty();
153 
154 		// manipulating the data stream
155 		status_t FindBlockRun(off_t pos, block_run &run, off_t &offset);
156 
157 		status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
158 		status_t WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer, size_t *length);
159 		status_t FillGapWithZeros(off_t oldSize, off_t newSize);
160 
161 		status_t SetFileSize(Transaction *transaction, off_t size);
162 		status_t Append(Transaction *transaction, off_t bytes);
163 		status_t Trim(Transaction *transaction);
164 
165 		status_t Free(Transaction *transaction);
166 		status_t Sync();
167 
168 		// create/remove inodes
169 		status_t Remove(Transaction *transaction, const char *name, off_t *_id = NULL,
170 					bool isDirectory = false);
171 		static status_t Create(Transaction *transaction, Inode *parent, const char *name,
172 					int32 mode, int omode, uint32 type, off_t *_id = NULL, Inode **_inode = NULL);
173 
174 		// index maintaining helper
175 		void UpdateOldSize() { fOldSize = Size(); }
176 		void UpdateOldLastModified() { fOldLastModified = Node()->LastModifiedTime(); }
177 		off_t OldSize() { return fOldSize; }
178 		off_t OldLastModified() { return fOldLastModified; }
179 
180 	private:
181 		Inode(const Inode &);
182 		Inode &operator=(const Inode &);
183 			// no implementation
184 
185 		friend void dump_inode(Inode &inode);
186 		friend AttributeIterator;
187 		friend InodeAllocator;
188 
189 		void Initialize();
190 
191 		status_t RemoveSmallData(small_data *item, int32 index);
192 
193 		void AddIterator(AttributeIterator *iterator);
194 		void RemoveIterator(AttributeIterator *iterator);
195 
196 		status_t FreeStaticStreamArray(Transaction *transaction, int32 level, block_run run,
197 					off_t size, off_t offset, off_t &max);
198 		status_t FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayLength,
199 					off_t size, off_t &offset, off_t &max);
200 		status_t AllocateBlockArray(Transaction *transaction, block_run &run);
201 		status_t GrowStream(Transaction *transaction, off_t size);
202 		status_t ShrinkStream(Transaction *transaction, off_t size);
203 
204 		BPlusTree		*fTree;
205 		Inode			*fAttributes;
206 		ReadWriteLock	fLock;
207 		off_t			fOldSize;			// we need those values to ensure we will remove
208 		off_t			fOldLastModified;	// the correct keys from the indices
209 
210 		mutable SimpleLock	fSmallDataLock;
211 		Chain<AttributeIterator> fIterators;
212 };
213 
214 
215 // The Vnode class provides a convenience layer upon get_vnode(), so that
216 // you don't have to call put_vnode() anymore, which may make code more
217 // readable in some cases
218 
219 class Vnode {
220 	public:
221 		Vnode(Volume *volume, vnode_id id)
222 			:
223 			fVolume(volume),
224 			fID(id)
225 		{
226 		}
227 
228 		Vnode(Volume *volume, block_run run)
229 			:
230 			fVolume(volume),
231 			fID(volume->ToVnode(run))
232 		{
233 		}
234 
235 		~Vnode()
236 		{
237 			Put();
238 		}
239 
240 		status_t Get(Inode **inode)
241 		{
242 			// should we check inode against NULL here? it should not be necessary
243 #ifdef UNSAFE_GET_VNODE
244 			RecursiveLocker locker(fVolume->Lock());
245 #endif
246 			return get_vnode(fVolume->ID(), fID, (void **)inode);
247 		}
248 
249 		void Put()
250 		{
251 			if (fVolume)
252 				put_vnode(fVolume->ID(), fID);
253 			fVolume = NULL;
254 		}
255 
256 		void Keep()
257 		{
258 			fVolume = NULL;
259 		}
260 
261 	private:
262 		Volume		*fVolume;
263 		vnode_id	fID;
264 };
265 
266 
267 class AttributeIterator {
268 	public:
269 		AttributeIterator(Inode *inode);
270 		~AttributeIterator();
271 
272 		status_t Rewind();
273 		status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id);
274 
275 	private:
276 		int32		fCurrentSmallData;
277 		Inode		*fInode, *fAttributes;
278 		TreeIterator *fIterator;
279 		void		*fBuffer;
280 
281 	private:
282 		friend Chain<AttributeIterator>;
283 		friend Inode;
284 
285 		void Update(uint16 index, int8 change);
286 		AttributeIterator *fNext;
287 };
288 
289 
290 //--------------------------------------
291 // inlines
292 
293 
294 inline
295 CachedBlock::CachedBlock(Volume *volume)
296 	:
297 	fVolume(volume),
298 	fBlock(NULL)
299 {
300 }
301 
302 
303 inline
304 CachedBlock::CachedBlock(Volume *volume, off_t block, bool empty)
305 	:
306 	fVolume(volume),
307 	fBlock(NULL)
308 {
309 	SetTo(block, empty);
310 }
311 
312 
313 inline
314 CachedBlock::CachedBlock(Volume *volume, block_run run, bool empty)
315 	:
316 	fVolume(volume),
317 	fBlock(NULL)
318 {
319 	SetTo(volume->ToBlock(run), empty);
320 }
321 
322 
323 inline
324 CachedBlock::CachedBlock(CachedBlock *cached)
325 	:
326 	fVolume(cached->fVolume),
327 	fBlockNumber(cached->BlockNumber()),
328 	fBlock(cached->fBlock)
329 {
330 	cached->Keep();
331 }
332 
333 
334 inline
335 CachedBlock::~CachedBlock()
336 {
337 	Unset();
338 }
339 
340 
341 inline void
342 CachedBlock::Keep()
343 {
344 	fBlock = NULL;
345 }
346 
347 
348 inline void
349 CachedBlock::Unset()
350 {
351 	if (fBlock != NULL)
352 		release_block(fVolume->Device(), fBlockNumber);
353 }
354 
355 
356 inline uint8 *
357 CachedBlock::SetTo(off_t block, bool empty)
358 {
359 	Unset();
360 	fBlockNumber = block;
361 	return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(), block, BlockSize())
362 						  : (uint8 *)get_block(fVolume->Device(), block, BlockSize());
363 }
364 
365 
366 inline uint8 *
367 CachedBlock::SetTo(block_run run, bool empty)
368 {
369 	return SetTo(fVolume->ToBlock(run), empty);
370 }
371 
372 
373 inline status_t
374 CachedBlock::WriteBack(Transaction *transaction)
375 {
376 	if (transaction == NULL || fBlock == NULL)
377 		RETURN_ERROR(B_BAD_VALUE);
378 
379 	return transaction->WriteBlocks(fBlockNumber, fBlock);
380 }
381 
382 
383 /**	Converts the "omode", the open flags given to bfs_open(), into
384  *	access modes, e.g. since O_RDONLY requires read access to the
385  *	file, it will be converted to R_OK.
386  */
387 
388 inline int
389 oModeToAccess(int omode)
390 {
391 	omode &= O_RWMASK;
392 	if (omode == O_RDONLY)
393 		return R_OK;
394 	else if (omode == O_WRONLY)
395 		return W_OK;
396 
397 	return R_OK | W_OK;
398 }
399 
400 #endif	/* INODE_H */
401