This source file includes following definitions.
- msdosfs_create
- msdosfs_mknod
- msdosfs_open
- msdosfs_close
- msdosfs_access
- msdosfs_getattr
- msdosfs_setattr
- msdosfs_read
- msdosfs_write
- msdosfs_ioctl
- msdosfs_poll
- msdosfs_fsync
- msdosfs_remove
- msdosfs_link
- msdosfs_rename
- msdosfs_mkdir
- msdosfs_rmdir
- msdosfs_symlink
- msdosfs_readdir
- msdosfs_readlink
- msdosfs_lock
- msdosfs_unlock
- msdosfs_islocked
- msdosfs_bmap
- msdosfs_strategy
- msdosfs_print
- msdosfs_advlock
- msdosfs_pathconf
- fileidhash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/namei.h>
55 #include <sys/resourcevar.h>
56 #include <sys/kernel.h>
57 #include <sys/file.h>
58 #include <sys/stat.h>
59 #include <sys/buf.h>
60 #include <sys/proc.h>
61 #include <sys/mount.h>
62 #include <sys/vnode.h>
63 #include <sys/signalvar.h>
64 #include <miscfs/specfs/specdev.h>
65 #include <sys/malloc.h>
66 #include <sys/pool.h>
67 #include <sys/dirent.h>
68 #include <sys/lockf.h>
69 #include <sys/poll.h>
70
71 #include <uvm/uvm_extern.h>
72
73 #include <msdosfs/bpb.h>
74 #include <msdosfs/direntry.h>
75 #include <msdosfs/denode.h>
76 #include <msdosfs/msdosfsmount.h>
77 #include <msdosfs/fat.h>
78
79 static uint32_t fileidhash(uint64_t);
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 int
106 msdosfs_create(v)
107 void *v;
108 {
109 struct vop_create_args *ap = v;
110 struct componentname *cnp = ap->a_cnp;
111 struct denode ndirent;
112 struct denode *dep;
113 struct denode *pdep = VTODE(ap->a_dvp);
114 int error;
115 struct timespec ts;
116
117 #ifdef MSDOSFS_DEBUG
118 printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
119 #endif
120
121
122
123
124
125
126 if (pdep->de_StartCluster == MSDOSFSROOT
127 && pdep->de_fndoffset >= pdep->de_FileSize) {
128 error = ENOSPC;
129 goto bad;
130 }
131
132
133
134
135
136
137
138 #ifdef DIAGNOSTIC
139 if ((cnp->cn_flags & HASBUF) == 0)
140 panic("msdosfs_create: no name");
141 #endif
142 bzero(&ndirent, sizeof(ndirent));
143 if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
144 goto bad;
145
146 ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
147 ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
148 ndirent.de_StartCluster = 0;
149 ndirent.de_FileSize = 0;
150 ndirent.de_dev = pdep->de_dev;
151 ndirent.de_devvp = pdep->de_devvp;
152 ndirent.de_pmp = pdep->de_pmp;
153 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
154 getnanotime(&ts);
155 DETIMES(&ndirent, &ts, &ts, &ts);
156 if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
157 goto bad;
158 if ((cnp->cn_flags & SAVESTART) == 0)
159 pool_put(&namei_pool, cnp->cn_pnbuf);
160 vput(ap->a_dvp);
161 *ap->a_vpp = DETOV(dep);
162 return (0);
163
164 bad:
165 pool_put(&namei_pool, cnp->cn_pnbuf);
166 vput(ap->a_dvp);
167 return (error);
168 }
169
170 int
171 msdosfs_mknod(v)
172 void *v;
173 {
174 struct vop_mknod_args *ap = v;
175
176 pool_put(&namei_pool, ap->a_cnp->cn_pnbuf);
177 vput(ap->a_dvp);
178 return (EINVAL);
179 }
180
181 int
182 msdosfs_open(v)
183 void *v;
184 {
185 #if 0
186 struct vop_open_args
187
188
189
190
191 *ap;
192 #endif
193
194 return (0);
195 }
196
197 int
198 msdosfs_close(v)
199 void *v;
200 {
201 struct vop_close_args *ap = v;
202 struct vnode *vp = ap->a_vp;
203 struct denode *dep = VTODE(vp);
204 struct timespec ts;
205
206 if (vp->v_usecount > 1 && !VOP_ISLOCKED(vp)) {
207 getnanotime(&ts);
208 DETIMES(dep, &ts, &ts, &ts);
209 }
210 return (0);
211 }
212
213 int
214 msdosfs_access(v)
215 void *v;
216 {
217 struct vop_access_args *ap = v;
218 struct denode *dep = VTODE(ap->a_vp);
219 struct msdosfsmount *pmp = dep->de_pmp;
220 mode_t dosmode;
221
222 dosmode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH);
223 if ((dep->de_Attributes & ATTR_READONLY) == 0)
224 dosmode |= (S_IWUSR|S_IWGRP|S_IWOTH);
225 dosmode &= pmp->pm_mask;
226 if (dep->de_Attributes & ATTR_DIRECTORY
227 && pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
228 dosmode |= (dosmode & S_IRUSR) ? S_IXUSR : 0;
229 dosmode |= (dosmode & S_IRGRP) ? S_IXGRP : 0;
230 dosmode |= (dosmode & S_IROTH) ? S_IXOTH : 0;
231 }
232
233 return (vaccess(dosmode, pmp->pm_uid, pmp->pm_gid, ap->a_mode,
234 ap->a_cred));
235 }
236
237 int
238 msdosfs_getattr(v)
239 void *v;
240 {
241 struct vop_getattr_args *ap = v;
242 struct denode *dep = VTODE(ap->a_vp);
243 struct msdosfsmount *pmp = dep->de_pmp;
244 struct vattr *vap = ap->a_vap;
245 struct timespec ts;
246 uint32_t fileid;
247
248 getnanotime(&ts);
249 DETIMES(dep, &ts, &ts, &ts);
250 vap->va_fsid = dep->de_dev;
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280 fileid = dep->de_StartCluster;
281
282 if (dep->de_Attributes & ATTR_DIRECTORY) {
283
284 if (dep->de_StartCluster == MSDOSFSROOT)
285 fileid = FAT32(pmp) ? pmp->pm_rootdirblk : 1;
286 } else {
287 if (dep->de_FileSize == 0) {
288 uint32_t dirsperblk;
289 uint64_t fileid64;
290
291 dirsperblk = pmp->pm_BytesPerSec /
292 sizeof(struct direntry);
293
294 fileid64 = (dep->de_dirclust == MSDOSFSROOT) ?
295 roottobn(pmp, 0) : cntobn(pmp, dep->de_dirclust);
296 fileid64 *= dirsperblk;
297 fileid64 += dep->de_diroffset / sizeof(struct direntry);
298
299 fileid = fileidhash(fileid64);
300 }
301 }
302
303 vap->va_fileid = fileid;
304 vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
305 ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
306 vap->va_mode &= dep->de_pmp->pm_mask;
307 if (dep->de_Attributes & ATTR_DIRECTORY) {
308 vap->va_mode |= S_IFDIR;
309 if (pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
310 vap->va_mode |= (vap->va_mode & S_IRUSR) ? S_IXUSR : 0;
311 vap->va_mode |= (vap->va_mode & S_IRGRP) ? S_IXGRP : 0;
312 vap->va_mode |= (vap->va_mode & S_IROTH) ? S_IXOTH : 0;
313 }
314 }
315 vap->va_nlink = 1;
316 vap->va_gid = dep->de_pmp->pm_gid;
317 vap->va_uid = dep->de_pmp->pm_uid;
318 vap->va_rdev = 0;
319 vap->va_size = dep->de_FileSize;
320 dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
321 if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
322 dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
323 dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CTimeHundredth, &vap->va_ctime);
324 } else {
325 vap->va_atime = vap->va_mtime;
326 vap->va_ctime = vap->va_mtime;
327 }
328 vap->va_flags = 0;
329 if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
330 vap->va_flags |= SF_ARCHIVED;
331 vap->va_gen = 0;
332 vap->va_blocksize = dep->de_pmp->pm_bpcluster;
333 vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
334 ~(dep->de_pmp->pm_crbomask);
335 vap->va_type = ap->a_vp->v_type;
336 return (0);
337 }
338
339 int
340 msdosfs_setattr(v)
341 void *v;
342 {
343 struct vop_setattr_args *ap = v;
344 int error = 0;
345 struct denode *dep = VTODE(ap->a_vp);
346 struct vattr *vap = ap->a_vap;
347 struct ucred *cred = ap->a_cred;
348
349 #ifdef MSDOSFS_DEBUG
350 printf("msdosfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n",
351 ap->a_vp, vap, cred, ap->a_p);
352 #endif
353 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
354 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
355 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
356 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL) ||
357 (vap->va_uid != VNOVAL) || (vap->va_gid != VNOVAL)) {
358 #ifdef MSDOSFS_DEBUG
359 printf("msdosfs_setattr(): returning EINVAL\n");
360 printf(" va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n",
361 vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
362 printf(" va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n",
363 vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
364 printf(" va_uid %x, va_gid %x\n",
365 vap->va_uid, vap->va_gid);
366 #endif
367 return (EINVAL);
368 }
369
370
371
372 if (ap->a_vp->v_type == VDIR)
373 return EISDIR;
374
375 if (vap->va_size != VNOVAL) {
376 error = detrunc(dep, (uint32_t)vap->va_size, 0, cred, ap->a_p);
377 if (error)
378 return (error);
379 }
380 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
381 if (cred->cr_uid != dep->de_pmp->pm_uid &&
382 (error = suser_ucred(cred)) &&
383 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
384 (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
385 return (error);
386 if (!(dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)
387 && vap->va_atime.tv_sec != VNOVAL)
388 unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
389 if (vap->va_mtime.tv_sec != VNOVAL)
390 unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
391 dep->de_Attributes |= ATTR_ARCHIVE;
392 dep->de_flag |= DE_MODIFIED;
393 }
394
395
396
397
398
399 if (vap->va_mode != (mode_t)VNOVAL) {
400 if (cred->cr_uid != dep->de_pmp->pm_uid &&
401 (error = suser_ucred(cred)))
402 return (error);
403
404 if (vap->va_mode & VWRITE)
405 dep->de_Attributes &= ~ATTR_READONLY;
406 else
407 dep->de_Attributes |= ATTR_READONLY;
408 dep->de_flag |= DE_MODIFIED;
409 }
410
411
412
413 if (vap->va_flags != VNOVAL) {
414 if (cred->cr_uid != dep->de_pmp->pm_uid &&
415 (error = suser_ucred(cred)))
416 return (error);
417 if (vap->va_flags & SF_ARCHIVED)
418 dep->de_Attributes &= ~ATTR_ARCHIVE;
419 else
420 dep->de_Attributes |= ATTR_ARCHIVE;
421 dep->de_flag |= DE_MODIFIED;
422 }
423 return (deupdat(dep, 1));
424 }
425
426 int
427 msdosfs_read(v)
428 void *v;
429 {
430 struct vop_read_args *ap = v;
431 int error = 0;
432 uint32_t diff;
433 int blsize;
434 int isadir;
435 uint32_t n;
436 long on;
437 daddr64_t lbn, rablock, rablkno;
438 struct buf *bp;
439 struct vnode *vp = ap->a_vp;
440 struct denode *dep = VTODE(vp);
441 struct msdosfsmount *pmp = dep->de_pmp;
442 struct uio *uio = ap->a_uio;
443
444
445
446
447 if (uio->uio_resid == 0)
448 return (0);
449 if (uio->uio_offset < 0)
450 return (EINVAL);
451
452 isadir = dep->de_Attributes & ATTR_DIRECTORY;
453 do {
454 if (uio->uio_offset >= dep->de_FileSize)
455 return (0);
456
457 lbn = de_cluster(pmp, uio->uio_offset);
458 on = uio->uio_offset & pmp->pm_crbomask;
459 n = min((uint32_t) (pmp->pm_bpcluster - on), uio->uio_resid);
460
461
462
463
464
465
466 diff = dep->de_FileSize - (uint32_t)uio->uio_offset;
467 if (diff < n)
468 n = diff;
469
470
471 if (isadir) {
472 error = pcbmap(dep, lbn, &lbn, 0, &blsize);
473 if (error)
474 return (error);
475 }
476
477
478
479
480
481 if (isadir) {
482 error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
483 } else {
484 rablock = lbn + 1;
485 rablkno = de_cn2bn(pmp, rablock);
486 if (dep->de_lastr + 1 == lbn &&
487 de_cn2off(pmp, rablock) < dep->de_FileSize)
488 error = breadn(vp, de_cn2bn(pmp, lbn),
489 pmp->pm_bpcluster, &rablkno,
490 &pmp->pm_bpcluster, 1, NOCRED, &bp);
491 else
492 error = bread(vp, de_cn2bn(pmp, lbn),
493 pmp->pm_bpcluster, NOCRED, &bp);
494 dep->de_lastr = lbn;
495 }
496 n = min(n, pmp->pm_bpcluster - bp->b_resid);
497 if (error) {
498 brelse(bp);
499 return (error);
500 }
501 error = uiomove(bp->b_data + on, (int) n, uio);
502 brelse(bp);
503 } while (error == 0 && uio->uio_resid > 0 && n != 0);
504 if (!isadir && !(vp->v_mount->mnt_flag & MNT_NOATIME))
505 dep->de_flag |= DE_ACCESS;
506 return (error);
507 }
508
509
510
511
512 int
513 msdosfs_write(v)
514 void *v;
515 {
516 struct vop_write_args *ap = v;
517 int n;
518 int croffset;
519 int resid;
520 uint32_t osize;
521 int error = 0;
522 uint32_t count, lastcn;
523 daddr64_t bn;
524 struct buf *bp;
525 int ioflag = ap->a_ioflag;
526 struct uio *uio = ap->a_uio;
527 struct proc *p = uio->uio_procp;
528 struct vnode *vp = ap->a_vp;
529 struct vnode *thisvp;
530 struct denode *dep = VTODE(vp);
531 struct msdosfsmount *pmp = dep->de_pmp;
532 struct ucred *cred = ap->a_cred;
533
534 #ifdef MSDOSFS_DEBUG
535 printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
536 vp, uio, ioflag, cred);
537 printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
538 dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
539 #endif
540
541 switch (vp->v_type) {
542 case VREG:
543 if (ioflag & IO_APPEND)
544 uio->uio_offset = dep->de_FileSize;
545 thisvp = vp;
546 break;
547 case VDIR:
548 return EISDIR;
549 default:
550 panic("msdosfs_write(): bad file type");
551 }
552
553 if (uio->uio_offset < 0)
554 return (EINVAL);
555
556 if (uio->uio_resid == 0)
557 return (0);
558
559
560 if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX)
561 return (EFBIG);
562
563
564
565
566 if (p &&
567 ((uio->uio_offset + uio->uio_resid) >
568 p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
569 psignal(p, SIGXFSZ);
570 return (EFBIG);
571 }
572
573
574
575
576
577
578
579 if (uio->uio_offset > dep->de_FileSize) {
580 if ((error = deextend(dep, uio->uio_offset, cred)) != 0)
581 return (error);
582 }
583
584
585
586
587 resid = uio->uio_resid;
588 osize = dep->de_FileSize;
589
590
591
592
593
594 if (uio->uio_offset + resid > osize) {
595 count = de_clcount(pmp, uio->uio_offset + resid) -
596 de_clcount(pmp, osize);
597 if ((error = extendfile(dep, count, NULL, NULL, 0)) &&
598 (error != ENOSPC || (ioflag & IO_UNIT)))
599 goto errexit;
600 lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
601 } else
602 lastcn = de_clcount(pmp, osize) - 1;
603
604 do {
605 if (de_cluster(pmp, uio->uio_offset) > lastcn) {
606 error = ENOSPC;
607 break;
608 }
609
610 bn = de_blk(pmp, uio->uio_offset);
611 if ((uio->uio_offset & pmp->pm_crbomask) == 0
612 && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
613 || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
614
615
616
617
618
619 bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
620 clrbuf(bp);
621
622
623
624
625 if (bp->b_blkno == bp->b_lblkno) {
626 error = pcbmap(dep,
627 de_bn2cn(pmp, bp->b_lblkno),
628 &bp->b_blkno, 0, 0);
629 if (error)
630 bp->b_blkno = -1;
631 }
632 if (bp->b_blkno == -1) {
633 brelse(bp);
634 if (!error)
635 error = EIO;
636 break;
637 }
638 } else {
639
640
641
642 error = bread(thisvp, bn, pmp->pm_bpcluster,
643 NOCRED, &bp);
644 if (error) {
645 brelse(bp);
646 break;
647 }
648 }
649
650 croffset = uio->uio_offset & pmp->pm_crbomask;
651 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
652 if (uio->uio_offset + n > dep->de_FileSize) {
653 dep->de_FileSize = uio->uio_offset + n;
654 uvm_vnp_setsize(vp, dep->de_FileSize);
655 }
656 uvm_vnp_uncache(vp);
657
658
659
660
661
662
663
664
665 error = uiomove(bp->b_data + croffset, n, uio);
666
667
668
669
670
671
672
673
674 if (ioflag & IO_SYNC)
675 (void) bwrite(bp);
676 else if (n + croffset == pmp->pm_bpcluster)
677 bawrite(bp);
678 else
679 bdwrite(bp);
680 dep->de_flag |= DE_UPDATE;
681 } while (error == 0 && uio->uio_resid > 0);
682
683
684
685
686
687 errexit:
688 if (error) {
689 if (ioflag & IO_UNIT) {
690 detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
691 uio->uio_offset -= resid - uio->uio_resid;
692 uio->uio_resid = resid;
693 } else {
694 detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
695 if (uio->uio_resid != resid)
696 error = 0;
697 }
698 } else if (ioflag & IO_SYNC)
699 error = deupdat(dep, 1);
700 return (error);
701 }
702
703 int
704 msdosfs_ioctl(v)
705 void *v;
706 {
707 #if 0
708 struct vop_ioctl_args
709
710
711
712
713
714
715 *ap;
716 #endif
717
718 return (ENOTTY);
719 }
720
721 int
722 msdosfs_poll(v)
723 void *v;
724 {
725 struct vop_poll_args *ap = v;
726
727 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
728 }
729
730
731
732
733
734
735
736 int
737 msdosfs_fsync(v)
738 void *v;
739 {
740 struct vop_fsync_args *ap = v;
741 struct vnode *vp = ap->a_vp;
742
743 vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
744 return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
745 }
746
747
748
749
750
751
752
753 int
754 msdosfs_remove(v)
755 void *v;
756 {
757 struct vop_remove_args *ap = v;
758 struct denode *dep = VTODE(ap->a_vp);
759 struct denode *ddep = VTODE(ap->a_dvp);
760 int error;
761
762 if (ap->a_vp->v_type == VDIR)
763 error = EPERM;
764 else
765 error = removede(ddep, dep);
766 #ifdef MSDOSFS_DEBUG
767 printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
768 #endif
769 if (ddep == dep)
770 vrele(ap->a_vp);
771 else
772 vput(ap->a_vp);
773
774 vput(ap->a_dvp);
775 return (error);
776 }
777
778
779
780
781
782
783 int
784 msdosfs_link(v)
785 void *v;
786 {
787 struct vop_link_args *ap = v;
788
789 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
790 vput(ap->a_dvp);
791 return (EOPNOTSUPP);
792 }
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847 int
848 msdosfs_rename(v)
849 void *v;
850 {
851 struct vop_rename_args *ap = v;
852 struct vnode *tvp = ap->a_tvp;
853 register struct vnode *tdvp = ap->a_tdvp;
854 struct vnode *fvp = ap->a_fvp;
855 register struct vnode *fdvp = ap->a_fdvp;
856 register struct componentname *tcnp = ap->a_tcnp;
857 register struct componentname *fcnp = ap->a_fcnp;
858 struct proc *p = curproc;
859 register struct denode *ip, *xp, *dp, *zp;
860 u_char toname[11], oldname[11];
861 uint32_t from_diroffset, to_diroffset;
862 u_char to_count;
863 int doingdirectory = 0, newparent = 0;
864 int error;
865 uint32_t cn, pcl;
866 daddr64_t bn;
867 struct msdosfsmount *pmp;
868 struct direntry *dotdotp;
869 struct buf *bp;
870
871 pmp = VFSTOMSDOSFS(fdvp->v_mount);
872
873 #ifdef DIAGNOSTIC
874 if ((tcnp->cn_flags & HASBUF) == 0 ||
875 (fcnp->cn_flags & HASBUF) == 0)
876 panic("msdosfs_rename: no name");
877 #endif
878
879
880
881 if ((fvp->v_mount != tdvp->v_mount) ||
882 (tvp && (fvp->v_mount != tvp->v_mount))) {
883 error = EXDEV;
884 abortit:
885 VOP_ABORTOP(tdvp, tcnp);
886 if (tdvp == tvp)
887 vrele(tdvp);
888 else
889 vput(tdvp);
890 if (tvp)
891 vput(tvp);
892 VOP_ABORTOP(fdvp, fcnp);
893 vrele(fdvp);
894 vrele(fvp);
895 return (error);
896 }
897
898
899
900
901 if (tvp == fvp) {
902 error = 0;
903 goto abortit;
904 }
905
906
907 if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
908 goto abortit;
909 dp = VTODE(fdvp);
910 ip = VTODE(fvp);
911
912
913
914
915
916
917
918 if (ip->de_Attributes & ATTR_DIRECTORY) {
919
920
921
922 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
923 dp == ip ||
924 (fcnp->cn_flags & ISDOTDOT) ||
925 (tcnp->cn_flags & ISDOTDOT) ||
926 (ip->de_flag & DE_RENAME)) {
927 VOP_UNLOCK(fvp, 0, p);
928 error = EINVAL;
929 goto abortit;
930 }
931 ip->de_flag |= DE_RENAME;
932 doingdirectory++;
933 }
934
935
936
937
938
939 dp = VTODE(tdvp);
940 xp = tvp ? VTODE(tvp) : NULL;
941
942
943
944 to_diroffset = dp->de_fndoffset;
945 to_count = dp->de_fndcnt;
946
947
948
949
950
951
952
953
954
955
956
957 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
958 VOP_UNLOCK(fvp, 0, p);
959 if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
960 newparent = 1;
961 vrele(fdvp);
962 if (doingdirectory && newparent) {
963 if (error)
964 goto bad1;
965 if (xp != NULL)
966 vput(tvp);
967
968
969
970
971 if ((error = doscheckpath(ip, dp)) != 0)
972 goto out;
973 if ((tcnp->cn_flags & SAVESTART) == 0)
974 panic("msdosfs_rename: lost to startdir");
975 if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
976 goto out;
977 dp = VTODE(tdvp);
978 xp = tvp ? VTODE(tvp) : NULL;
979 }
980
981 if (xp != NULL) {
982
983
984
985
986
987 if (xp->de_Attributes & ATTR_DIRECTORY) {
988 if (!dosdirempty(xp)) {
989 error = ENOTEMPTY;
990 goto bad1;
991 }
992 if (!doingdirectory) {
993 error = ENOTDIR;
994 goto bad1;
995 }
996 cache_purge(tdvp);
997 } else if (doingdirectory) {
998 error = EISDIR;
999 goto bad1;
1000 }
1001 if ((error = removede(dp, xp)) != 0)
1002 goto bad1;
1003 vput(tvp);
1004 xp = NULL;
1005 }
1006
1007
1008
1009
1010
1011
1012 if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0)
1013 goto bad1;
1014
1015
1016
1017
1018
1019 fcnp->cn_flags &= ~MODMASK;
1020 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1021 if ((fcnp->cn_flags & SAVESTART) == 0)
1022 panic("msdosfs_rename: lost from startdir");
1023 if (!newparent)
1024 VOP_UNLOCK(tdvp, 0, p);
1025 (void) relookup(fdvp, &fvp, fcnp);
1026 if (fvp == NULL) {
1027
1028
1029
1030 if (doingdirectory)
1031 panic("rename: lost dir entry");
1032 vrele(ap->a_fvp);
1033 if (newparent)
1034 VOP_UNLOCK(tdvp, 0, p);
1035 vrele(tdvp);
1036 return 0;
1037 }
1038 xp = VTODE(fvp);
1039 zp = VTODE(fdvp);
1040 from_diroffset = zp->de_fndoffset;
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050 if (xp != ip) {
1051 if (doingdirectory)
1052 panic("rename: lost dir entry");
1053 vrele(ap->a_fvp);
1054 if (newparent)
1055 VOP_UNLOCK(fdvp, 0, p);
1056 xp = NULL;
1057 } else {
1058 vrele(fvp);
1059 xp = NULL;
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 bcopy(ip->de_Name, oldname, 11);
1070 bcopy(toname, ip->de_Name, 11);
1071 dp->de_fndoffset = to_diroffset;
1072 dp->de_fndcnt = to_count;
1073 error = createde(ip, dp, (struct denode **)0, tcnp);
1074 if (error) {
1075 bcopy(oldname, ip->de_Name, 11);
1076 if (newparent)
1077 VOP_UNLOCK(fdvp, 0, p);
1078 goto bad;
1079 }
1080 ip->de_refcnt++;
1081 zp->de_fndoffset = from_diroffset;
1082 if ((error = removede(zp, ip)) != 0) {
1083
1084 if (newparent)
1085 VOP_UNLOCK(fdvp, 0, p);
1086 goto bad;
1087 }
1088
1089 cache_purge(fvp);
1090
1091 if (!doingdirectory) {
1092 error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
1093 &ip->de_dirclust, 0);
1094 if (error) {
1095
1096 if (newparent)
1097 VOP_UNLOCK(fdvp, 0, p);
1098 goto bad;
1099 }
1100 if (ip->de_dirclust != MSDOSFSROOT)
1101 ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
1102 }
1103 reinsert(ip);
1104 if (newparent)
1105 VOP_UNLOCK(fdvp, 0, p);
1106 }
1107
1108
1109
1110
1111
1112 if (doingdirectory && newparent) {
1113 cn = ip->de_StartCluster;
1114 if (cn == MSDOSFSROOT) {
1115
1116 panic("msdosfs_rename: updating .. in root directory?");
1117 } else
1118 bn = cntobn(pmp, cn);
1119 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
1120 NOCRED, &bp);
1121 if (error) {
1122
1123 brelse(bp);
1124 goto bad;
1125 }
1126 dotdotp = (struct direntry *)bp->b_data;
1127 putushort(dotdotp[0].deStartCluster, cn);
1128 pcl = dp->de_StartCluster;
1129 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
1130 pcl = 0;
1131 putushort(dotdotp[1].deStartCluster, pcl);
1132 if (FAT32(pmp)) {
1133 putushort(dotdotp[0].deHighClust, cn >> 16);
1134 putushort(dotdotp[1].deHighClust, pcl >> 16);
1135 }
1136 if ((error = bwrite(bp)) != 0) {
1137
1138 goto bad;
1139 }
1140 }
1141
1142 bad:
1143 VOP_UNLOCK(fvp, 0, p);
1144 vrele(fdvp);
1145 bad1:
1146 if (xp)
1147 vput(tvp);
1148 vput(tdvp);
1149 out:
1150 ip->de_flag &= ~DE_RENAME;
1151 vrele(fvp);
1152 return (error);
1153
1154 }
1155
1156 struct {
1157 struct direntry dot;
1158 struct direntry dotdot;
1159 } dosdirtemplate = {
1160 { ". ", " ",
1161 ATTR_DIRECTORY,
1162 CASE_LOWER_BASE | CASE_LOWER_EXT,
1163 0,
1164 { 0, 0 }, { 0, 0 },
1165 { 0, 0 },
1166 { 0, 0 },
1167 { 210, 4 }, { 210, 4 },
1168 { 0, 0 },
1169 { 0, 0, 0, 0 }
1170 },
1171 { ".. ", " ",
1172 ATTR_DIRECTORY,
1173 CASE_LOWER_BASE | CASE_LOWER_EXT,
1174 0,
1175 { 0, 0 }, { 0, 0 },
1176 { 0, 0 },
1177 { 0, 0 },
1178 { 210, 4 }, { 210, 4 },
1179 { 0, 0 },
1180 { 0, 0, 0, 0 }
1181 }
1182 };
1183
1184 int
1185 msdosfs_mkdir(v)
1186 void *v;
1187 {
1188 struct vop_mkdir_args *ap = v;
1189 struct componentname *cnp = ap->a_cnp;
1190 struct denode ndirent;
1191 struct denode *dep;
1192 struct denode *pdep = VTODE(ap->a_dvp);
1193 int error;
1194 daddr64_t bn;
1195 uint32_t newcluster, pcl;
1196 struct direntry *denp;
1197 struct msdosfsmount *pmp = pdep->de_pmp;
1198 struct buf *bp;
1199 struct timespec ts;
1200
1201
1202
1203
1204
1205
1206 if (pdep->de_StartCluster == MSDOSFSROOT
1207 && pdep->de_fndoffset >= pdep->de_FileSize) {
1208 error = ENOSPC;
1209 goto bad2;
1210 }
1211
1212
1213
1214
1215 error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
1216 if (error)
1217 goto bad2;
1218
1219 bzero(&ndirent, sizeof(ndirent));
1220 ndirent.de_pmp = pmp;
1221 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
1222 getnanotime(&ts);
1223 DETIMES(&ndirent, &ts, &ts, &ts);
1224
1225
1226
1227
1228
1229
1230 bn = cntobn(pmp, newcluster);
1231
1232 bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
1233 bzero(bp->b_data, pmp->pm_bpcluster);
1234 bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
1235 denp = (struct direntry *)bp->b_data;
1236 putushort(denp[0].deStartCluster, newcluster);
1237 putushort(denp[0].deCDate, ndirent.de_CDate);
1238 putushort(denp[0].deCTime, ndirent.de_CTime);
1239 denp[0].deCTimeHundredth = ndirent.de_CTimeHundredth;
1240 putushort(denp[0].deADate, ndirent.de_ADate);
1241 putushort(denp[0].deMDate, ndirent.de_MDate);
1242 putushort(denp[0].deMTime, ndirent.de_MTime);
1243 pcl = pdep->de_StartCluster;
1244 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
1245 pcl = 0;
1246 putushort(denp[1].deStartCluster, pcl);
1247 putushort(denp[1].deCDate, ndirent.de_CDate);
1248 putushort(denp[1].deCTime, ndirent.de_CTime);
1249 denp[1].deCTimeHundredth = ndirent.de_CTimeHundredth;
1250 putushort(denp[1].deADate, ndirent.de_ADate);
1251 putushort(denp[1].deMDate, ndirent.de_MDate);
1252 putushort(denp[1].deMTime, ndirent.de_MTime);
1253 if (FAT32(pmp)) {
1254 putushort(denp[0].deHighClust, newcluster >> 16);
1255 putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
1256 }
1257
1258 if ((error = bwrite(bp)) != 0)
1259 goto bad;
1260
1261
1262
1263
1264
1265
1266 #ifdef DIAGNOSTIC
1267 if ((cnp->cn_flags & HASBUF) == 0)
1268 panic("msdosfs_mkdir: no name");
1269 #endif
1270 if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
1271 goto bad;
1272
1273 ndirent.de_Attributes = ATTR_DIRECTORY;
1274 ndirent.de_StartCluster = newcluster;
1275 ndirent.de_FileSize = 0;
1276 ndirent.de_dev = pdep->de_dev;
1277 ndirent.de_devvp = pdep->de_devvp;
1278 if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
1279 goto bad;
1280 if ((cnp->cn_flags & SAVESTART) == 0)
1281 pool_put(&namei_pool, cnp->cn_pnbuf);
1282 vput(ap->a_dvp);
1283 *ap->a_vpp = DETOV(dep);
1284 return (0);
1285
1286 bad:
1287 clusterfree(pmp, newcluster, NULL);
1288 bad2:
1289 pool_put(&namei_pool, cnp->cn_pnbuf);
1290 vput(ap->a_dvp);
1291 return (error);
1292 }
1293
1294 int
1295 msdosfs_rmdir(v)
1296 void *v;
1297 {
1298 struct vop_rmdir_args *ap = v;
1299 register struct vnode *vp = ap->a_vp;
1300 register struct vnode *dvp = ap->a_dvp;
1301 register struct componentname *cnp = ap->a_cnp;
1302 register struct denode *ip, *dp;
1303 int error;
1304
1305 ip = VTODE(vp);
1306 dp = VTODE(dvp);
1307
1308
1309
1310 if (dp == ip) {
1311 vrele(dvp);
1312 vput(vp);
1313 return (EINVAL);
1314 }
1315
1316
1317
1318
1319
1320
1321
1322 error = 0;
1323 if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
1324 error = ENOTEMPTY;
1325 goto out;
1326 }
1327
1328
1329
1330
1331
1332
1333
1334
1335 if ((error = removede(dp, ip)) != 0)
1336 goto out;
1337
1338
1339
1340
1341
1342 cache_purge(dvp);
1343 vput(dvp);
1344 dvp = NULL;
1345
1346
1347
1348 error = detrunc(ip, (uint32_t)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
1349 cache_purge(vp);
1350 out:
1351 if (dvp)
1352 vput(dvp);
1353 vput(vp);
1354 return (error);
1355 }
1356
1357
1358
1359
1360 int
1361 msdosfs_symlink(v)
1362 void *v;
1363 {
1364 struct vop_symlink_args *ap = v;
1365
1366 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
1367 vput(ap->a_dvp);
1368 return (EOPNOTSUPP);
1369 }
1370
1371 int
1372 msdosfs_readdir(v)
1373 void *v;
1374 {
1375 struct vop_readdir_args *ap = v;
1376 int error = 0;
1377 int diff;
1378 long n;
1379 int blsize;
1380 long on;
1381 long lost;
1382 long count;
1383 uint32_t dirsperblk;
1384 uint32_t cn, lbn;
1385 uint32_t fileno;
1386 long bias = 0;
1387 daddr64_t bn;
1388 struct buf *bp;
1389 struct denode *dep = VTODE(ap->a_vp);
1390 struct msdosfsmount *pmp = dep->de_pmp;
1391 struct direntry *dentp;
1392 struct dirent dirbuf;
1393 struct uio *uio = ap->a_uio;
1394 u_long *cookies = NULL;
1395 int ncookies = 0;
1396 off_t offset, wlast = -1;
1397 int chksum = -1;
1398
1399 #ifdef MSDOSFS_DEBUG
1400 printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
1401 ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
1402 #endif
1403
1404
1405
1406
1407
1408
1409
1410 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
1411 return (ENOTDIR);
1412
1413
1414
1415
1416 bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
1417
1418
1419
1420
1421
1422
1423 count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
1424 offset = uio->uio_offset;
1425 if (count < sizeof(struct direntry) ||
1426 (offset & (sizeof(struct direntry) - 1)))
1427 return (EINVAL);
1428 lost = uio->uio_resid - count;
1429 uio->uio_resid = count;
1430
1431 if (ap->a_ncookies) {
1432 ncookies = uio->uio_resid / sizeof(struct direntry) + 3;
1433 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1434 M_WAITOK);
1435 *ap->a_cookies = cookies;
1436 *ap->a_ncookies = ncookies;
1437 }
1438
1439 dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
1440
1441
1442
1443
1444
1445
1446
1447
1448 if (dep->de_StartCluster == MSDOSFSROOT
1449 || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
1450 #if 0
1451 printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
1452 offset);
1453 #endif
1454 bias = 2 * sizeof(struct direntry);
1455 if (offset < bias) {
1456 for (n = (int)offset / sizeof(struct direntry);
1457 n < 2; n++) {
1458 if (FAT32(pmp))
1459 dirbuf.d_fileno = pmp->pm_rootdirblk;
1460 else
1461 dirbuf.d_fileno = 1;
1462 dirbuf.d_type = DT_DIR;
1463 switch (n) {
1464 case 0:
1465 dirbuf.d_namlen = 1;
1466 strlcpy(dirbuf.d_name, ".",
1467 sizeof dirbuf.d_name);
1468 break;
1469 case 1:
1470 dirbuf.d_namlen = 2;
1471 strlcpy(dirbuf.d_name, "..",
1472 sizeof dirbuf.d_name);
1473 break;
1474 }
1475 dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
1476 if (uio->uio_resid < dirbuf.d_reclen)
1477 goto out;
1478 error = uiomove((caddr_t) &dirbuf,
1479 dirbuf.d_reclen, uio);
1480 if (error)
1481 goto out;
1482 offset += sizeof(struct direntry);
1483 if (cookies) {
1484 *cookies++ = offset;
1485 if (--ncookies <= 0)
1486 goto out;
1487 }
1488 }
1489 }
1490 }
1491
1492 while (uio->uio_resid > 0) {
1493 lbn = de_cluster(pmp, offset - bias);
1494 on = (offset - bias) & pmp->pm_crbomask;
1495 n = min(pmp->pm_bpcluster - on, uio->uio_resid);
1496 diff = dep->de_FileSize - (offset - bias);
1497 if (diff <= 0)
1498 break;
1499 n = min(n, diff);
1500 if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0)
1501 break;
1502 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
1503 if (error) {
1504 brelse(bp);
1505 return (error);
1506 }
1507 n = min(n, blsize - bp->b_resid);
1508
1509
1510
1511
1512
1513 for (dentp = (struct direntry *)(bp->b_data + on);
1514 (char *)dentp < bp->b_data + on + n;
1515 dentp++, offset += sizeof(struct direntry)) {
1516 #if 0
1517 printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
1518 dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
1519 #endif
1520
1521
1522
1523 if (dentp->deName[0] == SLOT_EMPTY) {
1524 brelse(bp);
1525 goto out;
1526 }
1527
1528
1529
1530 if (dentp->deName[0] == SLOT_DELETED) {
1531 chksum = -1;
1532 wlast = -1;
1533 continue;
1534 }
1535
1536
1537
1538
1539 if (dentp->deAttributes == ATTR_WIN95) {
1540 struct winentry *wep;
1541 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
1542 continue;
1543 wep = (struct winentry *)dentp;
1544 chksum = win2unixfn(wep, &dirbuf, chksum);
1545 if (wep->weCnt & WIN_LAST)
1546 wlast = offset;
1547 continue;
1548 }
1549
1550
1551
1552
1553 if (dentp->deAttributes & ATTR_VOLUME) {
1554 chksum = -1;
1555 wlast = -1;
1556 continue;
1557 }
1558
1559
1560
1561
1562
1563
1564 fileno = getushort(dentp->deStartCluster);
1565 if (FAT32(pmp))
1566 fileno |= getushort(dentp->deHighClust) << 16;
1567
1568 if (dentp->deAttributes & ATTR_DIRECTORY) {
1569
1570 if (fileno == MSDOSFSROOT) {
1571 fileno = FAT32(pmp) ?
1572 pmp->pm_rootdirblk : 1;
1573 }
1574
1575 dirbuf.d_fileno = fileno;
1576 dirbuf.d_type = DT_DIR;
1577 } else {
1578 if (getulong(dentp->deFileSize) == 0) {
1579 uint64_t fileno64;
1580
1581 fileno64 = (cn == MSDOSFSROOT) ?
1582 roottobn(pmp, 0) : cntobn(pmp, cn);
1583
1584 fileno64 *= dirsperblk;
1585 fileno64 += dentp -
1586 (struct direntry *)bp->b_data;
1587
1588 fileno = fileidhash(fileno64);
1589 }
1590
1591 dirbuf.d_fileno = fileno;
1592 dirbuf.d_type = DT_REG;
1593 }
1594
1595 if (chksum != winChksum(dentp->deName))
1596 dirbuf.d_namlen = dos2unixfn(dentp->deName,
1597 (u_char *)dirbuf.d_name,
1598 pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
1599 else
1600 dirbuf.d_name[dirbuf.d_namlen] = 0;
1601 chksum = -1;
1602 dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
1603 if (uio->uio_resid < dirbuf.d_reclen) {
1604 brelse(bp);
1605
1606 if (wlast != -1)
1607 offset = wlast;
1608 goto out;
1609 }
1610 wlast = -1;
1611 error = uiomove((caddr_t) &dirbuf,
1612 dirbuf.d_reclen, uio);
1613 if (error) {
1614 brelse(bp);
1615 goto out;
1616 }
1617 if (cookies) {
1618 *cookies++ = offset + sizeof(struct direntry);
1619 if (--ncookies <= 0) {
1620 brelse(bp);
1621 goto out;
1622 }
1623 }
1624 }
1625 brelse(bp);
1626 }
1627
1628 out:
1629
1630 if (ap->a_ncookies)
1631 *ap->a_ncookies -= ncookies;
1632
1633 uio->uio_offset = offset;
1634 uio->uio_resid += lost;
1635 if (dep->de_FileSize - (offset - bias) <= 0)
1636 *ap->a_eofflag = 1;
1637 else
1638 *ap->a_eofflag = 0;
1639 return (error);
1640 }
1641
1642
1643
1644
1645 int
1646 msdosfs_readlink(v)
1647 void *v;
1648 {
1649 #if 0
1650 struct vop_readlink_args
1651
1652
1653
1654 *ap;
1655 #endif
1656
1657 return (EINVAL);
1658 }
1659
1660 int
1661 msdosfs_lock(v)
1662 void *v;
1663 {
1664 struct vop_lock_args *ap = v;
1665 struct vnode *vp = ap->a_vp;
1666
1667 return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags, NULL));
1668 }
1669
1670 int
1671 msdosfs_unlock(v)
1672 void *v;
1673 {
1674 struct vop_unlock_args *ap = v;
1675 struct vnode *vp = ap->a_vp;
1676
1677 return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags | LK_RELEASE, NULL));
1678 }
1679
1680 int
1681 msdosfs_islocked(v)
1682 void *v;
1683 {
1684 struct vop_islocked_args *ap = v;
1685
1686 return (lockstatus(&VTODE(ap->a_vp)->de_lock));
1687 }
1688
1689
1690
1691
1692
1693
1694
1695
1696 int
1697 msdosfs_bmap(v)
1698 void *v;
1699 {
1700 struct vop_bmap_args *ap = v;
1701 struct denode *dep = VTODE(ap->a_vp);
1702 struct msdosfsmount *pmp = dep->de_pmp;
1703
1704 if (ap->a_vpp != NULL)
1705 *ap->a_vpp = dep->de_devvp;
1706 if (ap->a_bnp == NULL)
1707 return (0);
1708 if (ap->a_runp) {
1709
1710
1711
1712 *ap->a_runp = 0;
1713 }
1714 return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
1715 }
1716
1717 int
1718 msdosfs_strategy(v)
1719 void *v;
1720 {
1721 struct vop_strategy_args *ap = v;
1722 struct buf *bp = ap->a_bp;
1723 struct denode *dep = VTODE(bp->b_vp);
1724 struct vnode *vp;
1725 int error = 0;
1726 int s;
1727
1728 if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
1729 panic("msdosfs_strategy: spec");
1730
1731
1732
1733
1734
1735
1736 if (bp->b_blkno == bp->b_lblkno) {
1737 error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
1738 &bp->b_blkno, 0, 0);
1739 if (error)
1740 bp->b_blkno = -1;
1741 if (bp->b_blkno == -1)
1742 clrbuf(bp);
1743 }
1744 if (bp->b_blkno == -1) {
1745 s = splbio();
1746 biodone(bp);
1747 splx(s);
1748 return (error);
1749 }
1750
1751
1752
1753
1754
1755
1756 vp = dep->de_devvp;
1757 bp->b_dev = vp->v_rdev;
1758 VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
1759 return (0);
1760 }
1761
1762 int
1763 msdosfs_print(v)
1764 void *v;
1765 {
1766 struct vop_print_args *ap = v;
1767 struct denode *dep = VTODE(ap->a_vp);
1768
1769 printf(
1770 "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
1771 dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
1772 printf(" dev %d, %d, %s\n",
1773 major(dep->de_dev), minor(dep->de_dev),
1774 VOP_ISLOCKED(ap->a_vp) ? "(LOCKED)" : "");
1775 #ifdef DIAGNOSTIC
1776 lockmgr_printinfo(&dep->de_lock);
1777 #endif
1778
1779 return (0);
1780 }
1781
1782 int
1783 msdosfs_advlock(v)
1784 void *v;
1785 {
1786 struct vop_advlock_args *ap = v;
1787 register struct denode *dep = VTODE(ap->a_vp);
1788
1789 return (lf_advlock(&dep->de_lockf, dep->de_FileSize, ap->a_id, ap->a_op,
1790 ap->a_fl, ap->a_flags));
1791 }
1792
1793 int
1794 msdosfs_pathconf(v)
1795 void *v;
1796 {
1797 struct vop_pathconf_args *ap = v;
1798 struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
1799
1800 switch (ap->a_name) {
1801 case _PC_LINK_MAX:
1802 *ap->a_retval = 1;
1803 return (0);
1804 case _PC_NAME_MAX:
1805 *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
1806 return (0);
1807 case _PC_PATH_MAX:
1808 *ap->a_retval = PATH_MAX;
1809 return (0);
1810 case _PC_CHOWN_RESTRICTED:
1811 *ap->a_retval = 1;
1812 return (0);
1813 case _PC_NO_TRUNC:
1814 *ap->a_retval = 0;
1815 return (0);
1816 default:
1817 return (EINVAL);
1818 }
1819
1820 }
1821
1822
1823
1824
1825
1826 static uint32_t
1827 fileidhash(uint64_t fileid)
1828 {
1829 uint64_t c1 = 0x6e5ea73858134343LL;
1830 uint64_t c2 = 0xb34e8f99a2ec9ef5LL;
1831
1832
1833
1834
1835
1836 fileid ^= ((c1 ^ fileid) >> 32);
1837 fileid *= c1;
1838 fileid ^= ((c2 ^ fileid) >> 31);
1839 fileid *= c2;
1840 fileid ^= ((c1 ^ fileid) >> 32);
1841
1842 return (uint32_t)(fileid | 0x80000000);
1843 }
1844
1845
1846 int (**msdosfs_vnodeop_p)(void *);
1847 struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
1848 { &vop_default_desc, vn_default_error },
1849 { &vop_lookup_desc, msdosfs_lookup },
1850 { &vop_create_desc, msdosfs_create },
1851 { &vop_mknod_desc, msdosfs_mknod },
1852 { &vop_open_desc, msdosfs_open },
1853 { &vop_close_desc, msdosfs_close },
1854 { &vop_access_desc, msdosfs_access },
1855 { &vop_getattr_desc, msdosfs_getattr },
1856 { &vop_setattr_desc, msdosfs_setattr },
1857 { &vop_read_desc, msdosfs_read },
1858 { &vop_write_desc, msdosfs_write },
1859 { &vop_ioctl_desc, msdosfs_ioctl },
1860 { &vop_poll_desc, msdosfs_poll },
1861 { &vop_fsync_desc, msdosfs_fsync },
1862 { &vop_remove_desc, msdosfs_remove },
1863 { &vop_link_desc, msdosfs_link },
1864 { &vop_rename_desc, msdosfs_rename },
1865 { &vop_mkdir_desc, msdosfs_mkdir },
1866 { &vop_rmdir_desc, msdosfs_rmdir },
1867 { &vop_symlink_desc, msdosfs_symlink },
1868 { &vop_readdir_desc, msdosfs_readdir },
1869 { &vop_readlink_desc, msdosfs_readlink },
1870 { &vop_abortop_desc, vop_generic_abortop },
1871 { &vop_inactive_desc, msdosfs_inactive },
1872 { &vop_reclaim_desc, msdosfs_reclaim },
1873 { &vop_lock_desc, msdosfs_lock },
1874 { &vop_unlock_desc, msdosfs_unlock },
1875 { &vop_bmap_desc, msdosfs_bmap },
1876 { &vop_strategy_desc, msdosfs_strategy },
1877 { &vop_print_desc, msdosfs_print },
1878 { &vop_islocked_desc, msdosfs_islocked },
1879 { &vop_pathconf_desc, msdosfs_pathconf },
1880 { &vop_advlock_desc, msdosfs_advlock },
1881 { &vop_bwrite_desc, vop_generic_bwrite },
1882 { (struct vnodeop_desc *)NULL, (int (*)(void *))NULL }
1883 };
1884 struct vnodeopv_desc msdosfs_vnodeop_opv_desc =
1885 { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries };