xref: /haiku/src/add-ons/kernel/file_systems/bfs/Inode.h (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /* Inode - inode access functions
2  *
3  * Copyright 2001-2006, Axel Dörfler, axeld@pinc-software.de.
4  * This file may be used under the terms of the MIT License.
5  */
6 #ifndef INODE_H
7 #define INODE_H
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 #include <string.h>
21 #include <unistd.h>
22 
23 #include "Volume.h"
24 #include "Journal.h"
25 #include "Lock.h"
26 #include "Chain.h"
27 #include "Debug.h"
28 #include "CachedBlock.h"
29 
30 
31 class BPlusTree;
32 class TreeIterator;
33 class AttributeIterator;
34 class InodeAllocator;
35 class NodeGetter;
36 
37 
38 enum inode_type {
39 	S_DIRECTORY		= S_IFDIR,
40 	S_FILE			= S_IFREG,
41 	S_SYMLINK		= S_IFLNK,
42 
43 	S_INDEX_TYPES	= (S_STR_INDEX | S_INT_INDEX | S_UINT_INDEX | S_LONG_LONG_INDEX
44 						| S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX)
45 };
46 
47 class Inode {
48 	public:
49 		Inode(Volume *volume, vnode_id id);
50 		Inode(Volume *volume, Transaction &transaction, vnode_id id, mode_t mode, block_run &run);
51 		//Inode(CachedBlock *cached);
52 		~Inode();
53 
54 		//bfs_inode *Node() const { return (bfs_inode *)fBlock; }
55 		vnode_id ID() const { return fID; }
56 		off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); }
57 
58 		ReadWriteLock &Lock() { return fLock; }
59 		SimpleLock &SmallDataLock() { return fSmallDataLock; }
60 		status_t WriteBack(Transaction &transaction);
61 
62 		bool IsContainer() const { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); }
63 			// note, that this test will also be true for S_IFBLK (not that it's used in the fs :)
64 		bool IsDirectory() const { return (Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY; }
65 		bool IsIndex() const { return (Mode() & (S_INDEX_DIR | 0777)) == S_INDEX_DIR; }
66 			// that's a stupid check, but AFAIK the only possible method...
67 
68 		bool IsAttributeDirectory() const { return (Mode() & S_ATTR_DIR) != 0; }
69 		bool IsAttribute() const { return (Mode() & S_ATTR) != 0; }
70 		bool IsFile() const { return (Mode() & (S_IFMT | S_ATTR)) == S_FILE; }
71 		bool IsRegularNode() const { return (Mode() & (S_ATTR_DIR | S_INDEX_DIR | S_ATTR)) == 0; }
72 			// a regular node in the standard namespace (i.e. not an index or attribute)
73 		bool IsSymLink() const { return S_ISLNK(Mode()); }
74 		bool HasUserAccessableStream() const { return IsFile(); }
75 			// currently only files can be accessed with bfs_read()/bfs_write()
76 
77 		bool IsDeleted() const { return (Flags() & INODE_DELETED) != 0; }
78 
79 		mode_t Mode() const { return fNode.Mode(); }
80 		uint32 Type() const { return fNode.Type(); }
81 		int32 Flags() const { return fNode.Flags(); }
82 
83 		off_t Size() const { return fNode.data.Size(); }
84 		off_t LastModified() const { return fNode.last_modified_time; }
85 
86 		const block_run &BlockRun() const { return fNode.inode_num; }
87 		block_run &Parent() { return fNode.parent; }
88 		block_run &Attributes() { return fNode.attributes; }
89 
90 		Volume *GetVolume() const { return fVolume; }
91 
92 		status_t InitCheck(bool checkNode = true);
93 
94 		status_t CheckPermissions(int accessMode) const;
95 
96 		// small_data access methods
97 		status_t MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const char *name, int32 length);
98 		status_t RemoveSmallData(Transaction &transaction, NodeGetter &node, const char *name);
99 		status_t AddSmallData(Transaction &transaction, NodeGetter &node, const char *name, uint32 type,
100 					const uint8 *data, size_t length, bool force = false);
101 		status_t GetNextSmallData(bfs_inode *node, small_data **_smallData) const;
102 		small_data *FindSmallData(const bfs_inode *node, const char *name) const;
103 		const char *Name(const bfs_inode *node) const;
104 		status_t GetName(char *buffer, size_t bufferSize = B_FILE_NAME_LENGTH) const;
105 		status_t SetName(Transaction &transaction, const char *name);
106 
107 		// high-level attribute methods
108 		status_t ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer, size_t *_length);
109 		status_t WriteAttribute(Transaction &transaction, const char *name, int32 type, off_t pos, const uint8 *buffer, size_t *_length);
110 		status_t RemoveAttribute(Transaction &transaction, const char *name);
111 
112 		// attribute methods
113 		status_t GetAttribute(const char *name, Inode **attribute);
114 		void ReleaseAttribute(Inode *attribute);
115 		status_t CreateAttribute(Transaction &transaction, const char *name, uint32 type, Inode **attribute);
116 
117 		// for directories only:
118 		status_t GetTree(BPlusTree **);
119 		bool IsEmpty();
120 
121 		// manipulating the data stream
122 		status_t FindBlockRun(off_t pos, block_run &run, off_t &offset);
123 
124 		status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
125 		status_t WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer, size_t *length);
126 		status_t FillGapWithZeros(off_t oldSize, off_t newSize);
127 
128 		status_t SetFileSize(Transaction &transaction, off_t size);
129 		status_t Append(Transaction &transaction, off_t bytes);
130 		status_t TrimPreallocation(Transaction &transaction);
131 		bool NeedsTrimming();
132 
133 		status_t Free(Transaction &transaction);
134 		status_t Sync();
135 
136 		bfs_inode &Node() { return fNode; }
137 
138 		// create/remove inodes
139 		status_t Remove(Transaction &transaction, const char *name, off_t *_id = NULL,
140 					bool isDirectory = false);
141 		static status_t Create(Transaction &transaction, Inode *parent, const char *name,
142 					int32 mode, int omode, uint32 type, off_t *_id = NULL, Inode **_inode = NULL);
143 
144 		// index maintaining helper
145 		void UpdateOldSize() { fOldSize = Size(); }
146 		void UpdateOldLastModified() { fOldLastModified = Node().LastModifiedTime(); }
147 		off_t OldSize() { return fOldSize; }
148 		off_t OldLastModified() { return fOldLastModified; }
149 
150 		// file cache
151 		void *FileCache() const { return fCache; }
152 		void SetFileCache(void *cache) { fCache = cache; }
153 
154 	private:
155 		Inode(const Inode &);
156 		Inode &operator=(const Inode &);
157 			// no implementation
158 
159 		friend class AttributeIterator;
160 		friend class InodeAllocator;
161 
162 		status_t _RemoveSmallData(bfs_inode *node, small_data *item, int32 index);
163 
164 		void _AddIterator(AttributeIterator *iterator);
165 		void _RemoveIterator(AttributeIterator *iterator);
166 
167 		status_t _FreeStaticStreamArray(Transaction &transaction, int32 level,
168 					block_run run, off_t size, off_t offset, off_t &max);
169 		status_t _FreeStreamArray(Transaction &transaction, block_run *array,
170 					uint32 arrayLength, off_t size, off_t &offset, off_t &max);
171 		status_t _AllocateBlockArray(Transaction &transaction, block_run &run);
172 		status_t _GrowStream(Transaction &transaction, off_t size);
173 		status_t _ShrinkStream(Transaction &transaction, off_t size);
174 
175 	private:
176 		ReadWriteLock	fLock;
177 		Volume			*fVolume;
178 		vnode_id		fID;
179 		BPlusTree		*fTree;
180 		Inode			*fAttributes;
181 		void			*fCache;
182 		bfs_inode		fNode;
183 		off_t			fOldSize;			// we need those values to ensure we will remove
184 		off_t			fOldLastModified;	// the correct keys from the indices
185 
186 		mutable SimpleLock	fSmallDataLock;
187 		Chain<AttributeIterator> fIterators;
188 };
189 
190 
191 class NodeGetter : public CachedBlock {
192 	public:
193 		NodeGetter(Volume *volume)
194 			: CachedBlock(volume)
195 		{
196 		}
197 
198 		NodeGetter(Volume *volume, const Inode *inode)
199 			: CachedBlock(volume)
200 		{
201 			SetTo(volume->VnodeToBlock(inode->ID()));
202 		}
203 
204 		NodeGetter(Volume *volume, Transaction &transaction, const Inode *inode, bool empty = false)
205 			: CachedBlock(volume)
206 		{
207 			SetToWritable(transaction, volume->VnodeToBlock(inode->ID()), empty);
208 		}
209 
210 		~NodeGetter()
211 		{
212 		}
213 
214 		const bfs_inode *
215 		SetToNode(const Inode *inode)
216 		{
217 			return (const bfs_inode *)SetTo(fVolume->VnodeToBlock(inode->ID()));
218 		}
219 
220 		const bfs_inode *Node() const { return (const bfs_inode *)Block(); }
221 		bfs_inode *WritableNode() const { return (bfs_inode *)Block();  }
222 };
223 
224 
225 // The Vnode class provides a convenience layer upon get_vnode(), so that
226 // you don't have to call put_vnode() anymore, which may make code more
227 // readable in some cases
228 
229 class Vnode {
230 	public:
231 		Vnode(Volume *volume, vnode_id id)
232 			:
233 			fVolume(volume),
234 			fID(id)
235 		{
236 		}
237 
238 		Vnode(Volume *volume, block_run run)
239 			:
240 			fVolume(volume),
241 			fID(volume->ToVnode(run))
242 		{
243 		}
244 
245 		~Vnode()
246 		{
247 			Put();
248 		}
249 
250 		status_t Get(Inode **_inode)
251 		{
252 			// should we check inode against NULL here? it should not be necessary
253 #ifdef UNSAFE_GET_VNODE
254 			RecursiveLocker locker(fVolume->Lock());
255 #endif
256 			return get_vnode(fVolume->ID(), fID, (void **)_inode);
257 		}
258 
259 		void Put()
260 		{
261 			if (fVolume)
262 				put_vnode(fVolume->ID(), fID);
263 			fVolume = NULL;
264 		}
265 
266 		void Keep()
267 		{
268 			fVolume = NULL;
269 		}
270 
271 	private:
272 		Volume		*fVolume;
273 		vnode_id	fID;
274 };
275 
276 
277 class AttributeIterator {
278 	public:
279 		AttributeIterator(Inode *inode);
280 		~AttributeIterator();
281 
282 		status_t Rewind();
283 		status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id);
284 
285 	private:
286 		friend class Chain<AttributeIterator>;
287 		friend class Inode;
288 
289 		void Update(uint16 index, int8 change);
290 		AttributeIterator *fNext;
291 
292 	private:
293 		int32		fCurrentSmallData;
294 		Inode		*fInode, *fAttributes;
295 		TreeIterator *fIterator;
296 		void		*fBuffer;
297 };
298 
299 
300 /**	Converts the open mode, the open flags given to bfs_open(), into
301  *	access modes, e.g. since O_RDONLY requires read access to the
302  *	file, it will be converted to R_OK.
303  */
304 
305 inline int
306 openModeToAccess(int openMode)
307 {
308 	openMode &= O_RWMASK;
309 	if (openMode == O_RDONLY)
310 		return R_OK;
311 	else if (openMode == O_WRONLY)
312 		return W_OK;
313 
314 	return R_OK | W_OK;
315 }
316 
317 #endif	/* INODE_H */
318