1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_FS_PC_FS_H
#define _SYS_FS_PC_FS_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/thread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint16_t pc_cluster16_t;
typedef uint32_t pc_cluster32_t;
/*
* PC (MSDOS) compatible virtual file system.
*
* A main goal of the implementation was to maintain statelessness
* except while files are open. Thus mounting and unmounting merely
* declared the file system name. The user may change disks at almost
* any time without concern (just like the PC). It is assumed that when
* files are open for writing the disk access light will be on, as a
* warning not to change disks. The implementation must, however, detect
* disk change and recover gracefully. It does this by comparing the
* in core entry for a directory to the on disk entry whenever a directory
* is searched. If a discrepancy is found active directories become root and
* active files are marked invalid.
*
* There are only two type of nodes on the PC file system; files and
* directories. These are represented by two separate vnode op vectors,
* and they are kept in two separate tables. Files are known by the
* disk block number and block (cluster) offset of the files directory
* entry. Directories are known by the starting cluster number.
*
* The file system is locked for during each user operation. This is
* done to simplify disk verification error conditions.
*
* Notes on FAT32 support
* ----------------------
* The basic difference between FAT32 and FAT16 is that cluster numbers are now
* 32-bit instead of 16-bit. The FAT is thus an array of 32-bit cluster numbers,
* and because of this the cluster size can be much smaller on a large disk
* (4k, say, on a 1 Gig drive instead of 16k). Unfortunately, the FAT is not
* the only place cluster numbers are stored - the starting cluster is stored
* in the directory entry for a file, and of course it's only 16-bit. Luckily,
* there's a 16-bit OS/2 Extended Attribute field that is now used to store the
* upper 16-bits of the starting cluster number.
*
* Most of the FAT32 changes to pcfs are under 'if it's FAT32' to minimize the
* effect on non-FAT32 filesystems (and still share the code), except for the
* starting cluster changes. It seemed easier to make common functions to
* handle that.
*
* Other changes:
*
* 1. FAT32 partitions are indicated by partition types 0xB and 0xC.
* 2. The boot sector is now 2 sectors, to make room for FAT32 extensions.
* 3. The root directory is no longer stored in a fixed location. Its'
* starting cluster is stored in the extended boot sector.
* 4. "Summary information" is now stored and we need to (at least) maintain
* the number of free clusters or scandisk will be upset. Though the
* sector this info is in is pointed to by the extensions in the boot
* sector, the magic offset of this information is just that so
* far - magic. 0x1e0.
* 5. FAT32 can use the alternate FAT. But we don't.
*
* FAT32 also exposed a latent bug: we bread() each copy of the FAT in one
* big chunk. This is not good on a large FAT32 drive, such as a 1 Gig
* Jaz drive that has 4k clusters, since the FAT becomes 1 Meg in size and
* bread blocks forever. So now we read the FAT in chunks.
*/
/*
* pre-FAT32 boot sector.
*/
struct bootsec {
uchar_t instr[3];
uchar_t version[8];
uchar_t bps[2]; /* bytes per sector */
uchar_t spcl; /* sectors per allocation unit */
uchar_t res_sec[2]; /* reserved sectors, starting at 0 */
uchar_t nfat; /* number of FATs */
uchar_t rdirents[2]; /* number of root directory entries */
uchar_t numsect[2]; /* old total sectors in logical image */
uchar_t mediadesriptor; /* media descriptor byte */
ushort_t fatsec; /* number of sectors per FAT */
ushort_t spt; /* sectors per track */
ushort_t nhead; /* number of heads */
uint_t hiddensec; /* number of hidden sectors */
uint_t totalsec; /* total sectors in logical image */
};
/*
* FAT32 volumes have a bigger boot sector. They include the normal
* boot sector.
*/
struct fat32_bootsec {
struct bootsec f_bs;
uint32_t f_fatlength; /* size of FAT */
uint16_t f_flags;
uint8_t f_major; /* major filesystem version #? */
uint8_t f_minor; /* minor filesystem version #? */
uint32_t f_rootcluster; /* first cluster in root directory */
uint16_t f_infosector; /* where summary info is */
uint16_t f_backupboot; /* backup boot sector */
uint16_t f_reserved2[6];
};
#define FAT32_FS_SIGN 0x61417272
#define FAT32_BOOT_FSINFO_OFF 0x1e0
/*
* summary information for fat32 volumes. We need to maintain fs_free_clusters
* or Microsoft Scandisk will be upset.
*/
struct fat32_boot_fsinfo {
uint32_t fs_reserved1;
uint32_t fs_signature; /* 0x61417272 */
uint32_t fs_free_clusters; /* # free clusters. -1 if unknown */
uint32_t fs_next_cluster; /* unused by pcfs */
uint32_t fs_reserved2[4];
};
#define FSINFO_UNKNOWN (-1)
struct pcfs {
struct vfs *pcfs_vfs; /* vfs for this fs */
int pcfs_flags; /* flags */
int pcfs_ldrv; /* logical DOS drive number */
dev_t pcfs_xdev; /* actual device that is mounted */
struct vnode *pcfs_devvp; /* and a vnode for it */
int pcfs_secsize; /* sector size in bytes */
int pcfs_spcl; /* sectors per cluster */
int pcfs_spt; /* sectors per track */
int pcfs_sdshift; /* shift to convert sector into */
/* DEV_BSIZE "sectors"; assume */
/* pcfs_secsize is 2**n times of */
/* DEV_BSIZE */
int pcfs_fatsec; /* number of sec per FAT */
int pcfs_numfat; /* number of FAT copies */
int pcfs_rdirsec; /* number of sec in root dir */
daddr_t pcfs_dosstart; /* start blkno of DOS partition */
daddr_t pcfs_fatstart; /* start blkno of first FAT */
daddr_t pcfs_rdirstart; /* start blkno of root dir */
daddr_t pcfs_datastart; /* start blkno of data area */
int pcfs_clsize; /* cluster size in bytes */
int pcfs_ncluster; /* number of clusters in fs */
int pcfs_entps; /* number of dir entry per sector */
int pcfs_nrefs; /* number of active pcnodes */
int pcfs_frefs; /* number of active file pcnodes */
int pcfs_nxfrecls; /* next free cluster */
uchar_t *pcfs_fatp; /* ptr to FAT data */
uchar_t *pcfs_fat_changemap; /* map of changed fat data */
int pcfs_fatsize; /* size of FAT data */
int pcfs_fat_changemapsize; /* size of FAT changemap */
time_t pcfs_fattime; /* time FAT becomes invalid */
time_t pcfs_verifytime; /* time to reverify disk */
kmutex_t pcfs_lock; /* per filesystem lock */
kthread_id_t pcfs_owner; /* id of thread locking pcfs */
int pcfs_count; /* # of pcfs locks for pcfs_owner */
struct fat32_boot_fsinfo fsinfo_native; /* native fsinfo for fat32 */
uint32_t f32fsinfo_sector; /* where to read/write fsinfo */
struct pcfs *pcfs_nxt; /* linked list of all mounts */
int pcfs_fatjustread; /* Used to flag a freshly found FAT */
struct vnode *pcfs_root; /* vnode for the root dir of the fs */
};
/*
* flags
*/
#define PCFS_FATMOD 0x01 /* FAT has been modified */
#define PCFS_LOCKED 0x02 /* fs is locked */
#define PCFS_WANTED 0x04 /* locked fs is wanted */
#define PCFS_FAT16 0x400 /* 16 bit FAT */
#define PCFS_NOCHK 0x800 /* don't resync fat on error */
#define PCFS_BOOTPART 0x1000 /* boot partition type */
#define PCFS_HIDDEN 0x2000 /* show hidden files */
#define PCFS_PCMCIA_NO_CIS 0x4000 /* PCMCIA psuedo floppy */
#define PCFS_FOLDCASE 0x8000 /* fold filenames to lowercase */
#define PCFS_FAT32 0x10000 /* 32 bit FAT */
#define PCFS_IRRECOV 0x20000 /* FS was messed with during write */
#define PCFS_NOCLAMPTIME 0x40000 /* expose full FAT timestamp range */
/* for compatibility */
struct old_pcfs_args {
int secondswest; /* seconds west of Greenwich */
int dsttime; /* type of dst correction */
};
struct pcfs_args {
int secondswest; /* seconds west of Greenwich */
int dsttime; /* type of dst correction */
int flags;
};
/*
* flags for the pcfs_args 'flags' field.
*
* Note that these two macros are obsolete - do not use them.
*/
#define PCFS_MNT_HIDDEN 0x01 /* show hidden files */
#define PCFS_MNT_FOLDCASE 0x02 /* fold all names from media to */
/* lowercase */
#define PCFS_MNT_NOCLAMPTIME 0x04 /* expose full FAT timestamp range */
/*
* pcfs mount options.
*/
#define MNTOPT_PCFS_HIDDEN "hidden"
#define MNTOPT_PCFS_NOHIDDEN "nohidden"
#define MNTOPT_PCFS_FOLDCASE "foldcase"
#define MNTOPT_PCFS_NOFOLDCASE "nofoldcase"
#define MNTOPT_PCFS_CLAMPTIME "clamptime"
#define MNTOPT_PCFS_NOCLAMPTIME "noclamptime"
/*
* Disk timeout value in sec.
* This is used to time out the in core FAT and to re-verify the disk.
* This should be less than the time it takes to change floppys
*/
#define PCFS_DISKTIMEOUT 2
#define VFSTOPCFS(VFSP) ((struct pcfs *)((VFSP)->vfs_data))
#define PCFSTOVFS(FSP) ((FSP)->pcfs_vfs)
/*
* special cluster numbers in FAT
*/
#define PCF_FREECLUSTER 0x00 /* cluster is available */
#define PCF_ERRORCLUSTER 0x01 /* error occurred allocating cluster */
#define PCF_12BCLUSTER 0xFF0 /* 12-bit version of reserved cluster */
#define PCF_RESCLUSTER 0xFFF0 /* 16-bit version of reserved cluster */
#define PCF_RESCLUSTER32 0xFFFFFF0 /* 32-bit version */
#define PCF_BADCLUSTER 0xFFF7 /* bad cluster, do not use */
#define PCF_BADCLUSTER32 0xFFFFFF7 /* 32-bit version */
#define PCF_LASTCLUSTER 0xFFF8 /* >= means last cluster in file */
#define PCF_LASTCLUSTER32 0xFFFFFF8 /* 32-bit version */
#define PCF_LASTCLUSTERMARK 0xFFFF /* value used to mark last cluster */
#define PCF_LASTCLUSTERMARK32 0xFFFFFFF /* 32-bit version */
#define PCF_FIRSTCLUSTER 2 /* first valid cluster number */
/*
* file system constants
*/
#define PC_MAXFATSEC 256 /* maximum number of sectors in FAT */
/*
* file system parameter macros
*/
#define IS_FAT32(PCFS) \
(((PCFS)->pcfs_flags & PCFS_FAT32) == PCFS_FAT32)
#define IS_FAT16(PCFS) \
(((PCFS)->pcfs_flags & PCFS_FAT16) == PCFS_FAT16)
#define IS_FAT12(PCFS) \
(((PCFS)->pcfs_flags & (PCFS_FAT16 | PCFS_FAT32)) == 0)
#define pc_clear_fatchanges(PCFS) \
bzero((PCFS)->pcfs_fat_changemap, (PCFS)->pcfs_fat_changemapsize)
#define pc_blksize(PCFS, PCP, OFF) /* file system block size */ \
(((PCTOV(PCP)->v_flag & VROOT) && !IS_FAT32(PCFS)) ? \
((OFF) >= \
((PCFS)->pcfs_rdirsec & \
~((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize)? \
((PCFS)->pcfs_rdirsec & \
((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize): \
(PCFS)->pcfs_clsize): \
(PCFS)->pcfs_clsize)
#define pc_blkoff(PCFS, OFF) /* offset within block */ \
((int)((OFF) & ((PCFS)->pcfs_clsize - 1)))
#define pc_lblkno(PCFS, OFF) /* logical block (cluster) no */ \
((daddr_t)((OFF) / (PCFS)->pcfs_clsize))
#define pc_dbtocl(PCFS, DB) /* disk blks to clusters */ \
((int)((DB) / (PCFS)->pcfs_spcl))
#define pc_cltodb(PCFS, CL) /* clusters to disk blks */ \
((daddr_t)((CL) * (PCFS)->pcfs_spcl))
#define pc_cldaddr(PCFS, CL) /* DEV_BSIZE "sector" addr for cluster */ \
(((daddr_t)((PCFS)->pcfs_datastart + \
((CL) - PCF_FIRSTCLUSTER) * (PCFS)->pcfs_spcl)) << \
(PCFS)->pcfs_sdshift)
#define pc_daddrcl(PCFS, DADDR) /* cluster for disk address */ \
((int)(((((DADDR) >> (PCFS)->pcfs_sdshift) - (PCFS)->pcfs_datastart) / \
(PCFS)->pcfs_spcl) + 2))
#define pc_dbdaddr(PCFS, DB) /* sector to DEV_BSIZE "sector" addr */ \
((DB) << (PCFS)->pcfs_sdshift)
#define pc_daddrdb(PCFS, DADDR) /* DEV_BSIZE "sector" addr to sector addr */ \
((DADDR) >> (PCFS)->pcfs_sdshift)
#define pc_validcl(PCFS, CL) /* check that cluster no is legit */ \
((int)(CL) >= PCF_FIRSTCLUSTER && \
(int)(CL) <= (PCFS)->pcfs_ncluster)
/*
* external routines.
*/
extern int pc_lockfs(struct pcfs *, int, int); /* lock fs and get fat */
extern void pc_unlockfs(struct pcfs *); /* ulock the fs */
extern int pc_getfat(struct pcfs *); /* get fat from disk */
extern void pc_invalfat(struct pcfs *); /* invalidate incore fat */
extern int pc_syncfat(struct pcfs *); /* sync fat to disk */
extern int pc_freeclusters(struct pcfs *); /* num free clusters in fs */
extern pc_cluster32_t pc_alloccluster(struct pcfs *, int);
extern void pc_setcluster(struct pcfs *, pc_cluster32_t, pc_cluster32_t);
extern void pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn);
extern int pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn);
/*
* debugging
*/
extern int pcfsdebuglevel;
#define PC_DPRINTF0(level, A) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A))
#define PC_DPRINTF1(level, A, B) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B))
#define PC_DPRINTF2(level, A, B, C) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B), (C))
#define PC_DPRINTF3(level, A, B, C, D) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B), (C), (D))
#define PC_DPRINTF4(level, A, B, C, D, E) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B), (C), (D), (E))
#ifdef __cplusplus
}
#endif
#endif /* _SYS_FS_PC_FS_H */
|