xref: /haiku/src/add-ons/kernel/file_systems/bfs/Inode.h (revision 51978af14a173e7fae0563b562be5603bc652aeb)
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 AttributeIterator;
186 		friend InodeAllocator;
187 
188 		void Initialize();
189 
190 		status_t RemoveSmallData(small_data *item, int32 index);
191 
192 		void AddIterator(AttributeIterator *iterator);
193 		void RemoveIterator(AttributeIterator *iterator);
194 
195 		status_t FreeStaticStreamArray(Transaction *transaction, int32 level, block_run run,
196 					off_t size, off_t offset, off_t &max);
197 		status_t FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayLength,
198 					off_t size, off_t &offset, off_t &max);
199 		status_t AllocateBlockArray(Transaction *transaction, block_run &run);
200 		status_t GrowStream(Transaction *transaction, off_t size);
201 		status_t ShrinkStream(Transaction *transaction, off_t size);
202 
203 		BPlusTree		*fTree;
204 		Inode			*fAttributes;
205 		ReadWriteLock	fLock;
206 		off_t			fOldSize;			// we need those values to ensure we will remove
207 		off_t			fOldLastModified;	// the correct keys from the indices
208 
209 		mutable SimpleLock	fSmallDataLock;
210 		Chain<AttributeIterator> fIterators;
211 };
212 
213 
214 // The Vnode class provides a convenience layer upon get_vnode(), so that
215 // you don't have to call put_vnode() anymore, which may make code more
216 // readable in some cases
217 
218 class Vnode {
219 	public:
220 		Vnode(Volume *volume, vnode_id id)
221 			:
222 			fVolume(volume),
223 			fID(id)
224 		{
225 		}
226 
227 		Vnode(Volume *volume, block_run run)
228 			:
229 			fVolume(volume),
230 			fID(volume->ToVnode(run))
231 		{
232 		}
233 
234 		~Vnode()
235 		{
236 			Put();
237 		}
238 
239 		status_t Get(Inode **inode)
240 		{
241 			// should we check inode against NULL here? it should not be necessary
242 			return get_vnode(fVolume->ID(), fID, (void **)inode);
243 		}
244 
245 		void Put()
246 		{
247 			if (fVolume)
248 				put_vnode(fVolume->ID(), fID);
249 			fVolume = NULL;
250 		}
251 
252 		void Keep()
253 		{
254 			fVolume = NULL;
255 		}
256 
257 	private:
258 		Volume		*fVolume;
259 		vnode_id	fID;
260 };
261 
262 
263 class AttributeIterator {
264 	public:
265 		AttributeIterator(Inode *inode);
266 		~AttributeIterator();
267 
268 		status_t Rewind();
269 		status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id);
270 
271 	private:
272 		int32		fCurrentSmallData;
273 		Inode		*fInode, *fAttributes;
274 		TreeIterator *fIterator;
275 		void		*fBuffer;
276 
277 	private:
278 		friend Chain<AttributeIterator>;
279 		friend Inode;
280 
281 		void Update(uint16 index, int8 change);
282 		AttributeIterator *fNext;
283 };
284 
285 
286 //--------------------------------------
287 // inlines
288 
289 
290 inline
291 CachedBlock::CachedBlock(Volume *volume)
292 	:
293 	fVolume(volume),
294 	fBlock(NULL)
295 {
296 }
297 
298 
299 inline
300 CachedBlock::CachedBlock(Volume *volume, off_t block, bool empty = false)
301 	:
302 	fVolume(volume),
303 	fBlock(NULL)
304 {
305 	SetTo(block, empty);
306 }
307 
308 
309 inline
310 CachedBlock::CachedBlock(Volume *volume, block_run run, bool empty = false)
311 	:
312 	fVolume(volume),
313 	fBlock(NULL)
314 {
315 	SetTo(volume->ToBlock(run), empty);
316 }
317 
318 
319 inline
320 CachedBlock::CachedBlock(CachedBlock *cached)
321 	:
322 	fVolume(cached->fVolume),
323 	fBlockNumber(cached->BlockNumber()),
324 	fBlock(cached->fBlock)
325 {
326 	cached->Keep();
327 }
328 
329 
330 inline
331 CachedBlock::~CachedBlock()
332 {
333 	Unset();
334 }
335 
336 
337 inline void
338 CachedBlock::Keep()
339 {
340 	fBlock = NULL;
341 }
342 
343 
344 inline void
345 CachedBlock::Unset()
346 {
347 	if (fBlock != NULL)
348 		release_block(fVolume->Device(), fBlockNumber);
349 }
350 
351 
352 inline uint8 *
353 CachedBlock::SetTo(off_t block, bool empty = false)
354 {
355 	Unset();
356 	fBlockNumber = block;
357 	return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(), block, BlockSize())
358 						  : (uint8 *)get_block(fVolume->Device(), block, BlockSize());
359 }
360 
361 
362 inline uint8 *
363 CachedBlock::SetTo(block_run run, bool empty = false)
364 {
365 	return SetTo(fVolume->ToBlock(run), empty);
366 }
367 
368 
369 inline status_t
370 CachedBlock::WriteBack(Transaction *transaction)
371 {
372 	if (transaction == NULL || fBlock == NULL)
373 		RETURN_ERROR(B_BAD_VALUE);
374 
375 	return transaction->WriteBlocks(fBlockNumber, fBlock);
376 }
377 
378 
379 /**	Converts the "omode", the open flags given to bfs_open(), into
380  *	access modes, e.g. since O_RDONLY requires read access to the
381  *	file, it will be converted to R_OK.
382  */
383 
384 inline int
385 oModeToAccess(int omode)
386 {
387 	omode &= O_RWMASK;
388 	if (omode == O_RDONLY)
389 		return R_OK;
390 	else if (omode == O_WRONLY)
391 		return W_OK;
392 
393 	return R_OK | W_OK;
394 }
395 
396 #endif	/* INODE_H */
397