1 /** $MirOS: src/sys/msdosfs/msdosfs_vnops.c,v 1.3 2005/07/03 21:19:02 tg Exp $ */
2 /* $OpenBSD: msdosfs_vnops.c,v 1.53 2005/03/14 22:31:52 tom Exp $ */
3 /* $NetBSD: msdosfs_vnops.c,v 1.63 1997/10/17 11:24:19 ws Exp $ */
4
5 /*-
6 * Copyright (C) 2005 Thomas Wang.
7 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
8 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
9 * All rights reserved.
10 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by TooLs GmbH.
23 * 4. The name of TooLs GmbH may not be used to endorse or promote products
24 * derived from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
32 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37 /*
38 * Written by Paul Popelka (paulp@uts.amdahl.com)
39 *
40 * You can do anything you want with this software, just don't say you wrote
41 * it, and don't remove this notice.
42 *
43 * This software is provided "as is".
44 *
45 * The author supplies this software to be publicly redistributed on the
46 * understanding that the author is not responsible for the correct
47 * functioning of this software in any circumstances and is not liable for
48 * any damages caused by this software.
49 *
50 * October 1992
51 */
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/namei.h>
56 #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
57 #include <sys/kernel.h>
58 #include <sys/file.h> /* define FWRITE ... */
59 #include <sys/stat.h>
60 #include <sys/buf.h>
61 #include <sys/proc.h>
62 #include <sys/mount.h>
63 #include <sys/vnode.h>
64 #include <sys/signalvar.h>
65 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
66 #include <sys/malloc.h>
67 #include <sys/pool.h>
68 #include <sys/dirent.h> /* defines dirent structure */
69 #include <sys/lockf.h>
70 #include <sys/poll.h>
71
72 #include <uvm/uvm_extern.h>
73
74 #include <msdosfs/bpb.h>
75 #include <msdosfs/direntry.h>
76 #include <msdosfs/denode.h>
77 #include <msdosfs/msdosfsmount.h>
78 #include <msdosfs/fat.h>
79
80 static uint32_t fileidhash(uint64_t);
81
82 /*
83 * Some general notes:
84 *
85 * In the ufs filesystem the inodes, superblocks, and indirect blocks are
86 * read/written using the vnode for the filesystem. Blocks that represent
87 * the contents of a file are read/written using the vnode for the file
88 * (including directories when they are read/written as files). This
89 * presents problems for the dos filesystem because data that should be in
90 * an inode (if dos had them) resides in the directory itself. Since we
91 * must update directory entries without the benefit of having the vnode
92 * for the directory we must use the vnode for the filesystem. This means
93 * that when a directory is actually read/written (via read, write, or
94 * readdir, or seek) we must use the vnode for the filesystem instead of
95 * the vnode for the directory as would happen in ufs. This is to insure we
96 * retrieve the correct block from the buffer cache since the hash value is
97 * based upon the vnode address and the desired block number.
98 */
99
100 /*
101 * Create a regular file. On entry the directory to contain the file being
102 * created is locked. We must release before we return. We must also free
103 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
104 * only if the SAVESTART bit in cn_flags is clear on success.
105 */
106 int
msdosfs_create(v)107 msdosfs_create(v)
108 void *v;
109 {
110 struct vop_create_args /* {
111 struct vnode *a_dvp;
112 struct vnode **a_vpp;
113 struct componentname *a_cnp;
114 struct vattr *a_vap;
115 } */ *ap = v;
116 struct componentname *cnp = ap->a_cnp;
117 struct denode ndirent;
118 struct denode *dep;
119 struct denode *pdep = VTODE(ap->a_dvp);
120 int error;
121 struct timespec ts;
122
123 #ifdef MSDOSFS_DEBUG
124 printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
125 #endif
126
127 /*
128 * If this is the root directory and there is no space left we
129 * can't do anything. This is because the root directory can not
130 * change size.
131 */
132 if (pdep->de_StartCluster == MSDOSFSROOT
133 && pdep->de_fndoffset >= pdep->de_FileSize) {
134 error = ENOSPC;
135 goto bad;
136 }
137
138 /*
139 * Create a directory entry for the file, then call createde() to
140 * have it installed. NOTE: DOS files are always executable. We
141 * use the absence of the owner write bit to make the file
142 * readonly.
143 */
144 #ifdef DIAGNOSTIC
145 if ((cnp->cn_flags & HASBUF) == 0)
146 panic("msdosfs_create: no name");
147 #endif
148 bzero(&ndirent, sizeof(ndirent));
149 if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
150 goto bad;
151
152 ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
153 ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
154 ndirent.de_StartCluster = 0;
155 ndirent.de_FileSize = 0;
156 ndirent.de_dev = pdep->de_dev;
157 ndirent.de_devvp = pdep->de_devvp;
158 ndirent.de_pmp = pdep->de_pmp;
159 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
160 TIMEVAL_TO_TIMESPEC(&time, &ts);
161 DETIMES(&ndirent, &ts, &ts, &ts);
162 if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
163 goto bad;
164 if ((cnp->cn_flags & SAVESTART) == 0)
165 pool_put(&namei_pool, cnp->cn_pnbuf);
166 vput(ap->a_dvp);
167 *ap->a_vpp = DETOV(dep);
168 return (0);
169
170 bad:
171 pool_put(&namei_pool, cnp->cn_pnbuf);
172 vput(ap->a_dvp);
173 return (error);
174 }
175
176 int
msdosfs_mknod(v)177 msdosfs_mknod(v)
178 void *v;
179 {
180 struct vop_mknod_args /* {
181 struct vnode *a_dvp;
182 struct vnode **a_vpp;
183 struct componentname *a_cnp;
184 struct vattr *a_vap;
185 } */ *ap = v;
186
187 pool_put(&namei_pool, ap->a_cnp->cn_pnbuf);
188 vput(ap->a_dvp);
189 return (EINVAL);
190 }
191
192 int
msdosfs_open(v)193 msdosfs_open(v)
194 void *v;
195 {
196 #if 0
197 struct vop_open_args /* {
198 struct vnode *a_vp;
199 int a_mode;
200 struct ucred *a_cred;
201 struct proc *a_p;
202 } */ *ap;
203 #endif
204
205 return (0);
206 }
207
208 int
msdosfs_close(v)209 msdosfs_close(v)
210 void *v;
211 {
212 struct vop_close_args /* {
213 struct vnode *a_vp;
214 int a_fflag;
215 struct ucred *a_cred;
216 struct proc *a_p;
217 } */ *ap = v;
218 struct vnode *vp = ap->a_vp;
219 struct denode *dep = VTODE(vp);
220 struct timespec ts;
221
222 if (vp->v_usecount > 1 && !VOP_ISLOCKED(vp)) {
223 TIMEVAL_TO_TIMESPEC(&time, &ts);
224 DETIMES(dep, &ts, &ts, &ts);
225 }
226 return (0);
227 }
228
229 int
msdosfs_access(v)230 msdosfs_access(v)
231 void *v;
232 {
233 struct vop_access_args /* {
234 struct vnode *a_vp;
235 int a_mode;
236 struct ucred *a_cred;
237 struct proc *a_p;
238 } */ *ap = v;
239 struct denode *dep = VTODE(ap->a_vp);
240 struct msdosfsmount *pmp = dep->de_pmp;
241 mode_t dosmode;
242
243 dosmode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH);
244 if ((dep->de_Attributes & ATTR_READONLY) == 0)
245 dosmode |= (S_IWUSR|S_IWGRP|S_IWOTH);
246 dosmode &= pmp->pm_mask;
247 if (dep->de_Attributes & ATTR_DIRECTORY
248 && pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
249 dosmode |= (dosmode & S_IRUSR) ? S_IXUSR : 0;
250 dosmode |= (dosmode & S_IRGRP) ? S_IXGRP : 0;
251 dosmode |= (dosmode & S_IROTH) ? S_IXOTH : 0;
252 }
253
254 return (vaccess(dosmode, pmp->pm_uid, pmp->pm_gid, ap->a_mode,
255 ap->a_cred));
256 }
257
258 int
msdosfs_getattr(v)259 msdosfs_getattr(v)
260 void *v;
261 {
262 struct vop_getattr_args /* {
263 struct vnode *a_vp;
264 struct vattr *a_vap;
265 struct ucred *a_cred;
266 struct proc *a_p;
267 } */ *ap = v;
268 struct denode *dep = VTODE(ap->a_vp);
269 struct msdosfsmount *pmp = dep->de_pmp;
270 struct vattr *vap = ap->a_vap;
271 struct timespec ts;
272 uint32_t fileid;
273
274 TIMEVAL_TO_TIMESPEC(&time, &ts);
275 DETIMES(dep, &ts, &ts, &ts);
276 vap->va_fsid = dep->de_dev;
277
278 /*
279 * The following computation of the fileid must be the same as
280 * that used in msdosfs_readdir() to compute d_fileno. If not,
281 * pwd doesn't work.
282 *
283 * We now use the starting cluster number as the fileid/fileno.
284 * This works for both files and directories (including the root
285 * directory, on FAT32). Even on FAT32, this will at most be a
286 * 28-bit number, as the high 4 bits of FAT32 cluster numbers
287 * are reserved.
288 *
289 * However, we do need to do something for 0-length files, which
290 * will not have a starting cluster number.
291 *
292 * These files cannot be directories, since (except for /, which
293 * is special-cased anyway) directories contain entries for . and
294 * .., so must have non-zero length.
295 *
296 * In this case, we just create a non-cryptographic hash of the
297 * original fileid calculation, and set the top bit.
298 *
299 * This algorithm has the benefit that all directories, and all
300 * non-zero-length files, will have fileids that are persistent
301 * across mounts and reboots, and that cannot collide (as long
302 * as the filesystem is not corrupt). Zero-length files will
303 * have fileids that are persistent, but that may collide. We
304 * will just have to live with that.
305 */
306 fileid = dep->de_StartCluster;
307
308 if (dep->de_Attributes & ATTR_DIRECTORY) {
309 /* Special-case root */
310 if (dep->de_StartCluster == MSDOSFSROOT)
311 fileid = FAT32(pmp) ? pmp->pm_rootdirblk : 1;
312 } else {
313 if (dep->de_FileSize == 0) {
314 uint32_t dirsperblk;
315 uint64_t fileid64;
316
317 dirsperblk = pmp->pm_BytesPerSec /
318 sizeof(struct direntry);
319
320 fileid64 = (dep->de_dirclust == MSDOSFSROOT) ?
321 roottobn(pmp, 0) : cntobn(pmp, dep->de_dirclust);
322 fileid64 *= dirsperblk;
323 fileid64 += dep->de_diroffset / sizeof(struct direntry);
324
325 fileid = fileidhash(fileid64);
326 }
327 }
328
329 vap->va_fileid = fileid;
330 vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
331 ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
332 vap->va_mode &= dep->de_pmp->pm_mask;
333 if (dep->de_Attributes & ATTR_DIRECTORY) {
334 vap->va_mode |= S_IFDIR;
335 if (pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
336 vap->va_mode |= (vap->va_mode & S_IRUSR) ? S_IXUSR : 0;
337 vap->va_mode |= (vap->va_mode & S_IRGRP) ? S_IXGRP : 0;
338 vap->va_mode |= (vap->va_mode & S_IROTH) ? S_IXOTH : 0;
339 }
340 }
341 vap->va_nlink = 1;
342 vap->va_gid = dep->de_pmp->pm_gid;
343 vap->va_uid = dep->de_pmp->pm_uid;
344 vap->va_rdev = 0;
345 vap->va_size = dep->de_FileSize;
346 dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
347 if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
348 dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
349 dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CTimeHundredth, &vap->va_ctime);
350 } else {
351 vap->va_atime = vap->va_mtime;
352 vap->va_ctime = vap->va_mtime;
353 }
354 vap->va_flags = 0;
355 if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
356 vap->va_flags |= SF_ARCHIVED;
357 vap->va_gen = 0;
358 vap->va_blocksize = dep->de_pmp->pm_bpcluster;
359 vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
360 ~(dep->de_pmp->pm_crbomask);
361 vap->va_type = ap->a_vp->v_type;
362 return (0);
363 }
364
365 int
msdosfs_setattr(v)366 msdosfs_setattr(v)
367 void *v;
368 {
369 struct vop_setattr_args /* {
370 struct vnode *a_vp;
371 struct vattr *a_vap;
372 struct ucred *a_cred;
373 struct proc *a_p;
374 } */ *ap = v;
375 int error = 0;
376 struct denode *dep = VTODE(ap->a_vp);
377 struct vattr *vap = ap->a_vap;
378 struct ucred *cred = ap->a_cred;
379
380 #ifdef MSDOSFS_DEBUG
381 printf("msdosfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n",
382 ap->a_vp, vap, cred, ap->a_p);
383 #endif
384 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
385 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
386 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
387 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL) ||
388 (vap->va_uid != VNOVAL) || (vap->va_gid != VNOVAL)) {
389 #ifdef MSDOSFS_DEBUG
390 printf("msdosfs_setattr(): returning EINVAL\n");
391 printf(" va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n",
392 vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
393 printf(" va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n",
394 vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
395 printf(" va_uid %x, va_gid %x\n",
396 vap->va_uid, vap->va_gid);
397 #endif
398 return (EINVAL);
399 }
400 /*
401 * Directories must not ever get their attributes modified
402 */
403 if (ap->a_vp->v_type == VDIR)
404 return EISDIR;
405
406 if (vap->va_size != VNOVAL) {
407 error = detrunc(dep, (uint32_t)vap->va_size, 0, cred, ap->a_p);
408 if (error)
409 return (error);
410 }
411 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
412 if (cred->cr_uid != dep->de_pmp->pm_uid &&
413 (error = suser_ucred(cred)) &&
414 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
415 (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
416 return (error);
417 if (!(dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)
418 && vap->va_atime.tv_sec != VNOVAL)
419 unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
420 if (vap->va_mtime.tv_sec != VNOVAL)
421 unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
422 dep->de_Attributes |= ATTR_ARCHIVE;
423 dep->de_flag |= DE_MODIFIED;
424 }
425 /*
426 * DOS files only have the ability to have their writability
427 * attribute set, so we use the owner write bit to set the readonly
428 * attribute.
429 */
430 if (vap->va_mode != (mode_t)VNOVAL) {
431 if (cred->cr_uid != dep->de_pmp->pm_uid &&
432 (error = suser_ucred(cred)))
433 return (error);
434 /* We ignore the read and execute bits. */
435 if (vap->va_mode & VWRITE)
436 dep->de_Attributes &= ~ATTR_READONLY;
437 else
438 dep->de_Attributes |= ATTR_READONLY;
439 dep->de_flag |= DE_MODIFIED;
440 }
441 /*
442 * Allow the `archived' bit to be toggled.
443 */
444 if (vap->va_flags != VNOVAL) {
445 if (cred->cr_uid != dep->de_pmp->pm_uid &&
446 (error = suser_ucred(cred)))
447 return (error);
448 if (vap->va_flags & SF_ARCHIVED)
449 dep->de_Attributes &= ~ATTR_ARCHIVE;
450 else
451 dep->de_Attributes |= ATTR_ARCHIVE;
452 dep->de_flag |= DE_MODIFIED;
453 }
454 return (deupdat(dep, 1));
455 }
456
457 int
msdosfs_read(v)458 msdosfs_read(v)
459 void *v;
460 {
461 struct vop_read_args /* {
462 struct vnode *a_vp;
463 struct uio *a_uio;
464 int a_ioflag;
465 struct ucred *a_cred;
466 } */ *ap = v;
467 int error = 0;
468 uint32_t diff;
469 int blsize;
470 int isadir;
471 uint32_t n;
472 long on;
473 daddr_t lbn;
474 daddr_t rablock;
475 daddr_t rablkno;
476 struct buf *bp;
477 struct vnode *vp = ap->a_vp;
478 struct denode *dep = VTODE(vp);
479 struct msdosfsmount *pmp = dep->de_pmp;
480 struct uio *uio = ap->a_uio;
481
482 /*
483 * If they didn't ask for any data, then we are done.
484 */
485 if (uio->uio_resid == 0)
486 return (0);
487 if (uio->uio_offset < 0)
488 return (EINVAL);
489
490 isadir = dep->de_Attributes & ATTR_DIRECTORY;
491 do {
492 if (uio->uio_offset >= dep->de_FileSize)
493 return (0);
494
495 lbn = de_cluster(pmp, uio->uio_offset);
496 on = uio->uio_offset & pmp->pm_crbomask;
497 n = min((uint32_t) (pmp->pm_bpcluster - on), uio->uio_resid);
498
499 /*
500 * de_FileSize is uint32_t, and we know that uio_offset <
501 * de_FileSize, so uio->uio_offset < 2^32. Therefore
502 * the cast to uint32_t on the next line is safe.
503 */
504 diff = dep->de_FileSize - (uint32_t)uio->uio_offset;
505 if (diff < n)
506 n = diff;
507
508 /* convert cluster # to block # if a directory */
509 if (isadir) {
510 error = pcbmap(dep, lbn, &lbn, 0, &blsize);
511 if (error)
512 return (error);
513 }
514 /*
515 * If we are operating on a directory file then be sure to
516 * do i/o with the vnode for the filesystem instead of the
517 * vnode for the directory.
518 */
519 if (isadir) {
520 error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
521 } else {
522 rablock = lbn + 1;
523 rablkno = de_cn2bn(pmp, rablock);
524 if (dep->de_lastr + 1 == lbn &&
525 de_cn2off(pmp, rablock) < dep->de_FileSize)
526 error = breadn(vp, de_cn2bn(pmp, lbn),
527 pmp->pm_bpcluster, &rablkno,
528 &pmp->pm_bpcluster, 1, NOCRED, &bp);
529 else
530 error = bread(vp, de_cn2bn(pmp, lbn),
531 pmp->pm_bpcluster, NOCRED, &bp);
532 dep->de_lastr = lbn;
533 }
534 n = min(n, pmp->pm_bpcluster - bp->b_resid);
535 if (error) {
536 brelse(bp);
537 return (error);
538 }
539 error = uiomove(bp->b_data + on, (int) n, uio);
540 brelse(bp);
541 } while (error == 0 && uio->uio_resid > 0 && n != 0);
542 if (!isadir && !(vp->v_mount->mnt_flag & MNT_NOATIME))
543 dep->de_flag |= DE_ACCESS;
544 return (error);
545 }
546
547 /*
548 * Write data to a file or directory.
549 */
550 int
msdosfs_write(v)551 msdosfs_write(v)
552 void *v;
553 {
554 struct vop_write_args /* {
555 struct vnode *a_vp;
556 struct uio *a_uio;
557 int a_ioflag;
558 struct ucred *a_cred;
559 } */ *ap = v;
560 int n;
561 int croffset;
562 int resid;
563 uint32_t osize;
564 int error = 0;
565 uint32_t count;
566 daddr_t bn, lastcn;
567 struct buf *bp;
568 int ioflag = ap->a_ioflag;
569 struct uio *uio = ap->a_uio;
570 struct proc *p = uio->uio_procp;
571 struct vnode *vp = ap->a_vp;
572 struct vnode *thisvp;
573 struct denode *dep = VTODE(vp);
574 struct msdosfsmount *pmp = dep->de_pmp;
575 struct ucred *cred = ap->a_cred;
576
577 #ifdef MSDOSFS_DEBUG
578 printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
579 vp, uio, ioflag, cred);
580 printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
581 dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
582 #endif
583
584 switch (vp->v_type) {
585 case VREG:
586 if (ioflag & IO_APPEND)
587 uio->uio_offset = dep->de_FileSize;
588 thisvp = vp;
589 break;
590 case VDIR:
591 return EISDIR;
592 default:
593 panic("msdosfs_write(): bad file type");
594 }
595
596 if (uio->uio_offset < 0)
597 return (EINVAL);
598
599 if (uio->uio_resid == 0)
600 return (0);
601
602 /* Don't bother to try to write files larger than the f/s limit */
603 if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX)
604 return (EFBIG);
605
606 /*
607 * If they've exceeded their filesize limit, tell them about it.
608 */
609 if (p &&
610 ((uio->uio_offset + uio->uio_resid) >
611 p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
612 psignal(p, SIGXFSZ);
613 return (EFBIG);
614 }
615
616 /*
617 * If the offset we are starting the write at is beyond the end of
618 * the file, then they've done a seek. Unix filesystems allow
619 * files with holes in them, DOS doesn't so we must fill the hole
620 * with zeroed blocks.
621 */
622 if (uio->uio_offset > dep->de_FileSize) {
623 if ((error = deextend(dep, uio->uio_offset, cred)) != 0)
624 return (error);
625 }
626
627 /*
628 * Remember some values in case the write fails.
629 */
630 resid = uio->uio_resid;
631 osize = dep->de_FileSize;
632
633 /*
634 * If we write beyond the end of the file, extend it to its ultimate
635 * size ahead of the time to hopefully get a contiguous area.
636 */
637 if (uio->uio_offset + resid > osize) {
638 count = de_clcount(pmp, uio->uio_offset + resid) -
639 de_clcount(pmp, osize);
640 if ((error = extendfile(dep, count, NULL, NULL, 0)) &&
641 (error != ENOSPC || (ioflag & IO_UNIT)))
642 goto errexit;
643 lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
644 } else
645 lastcn = de_clcount(pmp, osize) - 1;
646
647 do {
648 if (de_cluster(pmp, uio->uio_offset) > lastcn) {
649 error = ENOSPC;
650 break;
651 }
652
653 bn = de_blk(pmp, uio->uio_offset);
654 if ((uio->uio_offset & pmp->pm_crbomask) == 0
655 && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
656 || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
657 /*
658 * If either the whole cluster gets written,
659 * or we write the cluster from its start beyond EOF,
660 * then no need to read data from disk.
661 */
662 bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
663 clrbuf(bp);
664 /*
665 * Do the bmap now, since pcbmap needs buffers
666 * for the fat table. (see msdosfs_strategy)
667 */
668 if (bp->b_blkno == bp->b_lblkno) {
669 error = pcbmap(dep,
670 de_bn2cn(pmp, bp->b_lblkno),
671 &bp->b_blkno, 0, 0);
672 if (error)
673 bp->b_blkno = -1;
674 }
675 if (bp->b_blkno == -1) {
676 brelse(bp);
677 if (!error)
678 error = EIO; /* XXX */
679 break;
680 }
681 } else {
682 /*
683 * The block we need to write into exists, so read it in.
684 */
685 error = bread(thisvp, bn, pmp->pm_bpcluster,
686 NOCRED, &bp);
687 if (error) {
688 brelse(bp);
689 break;
690 }
691 }
692
693 croffset = uio->uio_offset & pmp->pm_crbomask;
694 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
695 if (uio->uio_offset + n > dep->de_FileSize) {
696 dep->de_FileSize = uio->uio_offset + n;
697 uvm_vnp_setsize(vp, dep->de_FileSize);
698 }
699 uvm_vnp_uncache(vp);
700 /*
701 * Should these vnode_pager_* functions be done on dir
702 * files?
703 */
704
705 /*
706 * Copy the data from user space into the buf header.
707 */
708 error = uiomove(bp->b_data + croffset, n, uio);
709
710 /*
711 * If they want this synchronous then write it and wait for
712 * it. Otherwise, if on a cluster boundary write it
713 * asynchronously so we can move on to the next block
714 * without delay. Otherwise do a delayed write because we
715 * may want to write somemore into the block later.
716 */
717 if (ioflag & IO_SYNC)
718 (void) bwrite(bp);
719 else if (n + croffset == pmp->pm_bpcluster)
720 bawrite(bp);
721 else
722 bdwrite(bp);
723 dep->de_flag |= DE_UPDATE;
724 } while (error == 0 && uio->uio_resid > 0);
725
726 /*
727 * If the write failed and they want us to, truncate the file back
728 * to the size it was before the write was attempted.
729 */
730 errexit:
731 if (error) {
732 if (ioflag & IO_UNIT) {
733 detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
734 uio->uio_offset -= resid - uio->uio_resid;
735 uio->uio_resid = resid;
736 } else {
737 detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
738 if (uio->uio_resid != resid)
739 error = 0;
740 }
741 } else if (ioflag & IO_SYNC)
742 error = deupdat(dep, 1);
743 return (error);
744 }
745
746 int
msdosfs_ioctl(v)747 msdosfs_ioctl(v)
748 void *v;
749 {
750 #if 0
751 struct vop_ioctl_args /* {
752 struct vnode *a_vp;
753 uint32_t a_command;
754 caddr_t a_data;
755 int a_fflag;
756 struct ucred *a_cred;
757 struct proc *a_p;
758 } */ *ap;
759 #endif
760
761 return (ENOTTY);
762 }
763
764 int
msdosfs_poll(v)765 msdosfs_poll(v)
766 void *v;
767 {
768 struct vop_poll_args /* {
769 struct vnode *a_vp;
770 int a_events;
771 struct proc *a_p;
772 } */ *ap = v;
773
774 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
775 }
776
777 /*
778 * Flush the blocks of a file to disk.
779 *
780 * This function is worthless for vnodes that represent directories. Maybe we
781 * could just do a sync if they try an fsync on a directory file.
782 */
783 int
msdosfs_fsync(v)784 msdosfs_fsync(v)
785 void *v;
786 {
787 struct vop_fsync_args /* {
788 struct vnode *a_vp;
789 struct ucred *a_cred;
790 int a_waitfor;
791 struct proc *a_p;
792 } */ *ap = v;
793 struct vnode *vp = ap->a_vp;
794
795 vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
796 return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
797 }
798
799 /*
800 * Flush the blocks of a file to disk.
801 *
802 * This function is worthless for vnodes that represent directories. Maybe we
803 * could just do a sync if they try an fsync on a directory file.
804 */
805 int
msdosfs_remove(v)806 msdosfs_remove(v)
807 void *v;
808 {
809 struct vop_remove_args /* {
810 struct vnode *a_dvp;
811 struct vnode *a_vp;
812 struct componentname *a_cnp;
813 } */ *ap = v;
814 struct denode *dep = VTODE(ap->a_vp);
815 struct denode *ddep = VTODE(ap->a_dvp);
816 int error;
817
818 if (ap->a_vp->v_type == VDIR)
819 error = EPERM;
820 else
821 error = removede(ddep, dep);
822 #ifdef MSDOSFS_DEBUG
823 printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
824 #endif
825 if (ddep == dep)
826 vrele(ap->a_vp);
827 else
828 vput(ap->a_vp); /* causes msdosfs_inactive() to be called
829 * via vrele() */
830 vput(ap->a_dvp);
831 return (error);
832 }
833
834 /*
835 * DOS filesystems don't know what links are. But since we already called
836 * msdosfs_lookup() with create and lockparent, the parent is locked so we
837 * have to free it before we return the error.
838 */
839 int
msdosfs_link(v)840 msdosfs_link(v)
841 void *v;
842 {
843 struct vop_link_args /* {
844 struct vnode *a_dvp;
845 struct vnode *a_vp;
846 struct componentname *a_cnp;
847 } */ *ap = v;
848
849 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
850 vput(ap->a_dvp);
851 return (EOPNOTSUPP);
852 }
853
854 /*
855 * Renames on files require moving the denode to a new hash queue since the
856 * denode's location is used to compute which hash queue to put the file
857 * in. Unless it is a rename in place. For example "mv a b".
858 *
859 * What follows is the basic algorithm:
860 *
861 * if (file move) {
862 * if (dest file exists) {
863 * remove dest file
864 * }
865 * if (dest and src in same directory) {
866 * rewrite name in existing directory slot
867 * } else {
868 * write new entry in dest directory
869 * update offset and dirclust in denode
870 * move denode to new hash chain
871 * clear old directory entry
872 * }
873 * } else {
874 * directory move
875 * if (dest directory exists) {
876 * if (dest is not empty) {
877 * return ENOTEMPTY
878 * }
879 * remove dest directory
880 * }
881 * if (dest and src in same directory) {
882 * rewrite name in existing entry
883 * } else {
884 * be sure dest is not a child of src directory
885 * write entry in dest directory
886 * update "." and ".." in moved directory
887 * update offset and dirclust in denode
888 * move denode to new hash chain
889 * clear old directory entry for moved directory
890 * }
891 * }
892 *
893 * On entry:
894 * source's parent directory is unlocked
895 * source file or directory is unlocked
896 * destination's parent directory is locked
897 * destination file or directory is locked if it exists
898 *
899 * On exit:
900 * all denodes should be released
901 *
902 * Notes:
903 * I'm not sure how the memory containing the pathnames pointed at by the
904 * componentname structures is freed, there may be some memory bleeding
905 * for each rename done.
906 */
907 int
msdosfs_rename(v)908 msdosfs_rename(v)
909 void *v;
910 {
911 struct vop_rename_args /* {
912 struct vnode *a_fdvp;
913 struct vnode *a_fvp;
914 struct componentname *a_fcnp;
915 struct vnode *a_tdvp;
916 struct vnode *a_tvp;
917 struct componentname *a_tcnp;
918 } */ *ap = v;
919 struct vnode *tvp = ap->a_tvp;
920 register struct vnode *tdvp = ap->a_tdvp;
921 struct vnode *fvp = ap->a_fvp;
922 register struct vnode *fdvp = ap->a_fdvp;
923 register struct componentname *tcnp = ap->a_tcnp;
924 register struct componentname *fcnp = ap->a_fcnp;
925 struct proc *p = curproc; /* XXX */
926 register struct denode *ip, *xp, *dp, *zp;
927 u_char toname[11], oldname[11];
928 uint32_t from_diroffset, to_diroffset;
929 u_char to_count;
930 int doingdirectory = 0, newparent = 0;
931 int error;
932 uint32_t cn, pcl;
933 daddr_t bn;
934 struct msdosfsmount *pmp;
935 struct direntry *dotdotp;
936 struct buf *bp;
937
938 pmp = VFSTOMSDOSFS(fdvp->v_mount);
939
940 #ifdef DIAGNOSTIC
941 if ((tcnp->cn_flags & HASBUF) == 0 ||
942 (fcnp->cn_flags & HASBUF) == 0)
943 panic("msdosfs_rename: no name");
944 #endif
945 /*
946 * Check for cross-device rename.
947 */
948 if ((fvp->v_mount != tdvp->v_mount) ||
949 (tvp && (fvp->v_mount != tvp->v_mount))) {
950 error = EXDEV;
951 abortit:
952 VOP_ABORTOP(tdvp, tcnp);
953 if (tdvp == tvp)
954 vrele(tdvp);
955 else
956 vput(tdvp);
957 if (tvp)
958 vput(tvp);
959 VOP_ABORTOP(fdvp, fcnp);
960 vrele(fdvp);
961 vrele(fvp);
962 return (error);
963 }
964
965 /*
966 * If source and dest are the same, do nothing.
967 */
968 if (tvp == fvp) {
969 error = 0;
970 goto abortit;
971 }
972
973 /* */
974 if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
975 goto abortit;
976 dp = VTODE(fdvp);
977 ip = VTODE(fvp);
978
979 /*
980 * Be sure we are not renaming ".", "..", or an alias of ".". This
981 * leads to a crippled directory tree. It's pretty tough to do a
982 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
983 * doesn't work if the ".." entry is missing.
984 */
985 if (ip->de_Attributes & ATTR_DIRECTORY) {
986 /*
987 * Avoid ".", "..", and aliases of "." for obvious reasons.
988 */
989 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
990 dp == ip ||
991 (fcnp->cn_flags & ISDOTDOT) ||
992 (tcnp->cn_flags & ISDOTDOT) ||
993 (ip->de_flag & DE_RENAME)) {
994 VOP_UNLOCK(fvp, 0, p);
995 error = EINVAL;
996 goto abortit;
997 }
998 ip->de_flag |= DE_RENAME;
999 doingdirectory++;
1000 }
1001
1002 /*
1003 * When the target exists, both the directory
1004 * and target vnodes are returned locked.
1005 */
1006 dp = VTODE(tdvp);
1007 xp = tvp ? VTODE(tvp) : NULL;
1008 /*
1009 * Remember direntry place to use for destination
1010 */
1011 to_diroffset = dp->de_fndoffset;
1012 to_count = dp->de_fndcnt;
1013
1014 /*
1015 * If ".." must be changed (ie the directory gets a new
1016 * parent) then the source directory must not be in the
1017 * directory hierarchy above the target, as this would
1018 * orphan everything below the source directory. Also
1019 * the user must have write permission in the source so
1020 * as to be able to change "..". We must repeat the call
1021 * to namei, as the parent directory is unlocked by the
1022 * call to doscheckpath().
1023 */
1024 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
1025 VOP_UNLOCK(fvp, 0, p);
1026 if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
1027 newparent = 1;
1028 vrele(fdvp);
1029 if (doingdirectory && newparent) {
1030 if (error) /* write access check above */
1031 goto bad1;
1032 if (xp != NULL)
1033 vput(tvp);
1034 /*
1035 * doscheckpath() vput()'s dp,
1036 * so we have to do a relookup afterwards
1037 */
1038 if ((error = doscheckpath(ip, dp)) != 0)
1039 goto out;
1040 if ((tcnp->cn_flags & SAVESTART) == 0)
1041 panic("msdosfs_rename: lost to startdir");
1042 if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
1043 goto out;
1044 dp = VTODE(tdvp);
1045 xp = tvp ? VTODE(tvp) : NULL;
1046 }
1047
1048 if (xp != NULL) {
1049 /*
1050 * Target must be empty if a directory and have no links
1051 * to it. Also, ensure source and target are compatible
1052 * (both directories, or both not directories).
1053 */
1054 if (xp->de_Attributes & ATTR_DIRECTORY) {
1055 if (!dosdirempty(xp)) {
1056 error = ENOTEMPTY;
1057 goto bad1;
1058 }
1059 if (!doingdirectory) {
1060 error = ENOTDIR;
1061 goto bad1;
1062 }
1063 cache_purge(tdvp);
1064 } else if (doingdirectory) {
1065 error = EISDIR;
1066 goto bad1;
1067 }
1068 if ((error = removede(dp, xp)) != 0)
1069 goto bad1;
1070 vput(tvp);
1071 xp = NULL;
1072 }
1073
1074 /*
1075 * Convert the filename in tcnp into a dos filename. We copy this
1076 * into the denode and directory entry for the destination
1077 * file/directory.
1078 */
1079 if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0)
1080 goto bad1;
1081
1082 /*
1083 * Since from wasn't locked at various places above,
1084 * have to do a relookup here.
1085 */
1086 fcnp->cn_flags &= ~MODMASK;
1087 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1088 if ((fcnp->cn_flags & SAVESTART) == 0)
1089 panic("msdosfs_rename: lost from startdir");
1090 if (!newparent)
1091 VOP_UNLOCK(tdvp, 0, p);
1092 (void) relookup(fdvp, &fvp, fcnp);
1093 if (fvp == NULL) {
1094 /*
1095 * From name has disappeared.
1096 */
1097 if (doingdirectory)
1098 panic("rename: lost dir entry");
1099 vrele(ap->a_fvp);
1100 if (newparent)
1101 VOP_UNLOCK(tdvp, 0, p);
1102 vrele(tdvp);
1103 return 0;
1104 }
1105 xp = VTODE(fvp);
1106 zp = VTODE(fdvp);
1107 from_diroffset = zp->de_fndoffset;
1108
1109 /*
1110 * Ensure that the directory entry still exists and has not
1111 * changed till now. If the source is a file the entry may
1112 * have been unlinked or renamed. In either case there is
1113 * no further work to be done. If the source is a directory
1114 * then it cannot have been rmdir'ed or renamed; this is
1115 * prohibited by the DE_RENAME flag.
1116 */
1117 if (xp != ip) {
1118 if (doingdirectory)
1119 panic("rename: lost dir entry");
1120 vrele(ap->a_fvp);
1121 if (newparent)
1122 VOP_UNLOCK(fdvp, 0, p);
1123 xp = NULL;
1124 } else {
1125 vrele(fvp);
1126 xp = NULL;
1127
1128 /*
1129 * First write a new entry in the destination
1130 * directory and mark the entry in the source directory
1131 * as deleted. Then move the denode to the correct hash
1132 * chain for its new location in the filesystem. And, if
1133 * we moved a directory, then update its .. entry to point
1134 * to the new parent directory.
1135 */
1136 bcopy(ip->de_Name, oldname, 11);
1137 bcopy(toname, ip->de_Name, 11); /* update denode */
1138 dp->de_fndoffset = to_diroffset;
1139 dp->de_fndcnt = to_count;
1140 error = createde(ip, dp, (struct denode **)0, tcnp);
1141 if (error) {
1142 bcopy(oldname, ip->de_Name, 11);
1143 if (newparent)
1144 VOP_UNLOCK(fdvp, 0, p);
1145 goto bad;
1146 }
1147 ip->de_refcnt++;
1148 zp->de_fndoffset = from_diroffset;
1149 if ((error = removede(zp, ip)) != 0) {
1150 /* XXX should really panic here, fs is corrupt */
1151 if (newparent)
1152 VOP_UNLOCK(fdvp, 0, p);
1153 goto bad;
1154 }
1155 if (!doingdirectory) {
1156 error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
1157 &ip->de_dirclust, 0);
1158 if (error) {
1159 /* XXX should really panic here, fs is corrupt */
1160 if (newparent)
1161 VOP_UNLOCK(fdvp, 0, p);
1162 goto bad;
1163 }
1164 if (ip->de_dirclust != MSDOSFSROOT)
1165 ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
1166 }
1167 reinsert(ip);
1168 if (newparent)
1169 VOP_UNLOCK(fdvp, 0, p);
1170 }
1171
1172 /*
1173 * If we moved a directory to a new parent directory, then we must
1174 * fixup the ".." entry in the moved directory.
1175 */
1176 if (doingdirectory && newparent) {
1177 cn = ip->de_StartCluster;
1178 if (cn == MSDOSFSROOT) {
1179 /* this should never happen */
1180 panic("msdosfs_rename: updating .. in root directory?");
1181 } else
1182 bn = cntobn(pmp, cn);
1183 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
1184 NOCRED, &bp);
1185 if (error) {
1186 /* XXX should really panic here, fs is corrupt */
1187 brelse(bp);
1188 goto bad;
1189 }
1190 dotdotp = (struct direntry *)bp->b_data;
1191 putushort(dotdotp[0].deStartCluster, dp->de_StartCluster);
1192 pcl = dp->de_StartCluster;
1193 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
1194 pcl = 0;
1195 putushort(dotdotp[1].deStartCluster, pcl);
1196 if (FAT32(pmp)) {
1197 putushort(dotdotp[0].deHighClust, cn >> 16);
1198 putushort(dotdotp[1].deHighClust, pcl >> 16);
1199 }
1200 if ((error = bwrite(bp)) != 0) {
1201 /* XXX should really panic here, fs is corrupt */
1202 goto bad;
1203 }
1204 }
1205
1206 bad:
1207 VOP_UNLOCK(fvp, 0, p);
1208 vrele(fdvp);
1209 bad1:
1210 if (xp)
1211 vput(tvp);
1212 vput(tdvp);
1213 out:
1214 ip->de_flag &= ~DE_RENAME;
1215 vrele(fvp);
1216 return (error);
1217
1218 }
1219
1220 struct {
1221 struct direntry dot;
1222 struct direntry dotdot;
1223 } dosdirtemplate = {
1224 { ". ", " ", /* the . entry */
1225 ATTR_DIRECTORY, /* file attribute */
1226 CASE_LOWER_BASE | CASE_LOWER_EXT, /* lower case */
1227 0, /* create time 100ths */
1228 { 0, 0 }, { 0, 0 }, /* create time & date */
1229 { 0, 0 }, /* access date */
1230 { 0, 0 }, /* high bits of start cluster */
1231 { 210, 4 }, { 210, 4 }, /* modify time & date */
1232 { 0, 0 }, /* startcluster */
1233 { 0, 0, 0, 0 } /* filesize */
1234 },
1235 { ".. ", " ", /* the .. entry */
1236 ATTR_DIRECTORY, /* file attribute */
1237 CASE_LOWER_BASE | CASE_LOWER_EXT, /* lower case */
1238 0, /* create time 100ths */
1239 { 0, 0 }, { 0, 0 }, /* create time & date */
1240 { 0, 0 }, /* access date */
1241 { 0, 0 }, /* high bits of start cluster */
1242 { 210, 4 }, { 210, 4 }, /* modify time & date */
1243 { 0, 0 }, /* startcluster */
1244 { 0, 0, 0, 0 } /* filesize */
1245 }
1246 };
1247
1248 int
msdosfs_mkdir(v)1249 msdosfs_mkdir(v)
1250 void *v;
1251 {
1252 struct vop_mkdir_args /* {
1253 struct vnode *a_dvp;
1254 struvt vnode **a_vpp;
1255 struvt componentname *a_cnp;
1256 struct vattr *a_vap;
1257 } */ *ap = v;
1258 struct componentname *cnp = ap->a_cnp;
1259 struct denode ndirent;
1260 struct denode *dep;
1261 struct denode *pdep = VTODE(ap->a_dvp);
1262 int error;
1263 int bn;
1264 uint32_t newcluster, pcl;
1265 struct direntry *denp;
1266 struct msdosfsmount *pmp = pdep->de_pmp;
1267 struct buf *bp;
1268 struct timespec ts;
1269
1270 /*
1271 * If this is the root directory and there is no space left we
1272 * can't do anything. This is because the root directory can not
1273 * change size.
1274 */
1275 if (pdep->de_StartCluster == MSDOSFSROOT
1276 && pdep->de_fndoffset >= pdep->de_FileSize) {
1277 error = ENOSPC;
1278 goto bad2;
1279 }
1280
1281 /*
1282 * Allocate a cluster to hold the about to be created directory.
1283 */
1284 error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
1285 if (error)
1286 goto bad2;
1287
1288 bzero(&ndirent, sizeof(ndirent));
1289 ndirent.de_pmp = pmp;
1290 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
1291 TIMEVAL_TO_TIMESPEC(&time, &ts);
1292 DETIMES(&ndirent, &ts, &ts, &ts);
1293
1294 /*
1295 * Now fill the cluster with the "." and ".." entries. And write
1296 * the cluster to disk. This way it is there for the parent
1297 * directory to be pointing at if there were a crash.
1298 */
1299 bn = cntobn(pmp, newcluster);
1300 /* always succeeds */
1301 bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
1302 bzero(bp->b_data, pmp->pm_bpcluster);
1303 bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
1304 denp = (struct direntry *)bp->b_data;
1305 putushort(denp[0].deStartCluster, newcluster);
1306 putushort(denp[0].deCDate, ndirent.de_CDate);
1307 putushort(denp[0].deCTime, ndirent.de_CTime);
1308 denp[0].deCTimeHundredth = ndirent.de_CTimeHundredth;
1309 putushort(denp[0].deADate, ndirent.de_ADate);
1310 putushort(denp[0].deMDate, ndirent.de_MDate);
1311 putushort(denp[0].deMTime, ndirent.de_MTime);
1312 pcl = pdep->de_StartCluster;
1313 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
1314 pcl = 0;
1315 putushort(denp[1].deStartCluster, pcl);
1316 putushort(denp[1].deCDate, ndirent.de_CDate);
1317 putushort(denp[1].deCTime, ndirent.de_CTime);
1318 denp[1].deCTimeHundredth = ndirent.de_CTimeHundredth;
1319 putushort(denp[1].deADate, ndirent.de_ADate);
1320 putushort(denp[1].deMDate, ndirent.de_MDate);
1321 putushort(denp[1].deMTime, ndirent.de_MTime);
1322 if (FAT32(pmp)) {
1323 putushort(denp[0].deHighClust, newcluster >> 16);
1324 putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
1325 }
1326
1327 if ((error = bwrite(bp)) != 0)
1328 goto bad;
1329
1330 /*
1331 * Now build up a directory entry pointing to the newly allocated
1332 * cluster. This will be written to an empty slot in the parent
1333 * directory.
1334 */
1335 #ifdef DIAGNOSTIC
1336 if ((cnp->cn_flags & HASBUF) == 0)
1337 panic("msdosfs_mkdir: no name");
1338 #endif
1339 if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
1340 goto bad;
1341
1342 ndirent.de_Attributes = ATTR_DIRECTORY;
1343 ndirent.de_StartCluster = newcluster;
1344 ndirent.de_FileSize = 0;
1345 ndirent.de_dev = pdep->de_dev;
1346 ndirent.de_devvp = pdep->de_devvp;
1347 if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
1348 goto bad;
1349 if ((cnp->cn_flags & SAVESTART) == 0)
1350 pool_put(&namei_pool, cnp->cn_pnbuf);
1351 vput(ap->a_dvp);
1352 *ap->a_vpp = DETOV(dep);
1353 return (0);
1354
1355 bad:
1356 clusterfree(pmp, newcluster, NULL);
1357 bad2:
1358 pool_put(&namei_pool, cnp->cn_pnbuf);
1359 vput(ap->a_dvp);
1360 return (error);
1361 }
1362
1363 int
msdosfs_rmdir(v)1364 msdosfs_rmdir(v)
1365 void *v;
1366 {
1367 struct vop_rmdir_args /* {
1368 struct vnode *a_dvp;
1369 struct vnode *a_vp;
1370 struct componentname *a_cnp;
1371 } */ *ap = v;
1372 register struct vnode *vp = ap->a_vp;
1373 register struct vnode *dvp = ap->a_dvp;
1374 register struct componentname *cnp = ap->a_cnp;
1375 register struct denode *ip, *dp;
1376 int error;
1377
1378 ip = VTODE(vp);
1379 dp = VTODE(dvp);
1380 /*
1381 * No rmdir "." please.
1382 */
1383 if (dp == ip) {
1384 vrele(dvp);
1385 vput(vp);
1386 return (EINVAL);
1387 }
1388 /*
1389 * Verify the directory is empty (and valid).
1390 * (Rmdir ".." won't be valid since
1391 * ".." will contain a reference to
1392 * the current directory and thus be
1393 * non-empty.)
1394 */
1395 error = 0;
1396 if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
1397 error = ENOTEMPTY;
1398 goto out;
1399 }
1400 /*
1401 * Delete the entry from the directory. For dos filesystems this
1402 * gets rid of the directory entry on disk, the in memory copy
1403 * still exists but the de_refcnt is <= 0. This prevents it from
1404 * being found by deget(). When the vput() on dep is done we give
1405 * up access and eventually msdosfs_reclaim() will be called which
1406 * will remove it from the denode cache.
1407 */
1408 if ((error = removede(dp, ip)) != 0)
1409 goto out;
1410 /*
1411 * This is where we decrement the link count in the parent
1412 * directory. Since dos filesystems don't do this we just purge
1413 * the name cache and let go of the parent directory denode.
1414 */
1415 cache_purge(dvp);
1416 vput(dvp);
1417 dvp = NULL;
1418 /*
1419 * Truncate the directory that is being deleted.
1420 */
1421 error = detrunc(ip, (uint32_t)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
1422 cache_purge(vp);
1423 out:
1424 if (dvp)
1425 vput(dvp);
1426 vput(vp);
1427 return (error);
1428 }
1429
1430 /*
1431 * DOS filesystems don't know what symlinks are.
1432 */
1433 int
msdosfs_symlink(v)1434 msdosfs_symlink(v)
1435 void *v;
1436 {
1437 struct vop_symlink_args /* {
1438 struct vnode *a_dvp;
1439 struct vnode **a_vpp;
1440 struct componentname *a_cnp;
1441 struct vattr *a_vap;
1442 char *a_target;
1443 } */ *ap = v;
1444
1445 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
1446 vput(ap->a_dvp);
1447 return (EOPNOTSUPP);
1448 }
1449
1450 int
msdosfs_readdir(v)1451 msdosfs_readdir(v)
1452 void *v;
1453 {
1454 struct vop_readdir_args /* {
1455 struct vnode *a_vp;
1456 struct uio *a_uio;
1457 struct ucred *a_cred;
1458 int *a_eofflag;
1459 u_long **a_cookies;
1460 int *a_ncookies;
1461 } */ *ap = v;
1462 int error = 0;
1463 int diff;
1464 long n;
1465 int blsize;
1466 long on;
1467 long lost;
1468 long count;
1469 uint32_t dirsperblk;
1470 uint32_t cn;
1471 uint32_t fileno;
1472 long bias = 0;
1473 daddr_t bn, lbn;
1474 struct buf *bp;
1475 struct denode *dep = VTODE(ap->a_vp);
1476 struct msdosfsmount *pmp = dep->de_pmp;
1477 struct direntry *dentp;
1478 struct dirent dirbuf;
1479 struct uio *uio = ap->a_uio;
1480 u_long *cookies = NULL;
1481 int ncookies = 0;
1482 off_t offset;
1483 int chksum = -1;
1484
1485 #ifdef MSDOSFS_DEBUG
1486 printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
1487 ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
1488 #endif
1489
1490 /*
1491 * msdosfs_readdir() won't operate properly on regular files since
1492 * it does i/o only with the filesystem vnode, and hence can
1493 * retrieve the wrong block from the buffer cache for a plain file.
1494 * So, fail attempts to readdir() on a plain file.
1495 */
1496 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
1497 return (ENOTDIR);
1498
1499 /*
1500 * To be safe, initialize dirbuf
1501 */
1502 bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
1503
1504 /*
1505 * If the user buffer is smaller than the size of one dos directory
1506 * entry or the file offset is not a multiple of the size of a
1507 * directory entry, then we fail the read.
1508 */
1509 count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
1510 offset = uio->uio_offset;
1511 if (count < sizeof(struct direntry) ||
1512 (offset & (sizeof(struct direntry) - 1)))
1513 return (EINVAL);
1514 lost = uio->uio_resid - count;
1515 uio->uio_resid = count;
1516
1517 if (ap->a_ncookies) {
1518 ncookies = uio->uio_resid / sizeof(struct direntry) + 3;
1519 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1520 M_WAITOK);
1521 *ap->a_cookies = cookies;
1522 *ap->a_ncookies = ncookies;
1523 }
1524
1525 dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
1526
1527 /*
1528 * If they are reading from the root directory then, we simulate
1529 * the . and .. entries since these don't exist in the root
1530 * directory. We also set the offset bias to make up for having to
1531 * simulate these entries. By this I mean that at file offset 64 we
1532 * read the first entry in the root directory that lives on disk.
1533 */
1534 if (dep->de_StartCluster == MSDOSFSROOT
1535 || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
1536 #if 0
1537 printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
1538 offset);
1539 #endif
1540 bias = 2 * sizeof(struct direntry);
1541 if (offset < bias) {
1542 for (n = (int)offset / sizeof(struct direntry);
1543 n < 2; n++) {
1544 if (FAT32(pmp))
1545 dirbuf.d_fileno = pmp->pm_rootdirblk;
1546 else
1547 dirbuf.d_fileno = 1;
1548 dirbuf.d_type = DT_DIR;
1549 switch (n) {
1550 case 0:
1551 dirbuf.d_namlen = 1;
1552 strlcpy(dirbuf.d_name, ".",
1553 sizeof dirbuf.d_name);
1554 break;
1555 case 1:
1556 dirbuf.d_namlen = 2;
1557 strlcpy(dirbuf.d_name, "..",
1558 sizeof dirbuf.d_name);
1559 break;
1560 }
1561 dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
1562 if (uio->uio_resid < dirbuf.d_reclen)
1563 goto out;
1564 error = uiomove((caddr_t) &dirbuf,
1565 dirbuf.d_reclen, uio);
1566 if (error)
1567 goto out;
1568 offset += sizeof(struct direntry);
1569 if (cookies) {
1570 *cookies++ = offset;
1571 if (--ncookies <= 0)
1572 goto out;
1573 }
1574 }
1575 }
1576 }
1577
1578 while (uio->uio_resid > 0) {
1579 lbn = de_cluster(pmp, offset - bias);
1580 on = (offset - bias) & pmp->pm_crbomask;
1581 n = min(pmp->pm_bpcluster - on, uio->uio_resid);
1582 diff = dep->de_FileSize - (offset - bias);
1583 if (diff <= 0)
1584 break;
1585 n = min(n, diff);
1586 if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0)
1587 break;
1588 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
1589 if (error) {
1590 brelse(bp);
1591 return (error);
1592 }
1593 n = min(n, blsize - bp->b_resid);
1594
1595 /*
1596 * Convert from dos directory entries to fs-independent
1597 * directory entries.
1598 */
1599 for (dentp = (struct direntry *)(bp->b_data + on);
1600 (char *)dentp < bp->b_data + on + n;
1601 dentp++, offset += sizeof(struct direntry)) {
1602 #if 0
1603 printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
1604 dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
1605 #endif
1606 /*
1607 * If this is an unused entry, we can stop.
1608 */
1609 if (dentp->deName[0] == SLOT_EMPTY) {
1610 brelse(bp);
1611 goto out;
1612 }
1613 /*
1614 * Skip deleted entries.
1615 */
1616 if (dentp->deName[0] == SLOT_DELETED) {
1617 chksum = -1;
1618 continue;
1619 }
1620
1621 /*
1622 * Handle Win95 long directory entries
1623 */
1624 if (dentp->deAttributes == ATTR_WIN95) {
1625 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
1626 continue;
1627 chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum);
1628 continue;
1629 }
1630
1631 /*
1632 * Skip volume labels
1633 */
1634 if (dentp->deAttributes & ATTR_VOLUME) {
1635 chksum = -1;
1636 continue;
1637 }
1638
1639 /*
1640 * This computation of d_fileno must match
1641 * the computation of va_fileid in
1642 * msdosfs_getattr.
1643 */
1644 fileno = getushort(dentp->deStartCluster);
1645 if (FAT32(pmp))
1646 fileno |= getushort(dentp->deHighClust) << 16;
1647
1648 if (dentp->deAttributes & ATTR_DIRECTORY) {
1649 /* Special-case root */
1650 if (fileno == MSDOSFSROOT) {
1651 fileno = FAT32(pmp) ?
1652 pmp->pm_rootdirblk : 1;
1653 }
1654
1655 dirbuf.d_fileno = fileno;
1656 dirbuf.d_type = DT_DIR;
1657 } else {
1658 if (getulong(dentp->deFileSize) == 0) {
1659 uint64_t fileno64;
1660
1661 fileno64 = (cn == MSDOSFSROOT) ?
1662 roottobn(pmp, 0) : cntobn(pmp, cn);
1663
1664 fileno64 *= dirsperblk;
1665 fileno64 += dentp -
1666 (struct direntry *)bp->b_data;
1667
1668 fileno = fileidhash(fileno64);
1669 }
1670
1671 dirbuf.d_fileno = fileno;
1672 dirbuf.d_type = DT_REG;
1673 }
1674
1675 if (chksum != winChksum(dentp->deName))
1676 dirbuf.d_namlen = dos2unixfn(dentp->deName,
1677 (u_char *)dirbuf.d_name,
1678 pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
1679 else
1680 dirbuf.d_name[dirbuf.d_namlen] = 0;
1681 chksum = -1;
1682 dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
1683 if (uio->uio_resid < dirbuf.d_reclen) {
1684 brelse(bp);
1685 goto out;
1686 }
1687 error = uiomove((caddr_t) &dirbuf,
1688 dirbuf.d_reclen, uio);
1689 if (error) {
1690 brelse(bp);
1691 goto out;
1692 }
1693 if (cookies) {
1694 *cookies++ = offset + sizeof(struct direntry);
1695 if (--ncookies <= 0) {
1696 brelse(bp);
1697 goto out;
1698 }
1699 }
1700 }
1701 brelse(bp);
1702 }
1703
1704 out:
1705 /* Subtract unused cookies */
1706 if (ap->a_ncookies)
1707 *ap->a_ncookies -= ncookies;
1708
1709 uio->uio_offset = offset;
1710 uio->uio_resid += lost;
1711 if (dep->de_FileSize - (offset - bias) <= 0)
1712 *ap->a_eofflag = 1;
1713 else
1714 *ap->a_eofflag = 0;
1715 return (error);
1716 }
1717
1718 /*
1719 * DOS filesystems don't know what symlinks are.
1720 */
1721 int
msdosfs_readlink(v)1722 msdosfs_readlink(v)
1723 void *v;
1724 {
1725 #if 0
1726 struct vop_readlink_args /* {
1727 struct vnode *a_vp;
1728 struct uio *a_uio;
1729 struct ucred *a_cred;
1730 } */ *ap;
1731 #endif
1732
1733 return (EINVAL);
1734 }
1735
1736 int
msdosfs_lock(v)1737 msdosfs_lock(v)
1738 void *v;
1739 {
1740 struct vop_lock_args /* {
1741 struct vnode *a_vp;
1742 int a_flags;
1743 struct proc *a_p;
1744 } */ *ap = v;
1745 struct vnode *vp = ap->a_vp;
1746
1747 return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags, &vp->v_interlock,
1748 ap->a_p));
1749 }
1750
1751 int
msdosfs_unlock(v)1752 msdosfs_unlock(v)
1753 void *v;
1754 {
1755 struct vop_unlock_args /* {
1756 struct vnode *vp;
1757 } */ *ap = v;
1758 struct vnode *vp = ap->a_vp;
1759
1760 return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags | LK_RELEASE,
1761 &vp->v_interlock, ap->a_p));
1762 }
1763
1764 int
msdosfs_islocked(v)1765 msdosfs_islocked(v)
1766 void *v;
1767 {
1768 struct vop_islocked_args /* {
1769 struct vnode *a_vp;
1770 } */ *ap = v;
1771
1772 return (lockstatus(&VTODE(ap->a_vp)->de_lock));
1773 }
1774
1775 /*
1776 * vp - address of vnode file the file
1777 * bn - which cluster we are interested in mapping to a filesystem block number.
1778 * vpp - returns the vnode for the block special file holding the filesystem
1779 * containing the file of interest
1780 * bnp - address of where to return the filesystem relative block number
1781 */
1782 int
msdosfs_bmap(v)1783 msdosfs_bmap(v)
1784 void *v;
1785 {
1786 struct vop_bmap_args /* {
1787 struct vnode *a_vp;
1788 daddr_t a_bn;
1789 struct vnode **a_vpp;
1790 daddr_t *a_bnp;
1791 int *a_runp;
1792 } */ *ap = v;
1793 struct denode *dep = VTODE(ap->a_vp);
1794 struct msdosfsmount *pmp = dep->de_pmp;
1795
1796 if (ap->a_vpp != NULL)
1797 *ap->a_vpp = dep->de_devvp;
1798 if (ap->a_bnp == NULL)
1799 return (0);
1800 if (ap->a_runp) {
1801 /*
1802 * Sequential clusters should be counted here.
1803 */
1804 *ap->a_runp = 0;
1805 }
1806 return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
1807 }
1808
1809 int
msdosfs_reallocblks(v)1810 msdosfs_reallocblks(v)
1811 void *v;
1812 {
1813 #if 0
1814 struct vop_reallocblks_args /* {
1815 struct vnode *a_vp;
1816 struct cluster_save *a_buflist;
1817 } */ *ap = v;
1818 #endif
1819
1820 /* Currently no support for clustering */ /* XXX */
1821 return (ENOSPC);
1822 }
1823
1824 int
msdosfs_strategy(v)1825 msdosfs_strategy(v)
1826 void *v;
1827 {
1828 struct vop_strategy_args /* {
1829 struct buf *a_bp;
1830 } */ *ap = v;
1831 struct buf *bp = ap->a_bp;
1832 struct denode *dep = VTODE(bp->b_vp);
1833 struct vnode *vp;
1834 int error = 0;
1835 int s;
1836
1837 if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
1838 panic("msdosfs_strategy: spec");
1839 /*
1840 * If we don't already know the filesystem relative block number
1841 * then get it using pcbmap(). If pcbmap() returns the block
1842 * number as -1 then we've got a hole in the file. DOS filesystems
1843 * don't allow files with holes, so we shouldn't ever see this.
1844 */
1845 if (bp->b_blkno == bp->b_lblkno) {
1846 error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
1847 &bp->b_blkno, 0, 0);
1848 if (error)
1849 bp->b_blkno = -1;
1850 if (bp->b_blkno == -1)
1851 clrbuf(bp);
1852 }
1853 if (bp->b_blkno == -1) {
1854 s = splbio();
1855 biodone(bp);
1856 splx(s);
1857 return (error);
1858 }
1859
1860 /*
1861 * Read/write the block from/to the disk that contains the desired
1862 * file block.
1863 */
1864
1865 vp = dep->de_devvp;
1866 bp->b_dev = vp->v_rdev;
1867 VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
1868 return (0);
1869 }
1870
1871 int
msdosfs_print(v)1872 msdosfs_print(v)
1873 void *v;
1874 {
1875 struct vop_print_args /* {
1876 struct vnode *vp;
1877 } */ *ap = v;
1878 struct denode *dep = VTODE(ap->a_vp);
1879
1880 printf(
1881 "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
1882 (long)dep->de_StartCluster, (long)dep->de_dirclust,
1883 (long)dep->de_diroffset);
1884 printf(" dev %d, %d, %s\n",
1885 major(dep->de_dev), minor(dep->de_dev),
1886 VOP_ISLOCKED(ap->a_vp) ? "(LOCKED)" : "");
1887 #ifdef DIAGNOSTIC
1888 lockmgr_printinfo(&dep->de_lock);
1889 #endif
1890
1891 return (0);
1892 }
1893
1894 int
msdosfs_advlock(v)1895 msdosfs_advlock(v)
1896 void *v;
1897 {
1898 struct vop_advlock_args /* {
1899 struct vnode *a_vp;
1900 caddr_t a_id;
1901 int a_op;
1902 struct flock *a_fl;
1903 int a_flags;
1904 } */ *ap = v;
1905 register struct denode *dep = VTODE(ap->a_vp);
1906
1907 return (lf_advlock(&dep->de_lockf, dep->de_FileSize, ap->a_id, ap->a_op,
1908 ap->a_fl, ap->a_flags));
1909 }
1910
1911 int
msdosfs_pathconf(v)1912 msdosfs_pathconf(v)
1913 void *v;
1914 {
1915 struct vop_pathconf_args /* {
1916 struct vnode *a_vp;
1917 int a_name;
1918 register_t *a_retval;
1919 } */ *ap = v;
1920 struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
1921
1922 switch (ap->a_name) {
1923 case _PC_LINK_MAX:
1924 *ap->a_retval = 1;
1925 return (0);
1926 case _PC_NAME_MAX:
1927 *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
1928 return (0);
1929 case _PC_PATH_MAX:
1930 *ap->a_retval = PATH_MAX;
1931 return (0);
1932 case _PC_CHOWN_RESTRICTED:
1933 *ap->a_retval = 1;
1934 return (0);
1935 case _PC_NO_TRUNC:
1936 *ap->a_retval = 0;
1937 return (0);
1938 default:
1939 return (EINVAL);
1940 }
1941 /* NOTREACHED */
1942 }
1943
1944 /*
1945 * Thomas Wang's hash function, severely hacked to always set the high
1946 * bit on the number it returns (so no longer a proper hash function).
1947 */
1948 static uint32_t
fileidhash(uint64_t fileid)1949 fileidhash(uint64_t fileid)
1950 {
1951 uint64_t c1 = 0x6e5ea73858134343LL;
1952 uint64_t c2 = 0xb34e8f99a2ec9ef5LL;
1953
1954 /*
1955 * We now have the original fileid value, as 64-bit value.
1956 * We need to reduce it to 32-bits, with the top bit set.
1957 */
1958 fileid ^= ((c1 ^ fileid) >> 32);
1959 fileid *= c1;
1960 fileid ^= ((c2 ^ fileid) >> 31);
1961 fileid *= c2;
1962 fileid ^= ((c1 ^ fileid) >> 32);
1963
1964 return (uint32_t)(fileid | 0x80000000);
1965 }
1966
1967 /* Global vfs data structures for msdosfs */
1968 int (**msdosfs_vnodeop_p)(void *);
1969 struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
1970 { &vop_default_desc, vn_default_error },
1971 { &vop_lookup_desc, msdosfs_lookup }, /* lookup */
1972 { &vop_create_desc, msdosfs_create }, /* create */
1973 { &vop_mknod_desc, msdosfs_mknod }, /* mknod */
1974 { &vop_open_desc, msdosfs_open }, /* open */
1975 { &vop_close_desc, msdosfs_close }, /* close */
1976 { &vop_access_desc, msdosfs_access }, /* access */
1977 { &vop_getattr_desc, msdosfs_getattr }, /* getattr */
1978 { &vop_setattr_desc, msdosfs_setattr }, /* setattr */
1979 { &vop_read_desc, msdosfs_read }, /* read */
1980 { &vop_write_desc, msdosfs_write }, /* write */
1981 { &vop_lease_desc, msdosfs_lease_check }, /* lease */
1982 { &vop_ioctl_desc, msdosfs_ioctl }, /* ioctl */
1983 { &vop_poll_desc, msdosfs_poll }, /* poll */
1984 { &vop_fsync_desc, msdosfs_fsync }, /* fsync */
1985 { &vop_remove_desc, msdosfs_remove }, /* remove */
1986 { &vop_link_desc, msdosfs_link }, /* link */
1987 { &vop_rename_desc, msdosfs_rename }, /* rename */
1988 { &vop_mkdir_desc, msdosfs_mkdir }, /* mkdir */
1989 { &vop_rmdir_desc, msdosfs_rmdir }, /* rmdir */
1990 { &vop_symlink_desc, msdosfs_symlink }, /* symlink */
1991 { &vop_readdir_desc, msdosfs_readdir }, /* readdir */
1992 { &vop_readlink_desc, msdosfs_readlink }, /* readlink */
1993 { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
1994 { &vop_inactive_desc, msdosfs_inactive }, /* inactive */
1995 { &vop_reclaim_desc, msdosfs_reclaim }, /* reclaim */
1996 { &vop_lock_desc, msdosfs_lock }, /* lock */
1997 { &vop_unlock_desc, msdosfs_unlock }, /* unlock */
1998 { &vop_bmap_desc, msdosfs_bmap }, /* bmap */
1999 { &vop_strategy_desc, msdosfs_strategy }, /* strategy */
2000 { &vop_print_desc, msdosfs_print }, /* print */
2001 { &vop_islocked_desc, msdosfs_islocked }, /* islocked */
2002 { &vop_pathconf_desc, msdosfs_pathconf }, /* pathconf */
2003 { &vop_advlock_desc, msdosfs_advlock }, /* advlock */
2004 { &vop_reallocblks_desc, msdosfs_reallocblks }, /* reallocblks */
2005 { &vop_bwrite_desc, vop_generic_bwrite }, /* bwrite */
2006 { (struct vnodeop_desc *)NULL, (int (*)(void *))NULL }
2007 };
2008 struct vnodeopv_desc msdosfs_vnodeop_opv_desc =
2009 { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries };
2010