Deleted Added
full compact
msdosfs_vfsops.c (30354) msdosfs_vfsops.c (31132)
1/* $Id: msdosfs_vfsops.c,v 1.21 1997/10/11 18:31:30 phk Exp $ */
1/* $Id: msdosfs_vfsops.c,v 1.22 1997/10/12 20:25:01 phk Exp $ */
2/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */
3
4/*-
5 * Copyright (C) 1994 Wolfgang Solfrank.
6 * Copyright (C) 1994 TooLs GmbH.
7 * All rights reserved.
8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by TooLs GmbH.
21 * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35/*
36 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 *
38 * You can do anything you want with this software, just don't say you wrote
39 * it, and don't remove this notice.
40 *
41 * This software is provided "as is".
42 *
43 * The author supplies this software to be publicly redistributed on the
44 * understanding that the author is not responsible for the correct
45 * functioning of this software in any circumstances and is not liable for
46 * any damages caused by this software.
47 *
48 * October 1992
49 */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/namei.h>
54#include <sys/proc.h>
55#include <sys/kernel.h>
56#include <sys/vnode.h>
57#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
58#include <sys/mount.h>
59#include <sys/buf.h>
60#include <sys/fcntl.h>
61#include <sys/malloc.h>
62
63#include <msdosfs/bpb.h>
64#include <msdosfs/bootsect.h>
65#include <msdosfs/direntry.h>
66#include <msdosfs/denode.h>
67#include <msdosfs/msdosfsmount.h>
68#include <msdosfs/fat.h>
69
70MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure");
71static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
72
73static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp,
74 struct proc *p));
75static int msdosfs_fhtovp __P((struct mount *, struct fid *,
76 struct sockaddr *, struct vnode **, int *,
77 struct ucred **));
78static int msdosfs_mount __P((struct mount *, char *, caddr_t,
79 struct nameidata *, struct proc *));
80static int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
81 struct proc *));
82static int msdosfs_root __P((struct mount *, struct vnode **));
83static int msdosfs_start __P((struct mount *, int, struct proc *));
84static int msdosfs_statfs __P((struct mount *, struct statfs *,
85 struct proc *));
86static int msdosfs_sync __P((struct mount *, int, struct ucred *,
87 struct proc *));
88static int msdosfs_unmount __P((struct mount *, int, struct proc *));
89static int msdosfs_vget __P((struct mount *mp, ino_t ino,
90 struct vnode **vpp));
91static int msdosfs_vptofh __P((struct vnode *, struct fid *));
92
93/*
94 * mp - path - addr in user space of mount point (ie /usr or whatever)
95 * data - addr in user space of mount params including the name of the block
96 * special file to treat as a filesystem.
97 */
98static int
99msdosfs_mount(mp, path, data, ndp, p)
100 struct mount *mp;
101 char *path;
102 caddr_t data;
103 struct nameidata *ndp;
104 struct proc *p;
105{
106 struct vnode *devvp; /* vnode for blk device to mount */
107 struct msdosfs_args args; /* will hold data from mount request */
108 struct msdosfsmount *pmp; /* msdosfs specific mount control block */
109 int error, flags;
110 u_int size;
111 struct ucred *cred, *scred;
112 struct vattr va;
113
114 /*
115 * Copy in the args for the mount request.
116 */
117 error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args));
118 if (error)
119 return error;
120
121 /*
122 * If they just want to update then be sure we can do what is
123 * asked. Can't change a filesystem from read/write to read only.
124 * Why? And if they've supplied a new device file name then we
125 * continue, otherwise return.
126 */
127 if (mp->mnt_flag & MNT_UPDATE) {
128 pmp = (struct msdosfsmount *) mp->mnt_data;
129 error = 0;
130 if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
131 flags = WRITECLOSE;
132 if (mp->mnt_flag & MNT_FORCE)
133 flags |= FORCECLOSE;
134 error = vflush(mp, NULLVP, flags);
135 }
136 if (!error && (mp->mnt_flag & MNT_RELOAD))
137 /* not yet implemented */
138 error = EINVAL;
139 if (error)
140 return error;
2/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */
3
4/*-
5 * Copyright (C) 1994 Wolfgang Solfrank.
6 * Copyright (C) 1994 TooLs GmbH.
7 * All rights reserved.
8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by TooLs GmbH.
21 * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35/*
36 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 *
38 * You can do anything you want with this software, just don't say you wrote
39 * it, and don't remove this notice.
40 *
41 * This software is provided "as is".
42 *
43 * The author supplies this software to be publicly redistributed on the
44 * understanding that the author is not responsible for the correct
45 * functioning of this software in any circumstances and is not liable for
46 * any damages caused by this software.
47 *
48 * October 1992
49 */
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/namei.h>
54#include <sys/proc.h>
55#include <sys/kernel.h>
56#include <sys/vnode.h>
57#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
58#include <sys/mount.h>
59#include <sys/buf.h>
60#include <sys/fcntl.h>
61#include <sys/malloc.h>
62
63#include <msdosfs/bpb.h>
64#include <msdosfs/bootsect.h>
65#include <msdosfs/direntry.h>
66#include <msdosfs/denode.h>
67#include <msdosfs/msdosfsmount.h>
68#include <msdosfs/fat.h>
69
70MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure");
71static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
72
73static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp,
74 struct proc *p));
75static int msdosfs_fhtovp __P((struct mount *, struct fid *,
76 struct sockaddr *, struct vnode **, int *,
77 struct ucred **));
78static int msdosfs_mount __P((struct mount *, char *, caddr_t,
79 struct nameidata *, struct proc *));
80static int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
81 struct proc *));
82static int msdosfs_root __P((struct mount *, struct vnode **));
83static int msdosfs_start __P((struct mount *, int, struct proc *));
84static int msdosfs_statfs __P((struct mount *, struct statfs *,
85 struct proc *));
86static int msdosfs_sync __P((struct mount *, int, struct ucred *,
87 struct proc *));
88static int msdosfs_unmount __P((struct mount *, int, struct proc *));
89static int msdosfs_vget __P((struct mount *mp, ino_t ino,
90 struct vnode **vpp));
91static int msdosfs_vptofh __P((struct vnode *, struct fid *));
92
93/*
94 * mp - path - addr in user space of mount point (ie /usr or whatever)
95 * data - addr in user space of mount params including the name of the block
96 * special file to treat as a filesystem.
97 */
98static int
99msdosfs_mount(mp, path, data, ndp, p)
100 struct mount *mp;
101 char *path;
102 caddr_t data;
103 struct nameidata *ndp;
104 struct proc *p;
105{
106 struct vnode *devvp; /* vnode for blk device to mount */
107 struct msdosfs_args args; /* will hold data from mount request */
108 struct msdosfsmount *pmp; /* msdosfs specific mount control block */
109 int error, flags;
110 u_int size;
111 struct ucred *cred, *scred;
112 struct vattr va;
113
114 /*
115 * Copy in the args for the mount request.
116 */
117 error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args));
118 if (error)
119 return error;
120
121 /*
122 * If they just want to update then be sure we can do what is
123 * asked. Can't change a filesystem from read/write to read only.
124 * Why? And if they've supplied a new device file name then we
125 * continue, otherwise return.
126 */
127 if (mp->mnt_flag & MNT_UPDATE) {
128 pmp = (struct msdosfsmount *) mp->mnt_data;
129 error = 0;
130 if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
131 flags = WRITECLOSE;
132 if (mp->mnt_flag & MNT_FORCE)
133 flags |= FORCECLOSE;
134 error = vflush(mp, NULLVP, flags);
135 }
136 if (!error && (mp->mnt_flag & MNT_RELOAD))
137 /* not yet implemented */
138 error = EINVAL;
139 if (error)
140 return error;
141 if (pmp->pm_ronly && (mp->mnt_flag & MNT_WANTRDWR))
141 if (pmp->pm_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR))
142 pmp->pm_ronly = 0;
143 if (args.fspec == 0) {
144 /*
145 * Process export requests.
146 */
147 return vfs_export(mp, &pmp->pm_export, &args.export);
148 }
149 } else
150 pmp = NULL;
151
152 /*
153 * check to see that the user in owns the target directory.
154 * Note the very XXX trick to make sure we're checking as the
155 * real user -- were mount() executable by anyone, this wouldn't
156 * be a problem.
157 *
158 * XXX there should be one consistent error out.
159 */
160 cred = crdup(p->p_ucred); /* XXX */
161 cred->cr_uid = p->p_cred->p_ruid; /* XXX */
162 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
163 if (error) {
164 crfree(cred); /* XXX */
165 return error;
166 }
167 if (cred->cr_uid != 0) {
168 if (va.va_uid != cred->cr_uid) {
169 error = EACCES;
170 crfree(cred); /* XXX */
171 return error;
172 }
173
174 /* a user mounted it; we'll verify permissions when unmounting */
175 mp->mnt_flag |= MNT_USER;
176 }
177
178 /*
179 * Now, lookup the name of the block device this mount or name
180 * update request is to apply to.
181 */
182 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
183 scred = p->p_ucred; /* XXX */
184 p->p_ucred = cred; /* XXX */
185 error = namei(ndp);
186 p->p_ucred = scred; /* XXX */
187 crfree(cred); /* XXX */
188 if (error != 0)
189 return error;
190
191 /*
192 * Be sure they've given us a block device to treat as a
193 * filesystem. And, that its major number is within the bdevsw
194 * table.
195 */
196 devvp = ndp->ni_vp;
197 if (devvp->v_type != VBLK) {
198 vrele(devvp);
199 return ENOTBLK;
200 }
201 if (major(devvp->v_rdev) >= nblkdev) {
202 vrele(devvp);
203 return ENXIO;
204 }
205
206 /*
207 * If this is an update, then make sure the vnode for the block
208 * special device is the same as the one our filesystem is in.
209 */
210 if (mp->mnt_flag & MNT_UPDATE) {
211 if (devvp != pmp->pm_devvp)
212 error = EINVAL;
213 else
214 vrele(devvp);
215 } else {
216
217 /*
218 * Well, it's not an update, it's a real mount request.
219 * Time to get dirty.
220 */
221 error = mountmsdosfs(devvp, mp, p);
222 }
223 if (error) {
224 vrele(devvp);
225 return error;
226 }
227
228 /*
229 * Copy in the name of the directory the filesystem is to be
230 * mounted on. Then copy in the name of the block special file
231 * representing the filesystem being mounted. And we clear the
232 * remainder of the character strings to be tidy. Set up the
233 * user id/group id/mask as specified by the user. Then, we try to
234 * fill in the filesystem stats structure as best we can with
235 * whatever applies from a dos file system.
236 */
237 pmp = (struct msdosfsmount *) mp->mnt_data;
238 copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
239 sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
240 bzero(mp->mnt_stat.f_mntonname + size,
241 sizeof(mp->mnt_stat.f_mntonname) - size);
242 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
243 bzero(mp->mnt_stat.f_mntfromname + size,
244 MNAMELEN - size);
245 pmp->pm_mounter = p->p_cred->p_ruid;
246 pmp->pm_gid = args.gid;
247 pmp->pm_uid = args.uid;
248 pmp->pm_mask = args.mask;
249 (void) msdosfs_statfs(mp, &mp->mnt_stat, p);
250#ifdef MSDOSFS_DEBUG
251 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
252#endif
253 return 0;
254}
255
256static int
257mountmsdosfs(devvp, mp, p)
258 struct vnode *devvp;
259 struct mount *mp;
260 struct proc *p;
261{
262 int i;
263 int bpc;
264 int bit;
265 int error;
266 int needclose;
267 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
268 dev_t dev = devvp->v_rdev;
269 union bootsector *bsp;
270 struct msdosfsmount *pmp = NULL;
271 struct buf *bp0 = NULL;
272 struct byte_bpb33 *b33;
273 struct byte_bpb50 *b50;
274#ifdef PC98
275 u_int pc98_wrk;
276 u_int Phy_Sector_Size;
277#endif
278
279 /*
280 * Multiple mounts of the same block special file aren't allowed.
281 * Make sure no one else has the special file open. And flush any
282 * old buffers from this filesystem. Presumably this prevents us
283 * from running into buffers that are the wrong blocksize.
284 */
285 error = vfs_mountedon(devvp);
286 if (error)
287 return error;
288 if (vcount(devvp) > 1)
289 return EBUSY;
290 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
291 if (error)
292 return error;
293
294 /*
295 * Now open the block special file.
296 */
297 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
298 if (error)
299 return error;
300 needclose = 1;
301#ifdef HDSUPPORT
302 /*
303 * Put this in when we support reading dos filesystems from
304 * partitioned harddisks.
305 */
306 if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
307 }
308#endif
309
310 /*
311 * Read the boot sector of the filesystem, and then check the boot
312 * signature. If not a dos boot sector then error out. We could
313 * also add some checking on the bsOemName field. So far I've seen
314 * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0"
315 */
316#ifdef PC98
317 devvp->v_flag &= 0xffff;
318 error = bread(devvp, 0, 1024, NOCRED, &bp0);
319#else
320 error = bread(devvp, 0, 512, NOCRED, &bp0);
321#endif
322 if (error)
323 goto error_exit;
324 bp0->b_flags |= B_AGE;
325 bsp = (union bootsector *) bp0->b_data;
326 b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
327 b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
328#ifdef MSDOSFS_CHECKSIG
329#ifdef PC98
330 if (bsp->bs50.bsBootSectSig != BOOTSIG &&
331 bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */
332 bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */
333 bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */
334#else
335 if (bsp->bs50.bsBootSectSig != BOOTSIG) {
336#endif
337 error = EINVAL;
338 goto error_exit;
339 }
340#endif
341 if ( bsp->bs50.bsJump[0] != 0xe9 &&
342 (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
343 error = EINVAL;
344 goto error_exit;
345 }
346
347 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
348 bzero((caddr_t)pmp, sizeof *pmp);
349 pmp->pm_mountp = mp;
350
351 /*
352 * Compute several useful quantities from the bpb in the
353 * bootsector. Copy in the dos 5 variant of the bpb then fix up
354 * the fields that are different between dos 5 and dos 3.3.
355 */
356 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
357 pmp->pm_SectPerClust = b50->bpbSecPerClust;
358 pmp->pm_ResSectors = getushort(b50->bpbResSectors);
359 pmp->pm_FATs = b50->bpbFATs;
360 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
361 pmp->pm_Sectors = getushort(b50->bpbSectors);
362 pmp->pm_Media = b50->bpbMedia;
363 pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
364 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
365 pmp->pm_Heads = getushort(b50->bpbHeads);
366
367 /* XXX - We should probably check more values here */
368 if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
369 !pmp->pm_Heads || pmp->pm_Heads > 255 ||
370#ifdef PC98
371 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
372#else
373 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
374#endif
375 error = EINVAL;
376 goto error_exit;
377 }
378
379 if (pmp->pm_Sectors == 0) {
380 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
381 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
382 } else {
383 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
384 pmp->pm_HugeSectors = pmp->pm_Sectors;
385 }
386#ifdef PC98 /* for PC98 added Satoshi Yasuda */
387 Phy_Sector_Size = 512;
388 if ((devvp->v_rdev>>8) == 2) { /* floppy check */
389 if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) {
390 Phy_Sector_Size = 1024; /* 2HD */
391 /*
392 * 1024byte/sector support
393 */
394 devvp->v_flag |= 0x10000;
395 } else {
396 if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */
397 && (pmp->pm_HugeSectors == 1440)) /* 9 sector */
398 || (((devvp->v_rdev&077) == 4)
399 && (pmp->pm_HugeSectors == 1280)) /* 8 sector */
400 || (((devvp->v_rdev&077) == 5)
401 && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */
402 Phy_Sector_Size = 512;
403 } else {
404 if (((devvp->v_rdev&077) != 1)
405 && ((devvp->v_rdev&077) != 0)) { /* 2HC */
406 error = EINVAL;
407 goto error_exit;
408 }
409 }
410 }
411 }
412 pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size;
413 pmp->pm_BytesPerSec = Phy_Sector_Size;
414 pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk;
415 pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk;
416 pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk;
417 pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk;
418 pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk;
419 pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk;
420#endif /* */
421 pmp->pm_fatblk = pmp->pm_ResSectors;
422 pmp->pm_rootdirblk = pmp->pm_fatblk +
423 (pmp->pm_FATs * pmp->pm_FATsecs);
424 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
425 /
426 pmp->pm_BytesPerSec;/* in sectors */
427 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
428 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
429 pmp->pm_SectPerClust;
430 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
431 pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
432 if (FAT12(pmp))
433 /*
434 * This will usually be a floppy disk. This size makes sure
435 * that one fat entry will not be split across multiple
436 * blocks.
437 */
438 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
439 else
440 /*
441 * This will usually be a hard disk. Reading or writing one
442 * block should be quite fast.
443 */
444 pmp->pm_fatblocksize = MAXBSIZE;
445 pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
446
447
448 if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
449 printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
450
451 /*
452 * Compute mask and shift value for isolating cluster relative byte
453 * offsets and cluster numbers from a file offset.
454 */
455 bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
456 pmp->pm_bpcluster = bpc;
457 pmp->pm_depclust = bpc / sizeof(struct direntry);
458 pmp->pm_crbomask = bpc - 1;
459 if (bpc == 0) {
460 error = EINVAL;
461 goto error_exit;
462 }
463 bit = 1;
464 for (i = 0; i < 32; i++) {
465 if (bit & bpc) {
466 if (bit ^ bpc) {
467 error = EINVAL;
468 goto error_exit;
469 }
470 pmp->pm_cnshift = i;
471 break;
472 }
473 bit <<= 1;
474 }
475
476#ifdef PC98
477 if (Phy_Sector_Size == 512) {
478 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
479 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
480 } else {
481 pmp->pm_brbomask = 0x03ff;
482 pmp->pm_bnshift = 10;
483 }
484#else
485 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
486 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
487#endif
488
489 /*
490 * Release the bootsector buffer.
491 */
492 brelse(bp0);
493 bp0 = NULL;
494
495 /*
496 * Allocate memory for the bitmap of allocated clusters, and then
497 * fill it in.
498 */
499 pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1)
500 / N_INUSEBITS)
501 * sizeof(*pmp->pm_inusemap),
502 M_MSDOSFSFAT, M_WAITOK);
503
504 /*
505 * fillinusemap() needs pm_devvp.
506 */
507 pmp->pm_dev = dev;
508 pmp->pm_devvp = devvp;
509
510 /*
511 * Have the inuse map filled in.
512 */
513 error = fillinusemap(pmp);
514 if (error)
515 goto error_exit;
516
517 /*
518 * If they want fat updates to be synchronous then let them suffer
519 * the performance degradation in exchange for the on disk copy of
520 * the fat being correct just about all the time. I suppose this
521 * would be a good thing to turn on if the kernel is still flakey.
522 */
523 pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
524
525 /*
526 * Finish up.
527 */
528 pmp->pm_ronly = ronly;
529 if (ronly == 0)
530 pmp->pm_fmod = 1;
531 mp->mnt_data = (qaddr_t) pmp;
532 mp->mnt_stat.f_fsid.val[0] = (long)dev;
533 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
534 mp->mnt_flag |= MNT_LOCAL;
535 devvp->v_specflags |= SI_MOUNTEDON;
536
537 return 0;
538
539error_exit:;
540 if (bp0)
541 brelse(bp0);
542 if (needclose)
543 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
544 NOCRED, p);
545 if (pmp) {
546 if (pmp->pm_inusemap)
547 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
548 free((caddr_t) pmp, M_MSDOSFSMNT);
549 mp->mnt_data = (qaddr_t) 0;
550 }
551 return error;
552}
553
554static int
555msdosfs_start(mp, flags, p)
556 struct mount *mp;
557 int flags;
558 struct proc *p;
559{
560 return 0;
561}
562
563/*
564 * Unmount the filesystem described by mp.
565 */
566static int
567msdosfs_unmount(mp, mntflags, p)
568 struct mount *mp;
569 int mntflags;
570 struct proc *p;
571{
572 int flags = 0;
573 int error;
574 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
575
576 /* only the mounter, or superuser can unmount */
577 if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
578 (error = suser(p->p_ucred, &p->p_acflag)))
579 return error;
580
581 if (mntflags & MNT_FORCE) {
582 flags |= FORCECLOSE;
583 }
584 error = vflush(mp, NULLVP, flags);
585 if (error)
586 return error;
587 pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
588 error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
589 NOCRED, p);
590 vrele(pmp->pm_devvp);
591 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
592 free((caddr_t) pmp, M_MSDOSFSMNT);
593 mp->mnt_data = (qaddr_t) 0;
594 mp->mnt_flag &= ~MNT_LOCAL;
595 return error;
596}
597
598static int
599msdosfs_root(mp, vpp)
600 struct mount *mp;
601 struct vnode **vpp;
602{
603 struct denode *ndep;
604 struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
605 int error;
606
607 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
608#ifdef MSDOSFS_DEBUG
609 printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
610 mp, pmp, ndep, DETOV(ndep));
611#endif
612 if (error == 0)
613 *vpp = DETOV(ndep);
614 return error;
615}
616
617static int
618msdosfs_quotactl(mp, cmds, uid, arg, p)
619 struct mount *mp;
620 int cmds;
621 uid_t uid;
622 caddr_t arg;
623 struct proc *p;
624{
625 return EOPNOTSUPP;
626}
627
628static int
629msdosfs_statfs(mp, sbp, p)
630 struct mount *mp;
631 struct statfs *sbp;
632 struct proc *p;
633{
634 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
635
636 /*
637 * Fill in the stat block.
638 */
639 sbp->f_bsize = pmp->pm_bpcluster;
640 sbp->f_iosize = pmp->pm_bpcluster;
641 sbp->f_blocks = pmp->pm_nmbrofclusters;
642 sbp->f_bfree = pmp->pm_freeclustercount;
643 sbp->f_bavail = pmp->pm_freeclustercount;
644 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
645 sbp->f_ffree = 0; /* what to put in here? */
646
647 /*
648 * Copy the mounted on and mounted from names into the passed in
649 * stat block, if it is not the one in the mount structure.
650 */
651 if (sbp != &mp->mnt_stat) {
652 sbp->f_type = mp->mnt_vfc->vfc_typenum;
653 bcopy((caddr_t) mp->mnt_stat.f_mntonname,
654 (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
655 bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
656 (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
657 }
658#if 0
659 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
660 sbp->f_fstypename[MFSNAMELEN] = '\0';
661#endif
662 return 0;
663}
664
665static int
666msdosfs_sync(mp, waitfor, cred, p)
667 struct mount *mp;
668 int waitfor;
669 struct ucred *cred;
670 struct proc *p;
671{
672 struct vnode *vp;
673 struct denode *dep;
674 struct msdosfsmount *pmp;
675 int error;
676 int allerror = 0;
677
678 pmp = (struct msdosfsmount *) mp->mnt_data;
679
680 /*
681 * If we ever switch to not updating all of the fats all the time,
682 * this would be the place to update them from the first one.
683 */
684 if (pmp->pm_fmod)
685 if (pmp->pm_ronly)
686 panic("msdosfs_sync: rofs mod");
687 else {
688 /* update fats here */
689 }
690
691 /*
692 * Go thru in memory denodes and write them out along with
693 * unwritten file blocks.
694 */
695 simple_lock(&mntvnode_slock);
696loop:
697 for (vp = mp->mnt_vnodelist.lh_first; vp;
698 vp = vp->v_mntvnodes.le_next) {
699 if (vp->v_mount != mp) /* not ours anymore */
700 goto loop;
701 simple_lock(&vp->v_interlock);
702 dep = VTODE(vp);
703 if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
704 vp->v_dirtyblkhd.lh_first == NULL) {
705 simple_unlock(&vp->v_interlock);
706 continue;
707 }
708 simple_unlock(&mntvnode_slock);
709 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
710 if (error) {
711 simple_lock(&mntvnode_slock);
712 if (error == ENOENT)
713 goto loop;
714 continue;
715 }
716 error = VOP_FSYNC(vp, cred, waitfor, p);
717 if (error)
718 allerror = error;
719 VOP_UNLOCK(vp, 0, p);
720 vrele(vp); /* done with this one */
721 simple_lock(&mntvnode_slock);
722 }
723 simple_unlock(&mntvnode_slock);
724
725 /*
726 * Flush filesystem control info.
727 */
728 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
729 if (error)
730 allerror = error;
731 return allerror;
732}
733
734static int
735msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
736 struct mount *mp;
737 struct fid *fhp;
738 struct sockaddr *nam;
739 struct vnode **vpp;
740 int *exflagsp;
741 struct ucred **credanonp;
742{
743 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
744 struct defid *defhp = (struct defid *) fhp;
745 struct denode *dep;
746 struct netcred *np;
747 int error;
748
749 np = vfs_export_lookup(mp, &pmp->pm_export, nam);
750 if (np == NULL)
751 return EACCES;
752 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
753 NULL, &dep);
754 if (error) {
755 *vpp = NULLVP;
756 return error;
757 }
758 *vpp = DETOV(dep);
759 *exflagsp = np->netc_exflags;
760 *credanonp = &np->netc_anon;
761 return 0;
762}
763
764
765static int
766msdosfs_vptofh(vp, fhp)
767 struct vnode *vp;
768 struct fid *fhp;
769{
770 struct denode *dep = VTODE(vp);
771 struct defid *defhp = (struct defid *) fhp;
772
773 defhp->defid_len = sizeof(struct defid);
774 defhp->defid_dirclust = dep->de_dirclust;
775 defhp->defid_dirofs = dep->de_diroffset;
776 /* defhp->defid_gen = ip->i_gen; */
777 return 0;
778}
779
780static int
781msdosfs_vget(mp, ino, vpp)
782 struct mount *mp;
783 ino_t ino;
784 struct vnode **vpp;
785{
786 return EOPNOTSUPP;
787}
788
789static struct vfsops msdosfs_vfsops = {
790 msdosfs_mount,
791 msdosfs_start,
792 msdosfs_unmount,
793 msdosfs_root,
794 msdosfs_quotactl,
795 msdosfs_statfs,
796 msdosfs_sync,
797 msdosfs_vget,
798 msdosfs_fhtovp,
799 msdosfs_vptofh,
800 msdosfs_init
801};
802
803VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0);
142 pmp->pm_ronly = 0;
143 if (args.fspec == 0) {
144 /*
145 * Process export requests.
146 */
147 return vfs_export(mp, &pmp->pm_export, &args.export);
148 }
149 } else
150 pmp = NULL;
151
152 /*
153 * check to see that the user in owns the target directory.
154 * Note the very XXX trick to make sure we're checking as the
155 * real user -- were mount() executable by anyone, this wouldn't
156 * be a problem.
157 *
158 * XXX there should be one consistent error out.
159 */
160 cred = crdup(p->p_ucred); /* XXX */
161 cred->cr_uid = p->p_cred->p_ruid; /* XXX */
162 error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
163 if (error) {
164 crfree(cred); /* XXX */
165 return error;
166 }
167 if (cred->cr_uid != 0) {
168 if (va.va_uid != cred->cr_uid) {
169 error = EACCES;
170 crfree(cred); /* XXX */
171 return error;
172 }
173
174 /* a user mounted it; we'll verify permissions when unmounting */
175 mp->mnt_flag |= MNT_USER;
176 }
177
178 /*
179 * Now, lookup the name of the block device this mount or name
180 * update request is to apply to.
181 */
182 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
183 scred = p->p_ucred; /* XXX */
184 p->p_ucred = cred; /* XXX */
185 error = namei(ndp);
186 p->p_ucred = scred; /* XXX */
187 crfree(cred); /* XXX */
188 if (error != 0)
189 return error;
190
191 /*
192 * Be sure they've given us a block device to treat as a
193 * filesystem. And, that its major number is within the bdevsw
194 * table.
195 */
196 devvp = ndp->ni_vp;
197 if (devvp->v_type != VBLK) {
198 vrele(devvp);
199 return ENOTBLK;
200 }
201 if (major(devvp->v_rdev) >= nblkdev) {
202 vrele(devvp);
203 return ENXIO;
204 }
205
206 /*
207 * If this is an update, then make sure the vnode for the block
208 * special device is the same as the one our filesystem is in.
209 */
210 if (mp->mnt_flag & MNT_UPDATE) {
211 if (devvp != pmp->pm_devvp)
212 error = EINVAL;
213 else
214 vrele(devvp);
215 } else {
216
217 /*
218 * Well, it's not an update, it's a real mount request.
219 * Time to get dirty.
220 */
221 error = mountmsdosfs(devvp, mp, p);
222 }
223 if (error) {
224 vrele(devvp);
225 return error;
226 }
227
228 /*
229 * Copy in the name of the directory the filesystem is to be
230 * mounted on. Then copy in the name of the block special file
231 * representing the filesystem being mounted. And we clear the
232 * remainder of the character strings to be tidy. Set up the
233 * user id/group id/mask as specified by the user. Then, we try to
234 * fill in the filesystem stats structure as best we can with
235 * whatever applies from a dos file system.
236 */
237 pmp = (struct msdosfsmount *) mp->mnt_data;
238 copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
239 sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
240 bzero(mp->mnt_stat.f_mntonname + size,
241 sizeof(mp->mnt_stat.f_mntonname) - size);
242 copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
243 bzero(mp->mnt_stat.f_mntfromname + size,
244 MNAMELEN - size);
245 pmp->pm_mounter = p->p_cred->p_ruid;
246 pmp->pm_gid = args.gid;
247 pmp->pm_uid = args.uid;
248 pmp->pm_mask = args.mask;
249 (void) msdosfs_statfs(mp, &mp->mnt_stat, p);
250#ifdef MSDOSFS_DEBUG
251 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
252#endif
253 return 0;
254}
255
256static int
257mountmsdosfs(devvp, mp, p)
258 struct vnode *devvp;
259 struct mount *mp;
260 struct proc *p;
261{
262 int i;
263 int bpc;
264 int bit;
265 int error;
266 int needclose;
267 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
268 dev_t dev = devvp->v_rdev;
269 union bootsector *bsp;
270 struct msdosfsmount *pmp = NULL;
271 struct buf *bp0 = NULL;
272 struct byte_bpb33 *b33;
273 struct byte_bpb50 *b50;
274#ifdef PC98
275 u_int pc98_wrk;
276 u_int Phy_Sector_Size;
277#endif
278
279 /*
280 * Multiple mounts of the same block special file aren't allowed.
281 * Make sure no one else has the special file open. And flush any
282 * old buffers from this filesystem. Presumably this prevents us
283 * from running into buffers that are the wrong blocksize.
284 */
285 error = vfs_mountedon(devvp);
286 if (error)
287 return error;
288 if (vcount(devvp) > 1)
289 return EBUSY;
290 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
291 if (error)
292 return error;
293
294 /*
295 * Now open the block special file.
296 */
297 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
298 if (error)
299 return error;
300 needclose = 1;
301#ifdef HDSUPPORT
302 /*
303 * Put this in when we support reading dos filesystems from
304 * partitioned harddisks.
305 */
306 if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
307 }
308#endif
309
310 /*
311 * Read the boot sector of the filesystem, and then check the boot
312 * signature. If not a dos boot sector then error out. We could
313 * also add some checking on the bsOemName field. So far I've seen
314 * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0"
315 */
316#ifdef PC98
317 devvp->v_flag &= 0xffff;
318 error = bread(devvp, 0, 1024, NOCRED, &bp0);
319#else
320 error = bread(devvp, 0, 512, NOCRED, &bp0);
321#endif
322 if (error)
323 goto error_exit;
324 bp0->b_flags |= B_AGE;
325 bsp = (union bootsector *) bp0->b_data;
326 b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
327 b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
328#ifdef MSDOSFS_CHECKSIG
329#ifdef PC98
330 if (bsp->bs50.bsBootSectSig != BOOTSIG &&
331 bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */
332 bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */
333 bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */
334#else
335 if (bsp->bs50.bsBootSectSig != BOOTSIG) {
336#endif
337 error = EINVAL;
338 goto error_exit;
339 }
340#endif
341 if ( bsp->bs50.bsJump[0] != 0xe9 &&
342 (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
343 error = EINVAL;
344 goto error_exit;
345 }
346
347 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
348 bzero((caddr_t)pmp, sizeof *pmp);
349 pmp->pm_mountp = mp;
350
351 /*
352 * Compute several useful quantities from the bpb in the
353 * bootsector. Copy in the dos 5 variant of the bpb then fix up
354 * the fields that are different between dos 5 and dos 3.3.
355 */
356 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
357 pmp->pm_SectPerClust = b50->bpbSecPerClust;
358 pmp->pm_ResSectors = getushort(b50->bpbResSectors);
359 pmp->pm_FATs = b50->bpbFATs;
360 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
361 pmp->pm_Sectors = getushort(b50->bpbSectors);
362 pmp->pm_Media = b50->bpbMedia;
363 pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
364 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
365 pmp->pm_Heads = getushort(b50->bpbHeads);
366
367 /* XXX - We should probably check more values here */
368 if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
369 !pmp->pm_Heads || pmp->pm_Heads > 255 ||
370#ifdef PC98
371 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
372#else
373 !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
374#endif
375 error = EINVAL;
376 goto error_exit;
377 }
378
379 if (pmp->pm_Sectors == 0) {
380 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
381 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
382 } else {
383 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
384 pmp->pm_HugeSectors = pmp->pm_Sectors;
385 }
386#ifdef PC98 /* for PC98 added Satoshi Yasuda */
387 Phy_Sector_Size = 512;
388 if ((devvp->v_rdev>>8) == 2) { /* floppy check */
389 if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) {
390 Phy_Sector_Size = 1024; /* 2HD */
391 /*
392 * 1024byte/sector support
393 */
394 devvp->v_flag |= 0x10000;
395 } else {
396 if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */
397 && (pmp->pm_HugeSectors == 1440)) /* 9 sector */
398 || (((devvp->v_rdev&077) == 4)
399 && (pmp->pm_HugeSectors == 1280)) /* 8 sector */
400 || (((devvp->v_rdev&077) == 5)
401 && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */
402 Phy_Sector_Size = 512;
403 } else {
404 if (((devvp->v_rdev&077) != 1)
405 && ((devvp->v_rdev&077) != 0)) { /* 2HC */
406 error = EINVAL;
407 goto error_exit;
408 }
409 }
410 }
411 }
412 pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size;
413 pmp->pm_BytesPerSec = Phy_Sector_Size;
414 pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk;
415 pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk;
416 pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk;
417 pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk;
418 pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk;
419 pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk;
420#endif /* */
421 pmp->pm_fatblk = pmp->pm_ResSectors;
422 pmp->pm_rootdirblk = pmp->pm_fatblk +
423 (pmp->pm_FATs * pmp->pm_FATsecs);
424 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
425 /
426 pmp->pm_BytesPerSec;/* in sectors */
427 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
428 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
429 pmp->pm_SectPerClust;
430 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
431 pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
432 if (FAT12(pmp))
433 /*
434 * This will usually be a floppy disk. This size makes sure
435 * that one fat entry will not be split across multiple
436 * blocks.
437 */
438 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
439 else
440 /*
441 * This will usually be a hard disk. Reading or writing one
442 * block should be quite fast.
443 */
444 pmp->pm_fatblocksize = MAXBSIZE;
445 pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
446
447
448 if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
449 printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
450
451 /*
452 * Compute mask and shift value for isolating cluster relative byte
453 * offsets and cluster numbers from a file offset.
454 */
455 bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
456 pmp->pm_bpcluster = bpc;
457 pmp->pm_depclust = bpc / sizeof(struct direntry);
458 pmp->pm_crbomask = bpc - 1;
459 if (bpc == 0) {
460 error = EINVAL;
461 goto error_exit;
462 }
463 bit = 1;
464 for (i = 0; i < 32; i++) {
465 if (bit & bpc) {
466 if (bit ^ bpc) {
467 error = EINVAL;
468 goto error_exit;
469 }
470 pmp->pm_cnshift = i;
471 break;
472 }
473 bit <<= 1;
474 }
475
476#ifdef PC98
477 if (Phy_Sector_Size == 512) {
478 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
479 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
480 } else {
481 pmp->pm_brbomask = 0x03ff;
482 pmp->pm_bnshift = 10;
483 }
484#else
485 pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
486 pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
487#endif
488
489 /*
490 * Release the bootsector buffer.
491 */
492 brelse(bp0);
493 bp0 = NULL;
494
495 /*
496 * Allocate memory for the bitmap of allocated clusters, and then
497 * fill it in.
498 */
499 pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1)
500 / N_INUSEBITS)
501 * sizeof(*pmp->pm_inusemap),
502 M_MSDOSFSFAT, M_WAITOK);
503
504 /*
505 * fillinusemap() needs pm_devvp.
506 */
507 pmp->pm_dev = dev;
508 pmp->pm_devvp = devvp;
509
510 /*
511 * Have the inuse map filled in.
512 */
513 error = fillinusemap(pmp);
514 if (error)
515 goto error_exit;
516
517 /*
518 * If they want fat updates to be synchronous then let them suffer
519 * the performance degradation in exchange for the on disk copy of
520 * the fat being correct just about all the time. I suppose this
521 * would be a good thing to turn on if the kernel is still flakey.
522 */
523 pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
524
525 /*
526 * Finish up.
527 */
528 pmp->pm_ronly = ronly;
529 if (ronly == 0)
530 pmp->pm_fmod = 1;
531 mp->mnt_data = (qaddr_t) pmp;
532 mp->mnt_stat.f_fsid.val[0] = (long)dev;
533 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
534 mp->mnt_flag |= MNT_LOCAL;
535 devvp->v_specflags |= SI_MOUNTEDON;
536
537 return 0;
538
539error_exit:;
540 if (bp0)
541 brelse(bp0);
542 if (needclose)
543 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
544 NOCRED, p);
545 if (pmp) {
546 if (pmp->pm_inusemap)
547 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
548 free((caddr_t) pmp, M_MSDOSFSMNT);
549 mp->mnt_data = (qaddr_t) 0;
550 }
551 return error;
552}
553
554static int
555msdosfs_start(mp, flags, p)
556 struct mount *mp;
557 int flags;
558 struct proc *p;
559{
560 return 0;
561}
562
563/*
564 * Unmount the filesystem described by mp.
565 */
566static int
567msdosfs_unmount(mp, mntflags, p)
568 struct mount *mp;
569 int mntflags;
570 struct proc *p;
571{
572 int flags = 0;
573 int error;
574 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
575
576 /* only the mounter, or superuser can unmount */
577 if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
578 (error = suser(p->p_ucred, &p->p_acflag)))
579 return error;
580
581 if (mntflags & MNT_FORCE) {
582 flags |= FORCECLOSE;
583 }
584 error = vflush(mp, NULLVP, flags);
585 if (error)
586 return error;
587 pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
588 error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
589 NOCRED, p);
590 vrele(pmp->pm_devvp);
591 free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
592 free((caddr_t) pmp, M_MSDOSFSMNT);
593 mp->mnt_data = (qaddr_t) 0;
594 mp->mnt_flag &= ~MNT_LOCAL;
595 return error;
596}
597
598static int
599msdosfs_root(mp, vpp)
600 struct mount *mp;
601 struct vnode **vpp;
602{
603 struct denode *ndep;
604 struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
605 int error;
606
607 error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
608#ifdef MSDOSFS_DEBUG
609 printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
610 mp, pmp, ndep, DETOV(ndep));
611#endif
612 if (error == 0)
613 *vpp = DETOV(ndep);
614 return error;
615}
616
617static int
618msdosfs_quotactl(mp, cmds, uid, arg, p)
619 struct mount *mp;
620 int cmds;
621 uid_t uid;
622 caddr_t arg;
623 struct proc *p;
624{
625 return EOPNOTSUPP;
626}
627
628static int
629msdosfs_statfs(mp, sbp, p)
630 struct mount *mp;
631 struct statfs *sbp;
632 struct proc *p;
633{
634 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
635
636 /*
637 * Fill in the stat block.
638 */
639 sbp->f_bsize = pmp->pm_bpcluster;
640 sbp->f_iosize = pmp->pm_bpcluster;
641 sbp->f_blocks = pmp->pm_nmbrofclusters;
642 sbp->f_bfree = pmp->pm_freeclustercount;
643 sbp->f_bavail = pmp->pm_freeclustercount;
644 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
645 sbp->f_ffree = 0; /* what to put in here? */
646
647 /*
648 * Copy the mounted on and mounted from names into the passed in
649 * stat block, if it is not the one in the mount structure.
650 */
651 if (sbp != &mp->mnt_stat) {
652 sbp->f_type = mp->mnt_vfc->vfc_typenum;
653 bcopy((caddr_t) mp->mnt_stat.f_mntonname,
654 (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
655 bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
656 (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
657 }
658#if 0
659 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
660 sbp->f_fstypename[MFSNAMELEN] = '\0';
661#endif
662 return 0;
663}
664
665static int
666msdosfs_sync(mp, waitfor, cred, p)
667 struct mount *mp;
668 int waitfor;
669 struct ucred *cred;
670 struct proc *p;
671{
672 struct vnode *vp;
673 struct denode *dep;
674 struct msdosfsmount *pmp;
675 int error;
676 int allerror = 0;
677
678 pmp = (struct msdosfsmount *) mp->mnt_data;
679
680 /*
681 * If we ever switch to not updating all of the fats all the time,
682 * this would be the place to update them from the first one.
683 */
684 if (pmp->pm_fmod)
685 if (pmp->pm_ronly)
686 panic("msdosfs_sync: rofs mod");
687 else {
688 /* update fats here */
689 }
690
691 /*
692 * Go thru in memory denodes and write them out along with
693 * unwritten file blocks.
694 */
695 simple_lock(&mntvnode_slock);
696loop:
697 for (vp = mp->mnt_vnodelist.lh_first; vp;
698 vp = vp->v_mntvnodes.le_next) {
699 if (vp->v_mount != mp) /* not ours anymore */
700 goto loop;
701 simple_lock(&vp->v_interlock);
702 dep = VTODE(vp);
703 if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
704 vp->v_dirtyblkhd.lh_first == NULL) {
705 simple_unlock(&vp->v_interlock);
706 continue;
707 }
708 simple_unlock(&mntvnode_slock);
709 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
710 if (error) {
711 simple_lock(&mntvnode_slock);
712 if (error == ENOENT)
713 goto loop;
714 continue;
715 }
716 error = VOP_FSYNC(vp, cred, waitfor, p);
717 if (error)
718 allerror = error;
719 VOP_UNLOCK(vp, 0, p);
720 vrele(vp); /* done with this one */
721 simple_lock(&mntvnode_slock);
722 }
723 simple_unlock(&mntvnode_slock);
724
725 /*
726 * Flush filesystem control info.
727 */
728 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
729 if (error)
730 allerror = error;
731 return allerror;
732}
733
734static int
735msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
736 struct mount *mp;
737 struct fid *fhp;
738 struct sockaddr *nam;
739 struct vnode **vpp;
740 int *exflagsp;
741 struct ucred **credanonp;
742{
743 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
744 struct defid *defhp = (struct defid *) fhp;
745 struct denode *dep;
746 struct netcred *np;
747 int error;
748
749 np = vfs_export_lookup(mp, &pmp->pm_export, nam);
750 if (np == NULL)
751 return EACCES;
752 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
753 NULL, &dep);
754 if (error) {
755 *vpp = NULLVP;
756 return error;
757 }
758 *vpp = DETOV(dep);
759 *exflagsp = np->netc_exflags;
760 *credanonp = &np->netc_anon;
761 return 0;
762}
763
764
765static int
766msdosfs_vptofh(vp, fhp)
767 struct vnode *vp;
768 struct fid *fhp;
769{
770 struct denode *dep = VTODE(vp);
771 struct defid *defhp = (struct defid *) fhp;
772
773 defhp->defid_len = sizeof(struct defid);
774 defhp->defid_dirclust = dep->de_dirclust;
775 defhp->defid_dirofs = dep->de_diroffset;
776 /* defhp->defid_gen = ip->i_gen; */
777 return 0;
778}
779
780static int
781msdosfs_vget(mp, ino, vpp)
782 struct mount *mp;
783 ino_t ino;
784 struct vnode **vpp;
785{
786 return EOPNOTSUPP;
787}
788
789static struct vfsops msdosfs_vfsops = {
790 msdosfs_mount,
791 msdosfs_start,
792 msdosfs_unmount,
793 msdosfs_root,
794 msdosfs_quotactl,
795 msdosfs_statfs,
796 msdosfs_sync,
797 msdosfs_vget,
798 msdosfs_fhtovp,
799 msdosfs_vptofh,
800 msdosfs_init
801};
802
803VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0);