1 /* $NetBSD: msdosfs_vnops.c,v 1.60 2009/06/23 19:36:39 elad Exp $ */
4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Written by Paul Popelka (paulp@uts.amdahl.com)
37 * You can do anything you want with this software, just don't say you wrote
38 * it, and don't remove this notice.
40 * This software is provided "as is".
42 * The author supplies this software to be publicly redistributed on the
43 * understanding that the author is not responsible for the correct
44 * functioning of this software in any circumstances and is not liable for
45 * any damages caused by this software.
50 #include <sys/cdefs.h>
51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.60 2009/06/23 19:36:39 elad Exp $");
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 ... */
62 #include <sys/mount.h>
63 #include <sys/vnode.h>
64 #include <sys/signalvar.h>
65 #include <sys/malloc.h>
66 #include <sys/dirent.h>
67 #include <sys/lockf.h>
68 #include <sys/kauth.h>
70 #include <miscfs/genfs/genfs.h>
71 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
73 #include <uvm/uvm_extern.h>
75 #include <fs/msdosfs/bpb.h>
76 #include <fs/msdosfs/direntry.h>
77 #include <fs/msdosfs/denode.h>
78 #include <fs/msdosfs/msdosfsmount.h>
79 #include <fs/msdosfs/fat.h>
84 * In the ufs filesystem the inodes, superblocks, and indirect blocks are
85 * read/written using the vnode for the filesystem. Blocks that represent
86 * the contents of a file are read/written using the vnode for the file
87 * (including directories when they are read/written as files). This
88 * presents problems for the dos filesystem because data that should be in
89 * an inode (if dos had them) resides in the directory itself. Since we
90 * must update directory entries without the benefit of having the vnode
91 * for the directory we must use the vnode for the filesystem. This means
92 * that when a directory is actually read/written (via read, write, or
93 * readdir, or seek) we must use the vnode for the filesystem instead of
94 * the vnode for the directory as would happen in ufs. This is to insure we
95 * retrieve the correct block from the buffer cache since the hash value is
96 * based upon the vnode address and the desired block number.
100 * Create a regular file. On entry the directory to contain the file being
101 * created is locked. We must release before we return. We must also free
102 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
103 * only if the SAVESTART bit in cn_flags is clear on success.
106 msdosfs_create(void *v
)
108 struct vop_create_args
/* {
110 struct vnode **a_vpp;
111 struct componentname *a_cnp;
114 struct componentname
*cnp
= ap
->a_cnp
;
115 struct denode ndirent
;
117 struct denode
*pdep
= VTODE(ap
->a_dvp
);
121 printf("msdosfs_create(cnp %p, vap %p\n", cnp
, ap
->a_vap
);
125 * If this is the root directory and there is no space left we
126 * can't do anything. This is because the root directory can not
129 if (pdep
->de_StartCluster
== MSDOSFSROOT
130 && pdep
->de_fndoffset
>= pdep
->de_FileSize
) {
136 * Create a directory entry for the file, then call createde() to
137 * have it installed. NOTE: DOS files are always executable. We
138 * use the absence of the owner write bit to make the file
142 if ((cnp
->cn_flags
& HASBUF
) == 0)
143 panic("msdosfs_create: no name");
145 memset(&ndirent
, 0, sizeof(ndirent
));
146 if ((error
= uniqdosname(pdep
, cnp
, ndirent
.de_Name
)) != 0)
149 ndirent
.de_Attributes
= (ap
->a_vap
->va_mode
& S_IWUSR
) ?
150 ATTR_ARCHIVE
: ATTR_ARCHIVE
| ATTR_READONLY
;
151 ndirent
.de_StartCluster
= 0;
152 ndirent
.de_FileSize
= 0;
153 ndirent
.de_dev
= pdep
->de_dev
;
154 ndirent
.de_devvp
= pdep
->de_devvp
;
155 ndirent
.de_pmp
= pdep
->de_pmp
;
156 ndirent
.de_flag
= DE_ACCESS
| DE_CREATE
| DE_UPDATE
;
157 DETIMES(&ndirent
, NULL
, NULL
, NULL
, pdep
->de_pmp
->pm_gmtoff
);
158 if ((error
= createde(&ndirent
, pdep
, &dep
, cnp
)) != 0)
160 if ((cnp
->cn_flags
& SAVESTART
) == 0)
161 PNBUF_PUT(cnp
->cn_pnbuf
);
162 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
164 *ap
->a_vpp
= DETOV(dep
);
168 PNBUF_PUT(cnp
->cn_pnbuf
);
174 msdosfs_mknod(void *v
)
176 struct vop_mknod_args
/* {
178 struct vnode **a_vpp;
179 struct componentname *a_cnp;
183 PNBUF_PUT(ap
->a_cnp
->cn_pnbuf
);
189 msdosfs_open(void *v
)
192 struct vop_open_args
/* {
203 msdosfs_close(void *v
)
205 struct vop_close_args
/* {
210 struct vnode
*vp
= ap
->a_vp
;
211 struct denode
*dep
= VTODE(vp
);
213 mutex_enter(&vp
->v_interlock
);
214 if (vp
->v_usecount
> 1)
215 DETIMES(dep
, NULL
, NULL
, NULL
, dep
->de_pmp
->pm_gmtoff
);
216 mutex_exit(&vp
->v_interlock
);
221 msdosfs_check_possible(struct vnode
*vp
, struct denode
*dep
, mode_t mode
)
225 * Disallow write attempts on read-only file systems;
226 * unless the file is a socket, fifo, or a block or
227 * character device resident on the file system.
230 switch (vp
->v_type
) {
234 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
245 msdosfs_check_permitted(struct vnode
*vp
, struct denode
*dep
, mode_t mode
,
248 struct msdosfsmount
*pmp
= dep
->de_pmp
;
251 if ((dep
->de_Attributes
& ATTR_READONLY
) == 0)
252 file_mode
= S_IRWXU
|S_IRWXG
|S_IRWXO
;
254 file_mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
256 return genfs_can_access(vp
->v_type
,
257 file_mode
& (vp
->v_type
== VDIR
? pmp
->pm_dirmask
: pmp
->pm_mask
),
258 pmp
->pm_uid
, pmp
->pm_gid
, mode
, cred
);
262 msdosfs_access(void *v
)
264 struct vop_access_args
/* {
269 struct vnode
*vp
= ap
->a_vp
;
270 struct denode
*dep
= VTODE(vp
);
273 error
= msdosfs_check_possible(vp
, dep
, ap
->a_mode
);
277 error
= msdosfs_check_permitted(vp
, dep
, ap
->a_mode
, ap
->a_cred
);
283 msdosfs_getattr(void *v
)
285 struct vop_getattr_args
/* {
290 struct denode
*dep
= VTODE(ap
->a_vp
);
291 struct msdosfsmount
*pmp
= dep
->de_pmp
;
292 struct vattr
*vap
= ap
->a_vap
;
294 u_long dirsperblk
= pmp
->pm_BytesPerSec
/ sizeof(struct direntry
);
297 DETIMES(dep
, NULL
, NULL
, NULL
, pmp
->pm_gmtoff
);
298 vap
->va_fsid
= dep
->de_dev
;
300 * The following computation of the fileid must be the same as that
301 * used in msdosfs_readdir() to compute d_fileno. If not, pwd
304 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
305 fileid
= cntobn(pmp
, (ino_t
)dep
->de_StartCluster
) * dirsperblk
;
306 if (dep
->de_StartCluster
== MSDOSFSROOT
)
309 fileid
= cntobn(pmp
, (ino_t
)dep
->de_dirclust
) * dirsperblk
;
310 if (dep
->de_dirclust
== MSDOSFSROOT
)
311 fileid
= roottobn(pmp
, 0) * dirsperblk
;
312 fileid
+= dep
->de_diroffset
/ sizeof(struct direntry
);
314 vap
->va_fileid
= fileid
;
315 if ((dep
->de_Attributes
& ATTR_READONLY
) == 0)
316 mode
= S_IRWXU
|S_IRWXG
|S_IRWXO
;
318 mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
320 mode
& (ap
->a_vp
->v_type
== VDIR
? pmp
->pm_dirmask
: pmp
->pm_mask
);
321 vap
->va_uid
= pmp
->pm_uid
;
322 vap
->va_gid
= pmp
->pm_gid
;
325 vap
->va_size
= ap
->a_vp
->v_size
;
326 dos2unixtime(dep
->de_MDate
, dep
->de_MTime
, 0, pmp
->pm_gmtoff
,
328 if (dep
->de_pmp
->pm_flags
& MSDOSFSMNT_LONGNAME
) {
329 dos2unixtime(dep
->de_ADate
, 0, 0, pmp
->pm_gmtoff
,
331 dos2unixtime(dep
->de_CDate
, dep
->de_CTime
, dep
->de_CHun
,
332 pmp
->pm_gmtoff
, &vap
->va_ctime
);
334 vap
->va_atime
= vap
->va_mtime
;
335 vap
->va_ctime
= vap
->va_mtime
;
338 if ((dep
->de_Attributes
& ATTR_ARCHIVE
) == 0)
339 vap
->va_mode
|= S_ARCH1
;
341 vap
->va_blocksize
= pmp
->pm_bpcluster
;
343 (dep
->de_FileSize
+ pmp
->pm_crbomask
) & ~pmp
->pm_crbomask
;
344 vap
->va_type
= ap
->a_vp
->v_type
;
349 msdosfs_setattr(void *v
)
351 struct vop_setattr_args
/* {
356 int error
= 0, de_changed
= 0;
357 struct denode
*dep
= VTODE(ap
->a_vp
);
358 struct msdosfsmount
*pmp
= dep
->de_pmp
;
359 struct vnode
*vp
= ap
->a_vp
;
360 struct vattr
*vap
= ap
->a_vap
;
361 kauth_cred_t cred
= ap
->a_cred
;
364 printf("msdosfs_setattr(): vp %p, vap %p, cred %p\n",
365 ap
->a_vp
, vap
, cred
);
368 * Note we silently ignore uid or gid changes.
370 if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= (nlink_t
)VNOVAL
) ||
371 (vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
372 (vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
373 (vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
) ||
374 (vap
->va_uid
!= VNOVAL
&& vap
->va_uid
!= pmp
->pm_uid
) ||
375 (vap
->va_gid
!= VNOVAL
&& vap
->va_gid
!= pmp
->pm_gid
)) {
377 printf("msdosfs_setattr(): returning EINVAL\n");
378 printf(" va_type %d, va_nlink %x, va_fsid %"PRIx64
", va_fileid %llx\n",
379 vap
->va_type
, vap
->va_nlink
, vap
->va_fsid
,
380 (unsigned long long)vap
->va_fileid
);
381 printf(" va_blocksize %lx, va_rdev %"PRIx64
", va_bytes %"PRIx64
", va_gen %lx\n",
382 vap
->va_blocksize
, vap
->va_rdev
, (long long)vap
->va_bytes
, vap
->va_gen
);
387 * Silently ignore attributes modifications on directories.
389 if (ap
->a_vp
->v_type
== VDIR
)
392 if (vap
->va_size
!= VNOVAL
) {
393 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
395 error
= detrunc(dep
, (u_long
)vap
->va_size
, 0, cred
);
400 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
) {
401 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
403 error
= genfs_can_chtimes(ap
->a_vp
, vap
->va_vaflags
,
407 if ((pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
) == 0 &&
408 vap
->va_atime
.tv_sec
!= VNOVAL
)
409 unix2dostime(&vap
->va_atime
, pmp
->pm_gmtoff
, &dep
->de_ADate
, NULL
, NULL
);
410 if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
411 unix2dostime(&vap
->va_mtime
, pmp
->pm_gmtoff
, &dep
->de_MDate
, &dep
->de_MTime
, NULL
);
412 dep
->de_Attributes
|= ATTR_ARCHIVE
;
413 dep
->de_flag
|= DE_MODIFIED
;
417 * DOS files only have the ability to have their writability
418 * attribute set, so we use the owner write bit to set the readonly
421 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
422 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
424 if (kauth_cred_geteuid(cred
) != pmp
->pm_uid
&&
425 (error
= kauth_authorize_generic(cred
, KAUTH_GENERIC_ISSUSER
,
428 /* We ignore the read and execute bits. */
429 if (vap
->va_mode
& S_IWUSR
)
430 dep
->de_Attributes
&= ~ATTR_READONLY
;
432 dep
->de_Attributes
|= ATTR_READONLY
;
433 dep
->de_flag
|= DE_MODIFIED
;
437 * Allow the `archived' bit to be toggled.
439 if (vap
->va_flags
!= VNOVAL
) {
440 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
442 if (kauth_cred_geteuid(cred
) != pmp
->pm_uid
&&
443 (error
= kauth_authorize_generic(cred
, KAUTH_GENERIC_ISSUSER
,
446 if (vap
->va_flags
& SF_ARCHIVED
)
447 dep
->de_Attributes
&= ~ATTR_ARCHIVE
;
449 dep
->de_Attributes
|= ATTR_ARCHIVE
;
450 dep
->de_flag
|= DE_MODIFIED
;
455 VN_KNOTE(vp
, NOTE_ATTRIB
);
456 return (deupdat(dep
, 1));
462 msdosfs_read(void *v
)
464 struct vop_read_args
/* {
478 struct vnode
*vp
= ap
->a_vp
;
479 struct denode
*dep
= VTODE(vp
);
480 struct msdosfsmount
*pmp
= dep
->de_pmp
;
481 struct uio
*uio
= ap
->a_uio
;
484 * If they didn't ask for any data, then we are done.
487 if (uio
->uio_resid
== 0)
489 if (uio
->uio_offset
< 0)
491 if (uio
->uio_offset
>= dep
->de_FileSize
)
494 if (vp
->v_type
== VREG
) {
495 const int advice
= IO_ADV_DECODE(ap
->a_ioflag
);
497 while (uio
->uio_resid
> 0) {
498 bytelen
= MIN(dep
->de_FileSize
- uio
->uio_offset
,
503 error
= ubc_uiomove(&vp
->v_uobj
, uio
, bytelen
, advice
,
504 UBC_READ
| UBC_PARTIALOK
| UBC_UNMAP_FLAG(vp
));
508 dep
->de_flag
|= DE_ACCESS
;
512 /* this loop is only for directories now */
514 lbn
= de_cluster(pmp
, uio
->uio_offset
);
515 on
= uio
->uio_offset
& pmp
->pm_crbomask
;
516 n
= MIN(pmp
->pm_bpcluster
- on
, uio
->uio_resid
);
517 if (uio
->uio_offset
>= dep
->de_FileSize
)
519 /* file size (and hence diff) may be up to 4GB */
520 diff
= dep
->de_FileSize
- uio
->uio_offset
;
524 /* convert cluster # to sector # */
525 error
= pcbmap(dep
, lbn
, &lbn
, 0, &blsize
);
530 * If we are operating on a directory file then be sure to
531 * do i/o with the vnode for the filesystem instead of the
532 * vnode for the directory.
534 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, lbn
), blsize
,
536 n
= MIN(n
, pmp
->pm_bpcluster
- bp
->b_resid
);
541 error
= uiomove((char *)bp
->b_data
+ on
, (int) n
, uio
);
543 } while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
546 if ((ap
->a_ioflag
& IO_SYNC
) == IO_SYNC
)
547 error
= deupdat(dep
, 1);
552 * Write data to a file or directory.
555 msdosfs_write(void *v
)
557 struct vop_write_args
/* {
563 int resid
, extended
= 0;
565 int ioflag
= ap
->a_ioflag
;
570 struct uio
*uio
= ap
->a_uio
;
571 struct proc
*p
= curproc
;
572 struct vnode
*vp
= ap
->a_vp
;
573 struct denode
*dep
= VTODE(vp
);
574 struct msdosfsmount
*pmp
= dep
->de_pmp
;
575 kauth_cred_t cred
= ap
->a_cred
;
579 printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
580 vp
, uio
, ioflag
, cred
);
581 printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
582 dep
->de_diroffset
, dep
->de_dirclust
, dep
->de_StartCluster
);
585 switch (vp
->v_type
) {
587 if (ioflag
& IO_APPEND
)
588 uio
->uio_offset
= dep
->de_FileSize
;
593 panic("msdosfs_write(): bad file type");
596 if (uio
->uio_offset
< 0)
599 if (uio
->uio_resid
== 0)
602 /* Don't bother to try to write files larger than the fs limit */
603 if (uio
->uio_offset
+ uio
->uio_resid
> MSDOSFS_FILESIZE_MAX
)
607 * If they've exceeded their filesize limit, tell them about it.
609 if (((uio
->uio_offset
+ uio
->uio_resid
) >
610 p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
)) {
611 mutex_enter(proc_lock
);
613 mutex_exit(proc_lock
);
618 * If the offset we are starting the write at is beyond the end of
619 * the file, then they've done a seek. Unix filesystems allow
620 * files with holes in them, DOS doesn't so we must fill the hole
621 * with zeroed blocks.
623 if (uio
->uio_offset
> dep
->de_FileSize
) {
624 if ((error
= deextend(dep
, uio
->uio_offset
, cred
)) != 0)
629 * Remember some values in case the write fails.
631 async
= vp
->v_mount
->mnt_flag
& MNT_ASYNC
;
632 resid
= uio
->uio_resid
;
633 osize
= dep
->de_FileSize
;
636 * If we write beyond the end of the file, extend it to its ultimate
637 * size ahead of the time to hopefully get a contiguous area.
639 if (uio
->uio_offset
+ resid
> osize
) {
640 count
= de_clcount(pmp
, uio
->uio_offset
+ resid
) -
641 de_clcount(pmp
, osize
);
642 if ((error
= extendfile(dep
, count
, NULL
, NULL
, 0)))
645 dep
->de_FileSize
= uio
->uio_offset
+ resid
;
646 /* hint uvm to not read in extended part */
647 uvm_vnp_setwritesize(vp
, dep
->de_FileSize
);
652 oldoff
= uio
->uio_offset
;
653 bytelen
= uio
->uio_resid
;
655 error
= ubc_uiomove(&vp
->v_uobj
, uio
, bytelen
,
656 IO_ADV_DECODE(ioflag
), UBC_WRITE
| UBC_UNMAP_FLAG(vp
));
661 * flush what we just wrote if necessary.
662 * XXXUBC simplistic async flushing.
665 if (!async
&& oldoff
>> 16 != uio
->uio_offset
>> 16) {
666 mutex_enter(&vp
->v_interlock
);
667 error
= VOP_PUTPAGES(vp
, (oldoff
>> 16) << 16,
668 (uio
->uio_offset
>> 16) << 16, PGO_CLEANIT
);
670 } while (error
== 0 && uio
->uio_resid
> 0);
673 uvm_vnp_setsize(vp
, dep
->de_FileSize
);
674 if (error
== 0 && ioflag
& IO_SYNC
) {
675 mutex_enter(&vp
->v_interlock
);
676 error
= VOP_PUTPAGES(vp
, trunc_page(oldoff
),
677 round_page(oldoff
+ bytelen
), PGO_CLEANIT
| PGO_SYNCIO
);
679 dep
->de_flag
|= DE_UPDATE
;
682 * If the write failed and they want us to, truncate the file back
683 * to the size it was before the write was attempted.
686 if (resid
> uio
->uio_resid
)
687 VN_KNOTE(vp
, NOTE_WRITE
| (extended
? NOTE_EXTEND
: 0));
689 detrunc(dep
, osize
, ioflag
& IO_SYNC
, NOCRED
);
690 uio
->uio_offset
-= resid
- uio
->uio_resid
;
691 uio
->uio_resid
= resid
;
692 } else if ((ioflag
& IO_SYNC
) == IO_SYNC
)
693 error
= deupdat(dep
, 1);
694 KASSERT(vp
->v_size
== dep
->de_FileSize
);
699 msdosfs_update(struct vnode
*vp
, const struct timespec
*acc
,
700 const struct timespec
*mod
, int flags
)
703 struct direntry
*dirp
;
707 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
710 DETIMES(dep
, acc
, mod
, NULL
, dep
->de_pmp
->pm_gmtoff
);
711 if ((dep
->de_flag
& DE_MODIFIED
) == 0)
713 dep
->de_flag
&= ~DE_MODIFIED
;
714 if (dep
->de_Attributes
& ATTR_DIRECTORY
)
716 if (dep
->de_refcnt
<= 0)
718 error
= readde(dep
, &bp
, &dirp
);
721 DE_EXTERNALIZE(dirp
, dep
);
722 if (flags
& (UPDATE_WAIT
|UPDATE_DIROP
))
731 * Flush the blocks of a file to disk.
733 * This function is worthless for vnodes that represent directories. Maybe we
734 * could just do a sync if they try an fsync on a directory file.
737 msdosfs_remove(void *v
)
739 struct vop_remove_args
/* {
742 struct componentname *a_cnp;
744 struct denode
*dep
= VTODE(ap
->a_vp
);
745 struct denode
*ddep
= VTODE(ap
->a_dvp
);
748 if (ap
->a_vp
->v_type
== VDIR
)
751 error
= removede(ddep
, dep
);
753 printf("msdosfs_remove(), dep %p, v_usecount %d\n",
754 dep
, ap
->a_vp
->v_usecount
);
756 VN_KNOTE(ap
->a_vp
, NOTE_DELETE
);
757 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
761 vput(ap
->a_vp
); /* causes msdosfs_inactive() to be called
768 * DOS filesystems don't know what links are. But since we already called
769 * msdosfs_lookup() with create and lockparent, the parent is locked so we
770 * have to free it before we return the error.
773 msdosfs_link(void *v
)
775 struct vop_link_args
/* {
778 struct componentname *a_cnp;
781 VOP_ABORTOP(ap
->a_dvp
, ap
->a_cnp
);
787 * Renames on files require moving the denode to a new hash queue since the
788 * denode's location is used to compute which hash queue to put the file
789 * in. Unless it is a rename in place. For example "mv a b".
791 * What follows is the basic algorithm:
794 * if (dest file exists) {
797 * if (dest and src in same directory) {
798 * rewrite name in existing directory slot
800 * write new entry in dest directory
801 * update offset and dirclust in denode
802 * move denode to new hash chain
803 * clear old directory entry
807 * if (dest directory exists) {
808 * if (dest is not empty) {
811 * remove dest directory
813 * if (dest and src in same directory) {
814 * rewrite name in existing entry
816 * be sure dest is not a child of src directory
817 * write entry in dest directory
818 * update "." and ".." in moved directory
819 * update offset and dirclust in denode
820 * move denode to new hash chain
821 * clear old directory entry for moved directory
826 * source's parent directory is unlocked
827 * source file or directory is unlocked
828 * destination's parent directory is locked
829 * destination file or directory is locked if it exists
832 * all denodes should be released
835 * I'm not sure how the memory containing the pathnames pointed at by the
836 * componentname structures is freed, there may be some memory bleeding
837 * for each rename done.
840 * This routine needs help. badly.
843 msdosfs_rename(void *v
)
845 struct vop_rename_args
/* {
846 struct vnode *a_fdvp;
848 struct componentname *a_fcnp;
849 struct vnode *a_tdvp;
851 struct componentname *a_tcnp;
853 struct vnode
*tvp
= ap
->a_tvp
;
854 struct vnode
*tdvp
= ap
->a_tdvp
;
855 struct vnode
*fvp
= ap
->a_fvp
;
856 struct vnode
*fdvp
= ap
->a_fdvp
;
857 struct componentname
*tcnp
= ap
->a_tcnp
;
858 struct componentname
*fcnp
= ap
->a_fcnp
;
859 struct denode
*ip
, *xp
, *dp
, *zp
;
860 u_char toname
[11], oldname
[11];
861 u_long from_diroffset
, to_diroffset
;
863 int doingdirectory
= 0, newparent
= 0;
867 struct msdosfsmount
*pmp
;
868 struct direntry
*dotdotp
;
872 pmp
= VFSTOMSDOSFS(fdvp
->v_mount
);
875 if ((tcnp
->cn_flags
& HASBUF
) == 0 ||
876 (fcnp
->cn_flags
& HASBUF
) == 0)
877 panic("msdosfs_rename: no name");
880 * Check for cross-device rename.
882 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
883 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
886 VOP_ABORTOP(tdvp
, tcnp
);
893 VOP_ABORTOP(fdvp
, fcnp
);
900 * If source and dest are the same, do nothing.
908 * XXX: This can deadlock since we hold tdvp/tvp locked.
909 * But I'm not going to fix it now.
911 if ((error
= vn_lock(fvp
, LK_EXCLUSIVE
)) != 0)
917 * Be sure we are not renaming ".", "..", or an alias of ".". This
918 * leads to a crippled directory tree. It's pretty tough to do a
919 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
920 * doesn't work if the ".." entry is missing.
922 if (ip
->de_Attributes
& ATTR_DIRECTORY
) {
924 * Avoid ".", "..", and aliases of "." for obvious reasons.
926 if ((fcnp
->cn_namelen
== 1 && fcnp
->cn_nameptr
[0] == '.') ||
928 (fcnp
->cn_flags
& ISDOTDOT
) ||
929 (tcnp
->cn_flags
& ISDOTDOT
) ||
930 (ip
->de_flag
& DE_RENAME
)) {
935 ip
->de_flag
|= DE_RENAME
;
938 VN_KNOTE(fdvp
, NOTE_WRITE
); /* XXXLUKEM/XXX: right place? */
941 * When the target exists, both the directory
942 * and target vnodes are returned locked.
945 xp
= tvp
? VTODE(tvp
) : NULL
;
947 * Remember direntry place to use for destination
949 to_diroffset
= dp
->de_fndoffset
;
950 to_count
= dp
->de_fndcnt
;
953 * If ".." must be changed (ie the directory gets a new
954 * parent) then the source directory must not be in the
955 * directory hierarchy above the target, as this would
956 * orphan everything below the source directory. Also
957 * the user must have write permission in the source so
958 * as to be able to change "..". We must repeat the call
959 * to namei, as the parent directory is unlocked by the
960 * call to doscheckpath().
962 error
= VOP_ACCESS(fvp
, VWRITE
, tcnp
->cn_cred
);
964 if (VTODE(fdvp
)->de_StartCluster
!= VTODE(tdvp
)->de_StartCluster
)
968 * XXX: We can do this here because rename uses SAVEFART and
969 * therefore fdvp has at least two references (one doesn't
970 * belong to us, though, and that's evil). We'll get
971 * another "extra" reference when we do relookup(), so we
972 * need to compensate. We should *NOT* be doing this, but
973 * it works, so whatever.
977 if (doingdirectory
&& newparent
) {
978 if (error
) /* write access check above */
984 * doscheckpath() vput()'s dp,
985 * so we have to do a relookup afterwards
987 if ((error
= doscheckpath(ip
, dp
)) != 0)
989 if ((tcnp
->cn_flags
& SAVESTART
) == 0)
990 panic("msdosfs_rename: lost to startdir");
991 vn_lock(tdvp
, LK_EXCLUSIVE
| LK_RETRY
);
992 if ((error
= relookup(tdvp
, &tvp
, tcnp
)) != 0) {
997 * XXX: SAVESTART causes us to get a reference, but
998 * that's released already above in doscheckpath()
1001 xp
= tvp
? VTODE(tvp
) : NULL
;
1006 * Target must be empty if a directory and have no links
1007 * to it. Also, ensure source and target are compatible
1008 * (both directories, or both not directories).
1010 if (xp
->de_Attributes
& ATTR_DIRECTORY
) {
1011 if (!dosdirempty(xp
)) {
1015 if (!doingdirectory
) {
1019 } else if (doingdirectory
) {
1023 if ((error
= removede(dp
, xp
)) != 0)
1025 VN_KNOTE(tdvp
, NOTE_WRITE
);
1026 VN_KNOTE(tvp
, NOTE_DELETE
);
1034 * Convert the filename in tcnp into a dos filename. We copy this
1035 * into the denode and directory entry for the destination
1038 if ((error
= uniqdosname(VTODE(tdvp
), tcnp
, toname
)) != 0)
1042 * Since from wasn't locked at various places above,
1043 * have to do a relookup here.
1045 fcnp
->cn_flags
&= ~MODMASK
;
1046 fcnp
->cn_flags
|= LOCKPARENT
| LOCKLEAF
;
1047 if ((fcnp
->cn_flags
& SAVESTART
) == 0)
1048 panic("msdosfs_rename: lost from startdir");
1049 VOP_UNLOCK(tdvp
, 0);
1050 vn_lock(fdvp
, LK_EXCLUSIVE
| LK_RETRY
);
1051 if ((error
= relookup(fdvp
, &fvp
, fcnp
))) {
1052 VOP_UNLOCK(fdvp
, 0);
1059 * From name has disappeared.
1062 panic("rename: lost dir entry");
1069 VOP_UNLOCK(fdvp
, 0);
1072 from_diroffset
= zp
->de_fndoffset
;
1075 * Ensure that the directory entry still exists and has not
1076 * changed till now. If the source is a file the entry may
1077 * have been unlinked or renamed. In either case there is
1078 * no further work to be done. If the source is a directory
1079 * then it cannot have been rmdir'ed or renamed; this is
1080 * prohibited by the DE_RENAME flag.
1084 panic("rename: lost dir entry");
1093 * First write a new entry in the destination
1094 * directory and mark the entry in the source directory
1095 * as deleted. Then move the denode to the correct hash
1096 * chain for its new location in the filesystem. And, if
1097 * we moved a directory, then update its .. entry to point
1098 * to the new parent directory.
1100 memcpy(oldname
, ip
->de_Name
, 11);
1101 memcpy(ip
->de_Name
, toname
, 11); /* update denode */
1102 dp
->de_fndoffset
= to_diroffset
;
1103 dp
->de_fndcnt
= to_count
;
1104 error
= createde(ip
, dp
, (struct denode
**)0, tcnp
);
1106 memcpy(ip
->de_Name
, oldname
, 11);
1111 zp
->de_fndoffset
= from_diroffset
;
1112 if ((error
= removede(zp
, ip
)) != 0) {
1113 /* XXX should really panic here, fs is corrupt */
1118 if (!doingdirectory
) {
1119 error
= pcbmap(dp
, de_cluster(pmp
, to_diroffset
), 0,
1120 &ip
->de_dirclust
, 0);
1122 /* XXX should really panic here, fs is corrupt */
1126 ip
->de_diroffset
= to_diroffset
;
1127 if (ip
->de_dirclust
!= MSDOSFSROOT
)
1128 ip
->de_diroffset
&= pmp
->pm_crbomask
;
1134 * If we moved a directory to a new parent directory, then we must
1135 * fixup the ".." entry in the moved directory.
1137 if (doingdirectory
&& newparent
) {
1138 cn
= ip
->de_StartCluster
;
1139 if (cn
== MSDOSFSROOT
) {
1140 /* this should never happen */
1141 panic("msdosfs_rename: updating .. in root directory?");
1143 bn
= cntobn(pmp
, cn
);
1144 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
),
1145 pmp
->pm_bpcluster
, NOCRED
, B_MODIFY
, &bp
);
1147 /* XXX should really panic here, fs is corrupt */
1152 dotdotp
= (struct direntry
*)bp
->b_data
+ 1;
1153 putushort(dotdotp
->deStartCluster
, dp
->de_StartCluster
);
1155 putushort(dotdotp
->deHighClust
,
1156 dp
->de_StartCluster
>> 16);
1158 putushort(dotdotp
->deHighClust
, 0);
1160 if ((error
= bwrite(bp
)) != 0) {
1161 /* XXX should really panic here, fs is corrupt */
1167 VN_KNOTE(fvp
, NOTE_RENAME
);
1174 ip
->de_flag
&= ~DE_RENAME
;
1182 VOP_UNLOCK(tdvp
, 0);
1186 static const struct {
1187 struct direntry dot
;
1188 struct direntry dotdot
;
1189 } dosdirtemplate
= {
1190 { ". ", " ", /* the . entry */
1191 ATTR_DIRECTORY
, /* file attribute */
1193 0, { 0, 0 }, { 0, 0 }, /* create time & date */
1194 { 0, 0 }, /* access date */
1195 { 0, 0 }, /* high bits of start cluster */
1196 { 210, 4 }, { 210, 4 }, /* modify time & date */
1197 { 0, 0 }, /* startcluster */
1198 { 0, 0, 0, 0 } /* filesize */
1200 { ".. ", " ", /* the .. entry */
1201 ATTR_DIRECTORY
, /* file attribute */
1203 0, { 0, 0 }, { 0, 0 }, /* create time & date */
1204 { 0, 0 }, /* access date */
1205 { 0, 0 }, /* high bits of start cluster */
1206 { 210, 4 }, { 210, 4 }, /* modify time & date */
1207 { 0, 0 }, /* startcluster */
1208 { 0, 0, 0, 0 } /* filesize */
1213 msdosfs_mkdir(void *v
)
1215 struct vop_mkdir_args
/* {
1216 struct vnode *a_dvp;
1217 struvt vnode **a_vpp;
1218 struvt componentname *a_cnp;
1219 struct vattr *a_vap;
1221 struct componentname
*cnp
= ap
->a_cnp
;
1222 struct denode ndirent
;
1224 struct denode
*pdep
= VTODE(ap
->a_dvp
);
1227 u_long newcluster
, pcl
;
1229 struct direntry
*denp
;
1230 struct msdosfsmount
*pmp
= pdep
->de_pmp
;
1232 int async
= pdep
->de_pmp
->pm_mountp
->mnt_flag
& MNT_ASYNC
;
1235 * If this is the root directory and there is no space left we
1236 * can't do anything. This is because the root directory can not
1239 if (pdep
->de_StartCluster
== MSDOSFSROOT
1240 && pdep
->de_fndoffset
>= pdep
->de_FileSize
) {
1246 * Allocate a cluster to hold the about to be created directory.
1248 error
= clusteralloc(pmp
, 0, 1, &newcluster
, NULL
);
1252 memset(&ndirent
, 0, sizeof(ndirent
));
1253 ndirent
.de_pmp
= pmp
;
1254 ndirent
.de_flag
= DE_ACCESS
| DE_CREATE
| DE_UPDATE
;
1255 DETIMES(&ndirent
, NULL
, NULL
, NULL
, pmp
->pm_gmtoff
);
1258 * Now fill the cluster with the "." and ".." entries. And write
1259 * the cluster to disk. This way it is there for the parent
1260 * directory to be pointing at if there were a crash.
1262 bn
= cntobn(pmp
, newcluster
);
1263 lbn
= de_bn2kb(pmp
, bn
);
1264 /* always succeeds */
1265 bp
= getblk(pmp
->pm_devvp
, lbn
, pmp
->pm_bpcluster
, 0, 0);
1266 memset(bp
->b_data
, 0, pmp
->pm_bpcluster
);
1267 memcpy(bp
->b_data
, &dosdirtemplate
, sizeof dosdirtemplate
);
1268 denp
= (struct direntry
*)bp
->b_data
;
1269 putushort(denp
[0].deStartCluster
, newcluster
);
1270 putushort(denp
[0].deCDate
, ndirent
.de_CDate
);
1271 putushort(denp
[0].deCTime
, ndirent
.de_CTime
);
1272 denp
[0].deCHundredth
= ndirent
.de_CHun
;
1273 putushort(denp
[0].deADate
, ndirent
.de_ADate
);
1274 putushort(denp
[0].deMDate
, ndirent
.de_MDate
);
1275 putushort(denp
[0].deMTime
, ndirent
.de_MTime
);
1276 pcl
= pdep
->de_StartCluster
;
1277 if (FAT32(pmp
) && pcl
== pmp
->pm_rootdirblk
)
1279 putushort(denp
[1].deStartCluster
, pcl
);
1280 putushort(denp
[1].deCDate
, ndirent
.de_CDate
);
1281 putushort(denp
[1].deCTime
, ndirent
.de_CTime
);
1282 denp
[1].deCHundredth
= ndirent
.de_CHun
;
1283 putushort(denp
[1].deADate
, ndirent
.de_ADate
);
1284 putushort(denp
[1].deMDate
, ndirent
.de_MDate
);
1285 putushort(denp
[1].deMTime
, ndirent
.de_MTime
);
1287 putushort(denp
[0].deHighClust
, newcluster
>> 16);
1288 putushort(denp
[1].deHighClust
, pdep
->de_StartCluster
>> 16);
1290 putushort(denp
[0].deHighClust
, 0);
1291 putushort(denp
[1].deHighClust
, 0);
1296 else if ((error
= bwrite(bp
)) != 0)
1300 * Now build up a directory entry pointing to the newly allocated
1301 * cluster. This will be written to an empty slot in the parent
1305 if ((cnp
->cn_flags
& HASBUF
) == 0)
1306 panic("msdosfs_mkdir: no name");
1308 if ((error
= uniqdosname(pdep
, cnp
, ndirent
.de_Name
)) != 0)
1311 ndirent
.de_Attributes
= ATTR_DIRECTORY
;
1312 ndirent
.de_StartCluster
= newcluster
;
1313 ndirent
.de_FileSize
= 0;
1314 ndirent
.de_dev
= pdep
->de_dev
;
1315 ndirent
.de_devvp
= pdep
->de_devvp
;
1316 if ((error
= createde(&ndirent
, pdep
, &dep
, cnp
)) != 0)
1318 if ((cnp
->cn_flags
& SAVESTART
) == 0)
1319 PNBUF_PUT(cnp
->cn_pnbuf
);
1320 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
| NOTE_LINK
);
1322 *ap
->a_vpp
= DETOV(dep
);
1326 clusterfree(pmp
, newcluster
, NULL
);
1328 PNBUF_PUT(cnp
->cn_pnbuf
);
1334 msdosfs_rmdir(void *v
)
1336 struct vop_rmdir_args
/* {
1337 struct vnode *a_dvp;
1339 struct componentname *a_cnp;
1341 struct vnode
*vp
= ap
->a_vp
;
1342 struct vnode
*dvp
= ap
->a_dvp
;
1343 struct componentname
*cnp
= ap
->a_cnp
;
1344 struct denode
*ip
, *dp
;
1350 * No rmdir "." please.
1358 * Verify the directory is empty (and valid).
1359 * (Rmdir ".." won't be valid since
1360 * ".." will contain a reference to
1361 * the current directory and thus be
1365 if (!dosdirempty(ip
) || ip
->de_flag
& DE_RENAME
) {
1370 * Delete the entry from the directory. For dos filesystems this
1371 * gets rid of the directory entry on disk, the in memory copy
1372 * still exists but the de_refcnt is <= 0. This prevents it from
1373 * being found by deget(). When the vput() on dep is done we give
1374 * up access and eventually msdosfs_reclaim() will be called which
1375 * will remove it from the denode cache.
1377 if ((error
= removede(dp
, ip
)) != 0)
1380 * This is where we decrement the link count in the parent
1381 * directory. Since dos filesystems don't do this we just purge
1382 * the name cache and let go of the parent directory denode.
1384 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
1389 * Truncate the directory that is being deleted.
1391 error
= detrunc(ip
, (u_long
)0, IO_SYNC
, cnp
->cn_cred
);
1394 VN_KNOTE(vp
, NOTE_DELETE
);
1402 * DOS filesystems don't know what symlinks are.
1405 msdosfs_symlink(void *v
)
1407 struct vop_symlink_args
/* {
1408 struct vnode *a_dvp;
1409 struct vnode **a_vpp;
1410 struct componentname *a_cnp;
1411 struct vattr *a_vap;
1415 VOP_ABORTOP(ap
->a_dvp
, ap
->a_cnp
);
1417 return (EOPNOTSUPP
);
1421 msdosfs_readdir(void *v
)
1423 struct vop_readdir_args
/* {
1426 kauth_cred_t a_cred;
1444 struct denode
*dep
= VTODE(ap
->a_vp
);
1445 struct msdosfsmount
*pmp
= dep
->de_pmp
;
1446 struct direntry
*dentp
;
1447 struct dirent
*dirbuf
;
1448 struct uio
*uio
= ap
->a_uio
;
1449 off_t
*cookies
= NULL
;
1450 int ncookies
= 0, nc
= 0;
1451 off_t offset
, uio_off
;
1454 #ifdef MSDOSFS_DEBUG
1455 printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
1456 ap
->a_vp
, uio
, ap
->a_cred
, ap
->a_eofflag
);
1460 * msdosfs_readdir() won't operate properly on regular files since
1461 * it does i/o only with the filesystem vnode, and hence can
1462 * retrieve the wrong block from the buffer cache for a plain file.
1463 * So, fail attempts to readdir() on a plain file.
1465 if ((dep
->de_Attributes
& ATTR_DIRECTORY
) == 0)
1469 * If the user buffer is smaller than the size of one dos directory
1470 * entry or the file offset is not a multiple of the size of a
1471 * directory entry, then we fail the read.
1473 count
= uio
->uio_resid
& ~(sizeof(struct direntry
) - 1);
1474 offset
= uio
->uio_offset
;
1475 if (count
< sizeof(struct direntry
) ||
1476 (offset
& (sizeof(struct direntry
) - 1)))
1478 lost
= uio
->uio_resid
- count
;
1479 uio
->uio_resid
= count
;
1480 uio_off
= uio
->uio_offset
;
1482 /* Allocate a temporary dirent buffer. */
1483 dirbuf
= malloc(sizeof(struct dirent
), M_MSDOSFSTMP
, M_WAITOK
| M_ZERO
);
1485 if (ap
->a_ncookies
) {
1486 nc
= uio
->uio_resid
/ _DIRENT_MINSIZE((struct dirent
*)0);
1487 cookies
= malloc(nc
* sizeof (off_t
), M_TEMP
, M_WAITOK
);
1488 *ap
->a_cookies
= cookies
;
1491 dirsperblk
= pmp
->pm_BytesPerSec
/ sizeof(struct direntry
);
1494 * If they are reading from the root directory then, we simulate
1495 * the . and .. entries since these don't exist in the root
1496 * directory. We also set the offset bias to make up for having to
1497 * simulate these entries. By this I mean that at file offset 64 we
1498 * read the first entry in the root directory that lives on disk.
1500 if (dep
->de_StartCluster
== MSDOSFSROOT
1501 || (FAT32(pmp
) && dep
->de_StartCluster
== pmp
->pm_rootdirblk
)) {
1503 printf("msdosfs_readdir(): going after . or .. in root dir, "
1504 "offset %" PRIu64
"\n", offset
);
1506 bias
= 2 * sizeof(struct direntry
);
1507 if (offset
< bias
) {
1508 for (n
= (int)offset
/ sizeof(struct direntry
);
1511 dirbuf
->d_fileno
= cntobn(pmp
,
1512 (ino_t
)pmp
->pm_rootdirblk
)
1515 dirbuf
->d_fileno
= 1;
1516 dirbuf
->d_type
= DT_DIR
;
1519 dirbuf
->d_namlen
= 1;
1520 strlcpy(dirbuf
->d_name
, ".",
1521 sizeof(dirbuf
->d_name
));
1524 dirbuf
->d_namlen
= 2;
1525 strlcpy(dirbuf
->d_name
, "..",
1526 sizeof(dirbuf
->d_name
));
1529 dirbuf
->d_reclen
= _DIRENT_SIZE(dirbuf
);
1530 if (uio
->uio_resid
< dirbuf
->d_reclen
)
1532 error
= uiomove(dirbuf
, dirbuf
->d_reclen
, uio
);
1535 offset
+= sizeof(struct direntry
);
1538 *cookies
++ = offset
;
1547 while (uio
->uio_resid
> 0) {
1548 lbn
= de_cluster(pmp
, offset
- bias
);
1549 on
= (offset
- bias
) & pmp
->pm_crbomask
;
1550 n
= MIN(pmp
->pm_bpcluster
- on
, uio
->uio_resid
);
1551 diff
= dep
->de_FileSize
- (offset
- bias
);
1555 if ((error
= pcbmap(dep
, lbn
, &bn
, &cn
, &blsize
)) != 0)
1557 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), blsize
,
1561 free(dirbuf
, M_MSDOSFSTMP
);
1564 n
= MIN(n
, blsize
- bp
->b_resid
);
1567 * Convert from dos directory entries to fs-independent
1568 * directory entries.
1570 for (dentp
= (struct direntry
*)((char *)bp
->b_data
+ on
);
1571 (char *)dentp
< (char *)bp
->b_data
+ on
+ n
;
1572 dentp
++, offset
+= sizeof(struct direntry
)) {
1575 printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
1576 dentp
, prev
, crnt
, dentp
->deName
[0], dentp
->deAttributes
);
1579 * If this is an unused entry, we can stop.
1581 if (dentp
->deName
[0] == SLOT_EMPTY
) {
1586 * Skip deleted entries.
1588 if (dentp
->deName
[0] == SLOT_DELETED
) {
1594 * Handle Win95 long directory entries
1596 if (dentp
->deAttributes
== ATTR_WIN95
) {
1597 if (pmp
->pm_flags
& MSDOSFSMNT_SHORTNAME
)
1599 chksum
= win2unixfn((struct winentry
*)dentp
,
1605 * Skip volume labels
1607 if (dentp
->deAttributes
& ATTR_VOLUME
) {
1612 * This computation of d_fileno must match
1613 * the computation of va_fileid in
1616 if (dentp
->deAttributes
& ATTR_DIRECTORY
) {
1617 fileno
= getushort(dentp
->deStartCluster
);
1619 fileno
|= ((ino_t
)getushort(dentp
->deHighClust
)) << 16;
1620 /* if this is the root directory */
1621 if (fileno
== MSDOSFSROOT
)
1623 fileno
= cntobn(pmp
,
1624 (ino_t
)pmp
->pm_rootdirblk
)
1629 fileno
= cntobn(pmp
, fileno
) * dirsperblk
;
1630 dirbuf
->d_fileno
= fileno
;
1631 dirbuf
->d_type
= DT_DIR
;
1634 offset
/ sizeof(struct direntry
);
1635 dirbuf
->d_type
= DT_REG
;
1637 if (chksum
!= winChksum(dentp
->deName
))
1638 dirbuf
->d_namlen
= dos2unixfn(dentp
->deName
,
1639 (u_char
*)dirbuf
->d_name
,
1640 pmp
->pm_flags
& MSDOSFSMNT_SHORTNAME
);
1642 dirbuf
->d_name
[dirbuf
->d_namlen
] = 0;
1644 dirbuf
->d_reclen
= _DIRENT_SIZE(dirbuf
);
1645 if (uio
->uio_resid
< dirbuf
->d_reclen
) {
1649 error
= uiomove(dirbuf
, dirbuf
->d_reclen
, uio
);
1654 uio_off
= offset
+ sizeof(struct direntry
);
1656 *cookies
++ = offset
+ sizeof(struct direntry
);
1658 if (ncookies
>= nc
) {
1668 uio
->uio_offset
= uio_off
;
1669 uio
->uio_resid
+= lost
;
1670 if (dep
->de_FileSize
- (offset
- bias
) <= 0)
1675 if (ap
->a_ncookies
) {
1677 free(*ap
->a_cookies
, M_TEMP
);
1678 *ap
->a_ncookies
= 0;
1679 *ap
->a_cookies
= NULL
;
1681 *ap
->a_ncookies
= ncookies
;
1683 free(dirbuf
, M_MSDOSFSTMP
);
1688 * DOS filesystems don't know what symlinks are.
1691 msdosfs_readlink(void *v
)
1694 struct vop_readlink_args
/* {
1697 kauth_cred_t a_cred;
1705 * vp - address of vnode file the file
1706 * bn - which cluster we are interested in mapping to a filesystem block number.
1707 * vpp - returns the vnode for the block special file holding the filesystem
1708 * containing the file of interest
1709 * bnp - address of where to return the filesystem relative block number
1712 msdosfs_bmap(void *v
)
1714 struct vop_bmap_args
/* {
1717 struct vnode **a_vpp;
1721 struct denode
*dep
= VTODE(ap
->a_vp
);
1726 if (ap
->a_vpp
!= NULL
)
1727 *ap
->a_vpp
= dep
->de_devvp
;
1728 if (ap
->a_bnp
== NULL
)
1730 status
= pcbmap(dep
, ap
->a_bn
, ap
->a_bnp
, 0, 0);
1734 * A little kludgy, but we loop calling pcbmap until we
1735 * reach the end of the contiguous piece, or reach MAXPHYS.
1736 * Since it reduces disk I/Os, the "wasted" CPU is put to
1737 * good use (4 to 5 fold sequential read I/O improvement on USB
1740 if (ap
->a_runp
!= NULL
) {
1741 /* taken from ufs_bmap */
1742 maxrun
= ulmin(MAXPHYS
/ dep
->de_pmp
->pm_bpcluster
- 1,
1743 dep
->de_pmp
->pm_maxcluster
- ap
->a_bn
);
1744 for (run
= 1; run
<= maxrun
; run
++) {
1745 if (pcbmap(dep
, ap
->a_bn
+ run
, &runbn
, NULL
, NULL
)
1747 *ap
->a_bnp
+ de_cn2bn(dep
->de_pmp
, run
))
1750 *ap
->a_runp
= run
- 1;
1754 * We need to scale *ap->a_bnp by sector_size/DEV_BSIZE
1756 *ap
->a_bnp
= de_bn2kb(dep
->de_pmp
, *ap
->a_bnp
);
1761 msdosfs_strategy(void *v
)
1763 struct vop_strategy_args
/* {
1767 struct vnode
*vp
= ap
->a_vp
;
1768 struct buf
*bp
= ap
->a_bp
;
1769 struct denode
*dep
= VTODE(bp
->b_vp
);
1772 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1773 panic("msdosfs_strategy: spec");
1775 * If we don't already know the filesystem relative block number
1776 * then get it using pcbmap(). If pcbmap() returns the block
1777 * number as -1 then we've got a hole in the file. DOS filesystems
1778 * don't allow files with holes, so we shouldn't ever see this.
1780 if (bp
->b_blkno
== bp
->b_lblkno
) {
1781 error
= pcbmap(dep
, de_bn2cn(dep
->de_pmp
, bp
->b_lblkno
),
1782 &bp
->b_blkno
, 0, 0);
1785 if (bp
->b_blkno
== -1)
1788 bp
->b_blkno
= de_bn2kb(dep
->de_pmp
, bp
->b_blkno
);
1790 if (bp
->b_blkno
== -1) {
1796 * Read/write the block from/to the disk that contains the desired
1801 return (VOP_STRATEGY(vp
, bp
));
1805 msdosfs_print(void *v
)
1807 struct vop_print_args
/* {
1810 struct denode
*dep
= VTODE(ap
->a_vp
);
1813 "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
1814 dep
->de_StartCluster
, dep
->de_dirclust
, dep
->de_diroffset
);
1815 printf(" dev %llu, %llu ", (unsigned long long)major(dep
->de_dev
),
1816 (unsigned long long)minor(dep
->de_dev
));
1822 msdosfs_advlock(void *v
)
1824 struct vop_advlock_args
/* {
1831 struct denode
*dep
= VTODE(ap
->a_vp
);
1833 return lf_advlock(ap
, &dep
->de_lockf
, dep
->de_FileSize
);
1837 msdosfs_pathconf(void *v
)
1839 struct vop_pathconf_args
/* {
1842 register_t *a_retval;
1845 switch (ap
->a_name
) {
1850 *ap
->a_retval
= ap
->a_vp
->v_mount
->mnt_stat
.f_namemax
;
1853 *ap
->a_retval
= PATH_MAX
;
1855 case _PC_CHOWN_RESTRICTED
:
1864 case _PC_FILESIZEBITS
:
1874 msdosfs_fsync(void *v
)
1876 struct vop_fsync_args
/* {
1878 kauth_cred_t a_cred;
1883 struct vnode
*vp
= ap
->a_vp
;
1887 wait
= (ap
->a_flags
& FSYNC_WAIT
) != 0;
1888 vflushbuf(vp
, wait
);
1889 if ((ap
->a_flags
& FSYNC_DATAONLY
) != 0)
1892 error
= msdosfs_update(vp
, NULL
, NULL
, wait
? UPDATE_WAIT
: 0);
1894 if (error
== 0 && ap
->a_flags
& FSYNC_CACHE
) {
1895 struct denode
*dep
= VTODE(vp
);
1896 struct vnode
*devvp
= dep
->de_devvp
;
1899 error
= VOP_IOCTL(devvp
, DIOCCACHESYNC
, &l
, FWRITE
,
1907 msdosfs_detimes(struct denode
*dep
, const struct timespec
*acc
,
1908 const struct timespec
*mod
, const struct timespec
*cre
, int gmtoff
)
1910 struct timespec
*ts
= NULL
, tsb
;
1912 KASSERT(dep
->de_flag
& (DE_UPDATE
| DE_CREATE
| DE_ACCESS
));
1913 /* XXX just call getnanotime early and use result if needed? */
1914 dep
->de_flag
|= DE_MODIFIED
;
1915 if (dep
->de_flag
& DE_UPDATE
) {
1920 unix2dostime(mod
, gmtoff
, &dep
->de_MDate
, &dep
->de_MTime
, NULL
);
1921 dep
->de_Attributes
|= ATTR_ARCHIVE
;
1923 if ((dep
->de_pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
) == 0) {
1924 if (dep
->de_flag
& DE_ACCESS
) {
1927 (getnanotime(&tsb
), ts
= &tsb
) : ts
;
1928 unix2dostime(acc
, gmtoff
, &dep
->de_ADate
, NULL
, NULL
);
1930 if (dep
->de_flag
& DE_CREATE
) {
1933 (getnanotime(&tsb
), ts
= &tsb
) : ts
;
1934 unix2dostime(cre
, gmtoff
, &dep
->de_CDate
,
1935 &dep
->de_CTime
, &dep
->de_CHun
);
1939 dep
->de_flag
&= ~(DE_UPDATE
| DE_CREATE
| DE_ACCESS
);
1942 /* Global vfs data structures for msdosfs */
1943 int (**msdosfs_vnodeop_p
)(void *);
1944 const struct vnodeopv_entry_desc msdosfs_vnodeop_entries
[] = {
1945 { &vop_default_desc
, vn_default_error
},
1946 { &vop_lookup_desc
, msdosfs_lookup
}, /* lookup */
1947 { &vop_create_desc
, msdosfs_create
}, /* create */
1948 { &vop_mknod_desc
, msdosfs_mknod
}, /* mknod */
1949 { &vop_open_desc
, msdosfs_open
}, /* open */
1950 { &vop_close_desc
, msdosfs_close
}, /* close */
1951 { &vop_access_desc
, msdosfs_access
}, /* access */
1952 { &vop_getattr_desc
, msdosfs_getattr
}, /* getattr */
1953 { &vop_setattr_desc
, msdosfs_setattr
}, /* setattr */
1954 { &vop_read_desc
, msdosfs_read
}, /* read */
1955 { &vop_write_desc
, msdosfs_write
}, /* write */
1956 { &vop_fcntl_desc
, genfs_fcntl
}, /* fcntl */
1957 { &vop_ioctl_desc
, msdosfs_ioctl
}, /* ioctl */
1958 { &vop_poll_desc
, msdosfs_poll
}, /* poll */
1959 { &vop_kqfilter_desc
, genfs_kqfilter
}, /* kqfilter */
1960 { &vop_revoke_desc
, msdosfs_revoke
}, /* revoke */
1961 { &vop_mmap_desc
, msdosfs_mmap
}, /* mmap */
1962 { &vop_fsync_desc
, msdosfs_fsync
}, /* fsync */
1963 { &vop_seek_desc
, msdosfs_seek
}, /* seek */
1964 { &vop_remove_desc
, msdosfs_remove
}, /* remove */
1965 { &vop_link_desc
, msdosfs_link
}, /* link */
1966 { &vop_rename_desc
, msdosfs_rename
}, /* rename */
1967 { &vop_mkdir_desc
, msdosfs_mkdir
}, /* mkdir */
1968 { &vop_rmdir_desc
, msdosfs_rmdir
}, /* rmdir */
1969 { &vop_symlink_desc
, msdosfs_symlink
}, /* symlink */
1970 { &vop_readdir_desc
, msdosfs_readdir
}, /* readdir */
1971 { &vop_readlink_desc
, msdosfs_readlink
}, /* readlink */
1972 { &vop_abortop_desc
, msdosfs_abortop
}, /* abortop */
1973 { &vop_inactive_desc
, msdosfs_inactive
}, /* inactive */
1974 { &vop_reclaim_desc
, msdosfs_reclaim
}, /* reclaim */
1975 { &vop_lock_desc
, genfs_lock
}, /* lock */
1976 { &vop_unlock_desc
, genfs_unlock
}, /* unlock */
1977 { &vop_bmap_desc
, msdosfs_bmap
}, /* bmap */
1978 { &vop_strategy_desc
, msdosfs_strategy
}, /* strategy */
1979 { &vop_print_desc
, msdosfs_print
}, /* print */
1980 { &vop_islocked_desc
, genfs_islocked
}, /* islocked */
1981 { &vop_pathconf_desc
, msdosfs_pathconf
}, /* pathconf */
1982 { &vop_advlock_desc
, msdosfs_advlock
}, /* advlock */
1983 { &vop_bwrite_desc
, vn_bwrite
}, /* bwrite */
1984 { &vop_getpages_desc
, genfs_getpages
}, /* getpages */
1985 { &vop_putpages_desc
, genfs_putpages
}, /* putpages */
1988 const struct vnodeopv_desc msdosfs_vnodeop_opv_desc
=
1989 { &msdosfs_vnodeop_p
, msdosfs_vnodeop_entries
};