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