1/*
2	Copyright 1999-2001, Be Incorporated.   All Rights Reserved.
3	This file may be used under the terms of the Be Sample Code License.
4*/
5#ifndef _DOSFS_H_
6#define _DOSFS_H_
7
8#if USE_DMALLOC
9	#include <dmalloc.h>
10#else
11
12/* allocate memory from swappable heap */
13#define malloc smalloc
14#define free sfree
15#define calloc scalloc
16#define realloc srealloc
17
18#include <kalloc.h>
19
20#endif
21
22#include <KernelExport.h>
23
24/* for multiple reader/single writer locks */
25#define READERS 100000
26
27/* Unfortunately, vnode_id's are defined as signed. This causes problems with
28 * programs (notably cp) that use the modulo of a vnode_id (or ino_t) as a
29 * hash function to index an array. This means the high bit of every vnode_id
30 * is off-limits. Luckily, FAT32 is actually FAT28, so dosfs can make do with
31 * only 63 bits.
32 */
33#define ARTIFICIAL_VNID_BITS	(0x6LL << 60)
34#define DIR_CLUSTER_VNID_BITS	(0x4LL << 60)
35#define DIR_INDEX_VNID_BITS		0
36#define INVALID_VNID_BITS_MASK	(0x9LL << 60)
37
38#define IS_DIR_CLUSTER_VNID(vnid) \
39	(((vnid) & ARTIFICIAL_VNID_BITS) == DIR_CLUSTER_VNID_BITS)
40
41#define IS_DIR_INDEX_VNID(vnid) \
42	(((vnid) & ARTIFICIAL_VNID_BITS) == DIR_INDEX_VNID_BITS)
43
44#define IS_ARTIFICIAL_VNID(vnid) \
45	(((vnid) & ARTIFICIAL_VNID_BITS) == ARTIFICIAL_VNID_BITS)
46
47#define IS_INVALID_VNID(vnid) \
48	((!IS_DIR_CLUSTER_VNID((vnid)) && \
49	  !IS_DIR_INDEX_VNID((vnid)) && \
50	  !IS_ARTIFICIAL_VNID((vnid))) || \
51	 ((vnid) & INVALID_VNID_BITS_MASK))
52
53#define GENERATE_DIR_INDEX_VNID(dircluster, index) \
54	(DIR_INDEX_VNID_BITS | ((vnode_id)(dircluster) << 32) | (index))
55
56#define GENERATE_DIR_CLUSTER_VNID(dircluster, filecluster) \
57	(DIR_CLUSTER_VNID_BITS | ((vnode_id)(dircluster) << 32) | (filecluster))
58
59#define CLUSTER_OF_DIR_CLUSTER_VNID(vnid) \
60	((uint32)((vnid) & 0xffffffff))
61
62#define INDEX_OF_DIR_INDEX_VNID(vnid) \
63	((uint32)((vnid) & 0xffffffff))
64
65#define DIR_OF_VNID(vnid) \
66	((uint32)(((vnid) >> 32) & ~0xf0000000))
67
68#define VNODE_PARENT_DIR_CLUSTER(vnode) \
69	CLUSTER_OF_DIR_CLUSTER_VNID((vnode)->dir_vnid)
70
71#include <lock.h>
72
73#define VNODE_MAGIC 'treB'
74
75typedef struct vnode
76{
77	uint32		magic;
78	vnode_id	vnid; 			// self id
79	vnode_id 	dir_vnid;		// parent vnode id (directory containing entry)
80
81	uint32		disk_image;		// 0 = no, 1 = BEOS, 2 = IMAGE.BE
82
83	/* iteration is incremented each time the fat chain changes. it's used by
84	 * the file read/write code to determine if it needs to retraverse the
85	 * fat chain
86	 */
87	uint32		iteration;
88
89	/* any changes to this block of information should immediately be reflected
90	 * on the disk (or at least in the cache) so that get_next_dirent continues
91	 * to function properly
92	 */
93	uint32		sindex, eindex;	// starting and ending index of directory entry
94	uint32		cluster;		// starting cluster of the data
95	uint32		mode;			// dos-style attributes
96	off_t		st_size;		// in bytes
97	time_t		st_time;
98
99	uint32		end_cluster;	// last cluster of the data
100
101	const char *mime;			// mime type (null if none)
102
103	bool		dirty;			// track if vnode had been written to
104
105#if TRACK_FILENAME
106	char		*filename;
107#endif
108} vnode;
109
110// mode bits
111#define FAT_READ_ONLY	1
112#define FAT_HIDDEN		2
113#define FAT_SYSTEM		4
114#define FAT_VOLUME		8
115#define FAT_SUBDIR		16
116#define FAT_ARCHIVE		32
117
118#define NSPACE_MAGIC 'smaI'
119
120struct vcache_entry;
121
122typedef struct _nspace
123{
124	uint32	magic;
125	nspace_id		id;				// ID passed in to fs_mount
126	int				fd;				// File descriptor
127	char			device[256];
128	uint32			flags;			// see <fcntl.be.h> for modes
129
130	// info from bpb
131	uint32	bytes_per_sector;
132	uint32	sectors_per_cluster;
133	uint32	reserved_sectors;
134	uint32	fat_count;
135	uint32	root_entries_count;
136	uint32	total_sectors;
137	uint32	sectors_per_fat;
138	uint8	media_descriptor;
139	uint16	fsinfo_sector;
140
141	uint32	total_clusters;			// data clusters, that is
142	uint32	free_clusters;
143	uint8	fat_bits;
144	bool	fat_mirrored;			// true if fat mirroring on
145	uint8	active_fat;
146
147	uint32  root_start;				// for fat12 + fat16 only
148	uint32	root_sectors;			// for fat12 + fat16 only
149	vnode	root_vnode;				// root directory
150	int32	vol_entry;				// index in root directory
151	char	vol_label[12];			// lfn's need not apply
152
153	uint32	data_start;
154	uint32  last_allocated;			// last allocated cluster
155
156	vnode_id beos_vnid;				// vnid of \BEOS directory
157	bool	respect_disk_image;
158
159	int		fs_flags;				// flags for this mount
160
161	lock	vlock;					// volume lock
162
163	// vcache state
164	struct {
165		sem_id vc_sem;
166		vnode_id cur_vnid;
167		uint32 cache_size;
168		struct vcache_entry **by_vnid, **by_loc;
169	} vcache;
170
171	struct {
172		uint32	entries;
173		uint32	allocated;
174		vnode_id *vnid_list;
175	} dlist;
176} nspace;
177
178#define FS_FLAGS_OP_SYNC       0x1
179#define FS_FLAGS_LOCK_DOOR     0x2
180
181#define LOCK_VOL(vol) \
182	if (vol == NULL) { dprintf("null vol\n"); return EINVAL; } else LOCK((vol)->vlock)
183
184#define UNLOCK_VOL(vol) \
185	UNLOCK((vol)->vlock)
186
187#define CHECK_MAGIC(name,struc,magick) \
188	int check_##name##_magic(struc *t, char *funcname) \
189	{ \
190		if (t == NULL) { \
191			dprintf("%s passed null " #name " pointer\n", funcname); \
192			return EINVAL; \
193		} else if (t->magic != magick) { \
194			dprintf(#name " (%x) passed to %s has invalid magic number\n", (int)t, funcname); \
195			return EINVAL; \
196		} else \
197			return 0; \
198	}
199
200int check_vnode_magic(struct vnode *t, char *funcname);
201int check_nspace_magic(struct _nspace *t, char *funcname);
202
203#define TOUCH(x) ((void)(x))
204
205/* debug levels */
206extern int debug_attr, debug_dir, debug_dlist, debug_dosfs, debug_encodings,
207		debug_fat, debug_file, debug_iter, debug_vcache;
208
209int _dosfs_sync(nspace *vol);
210
211#endif
212