1/*
2** Copyright 2003, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3** Distributed under the terms of the MIT License.
4*/
5#ifndef AMIGA_FFS_H
6#define AMIGA_FFS_H
7
8
9#include <SupportDefs.h>
10#include <ByteOrder.h>
11
12
13namespace FFS {
14
15/** The base class for all FFS blocks */
16
17class BaseBlock{
18	public:
19		BaseBlock() : fData(NULL) {}
20		BaseBlock(void *data, int32 blockSize) { SetTo(data, blockSize); }
21		BaseBlock(int32 blockSize) { fSize = blockSize >> 2; }
22
23		void SetTo(void *data, int32 blockSize) { fData = (int32 *)data; fSize = blockSize >> 2; }
24		void SetTo(void *data) { fData = (int32 *)data; }
25
26		int32 *BlockData() const { return fData; }
27		int32 BlockSize() const { return fSize << 2; }
28		int32 LongWords() const { return fSize; }
29
30		int32 PrimaryType() const { return Offset(0); }
31		int32 SecondaryType() const { return BackOffset(1); }
32		int32 CheckSum() const { return Offset(5); }
33
34		inline bool IsRootBlock() const;
35		inline bool IsDirectory() const;
36		inline bool IsFile() const;
37		inline bool IsExtensionBlock() const;
38		inline bool IsDirectoryLink() const;
39		inline bool IsFileLink() const;
40		inline bool IsSymbolicLink() const;
41
42		status_t ValidateCheckSum() const;
43
44	protected:
45		int32 Offset(int16 i) const { return B_BENDIAN_TO_HOST_INT32(fData[i]); }
46		int32 BackOffset(int16 i) const { return B_BENDIAN_TO_HOST_INT32(fData[fSize - i]); }
47
48		status_t GetNameBackOffset(int32 offset, char *name, size_t size) const;
49
50	private:
51		int32	fSize;
52		int32	*fData;
53};
54
55
56/** The base class for all blocks that represent files and directories
57 *	(all blocks that are accessible to the user)
58 */
59
60class NodeBlock : public BaseBlock {
61	public:
62		NodeBlock() {}
63		NodeBlock(int32 blockSize) : BaseBlock(blockSize) {}
64		NodeBlock(void *data, int32 blockSize) : BaseBlock(data, blockSize) {}
65
66		int32 HeaderKey() const { return Offset(1); }
67		int32 Protection() const { return BackOffset(48); }
68
69		int32 Days() const { return BackOffset(23); }
70		int32 Minute() const { return BackOffset(22); }
71		int32 Ticks() const { return BackOffset(21); }
72
73		status_t GetName(char *name, size_t size) const { return GetNameBackOffset(20, name, size); }
74
75		int32 LinkChain() const { return BackOffset(10); }
76		int32 HashChain() const { return BackOffset(4); }
77
78		int32 Parent() const { return BackOffset(3); }
79};
80
81
82/** A standard user directory block */
83
84class DirectoryBlock : public NodeBlock {
85	public:
86		DirectoryBlock() : NodeBlock() {}
87		DirectoryBlock(int32 blockSize) : NodeBlock(blockSize) {}
88		DirectoryBlock(void *data, int32 blockSize) : NodeBlock(data, blockSize) {}
89
90		char ToUpperChar(int32 type, char c) const;
91		int32 HashIndexFor(int32 type, const char *name) const;
92
93		int32 HashValueAt(int32 index) const;
94		int32 NextHashValue(int32 &index) const;
95		int32 FirstHashValue(int32 &index) const;
96
97	protected:
98		int32 *HashTable() const { return BlockData() + 6; }
99		int32 HashSize() const { return LongWords() - 56; }
100};
101
102
103/** The root block of the device and at the same time the root directory */
104
105class RootBlock : public DirectoryBlock {
106	public:
107		RootBlock() : DirectoryBlock() {}
108		RootBlock(int32 blockSize) : DirectoryBlock(blockSize) {}
109		RootBlock(void *data, int32 blockSize) : DirectoryBlock(data, blockSize) {}
110
111		int32 BitmapFlag() const { return BackOffset(50); }
112		int32 BitmapExtension() const { return BackOffset(24); }
113
114		int32 VolumeDays() const { return BackOffset(10); }
115		int32 VolumeMinutes() const { return BackOffset(9); }
116		int32 VolumeTicks() const { return BackOffset(8); }
117
118		int32 CreationDays() const { return BackOffset(7); }
119		int32 CreationMinutes() const { return BackOffset(6); }
120		int32 CreationTicks() const { return BackOffset(5); }
121};
122
123
124/** A standard user file block */
125
126class FileBlock : public NodeBlock {
127	public:
128		FileBlock() : NodeBlock() {}
129		FileBlock(int32 blockSize) : NodeBlock(blockSize) {}
130		FileBlock(void *data, int32 blockSize) : NodeBlock(data, blockSize) {}
131
132		int32 BlockCount() const { return Offset(2); }
133		int32 FirstData() const { return Offset(4); }
134		int32 Size() const { return BackOffset(47); }
135		int32 NextExtension() const { return BackOffset(2); }
136			// The extension block is handled by this class as well
137
138		int32 DataBlock(int32 index) const { return BackOffset(51 + index); }
139		int32 NumDataBlocks() const { return LongWords() - 56; }
140};
141
142class HashIterator {
143	public:
144		HashIterator(int32 device, DirectoryBlock &node);
145		~HashIterator();
146
147		status_t InitCheck();
148		void Goto(int32 index);
149		NodeBlock *GetNext(int32 &block);
150		void Rewind();
151
152	private:
153		DirectoryBlock	&fDirectory;
154		int32		fDevice;
155		int32		fCurrent;
156		int32		fBlock;
157		NodeBlock	fNode;
158		int32		*fData;
159};
160
161enum primary_types {
162	PT_SHORT			= 2,
163	PT_DATA				= 8,
164	PT_LIST				= 16,
165};
166
167enum secondary_types {
168	ST_ROOT				= 1,
169	ST_DIRECTORY		= 2,
170	ST_FILE				= -3,
171	ST_DIRECTORY_LINK	= 4,
172	ST_FILE_LINK		= -4,
173	ST_SOFT_LINK		= 3
174};
175
176enum dos_types {
177	DT_AMIGA_OFS			= 'DOS\0',
178	DT_AMIGA_FFS			= 'DOS\1',
179	DT_AMIGA_FFS_INTL		= 'DOS\2',
180	DT_AMIGA_FFS_DCACHE		= 'DOS\3',
181};
182
183enum protection_flags {
184	FILE_IS_DELETABLE	= 1,
185	FILE_IS_EXECUTABLE	= 2,
186	FILE_IS_READABLE	= 4,
187	FILE_IS_WRITABLE	= 8,
188	FILE_IS_ARCHIVED	= 16,
189	FILE_IS_PURE		= 32,
190	FILE_IS_SCRIPT		= 64,
191	FILE_IS_HOLD		= 128,
192};
193
194enum name_lengths {
195	FFS_NAME_LENGTH		= 30,
196	COMMENT_LENGTH		= 79,
197};
198
199status_t get_root_block(int fDevice, char *buffer, int32 blockSize, off_t partitionSize);
200
201//	inline methods
202
203inline bool
204BaseBlock::IsRootBlock() const
205{
206	return PrimaryType() == PT_SHORT && SecondaryType() == ST_ROOT;
207}
208
209
210inline bool
211BaseBlock::IsDirectory() const
212{
213	return PrimaryType() == PT_SHORT && SecondaryType() == ST_DIRECTORY;
214}
215
216
217inline bool
218BaseBlock::IsFile() const
219{
220	return PrimaryType() == PT_SHORT && SecondaryType() == ST_FILE;
221}
222
223
224inline bool
225BaseBlock::IsExtensionBlock() const
226{
227	return PrimaryType() == PT_LIST && SecondaryType() == ST_FILE;
228}
229
230
231inline bool
232BaseBlock::IsDirectoryLink() const
233{
234	return PrimaryType() == PT_SHORT && SecondaryType() == ST_DIRECTORY_LINK;
235}
236
237
238inline bool
239BaseBlock::IsFileLink() const
240{
241	return PrimaryType() == PT_SHORT && SecondaryType() == ST_FILE_LINK;
242}
243
244
245inline bool
246BaseBlock::IsSymbolicLink() const
247{
248	return PrimaryType() == PT_SHORT && SecondaryType() == ST_SOFT_LINK;
249}
250
251}	// namespace FFS
252
253#endif	/* AMIGA_FFS_H */
254
255