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