1 /* $NetBSD: msdosfs_vnops.c,v 1.93 2015/04/04 12:34:44 riastradh 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.93 2015/04/04 12:34:44 riastradh 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/fstrans.h>
64 #include <sys/vnode.h>
65 #include <sys/signalvar.h>
66 #include <sys/malloc.h>
67 #include <sys/dirent.h>
68 #include <sys/lockf.h>
69 #include <sys/kauth.h>
71 #include <miscfs/genfs/genfs.h>
72 #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
74 #include <uvm/uvm_extern.h>
76 #include <fs/msdosfs/bpb.h>
77 #include <fs/msdosfs/direntry.h>
78 #include <fs/msdosfs/denode.h>
79 #include <fs/msdosfs/msdosfsmount.h>
80 #include <fs/msdosfs/fat.h>
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.
101 * Create a regular file. On entry the directory to contain the file being
102 * created is locked. We must release before we return.
105 msdosfs_create(void *v
)
107 struct vop_create_v3_args
/* {
109 struct vnode **a_vpp;
110 struct componentname *a_cnp;
113 struct componentname
*cnp
= ap
->a_cnp
;
114 struct denode ndirent
;
116 struct denode
*pdep
= VTODE(ap
->a_dvp
);
120 printf("msdosfs_create(cnp %p, vap %p\n", cnp
, ap
->a_vap
);
123 fstrans_start(ap
->a_dvp
->v_mount
, FSTRANS_SHARED
);
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
141 memset(&ndirent
, 0, sizeof(ndirent
));
142 if ((error
= uniqdosname(pdep
, cnp
, ndirent
.de_Name
)) != 0)
145 ndirent
.de_Attributes
= (ap
->a_vap
->va_mode
& S_IWUSR
) ?
146 ATTR_ARCHIVE
: ATTR_ARCHIVE
| ATTR_READONLY
;
147 ndirent
.de_StartCluster
= 0;
148 ndirent
.de_FileSize
= 0;
149 ndirent
.de_dev
= pdep
->de_dev
;
150 ndirent
.de_devvp
= pdep
->de_devvp
;
151 ndirent
.de_pmp
= pdep
->de_pmp
;
152 ndirent
.de_flag
= DE_ACCESS
| DE_CREATE
| DE_UPDATE
;
153 DETIMES(&ndirent
, NULL
, NULL
, NULL
, pdep
->de_pmp
->pm_gmtoff
);
154 if ((error
= createde(&ndirent
, pdep
, &dep
, cnp
)) != 0)
156 fstrans_done(ap
->a_dvp
->v_mount
);
157 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
158 *ap
->a_vpp
= DETOV(dep
);
162 fstrans_done(ap
->a_dvp
->v_mount
);
167 msdosfs_close(void *v
)
169 struct vop_close_args
/* {
174 struct vnode
*vp
= ap
->a_vp
;
175 struct denode
*dep
= VTODE(vp
);
177 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
178 mutex_enter(vp
->v_interlock
);
179 if (vp
->v_usecount
> 1)
180 DETIMES(dep
, NULL
, NULL
, NULL
, dep
->de_pmp
->pm_gmtoff
);
181 mutex_exit(vp
->v_interlock
);
182 fstrans_done(vp
->v_mount
);
187 msdosfs_check_possible(struct vnode
*vp
, struct denode
*dep
, mode_t mode
)
191 * Disallow write attempts on read-only file systems;
192 * unless the file is a socket, fifo, or a block or
193 * character device resident on the file system.
196 switch (vp
->v_type
) {
200 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
211 msdosfs_check_permitted(struct vnode
*vp
, struct denode
*dep
, mode_t mode
,
214 struct msdosfsmount
*pmp
= dep
->de_pmp
;
217 if ((dep
->de_Attributes
& ATTR_READONLY
) == 0)
218 file_mode
= S_IRWXU
|S_IRWXG
|S_IRWXO
;
220 file_mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
222 file_mode
&= (vp
->v_type
== VDIR
? pmp
->pm_dirmask
: pmp
->pm_mask
);
224 return kauth_authorize_vnode(cred
, KAUTH_ACCESS_ACTION(mode
,
225 vp
->v_type
, file_mode
), vp
, NULL
, genfs_can_access(vp
->v_type
,
226 file_mode
, pmp
->pm_uid
, pmp
->pm_gid
, mode
, cred
));
230 msdosfs_access(void *v
)
232 struct vop_access_args
/* {
237 struct vnode
*vp
= ap
->a_vp
;
238 struct denode
*dep
= VTODE(vp
);
241 error
= msdosfs_check_possible(vp
, dep
, ap
->a_mode
);
245 error
= msdosfs_check_permitted(vp
, dep
, ap
->a_mode
, ap
->a_cred
);
251 msdosfs_getattr(void *v
)
253 struct vop_getattr_args
/* {
258 struct denode
*dep
= VTODE(ap
->a_vp
);
259 struct msdosfsmount
*pmp
= dep
->de_pmp
;
260 struct vattr
*vap
= ap
->a_vap
;
262 u_long dirsperblk
= pmp
->pm_BytesPerSec
/ sizeof(struct direntry
);
265 fstrans_start(ap
->a_vp
->v_mount
, FSTRANS_SHARED
);
266 DETIMES(dep
, NULL
, NULL
, NULL
, pmp
->pm_gmtoff
);
267 vap
->va_fsid
= dep
->de_dev
;
269 * The following computation of the fileid must be the same as that
270 * used in msdosfs_readdir() to compute d_fileno. If not, pwd
273 if (dep
->de_Attributes
& ATTR_DIRECTORY
) {
274 fileid
= cntobn(pmp
, (ino_t
)dep
->de_StartCluster
) * dirsperblk
;
275 if (dep
->de_StartCluster
== MSDOSFSROOT
)
278 fileid
= cntobn(pmp
, (ino_t
)dep
->de_dirclust
) * dirsperblk
;
279 if (dep
->de_dirclust
== MSDOSFSROOT
)
280 fileid
= roottobn(pmp
, 0) * dirsperblk
;
281 fileid
+= dep
->de_diroffset
/ sizeof(struct direntry
);
283 vap
->va_fileid
= fileid
;
284 if ((dep
->de_Attributes
& ATTR_READONLY
) == 0)
285 mode
= S_IRWXU
|S_IRWXG
|S_IRWXO
;
287 mode
= S_IRUSR
|S_IXUSR
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
;
289 mode
& (ap
->a_vp
->v_type
== VDIR
? pmp
->pm_dirmask
: pmp
->pm_mask
);
290 vap
->va_uid
= pmp
->pm_uid
;
291 vap
->va_gid
= pmp
->pm_gid
;
294 vap
->va_size
= ap
->a_vp
->v_size
;
295 dos2unixtime(dep
->de_MDate
, dep
->de_MTime
, 0, pmp
->pm_gmtoff
,
297 if (dep
->de_pmp
->pm_flags
& MSDOSFSMNT_LONGNAME
) {
298 dos2unixtime(dep
->de_ADate
, 0, 0, pmp
->pm_gmtoff
,
300 dos2unixtime(dep
->de_CDate
, dep
->de_CTime
, dep
->de_CHun
,
301 pmp
->pm_gmtoff
, &vap
->va_ctime
);
303 vap
->va_atime
= vap
->va_mtime
;
304 vap
->va_ctime
= vap
->va_mtime
;
307 if ((dep
->de_Attributes
& ATTR_ARCHIVE
) == 0) {
308 vap
->va_flags
|= SF_ARCHIVED
;
309 vap
->va_mode
|= S_ARCH1
;
312 vap
->va_blocksize
= pmp
->pm_bpcluster
;
314 (dep
->de_FileSize
+ pmp
->pm_crbomask
) & ~pmp
->pm_crbomask
;
315 vap
->va_type
= ap
->a_vp
->v_type
;
316 fstrans_done(ap
->a_vp
->v_mount
);
321 msdosfs_setattr(void *v
)
323 struct vop_setattr_args
/* {
328 int error
= 0, de_changed
= 0;
329 struct denode
*dep
= VTODE(ap
->a_vp
);
330 struct msdosfsmount
*pmp
= dep
->de_pmp
;
331 struct vnode
*vp
= ap
->a_vp
;
332 struct vattr
*vap
= ap
->a_vap
;
333 kauth_cred_t cred
= ap
->a_cred
;
336 printf("msdosfs_setattr(): vp %p, vap %p, cred %p\n",
337 ap
->a_vp
, vap
, cred
);
340 * Note we silently ignore uid or gid changes.
342 if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= (nlink_t
)VNOVAL
) ||
343 (vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
344 (vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
345 (vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
) ||
346 (vap
->va_uid
!= VNOVAL
&& vap
->va_uid
!= pmp
->pm_uid
) ||
347 (vap
->va_gid
!= VNOVAL
&& vap
->va_gid
!= pmp
->pm_gid
)) {
349 printf("msdosfs_setattr(): returning EINVAL\n");
350 printf(" va_type %d, va_nlink %x, va_fsid %"PRIx64
", va_fileid %llx\n",
351 vap
->va_type
, vap
->va_nlink
, vap
->va_fsid
,
352 (unsigned long long)vap
->va_fileid
);
353 printf(" va_blocksize %lx, va_rdev %"PRIx64
", va_bytes %"PRIx64
", va_gen %lx\n",
354 vap
->va_blocksize
, vap
->va_rdev
, vap
->va_bytes
, vap
->va_gen
);
359 * Silently ignore attributes modifications on directories.
361 if (ap
->a_vp
->v_type
== VDIR
)
364 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
365 if (vap
->va_size
!= VNOVAL
) {
366 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
370 error
= detrunc(dep
, (u_long
)vap
->va_size
, 0, cred
);
375 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
) {
376 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
380 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_TIMES
,
381 ap
->a_vp
, NULL
, genfs_can_chtimes(ap
->a_vp
, vap
->va_vaflags
,
385 if ((pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
) == 0 &&
386 vap
->va_atime
.tv_sec
!= VNOVAL
)
387 unix2dostime(&vap
->va_atime
, pmp
->pm_gmtoff
, &dep
->de_ADate
, NULL
, NULL
);
388 if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
389 unix2dostime(&vap
->va_mtime
, pmp
->pm_gmtoff
, &dep
->de_MDate
, &dep
->de_MTime
, NULL
);
390 dep
->de_Attributes
|= ATTR_ARCHIVE
;
391 dep
->de_flag
|= DE_MODIFIED
;
395 * DOS files only have the ability to have their writability
396 * attribute set, so we use the owner write bit to set the readonly
399 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
400 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
404 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_FLAGS
, vp
,
405 NULL
, genfs_can_chflags(cred
, vp
->v_type
, pmp
->pm_uid
, false));
408 /* We ignore the read and execute bits. */
409 if (vap
->va_mode
& S_IWUSR
)
410 dep
->de_Attributes
&= ~ATTR_READONLY
;
412 dep
->de_Attributes
|= ATTR_READONLY
;
413 dep
->de_flag
|= DE_MODIFIED
;
417 * Allow the `archived' bit to be toggled.
419 if (vap
->va_flags
!= VNOVAL
) {
420 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
424 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_FLAGS
, vp
,
425 NULL
, genfs_can_chflags(cred
, vp
->v_type
, pmp
->pm_uid
, false));
428 if (vap
->va_flags
& SF_ARCHIVED
)
429 dep
->de_Attributes
&= ~ATTR_ARCHIVE
;
431 dep
->de_Attributes
|= ATTR_ARCHIVE
;
432 dep
->de_flag
|= DE_MODIFIED
;
437 VN_KNOTE(vp
, NOTE_ATTRIB
);
438 error
= deupdat(dep
, 1);
444 fstrans_done(vp
->v_mount
);
449 msdosfs_read(void *v
)
451 struct vop_read_args
/* {
465 struct vnode
*vp
= ap
->a_vp
;
466 struct denode
*dep
= VTODE(vp
);
467 struct msdosfsmount
*pmp
= dep
->de_pmp
;
468 struct uio
*uio
= ap
->a_uio
;
471 * If they didn't ask for any data, then we are done.
474 if (uio
->uio_resid
== 0)
476 if (uio
->uio_offset
< 0)
478 if (uio
->uio_offset
>= dep
->de_FileSize
)
481 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
482 if (vp
->v_type
== VREG
) {
483 const int advice
= IO_ADV_DECODE(ap
->a_ioflag
);
485 while (uio
->uio_resid
> 0) {
486 bytelen
= MIN(dep
->de_FileSize
- uio
->uio_offset
,
491 error
= ubc_uiomove(&vp
->v_uobj
, uio
, bytelen
, advice
,
492 UBC_READ
| UBC_PARTIALOK
| UBC_UNMAP_FLAG(vp
));
496 dep
->de_flag
|= DE_ACCESS
;
500 /* this loop is only for directories now */
502 lbn
= de_cluster(pmp
, uio
->uio_offset
);
503 on
= uio
->uio_offset
& pmp
->pm_crbomask
;
504 n
= MIN(pmp
->pm_bpcluster
- on
, uio
->uio_resid
);
505 if (uio
->uio_offset
>= dep
->de_FileSize
) {
506 fstrans_done(vp
->v_mount
);
509 /* file size (and hence diff) may be up to 4GB */
510 diff
= dep
->de_FileSize
- uio
->uio_offset
;
514 /* convert cluster # to sector # */
515 error
= pcbmap(dep
, lbn
, &lbn
, 0, &blsize
);
520 * If we are operating on a directory file then be sure to
521 * do i/o with the vnode for the filesystem instead of the
522 * vnode for the directory.
524 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, lbn
), blsize
,
529 n
= MIN(n
, pmp
->pm_bpcluster
- bp
->b_resid
);
530 error
= uiomove((char *)bp
->b_data
+ on
, (int) n
, uio
);
532 } while (error
== 0 && uio
->uio_resid
> 0 && n
!= 0);
535 if ((ap
->a_ioflag
& IO_SYNC
) == IO_SYNC
) {
538 uerror
= deupdat(dep
, 1);
543 fstrans_done(vp
->v_mount
);
548 * Write data to a file or directory.
551 msdosfs_write(void *v
)
553 struct vop_write_args
/* {
559 int resid
, extended
= 0;
561 int ioflag
= ap
->a_ioflag
;
567 struct uio
*uio
= ap
->a_uio
;
568 struct vnode
*vp
= ap
->a_vp
;
569 struct denode
*dep
= VTODE(vp
);
570 struct msdosfsmount
*pmp
= dep
->de_pmp
;
571 kauth_cred_t cred
= ap
->a_cred
;
575 printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
576 vp
, uio
, ioflag
, cred
);
577 printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
578 dep
->de_diroffset
, dep
->de_dirclust
, dep
->de_StartCluster
);
581 switch (vp
->v_type
) {
583 if (ioflag
& IO_APPEND
)
584 uio
->uio_offset
= dep
->de_FileSize
;
589 panic("msdosfs_write(): bad file type");
592 if (uio
->uio_offset
< 0)
595 if (uio
->uio_resid
== 0)
598 /* Don't bother to try to write files larger than the fs limit */
599 if (uio
->uio_offset
+ uio
->uio_resid
> MSDOSFS_FILESIZE_MAX
)
602 fstrans_start(vp
->v_mount
, FSTRANS_SHARED
);
604 * If the offset we are starting the write at is beyond the end of
605 * the file, then they've done a seek. Unix filesystems allow
606 * files with holes in them, DOS doesn't so we must fill the hole
607 * with zeroed blocks.
609 if (uio
->uio_offset
> dep
->de_FileSize
) {
610 if ((error
= deextend(dep
, uio
->uio_offset
, cred
)) != 0) {
611 fstrans_done(vp
->v_mount
);
617 * Remember some values in case the write fails.
619 async
= vp
->v_mount
->mnt_flag
& MNT_ASYNC
;
620 resid
= uio
->uio_resid
;
621 osize
= dep
->de_FileSize
;
624 * If we write beyond the end of the file, extend it to its ultimate
625 * size ahead of the time to hopefully get a contiguous area.
627 if (uio
->uio_offset
+ resid
> osize
) {
628 count
= de_clcount(pmp
, uio
->uio_offset
+ resid
) -
629 de_clcount(pmp
, osize
);
630 if ((error
= extendfile(dep
, count
, NULL
, NULL
, 0)))
633 dep
->de_FileSize
= uio
->uio_offset
+ resid
;
634 /* hint uvm to not read in extended part */
635 uvm_vnp_setwritesize(vp
, dep
->de_FileSize
);
636 /* zero out the remainder of the last page */
637 rem
= round_page(dep
->de_FileSize
) - dep
->de_FileSize
;
639 ubc_zerorange(&vp
->v_uobj
, (off_t
)dep
->de_FileSize
,
640 rem
, UBC_UNMAP_FLAG(vp
));
645 oldoff
= uio
->uio_offset
;
646 bytelen
= uio
->uio_resid
;
648 error
= ubc_uiomove(&vp
->v_uobj
, uio
, bytelen
,
649 IO_ADV_DECODE(ioflag
), UBC_WRITE
| UBC_UNMAP_FLAG(vp
));
654 * flush what we just wrote if necessary.
655 * XXXUBC simplistic async flushing.
658 if (!async
&& oldoff
>> 16 != uio
->uio_offset
>> 16) {
659 mutex_enter(vp
->v_interlock
);
660 error
= VOP_PUTPAGES(vp
, (oldoff
>> 16) << 16,
661 (uio
->uio_offset
>> 16) << 16,
662 PGO_CLEANIT
| PGO_LAZY
);
664 } while (error
== 0 && uio
->uio_resid
> 0);
667 uvm_vnp_setsize(vp
, dep
->de_FileSize
);
668 if (error
== 0 && ioflag
& IO_SYNC
) {
669 mutex_enter(vp
->v_interlock
);
670 error
= VOP_PUTPAGES(vp
, trunc_page(oldoff
),
671 round_page(oldoff
+ bytelen
), PGO_CLEANIT
| PGO_SYNCIO
);
673 dep
->de_flag
|= DE_UPDATE
;
676 * If the write failed and they want us to, truncate the file back
677 * to the size it was before the write was attempted.
680 if (resid
> uio
->uio_resid
)
681 VN_KNOTE(vp
, NOTE_WRITE
| (extended
? NOTE_EXTEND
: 0));
683 detrunc(dep
, osize
, ioflag
& IO_SYNC
, NOCRED
);
684 uio
->uio_offset
-= resid
- uio
->uio_resid
;
685 uio
->uio_resid
= resid
;
686 } else if ((ioflag
& IO_SYNC
) == IO_SYNC
)
687 error
= deupdat(dep
, 1);
688 fstrans_done(vp
->v_mount
);
689 KASSERT(vp
->v_size
== dep
->de_FileSize
);
694 msdosfs_update(struct vnode
*vp
, const struct timespec
*acc
,
695 const struct timespec
*mod
, int flags
)
698 struct direntry
*dirp
;
702 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
705 DETIMES(dep
, acc
, mod
, NULL
, dep
->de_pmp
->pm_gmtoff
);
706 if ((dep
->de_flag
& DE_MODIFIED
) == 0)
708 dep
->de_flag
&= ~DE_MODIFIED
;
709 if (dep
->de_Attributes
& ATTR_DIRECTORY
)
711 if (dep
->de_refcnt
<= 0)
713 error
= readde(dep
, &bp
, &dirp
);
716 DE_EXTERNALIZE(dirp
, dep
);
717 if (flags
& (UPDATE_WAIT
|UPDATE_DIROP
))
726 * Flush the blocks of a file to disk.
728 * This function is worthless for vnodes that represent directories. Maybe we
729 * could just do a sync if they try an fsync on a directory file.
732 msdosfs_remove(void *v
)
734 struct vop_remove_args
/* {
737 struct componentname *a_cnp;
739 struct denode
*dep
= VTODE(ap
->a_vp
);
740 struct denode
*ddep
= VTODE(ap
->a_dvp
);
743 fstrans_start(ap
->a_dvp
->v_mount
, FSTRANS_SHARED
);
744 if (ap
->a_vp
->v_type
== VDIR
)
747 error
= removede(ddep
, dep
);
749 printf("msdosfs_remove(), dep %p, v_usecount %d\n",
750 dep
, ap
->a_vp
->v_usecount
);
752 VN_KNOTE(ap
->a_vp
, NOTE_DELETE
);
753 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
757 vput(ap
->a_vp
); /* causes msdosfs_inactive() to be called
760 fstrans_done(ap
->a_dvp
->v_mount
);
765 * Renames on files require moving the denode to a new hash queue since the
766 * denode's location is used to compute which hash queue to put the file
767 * in. Unless it is a rename in place. For example "mv a b".
769 * What follows is the basic algorithm:
772 * if (dest file exists) {
775 * if (dest and src in same directory) {
776 * rewrite name in existing directory slot
778 * write new entry in dest directory
779 * update offset and dirclust in denode
780 * move denode to new hash chain
781 * clear old directory entry
785 * if (dest directory exists) {
786 * if (dest is not empty) {
789 * remove dest directory
791 * if (dest and src in same directory) {
792 * rewrite name in existing entry
794 * be sure dest is not a child of src directory
795 * write entry in dest directory
796 * update "." and ".." in moved directory
797 * update offset and dirclust in denode
798 * move denode to new hash chain
799 * clear old directory entry for moved directory
804 * source's parent directory is unlocked
805 * source file or directory is unlocked
806 * destination's parent directory is locked
807 * destination file or directory is locked if it exists
810 * all denodes should be released
813 * I'm not sure how the memory containing the pathnames pointed at by the
814 * componentname structures is freed, there may be some memory bleeding
815 * for each rename done.
818 * This routine needs help. badly.
821 msdosfs_rename(void *v
)
823 struct vop_rename_args
/* {
824 struct vnode *a_fdvp;
826 struct componentname *a_fcnp;
827 struct vnode *a_tdvp;
829 struct componentname *a_tcnp;
831 struct vnode
*tvp
= ap
->a_tvp
;
832 struct vnode
*tdvp
= ap
->a_tdvp
;
833 struct vnode
*fvp
= ap
->a_fvp
;
834 struct vnode
*fdvp
= ap
->a_fdvp
;
835 struct mount
*mp
= fdvp
->v_mount
;
836 struct componentname
*tcnp
= ap
->a_tcnp
;
837 struct componentname
*fcnp
= ap
->a_fcnp
;
838 struct denode
*ip
, *xp
, *dp
, *zp
;
839 u_char toname
[12], oldname
[12];
840 u_long from_diroffset
, to_diroffset
;
842 int doingdirectory
= 0, newparent
= 0;
846 struct msdosfsmount
*pmp
;
847 struct direntry
*dotdotp
;
850 pmp
= VFSTOMSDOSFS(fdvp
->v_mount
);
853 * Check for cross-device rename.
855 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
856 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
859 VOP_ABORTOP(tdvp
, tcnp
);
866 VOP_ABORTOP(fdvp
, fcnp
);
873 * If source and dest are the same, do nothing.
881 * XXX: This can deadlock since we hold tdvp/tvp locked.
882 * But I'm not going to fix it now.
884 if ((error
= vn_lock(fvp
, LK_EXCLUSIVE
)) != 0)
890 * Be sure we are not renaming ".", "..", or an alias of ".". This
891 * leads to a crippled directory tree. It's pretty tough to do a
892 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
893 * doesn't work if the ".." entry is missing.
895 if (ip
->de_Attributes
& ATTR_DIRECTORY
) {
897 * Avoid ".", "..", and aliases of "." for obvious reasons.
899 if ((fcnp
->cn_namelen
== 1 && fcnp
->cn_nameptr
[0] == '.') ||
901 (fcnp
->cn_flags
& ISDOTDOT
) ||
902 (tcnp
->cn_flags
& ISDOTDOT
) ||
903 (ip
->de_flag
& DE_RENAME
)) {
908 ip
->de_flag
|= DE_RENAME
;
911 VN_KNOTE(fdvp
, NOTE_WRITE
); /* XXXLUKEM/XXX: right place? */
913 fstrans_start(mp
, FSTRANS_SHARED
);
915 * When the target exists, both the directory
916 * and target vnodes are returned locked.
919 xp
= tvp
? VTODE(tvp
) : NULL
;
921 * Remember direntry place to use for destination
923 to_diroffset
= dp
->de_fndoffset
;
924 to_count
= dp
->de_fndcnt
;
927 * If ".." must be changed (ie the directory gets a new
928 * parent) then the source directory must not be in the
929 * directory hierarchy above the target, as this would
930 * orphan everything below the source directory. Also
931 * the user must have write permission in the source so
932 * as to be able to change "..". We must repeat the call
933 * to namei, as the parent directory is unlocked by the
934 * call to doscheckpath().
936 error
= VOP_ACCESS(fvp
, VWRITE
, tcnp
->cn_cred
);
938 if (VTODE(fdvp
)->de_StartCluster
!= VTODE(tdvp
)->de_StartCluster
)
941 if (doingdirectory
&& newparent
) {
942 if (error
) /* write access check above */
948 * doscheckpath() vput()'s tdvp (dp == VTODE(tdvp)),
949 * so we have to get an extra ref to it first, and
950 * because it's been unlocked we need to do a relookup
951 * afterwards in case tvp has changed.
954 if ((error
= doscheckpath(ip
, dp
)) != 0)
956 vn_lock(tdvp
, LK_EXCLUSIVE
| LK_RETRY
);
957 if ((error
= relookup(tdvp
, &tvp
, tcnp
, 0)) != 0) {
962 xp
= tvp
? VTODE(tvp
) : NULL
;
967 * Target must be empty if a directory and have no links
968 * to it. Also, ensure source and target are compatible
969 * (both directories, or both not directories).
971 if (xp
->de_Attributes
& ATTR_DIRECTORY
) {
972 if (!dosdirempty(xp
)) {
976 if (!doingdirectory
) {
980 } else if (doingdirectory
) {
984 if ((error
= removede(dp
, xp
)) != 0)
986 VN_KNOTE(tdvp
, NOTE_WRITE
);
987 VN_KNOTE(tvp
, NOTE_DELETE
);
995 * Convert the filename in tcnp into a dos filename. We copy this
996 * into the denode and directory entry for the destination
999 if ((error
= uniqdosname(VTODE(tdvp
), tcnp
, toname
)) != 0) {
1005 * Since from wasn't locked at various places above,
1006 * have to do a relookup here.
1008 fcnp
->cn_flags
&= ~MODMASK
;
1009 fcnp
->cn_flags
|= LOCKPARENT
| LOCKLEAF
;
1011 vn_lock(fdvp
, LK_EXCLUSIVE
| LK_RETRY
);
1012 if ((error
= relookup(fdvp
, &fvp
, fcnp
, 0))) {
1021 * From name has disappeared.
1024 panic("rename: lost dir entry");
1034 from_diroffset
= zp
->de_fndoffset
;
1037 * Ensure that the directory entry still exists and has not
1038 * changed till now. If the source is a file the entry may
1039 * have been unlinked or renamed. In either case there is
1040 * no further work to be done. If the source is a directory
1041 * then it cannot have been rmdir'ed or renamed; this is
1042 * prohibited by the DE_RENAME flag.
1046 panic("rename: lost dir entry");
1054 * First write a new entry in the destination
1055 * directory and mark the entry in the source directory
1056 * as deleted. Then move the denode to the correct hash
1057 * chain for its new location in the filesystem. And, if
1058 * we moved a directory, then update its .. entry to point
1059 * to the new parent directory.
1061 memcpy(oldname
, ip
->de_Name
, 11);
1062 memcpy(ip
->de_Name
, toname
, 11); /* update denode */
1063 dp
->de_fndoffset
= to_diroffset
;
1064 dp
->de_fndcnt
= to_count
;
1065 error
= createde(ip
, dp
, (struct denode
**)0, tcnp
);
1067 memcpy(ip
->de_Name
, oldname
, 11);
1072 zp
->de_fndoffset
= from_diroffset
;
1073 if ((error
= removede(zp
, ip
)) != 0) {
1074 /* XXX should really panic here, fs is corrupt */
1079 if (!doingdirectory
) {
1080 struct denode_key old_key
= ip
->de_key
;
1081 struct denode_key new_key
= ip
->de_key
;
1083 error
= pcbmap(dp
, de_cluster(pmp
, to_diroffset
), 0,
1084 &new_key
.dk_dirclust
, 0);
1086 /* XXX should really panic here, fs is corrupt */
1090 new_key
.dk_diroffset
= to_diroffset
;
1091 if (new_key
.dk_dirclust
!= MSDOSFSROOT
)
1092 new_key
.dk_diroffset
&= pmp
->pm_crbomask
;
1093 vcache_rekey_enter(pmp
->pm_mountp
, fvp
, &old_key
,
1094 sizeof(old_key
), &new_key
, sizeof(new_key
));
1095 ip
->de_key
= new_key
;
1096 vcache_rekey_exit(pmp
->pm_mountp
, fvp
, &old_key
,
1097 sizeof(old_key
), &ip
->de_key
, sizeof(ip
->de_key
));
1102 * If we moved a directory to a new parent directory, then we must
1103 * fixup the ".." entry in the moved directory.
1105 if (doingdirectory
&& newparent
) {
1106 cn
= ip
->de_StartCluster
;
1107 if (cn
== MSDOSFSROOT
) {
1108 /* this should never happen */
1109 panic("msdosfs_rename: updating .. in root directory?");
1111 bn
= cntobn(pmp
, cn
);
1112 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
),
1113 pmp
->pm_bpcluster
, B_MODIFY
, &bp
);
1115 /* XXX should really panic here, fs is corrupt */
1119 dotdotp
= (struct direntry
*)bp
->b_data
+ 1;
1120 putushort(dotdotp
->deStartCluster
, dp
->de_StartCluster
);
1122 putushort(dotdotp
->deHighClust
,
1123 dp
->de_StartCluster
>> 16);
1125 putushort(dotdotp
->deHighClust
, 0);
1127 if ((error
= bwrite(bp
)) != 0) {
1128 /* XXX should really panic here, fs is corrupt */
1134 VN_KNOTE(fvp
, NOTE_RENAME
);
1140 ip
->de_flag
&= ~DE_RENAME
;
1152 static const struct {
1153 struct direntry dot
;
1154 struct direntry dotdot
;
1155 } dosdirtemplate
= {
1156 { ". ", " ", /* the . entry */
1157 ATTR_DIRECTORY
, /* file attribute */
1159 0, { 0, 0 }, { 0, 0 }, /* create time & date */
1160 { 0, 0 }, /* access date */
1161 { 0, 0 }, /* high bits of start cluster */
1162 { 210, 4 }, { 210, 4 }, /* modify time & date */
1163 { 0, 0 }, /* startcluster */
1164 { 0, 0, 0, 0 } /* filesize */
1166 { ".. ", " ", /* the .. entry */
1167 ATTR_DIRECTORY
, /* file attribute */
1169 0, { 0, 0 }, { 0, 0 }, /* create time & date */
1170 { 0, 0 }, /* access date */
1171 { 0, 0 }, /* high bits of start cluster */
1172 { 210, 4 }, { 210, 4 }, /* modify time & date */
1173 { 0, 0 }, /* startcluster */
1174 { 0, 0, 0, 0 } /* filesize */
1179 msdosfs_mkdir(void *v
)
1181 struct vop_mkdir_v3_args
/* {
1182 struct vnode *a_dvp;
1183 struvt vnode **a_vpp;
1184 struvt componentname *a_cnp;
1185 struct vattr *a_vap;
1187 struct componentname
*cnp
= ap
->a_cnp
;
1188 struct denode ndirent
;
1190 struct denode
*pdep
= VTODE(ap
->a_dvp
);
1193 u_long newcluster
, pcl
;
1195 struct direntry
*denp
;
1196 struct msdosfsmount
*pmp
= pdep
->de_pmp
;
1198 int async
= pdep
->de_pmp
->pm_mountp
->mnt_flag
& MNT_ASYNC
;
1200 fstrans_start(ap
->a_dvp
->v_mount
, FSTRANS_SHARED
);
1202 * If this is the root directory and there is no space left we
1203 * can't do anything. This is because the root directory can not
1206 if (pdep
->de_StartCluster
== MSDOSFSROOT
1207 && pdep
->de_fndoffset
>= pdep
->de_FileSize
) {
1213 * Allocate a cluster to hold the about to be created directory.
1215 error
= clusteralloc(pmp
, 0, 1, &newcluster
, NULL
);
1219 memset(&ndirent
, 0, sizeof(ndirent
));
1220 ndirent
.de_pmp
= pmp
;
1221 ndirent
.de_flag
= DE_ACCESS
| DE_CREATE
| DE_UPDATE
;
1222 DETIMES(&ndirent
, NULL
, NULL
, NULL
, pmp
->pm_gmtoff
);
1225 * Now fill the cluster with the "." and ".." entries. And write
1226 * the cluster to disk. This way it is there for the parent
1227 * directory to be pointing at if there were a crash.
1229 bn
= cntobn(pmp
, newcluster
);
1230 lbn
= de_bn2kb(pmp
, bn
);
1231 /* always succeeds */
1232 bp
= getblk(pmp
->pm_devvp
, lbn
, pmp
->pm_bpcluster
, 0, 0);
1233 memset(bp
->b_data
, 0, pmp
->pm_bpcluster
);
1234 memcpy(bp
->b_data
, &dosdirtemplate
, 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].deCHundredth
= ndirent
.de_CHun
;
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
)
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].deCHundredth
= ndirent
.de_CHun
;
1250 putushort(denp
[1].deADate
, ndirent
.de_ADate
);
1251 putushort(denp
[1].deMDate
, ndirent
.de_MDate
);
1252 putushort(denp
[1].deMTime
, ndirent
.de_MTime
);
1254 putushort(denp
[0].deHighClust
, newcluster
>> 16);
1255 putushort(denp
[1].deHighClust
, pdep
->de_StartCluster
>> 16);
1257 putushort(denp
[0].deHighClust
, 0);
1258 putushort(denp
[1].deHighClust
, 0);
1263 else if ((error
= bwrite(bp
)) != 0)
1267 * Now build up a directory entry pointing to the newly allocated
1268 * cluster. This will be written to an empty slot in the parent
1271 if ((error
= uniqdosname(pdep
, cnp
, ndirent
.de_Name
)) != 0)
1274 ndirent
.de_Attributes
= ATTR_DIRECTORY
;
1275 ndirent
.de_StartCluster
= newcluster
;
1276 ndirent
.de_FileSize
= 0;
1277 ndirent
.de_dev
= pdep
->de_dev
;
1278 ndirent
.de_devvp
= pdep
->de_devvp
;
1279 if ((error
= createde(&ndirent
, pdep
, &dep
, cnp
)) != 0)
1281 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
| NOTE_LINK
);
1282 *ap
->a_vpp
= DETOV(dep
);
1283 fstrans_done(ap
->a_dvp
->v_mount
);
1287 clusterfree(pmp
, newcluster
, NULL
);
1289 fstrans_done(ap
->a_dvp
->v_mount
);
1294 msdosfs_rmdir(void *v
)
1296 struct vop_rmdir_args
/* {
1297 struct vnode *a_dvp;
1299 struct componentname *a_cnp;
1301 struct vnode
*vp
= ap
->a_vp
;
1302 struct vnode
*dvp
= ap
->a_dvp
;
1303 struct mount
*mp
= dvp
->v_mount
;
1304 struct componentname
*cnp
= ap
->a_cnp
;
1305 struct denode
*ip
, *dp
;
1311 * No rmdir "." please.
1318 fstrans_start(mp
, FSTRANS_SHARED
);
1320 * Verify the directory is empty (and valid).
1321 * (Rmdir ".." won't be valid since
1322 * ".." will contain a reference to
1323 * the current directory and thus be
1327 if (!dosdirempty(ip
) || ip
->de_flag
& DE_RENAME
) {
1332 * Delete the entry from the directory. For dos filesystems this
1333 * gets rid of the directory entry on disk, the in memory copy
1334 * still exists but the de_refcnt is <= 0. This prevents it from
1335 * being found by deget(). When the vput() on dep is done we give
1336 * up access and eventually msdosfs_reclaim() will be called which
1337 * will remove it from the denode cache.
1339 if ((error
= removede(dp
, ip
)) != 0)
1342 * This is where we decrement the link count in the parent
1343 * directory. Since dos filesystems don't do this we just purge
1344 * the name cache and let go of the parent directory denode.
1346 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
1351 * Truncate the directory that is being deleted.
1353 error
= detrunc(ip
, (u_long
)0, IO_SYNC
, cnp
->cn_cred
);
1356 VN_KNOTE(vp
, NOTE_DELETE
);
1365 msdosfs_readdir(void *v
)
1367 struct vop_readdir_args
/* {
1370 kauth_cred_t a_cred;
1388 struct denode
*dep
= VTODE(ap
->a_vp
);
1389 struct msdosfsmount
*pmp
= dep
->de_pmp
;
1390 struct direntry
*dentp
;
1391 struct dirent
*dirbuf
;
1392 struct uio
*uio
= ap
->a_uio
;
1393 off_t
*cookies
= NULL
;
1394 int ncookies
= 0, nc
= 0;
1395 off_t offset
, uio_off
;
1398 #ifdef MSDOSFS_DEBUG
1399 printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
1400 ap
->a_vp
, uio
, ap
->a_cred
, ap
->a_eofflag
);
1404 * msdosfs_readdir() won't operate properly on regular files since
1405 * it does i/o only with the filesystem vnode, and hence can
1406 * retrieve the wrong block from the buffer cache for a plain file.
1407 * So, fail attempts to readdir() on a plain file.
1409 if ((dep
->de_Attributes
& ATTR_DIRECTORY
) == 0)
1413 * If the user buffer is smaller than the size of one dos directory
1414 * entry or the file offset is not a multiple of the size of a
1415 * directory entry, then we fail the read.
1417 count
= uio
->uio_resid
& ~(sizeof(struct direntry
) - 1);
1418 offset
= uio
->uio_offset
;
1419 if (count
< sizeof(struct direntry
) ||
1420 (offset
& (sizeof(struct direntry
) - 1)))
1422 lost
= uio
->uio_resid
- count
;
1423 uio
->uio_resid
= count
;
1424 uio_off
= uio
->uio_offset
;
1426 fstrans_start(ap
->a_vp
->v_mount
, FSTRANS_SHARED
);
1428 /* Allocate a temporary dirent buffer. */
1429 dirbuf
= malloc(sizeof(struct dirent
), M_MSDOSFSTMP
, M_WAITOK
| M_ZERO
);
1431 if (ap
->a_ncookies
) {
1432 nc
= uio
->uio_resid
/ _DIRENT_MINSIZE((struct dirent
*)0);
1433 cookies
= malloc(nc
* sizeof (off_t
), M_TEMP
, M_WAITOK
);
1434 *ap
->a_cookies
= cookies
;
1437 dirsperblk
= pmp
->pm_BytesPerSec
/ sizeof(struct direntry
);
1440 * If they are reading from the root directory then, we simulate
1441 * the . and .. entries since these don't exist in the root
1442 * directory. We also set the offset bias to make up for having to
1443 * simulate these entries. By this I mean that at file offset 64 we
1444 * read the first entry in the root directory that lives on disk.
1446 if (dep
->de_StartCluster
== MSDOSFSROOT
1447 || (FAT32(pmp
) && dep
->de_StartCluster
== pmp
->pm_rootdirblk
)) {
1449 printf("msdosfs_readdir(): going after . or .. in root dir, "
1450 "offset %" PRIu64
"\n", offset
);
1452 bias
= 2 * sizeof(struct direntry
);
1453 if (offset
< bias
) {
1454 for (n
= (int)offset
/ sizeof(struct direntry
);
1457 dirbuf
->d_fileno
= cntobn(pmp
,
1458 (ino_t
)pmp
->pm_rootdirblk
)
1461 dirbuf
->d_fileno
= 1;
1462 dirbuf
->d_type
= DT_DIR
;
1465 dirbuf
->d_namlen
= 1;
1466 strlcpy(dirbuf
->d_name
, ".",
1467 sizeof(dirbuf
->d_name
));
1470 dirbuf
->d_namlen
= 2;
1471 strlcpy(dirbuf
->d_name
, "..",
1472 sizeof(dirbuf
->d_name
));
1475 dirbuf
->d_reclen
= _DIRENT_SIZE(dirbuf
);
1476 if (uio
->uio_resid
< dirbuf
->d_reclen
)
1478 error
= uiomove(dirbuf
, dirbuf
->d_reclen
, uio
);
1481 offset
+= sizeof(struct direntry
);
1484 *cookies
++ = offset
;
1493 while (uio
->uio_resid
> 0) {
1494 lbn
= de_cluster(pmp
, offset
- bias
);
1495 on
= (offset
- bias
) & pmp
->pm_crbomask
;
1496 n
= MIN(pmp
->pm_bpcluster
- on
, uio
->uio_resid
);
1497 diff
= dep
->de_FileSize
- (offset
- bias
);
1501 if ((error
= pcbmap(dep
, lbn
, &bn
, &cn
, &blsize
)) != 0)
1503 error
= bread(pmp
->pm_devvp
, de_bn2kb(pmp
, bn
), blsize
,
1508 n
= MIN(n
, blsize
- bp
->b_resid
);
1511 * Convert from dos directory entries to fs-independent
1512 * directory entries.
1514 for (dentp
= (struct direntry
*)((char *)bp
->b_data
+ on
);
1515 (char *)dentp
< (char *)bp
->b_data
+ on
+ n
;
1516 dentp
++, offset
+= sizeof(struct direntry
)) {
1519 printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
1520 dentp
, prev
, crnt
, dentp
->deName
[0], dentp
->deAttributes
);
1523 * If this is an unused entry, we can stop.
1525 if (dentp
->deName
[0] == SLOT_EMPTY
) {
1530 * Skip deleted entries.
1532 if (dentp
->deName
[0] == SLOT_DELETED
) {
1538 * Handle Win95 long directory entries
1540 if (dentp
->deAttributes
== ATTR_WIN95
) {
1541 if (pmp
->pm_flags
& MSDOSFSMNT_SHORTNAME
)
1543 chksum
= win2unixfn((struct winentry
*)dentp
,
1549 * Skip volume labels
1551 if (dentp
->deAttributes
& ATTR_VOLUME
) {
1556 * This computation of d_fileno must match
1557 * the computation of va_fileid in
1560 if (dentp
->deAttributes
& ATTR_DIRECTORY
) {
1561 fileno
= getushort(dentp
->deStartCluster
);
1563 fileno
|= ((ino_t
)getushort(dentp
->deHighClust
)) << 16;
1564 /* if this is the root directory */
1565 if (fileno
== MSDOSFSROOT
)
1567 fileno
= cntobn(pmp
,
1568 (ino_t
)pmp
->pm_rootdirblk
)
1573 fileno
= cntobn(pmp
, fileno
) * dirsperblk
;
1574 dirbuf
->d_fileno
= fileno
;
1575 dirbuf
->d_type
= DT_DIR
;
1578 offset
/ sizeof(struct direntry
);
1579 dirbuf
->d_type
= DT_REG
;
1581 if (chksum
!= winChksum(dentp
->deName
))
1582 dirbuf
->d_namlen
= dos2unixfn(dentp
->deName
,
1583 (u_char
*)dirbuf
->d_name
,
1584 pmp
->pm_flags
& MSDOSFSMNT_SHORTNAME
);
1586 dirbuf
->d_name
[dirbuf
->d_namlen
] = 0;
1588 dirbuf
->d_reclen
= _DIRENT_SIZE(dirbuf
);
1589 if (uio
->uio_resid
< dirbuf
->d_reclen
) {
1593 error
= uiomove(dirbuf
, dirbuf
->d_reclen
, uio
);
1598 uio_off
= offset
+ sizeof(struct direntry
);
1600 *cookies
++ = offset
+ sizeof(struct direntry
);
1602 if (ncookies
>= nc
) {
1612 uio
->uio_offset
= uio_off
;
1613 uio
->uio_resid
+= lost
;
1614 if (dep
->de_FileSize
- (offset
- bias
) <= 0)
1619 if (ap
->a_ncookies
) {
1621 free(*ap
->a_cookies
, M_TEMP
);
1622 *ap
->a_ncookies
= 0;
1623 *ap
->a_cookies
= NULL
;
1625 *ap
->a_ncookies
= ncookies
;
1629 free(dirbuf
, M_MSDOSFSTMP
);
1630 fstrans_done(ap
->a_vp
->v_mount
);
1635 * vp - address of vnode file the file
1636 * bn - which cluster we are interested in mapping to a filesystem block number.
1637 * vpp - returns the vnode for the block special file holding the filesystem
1638 * containing the file of interest
1639 * bnp - address of where to return the filesystem relative block number
1642 msdosfs_bmap(void *v
)
1644 struct vop_bmap_args
/* {
1647 struct vnode **a_vpp;
1651 struct denode
*dep
= VTODE(ap
->a_vp
);
1656 if (ap
->a_vpp
!= NULL
)
1657 *ap
->a_vpp
= dep
->de_devvp
;
1658 if (ap
->a_bnp
== NULL
)
1660 status
= pcbmap(dep
, ap
->a_bn
, ap
->a_bnp
, 0, 0);
1664 * A little kludgy, but we loop calling pcbmap until we
1665 * reach the end of the contiguous piece, or reach MAXPHYS.
1666 * Since it reduces disk I/Os, the "wasted" CPU is put to
1667 * good use (4 to 5 fold sequential read I/O improvement on USB
1670 if (ap
->a_runp
!= NULL
) {
1671 /* taken from ufs_bmap */
1672 maxrun
= ulmin(MAXPHYS
/ dep
->de_pmp
->pm_bpcluster
- 1,
1673 dep
->de_pmp
->pm_maxcluster
- ap
->a_bn
);
1674 for (run
= 1; run
<= maxrun
; run
++) {
1675 if (pcbmap(dep
, ap
->a_bn
+ run
, &runbn
, NULL
, NULL
)
1677 *ap
->a_bnp
+ de_cn2bn(dep
->de_pmp
, run
))
1680 *ap
->a_runp
= run
- 1;
1684 * We need to scale *ap->a_bnp by sector_size/DEV_BSIZE
1686 *ap
->a_bnp
= de_bn2kb(dep
->de_pmp
, *ap
->a_bnp
);
1691 msdosfs_strategy(void *v
)
1693 struct vop_strategy_args
/* {
1697 struct vnode
*vp
= ap
->a_vp
;
1698 struct buf
*bp
= ap
->a_bp
;
1699 struct denode
*dep
= VTODE(bp
->b_vp
);
1702 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1703 panic("msdosfs_strategy: spec");
1705 * If we don't already know the filesystem relative block number
1706 * then get it using pcbmap(). If pcbmap() returns the block
1707 * number as -1 then we've got a hole in the file. DOS filesystems
1708 * don't allow files with holes, so we shouldn't ever see this.
1710 if (bp
->b_blkno
== bp
->b_lblkno
) {
1711 error
= pcbmap(dep
, de_bn2cn(dep
->de_pmp
, bp
->b_lblkno
),
1712 &bp
->b_blkno
, 0, 0);
1715 if (bp
->b_blkno
== -1)
1718 bp
->b_blkno
= de_bn2kb(dep
->de_pmp
, bp
->b_blkno
);
1720 if (bp
->b_blkno
== -1) {
1726 * Read/write the block from/to the disk that contains the desired
1731 return (VOP_STRATEGY(vp
, bp
));
1735 msdosfs_print(void *v
)
1737 struct vop_print_args
/* {
1740 struct denode
*dep
= VTODE(ap
->a_vp
);
1743 "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
1744 dep
->de_StartCluster
, dep
->de_dirclust
, dep
->de_diroffset
);
1745 printf(" dev %llu, %llu ", (unsigned long long)major(dep
->de_dev
),
1746 (unsigned long long)minor(dep
->de_dev
));
1752 msdosfs_advlock(void *v
)
1754 struct vop_advlock_args
/* {
1761 struct denode
*dep
= VTODE(ap
->a_vp
);
1763 return lf_advlock(ap
, &dep
->de_lockf
, dep
->de_FileSize
);
1767 msdosfs_pathconf(void *v
)
1769 struct vop_pathconf_args
/* {
1772 register_t *a_retval;
1775 switch (ap
->a_name
) {
1780 *ap
->a_retval
= ap
->a_vp
->v_mount
->mnt_stat
.f_namemax
;
1783 *ap
->a_retval
= PATH_MAX
;
1785 case _PC_CHOWN_RESTRICTED
:
1794 case _PC_FILESIZEBITS
:
1804 msdosfs_fsync(void *v
)
1806 struct vop_fsync_args
/* {
1808 kauth_cred_t a_cred;
1813 struct vnode
*vp
= ap
->a_vp
;
1817 fstrans_start(vp
->v_mount
, FSTRANS_LAZY
);
1818 wait
= (ap
->a_flags
& FSYNC_WAIT
) != 0;
1819 error
= vflushbuf(vp
, ap
->a_flags
);
1820 if (error
== 0 && (ap
->a_flags
& FSYNC_DATAONLY
) == 0)
1821 error
= msdosfs_update(vp
, NULL
, NULL
, wait
? UPDATE_WAIT
: 0);
1823 if (error
== 0 && ap
->a_flags
& FSYNC_CACHE
) {
1824 struct denode
*dep
= VTODE(vp
);
1825 struct vnode
*devvp
= dep
->de_devvp
;
1828 error
= VOP_IOCTL(devvp
, DIOCCACHESYNC
, &l
, FWRITE
,
1831 fstrans_done(vp
->v_mount
);
1837 msdosfs_detimes(struct denode
*dep
, const struct timespec
*acc
,
1838 const struct timespec
*mod
, const struct timespec
*cre
, int gmtoff
)
1840 struct timespec
*ts
= NULL
, tsb
;
1842 KASSERT(dep
->de_flag
& (DE_UPDATE
| DE_CREATE
| DE_ACCESS
));
1843 /* XXX just call getnanotime early and use result if needed? */
1844 dep
->de_flag
|= DE_MODIFIED
;
1845 if (dep
->de_flag
& DE_UPDATE
) {
1850 unix2dostime(mod
, gmtoff
, &dep
->de_MDate
, &dep
->de_MTime
, NULL
);
1851 dep
->de_Attributes
|= ATTR_ARCHIVE
;
1853 if ((dep
->de_pmp
->pm_flags
& MSDOSFSMNT_NOWIN95
) == 0) {
1854 if (dep
->de_flag
& DE_ACCESS
) {
1857 (getnanotime(&tsb
), ts
= &tsb
) : ts
;
1858 unix2dostime(acc
, gmtoff
, &dep
->de_ADate
, NULL
, NULL
);
1860 if (dep
->de_flag
& DE_CREATE
) {
1863 (getnanotime(&tsb
), ts
= &tsb
) : ts
;
1864 unix2dostime(cre
, gmtoff
, &dep
->de_CDate
,
1865 &dep
->de_CTime
, &dep
->de_CHun
);
1869 dep
->de_flag
&= ~(DE_UPDATE
| DE_CREATE
| DE_ACCESS
);
1872 /* Global vfs data structures for msdosfs */
1873 int (**msdosfs_vnodeop_p
)(void *);
1874 const struct vnodeopv_entry_desc msdosfs_vnodeop_entries
[] = {
1875 { &vop_default_desc
, vn_default_error
},
1876 { &vop_lookup_desc
, msdosfs_lookup
}, /* lookup */
1877 { &vop_create_desc
, msdosfs_create
}, /* create */
1878 { &vop_mknod_desc
, genfs_eopnotsupp
}, /* mknod */
1879 { &vop_open_desc
, genfs_nullop
}, /* open */
1880 { &vop_close_desc
, msdosfs_close
}, /* close */
1881 { &vop_access_desc
, msdosfs_access
}, /* access */
1882 { &vop_getattr_desc
, msdosfs_getattr
}, /* getattr */
1883 { &vop_setattr_desc
, msdosfs_setattr
}, /* setattr */
1884 { &vop_read_desc
, msdosfs_read
}, /* read */
1885 { &vop_write_desc
, msdosfs_write
}, /* write */
1886 { &vop_fallocate_desc
, genfs_eopnotsupp
}, /* fallocate */
1887 { &vop_fdiscard_desc
, genfs_eopnotsupp
}, /* fdiscard */
1888 { &vop_fcntl_desc
, genfs_fcntl
}, /* fcntl */
1889 { &vop_ioctl_desc
, msdosfs_ioctl
}, /* ioctl */
1890 { &vop_poll_desc
, msdosfs_poll
}, /* poll */
1891 { &vop_kqfilter_desc
, genfs_kqfilter
}, /* kqfilter */
1892 { &vop_revoke_desc
, msdosfs_revoke
}, /* revoke */
1893 { &vop_mmap_desc
, msdosfs_mmap
}, /* mmap */
1894 { &vop_fsync_desc
, msdosfs_fsync
}, /* fsync */
1895 { &vop_seek_desc
, msdosfs_seek
}, /* seek */
1896 { &vop_remove_desc
, msdosfs_remove
}, /* remove */
1897 { &vop_link_desc
, genfs_eopnotsupp
}, /* link */
1898 { &vop_rename_desc
, msdosfs_rename
}, /* rename */
1899 { &vop_mkdir_desc
, msdosfs_mkdir
}, /* mkdir */
1900 { &vop_rmdir_desc
, msdosfs_rmdir
}, /* rmdir */
1901 { &vop_symlink_desc
, genfs_eopnotsupp
}, /* symlink */
1902 { &vop_readdir_desc
, msdosfs_readdir
}, /* readdir */
1903 { &vop_readlink_desc
, genfs_einval
}, /* readlink */
1904 { &vop_abortop_desc
, msdosfs_abortop
}, /* abortop */
1905 { &vop_inactive_desc
, msdosfs_inactive
}, /* inactive */
1906 { &vop_reclaim_desc
, msdosfs_reclaim
}, /* reclaim */
1907 { &vop_lock_desc
, genfs_lock
}, /* lock */
1908 { &vop_unlock_desc
, genfs_unlock
}, /* unlock */
1909 { &vop_bmap_desc
, msdosfs_bmap
}, /* bmap */
1910 { &vop_strategy_desc
, msdosfs_strategy
}, /* strategy */
1911 { &vop_print_desc
, msdosfs_print
}, /* print */
1912 { &vop_islocked_desc
, genfs_islocked
}, /* islocked */
1913 { &vop_pathconf_desc
, msdosfs_pathconf
}, /* pathconf */
1914 { &vop_advlock_desc
, msdosfs_advlock
}, /* advlock */
1915 { &vop_bwrite_desc
, vn_bwrite
}, /* bwrite */
1916 { &vop_getpages_desc
, genfs_getpages
}, /* getpages */
1917 { &vop_putpages_desc
, genfs_putpages
}, /* putpages */
1920 const struct vnodeopv_desc msdosfs_vnodeop_opv_desc
=
1921 { &msdosfs_vnodeop_p
, msdosfs_vnodeop_entries
};