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