Deleted Added
full compact
msdosfs_vnops.c (33134) msdosfs_vnops.c (33548)
1/* $Id: msdosfs_vnops.c,v 1.54 1998/02/04 22:33:01 eivind Exp $ */
2/* $NetBSD: msdosfs_vnops.c,v 1.20 1994/08/21 18:44:13 ws Exp $ */
1/* $Id: msdosfs_vnops.c,v 1.55 1998/02/06 12:13:46 eivind Exp $ */
2/* $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $ */
3
4/*-
3
4/*-
5 * Copyright (C) 1994 Wolfgang Solfrank.
6 * Copyright (C) 1994 TooLs GmbH.
5 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
6 * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7 * All rights reserved.
8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.

--- 120 unchanged lines hidden (view full) ---

135 struct componentname *cnp = ap->a_cnp;
136 struct denode ndirent;
137 struct denode *dep;
138 struct denode *pdep = VTODE(ap->a_dvp);
139 struct timespec ts;
140 int error;
141
142#ifdef MSDOSFS_DEBUG
7 * All rights reserved.
8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.

--- 120 unchanged lines hidden (view full) ---

135 struct componentname *cnp = ap->a_cnp;
136 struct denode ndirent;
137 struct denode *dep;
138 struct denode *pdep = VTODE(ap->a_dvp);
139 struct timespec ts;
140 int error;
141
142#ifdef MSDOSFS_DEBUG
143 printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
143 printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap);
144#endif
145
146 /*
144#endif
145
146 /*
147 * If this is the root directory and there is no space left we
148 * can't do anything. This is because the root directory can not
149 * change size.
150 */
151 if (pdep->de_StartCluster == MSDOSFSROOT
152 && pdep->de_fndoffset >= pdep->de_FileSize) {
153 error = ENOSPC;
154 goto bad;
155 }
156
157 /*
147 * Create a directory entry for the file, then call createde() to
148 * have it installed. NOTE: DOS files are always executable. We
149 * use the absence of the owner write bit to make the file
150 * readonly.
151 */
152#ifdef DIAGNOSTIC
158 * Create a directory entry for the file, then call createde() to
159 * have it installed. NOTE: DOS files are always executable. We
160 * use the absence of the owner write bit to make the file
161 * readonly.
162 */
163#ifdef DIAGNOSTIC
153 if ((cnp->cn_flags & SAVENAME) == 0)
164 if ((cnp->cn_flags & HASBUF) == 0)
154 panic("msdosfs_create: no name");
155#endif
156 bzero(&ndirent, sizeof(ndirent));
165 panic("msdosfs_create: no name");
166#endif
167 bzero(&ndirent, sizeof(ndirent));
157 TIMEVAL_TO_TIMESPEC(&time, &ts);
158 unix2dostime(&ts, &ndirent.de_Date, &ndirent.de_Time);
159 unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen);
160 ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE)
161 ? ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
168 error = uniqdosname(pdep, cnp, ndirent.de_Name);
169 if (error)
170 goto bad;
171
172 ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
173 ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
162 ndirent.de_StartCluster = 0;
163 ndirent.de_FileSize = 0;
164 ndirent.de_dev = pdep->de_dev;
165 ndirent.de_devvp = pdep->de_devvp;
174 ndirent.de_StartCluster = 0;
175 ndirent.de_FileSize = 0;
176 ndirent.de_dev = pdep->de_dev;
177 ndirent.de_devvp = pdep->de_devvp;
166 if ((error = createde(&ndirent, pdep, &dep)) == 0) {
167 *ap->a_vpp = DETOV(dep);
168 if ((cnp->cn_flags & SAVESTART) == 0)
169 zfree(namei_zone, cnp->cn_pnbuf);
170 } else {
178 ndirent.de_pmp = pdep->de_pmp;
179 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
180 TIMEVAL_TO_TIMESPEC(&time, &ts);
181 DETIMES(&ndirent, &ts, &ts, &ts);
182 error = createde(&ndirent, pdep, &dep, cnp);
183 if (error)
184 goto bad;
185 if ((cnp->cn_flags & SAVESTART) == 0)
171 zfree(namei_zone, cnp->cn_pnbuf);
186 zfree(namei_zone, cnp->cn_pnbuf);
172 }
173 vput(ap->a_dvp); /* release parent dir */
174 return error;
187 vput(ap->a_dvp);
188 *ap->a_vpp = DETOV(dep);
189 return (0);
190
191bad:
192 zfree(namei_zone, cnp->cn_pnbuf);
193 vput(ap->a_dvp);
194 return (error);
175}
176
177static int
178msdosfs_mknod(ap)
179 struct vop_mknod_args /* {
180 struct vnode *a_dvp;
181 struct vnode **a_vpp;
182 struct componentname *a_cnp;
183 struct vattr *a_vap;
184 } */ *ap;
185{
195}
196
197static int
198msdosfs_mknod(ap)
199 struct vop_mknod_args /* {
200 struct vnode *a_dvp;
201 struct vnode **a_vpp;
202 struct componentname *a_cnp;
203 struct vattr *a_vap;
204 } */ *ap;
205{
186 int error;
187
188 switch (ap->a_vap->va_type) {
189 case VDIR:
206
207 switch (ap->a_vap->va_type) {
208 case VDIR:
190 error = msdosfs_mkdir((struct vop_mkdir_args *)ap);
209 return (msdosfs_mkdir((struct vop_mkdir_args *)ap));
191 break;
192
193 case VREG:
210 break;
211
212 case VREG:
194 error = msdosfs_create((struct vop_create_args *)ap);
213 return (msdosfs_create((struct vop_create_args *)ap));
195 break;
196
197 default:
214 break;
215
216 default:
198 error = EINVAL;
199 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
200 vput(ap->a_dvp);
217 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
218 vput(ap->a_dvp);
201 break;
219 return (EINVAL);
202 }
220 }
203 return error;
221 /* NOTREACHED */
204}
205
206static int
207msdosfs_close(ap)
208 struct vop_close_args /* {
209 struct vnode *a_vp;
210 int a_fflag;
211 struct ucred *a_cred;
212 struct proc *a_p;
213 } */ *ap;
214{
215 struct vnode *vp = ap->a_vp;
216 struct denode *dep = VTODE(vp);
222}
223
224static int
225msdosfs_close(ap)
226 struct vop_close_args /* {
227 struct vnode *a_vp;
228 int a_fflag;
229 struct ucred *a_cred;
230 struct proc *a_p;
231 } */ *ap;
232{
233 struct vnode *vp = ap->a_vp;
234 struct denode *dep = VTODE(vp);
235 struct timespec ts;
217
218 simple_lock(&vp->v_interlock);
236
237 simple_lock(&vp->v_interlock);
219 if (vp->v_usecount > 1)
220 DE_TIMES(dep, &time);
238 if (vp->v_usecount > 1) {
239 TIMEVAL_TO_TIMESPEC(&time, &ts);
240 DETIMES(dep, &ts, &ts, &ts);
241 }
221 simple_unlock(&vp->v_interlock);
222 return 0;
223}
224
225static int
226msdosfs_access(ap)
227 struct vop_access_args /* {
228 struct vnode *a_vp;

--- 75 unchanged lines hidden (view full) ---

304 struct vnode *a_vp;
305 struct vattr *a_vap;
306 struct ucred *a_cred;
307 struct proc *a_p;
308 } */ *ap;
309{
310 u_int cn;
311 struct denode *dep = VTODE(ap->a_vp);
242 simple_unlock(&vp->v_interlock);
243 return 0;
244}
245
246static int
247msdosfs_access(ap)
248 struct vop_access_args /* {
249 struct vnode *a_vp;

--- 75 unchanged lines hidden (view full) ---

325 struct vnode *a_vp;
326 struct vattr *a_vap;
327 struct ucred *a_cred;
328 struct proc *a_p;
329 } */ *ap;
330{
331 u_int cn;
332 struct denode *dep = VTODE(ap->a_vp);
333 struct msdosfsmount *pmp = dep->de_pmp;
312 struct vattr *vap = ap->a_vap;
334 struct vattr *vap = ap->a_vap;
335 mode_t mode;
336 struct timespec ts;
337 u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
338 u_long fileid;
313
339
314 DE_TIMES(dep, &time);
340 TIMEVAL_TO_TIMESPEC(&time, &ts);
341 DETIMES(dep, &ts, &ts, &ts);
315 vap->va_fsid = dep->de_dev;
316 /*
317 * The following computation of the fileid must be the same as that
318 * used in msdosfs_readdir() to compute d_fileno. If not, pwd
319 * doesn't work.
320 */
321 if (dep->de_Attributes & ATTR_DIRECTORY) {
342 vap->va_fsid = dep->de_dev;
343 /*
344 * The following computation of the fileid must be the same as that
345 * used in msdosfs_readdir() to compute d_fileno. If not, pwd
346 * doesn't work.
347 */
348 if (dep->de_Attributes & ATTR_DIRECTORY) {
322 if ((cn = dep->de_StartCluster) == MSDOSFSROOT)
323 cn = 1;
349 fileid = cntobn(pmp, dep->de_StartCluster) * dirsperblk;
350 if (dep->de_StartCluster == MSDOSFSROOT)
351 fileid = 1;
324 } else {
352 } else {
325 if ((cn = dep->de_dirclust) == MSDOSFSROOT)
326 cn = 1;
327 cn = (cn << 16) | (dep->de_diroffset & 0xffff);
353 fileid = cntobn(pmp, dep->de_dirclust) * dirsperblk;
354 if (dep->de_dirclust == MSDOSFSROOT)
355 fileid = roottobn(pmp, 0) * dirsperblk;
356 fileid += dep->de_diroffset / sizeof(struct direntry);
328 }
357 }
329 vap->va_fileid = cn;
330 vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
331 ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
332 vap->va_mode &= dep->de_pmp->pm_mask;
333 if (dep->de_Attributes & ATTR_DIRECTORY)
334 vap->va_mode |= S_IFDIR;
358 vap->va_fileid = fileid;
359 if ((dep->de_Attributes & ATTR_READONLY) == 0)
360 mode = S_IRWXU|S_IRWXG|S_IRWXO;
361 else
362 mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
363 vap->va_mode = mode & pmp->pm_mask;
364 vap->va_uid = pmp->pm_uid;
365 vap->va_gid = pmp->pm_gid;
335 vap->va_nlink = 1;
366 vap->va_nlink = 1;
336 vap->va_gid = dep->de_pmp->pm_gid;
337 vap->va_uid = dep->de_pmp->pm_uid;
338 vap->va_rdev = 0;
339 vap->va_size = dep->de_FileSize;
367 vap->va_rdev = 0;
368 vap->va_size = dep->de_FileSize;
340 dos2unixtime(dep->de_Date, dep->de_Time, &vap->va_atime);
341 vap->va_mtime = vap->va_atime;
342#if 0
343#ifndef MSDOSFS_NODIRMOD
344 if (vap->va_mode & S_IFDIR)
345 TIMEVAL_TO_TIMESPEC(&time, &vap->va_mtime);
346#endif
347#endif
348 vap->va_ctime = vap->va_atime;
349 vap->va_flags = (dep->de_Attributes & ATTR_ARCHIVE) ? 0 : SF_ARCHIVED;
369 dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
370 if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
371 dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
372 dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CHun, &vap->va_ctime);
373 } else {
374 vap->va_atime = vap->va_mtime;
375 vap->va_ctime = vap->va_mtime;
376 }
377 vap->va_flags = 0;
378 if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
379 vap->va_flags |= SF_ARCHIVED;
350 vap->va_gen = 0;
380 vap->va_gen = 0;
351 vap->va_blocksize = dep->de_pmp->pm_bpcluster;
352 vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
353 ~(dep->de_pmp->pm_crbomask);
381 vap->va_blocksize = pmp->pm_bpcluster;
382 vap->va_bytes =
383 (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask;
354 vap->va_type = ap->a_vp->v_type;
355 vap->va_filerev = dep->de_modrev;
384 vap->va_type = ap->a_vp->v_type;
385 vap->va_filerev = dep->de_modrev;
356 return 0;
386 return (0);
357}
358
359static int
360msdosfs_setattr(ap)
361 struct vop_setattr_args /* {
362 struct vnode *a_vp;
363 struct vattr *a_vap;
364 struct ucred *a_cred;
365 struct proc *a_p;
366 } */ *ap;
367{
368 struct vnode *vp = ap->a_vp;
369 struct denode *dep = VTODE(ap->a_vp);
387}
388
389static int
390msdosfs_setattr(ap)
391 struct vop_setattr_args /* {
392 struct vnode *a_vp;
393 struct vattr *a_vap;
394 struct ucred *a_cred;
395 struct proc *a_p;
396 } */ *ap;
397{
398 struct vnode *vp = ap->a_vp;
399 struct denode *dep = VTODE(ap->a_vp);
400 struct msdosfsmount *pmp = dep->de_pmp;
370 struct vattr *vap = ap->a_vap;
371 struct ucred *cred = ap->a_cred;
372 int error = 0;
373
401 struct vattr *vap = ap->a_vap;
402 struct ucred *cred = ap->a_cred;
403 int error = 0;
404
405#ifdef MSDOSFS_DEBUG
406 printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n",
407 ap->a_vp, vap, cred, ap->a_p);
408#endif
409
374 /*
375 * Check for unsettable attributes.
376 */
377 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
378 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
379 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
380 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
410 /*
411 * Check for unsettable attributes.
412 */
413 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
414 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
415 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
416 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
417#ifdef MSDOSFS_DEBUG
418 printf("msdosfs_setattr(): returning EINVAL\n");
419 printf(" va_type %d, va_nlink %x, va_fsid %lx, va_fileid %lx\n",
420 vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
421 printf(" va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n",
422 vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
423 printf(" va_uid %x, va_gid %x\n",
424 vap->va_uid, vap->va_gid);
425#endif
381 return (EINVAL);
382 }
383 if (vap->va_flags != VNOVAL) {
384 if (vp->v_mount->mnt_flag & MNT_RDONLY)
385 return (EROFS);
426 return (EINVAL);
427 }
428 if (vap->va_flags != VNOVAL) {
429 if (vp->v_mount->mnt_flag & MNT_RDONLY)
430 return (EROFS);
386 if (cred->cr_uid != dep->de_pmp->pm_uid &&
431 if (cred->cr_uid != pmp->pm_uid &&
387 (error = suser(cred, &ap->a_p->p_acflag)))
388 return (error);
389 /*
390 * We are very inconsistent about handling unsupported
391 * attributes. We ignored the the access time and the
392 * read and execute bits. We were strict for the other
393 * attributes.
394 *

--- 11 unchanged lines hidden (view full) ---

406 return EINVAL;
407 if (vap->va_flags & SF_ARCHIVED)
408 dep->de_Attributes &= ~ATTR_ARCHIVE;
409 else if (!(dep->de_Attributes & ATTR_DIRECTORY))
410 dep->de_Attributes |= ATTR_ARCHIVE;
411 dep->de_flag |= DE_MODIFIED;
412 }
413
432 (error = suser(cred, &ap->a_p->p_acflag)))
433 return (error);
434 /*
435 * We are very inconsistent about handling unsupported
436 * attributes. We ignored the the access time and the
437 * read and execute bits. We were strict for the other
438 * attributes.
439 *

--- 11 unchanged lines hidden (view full) ---

451 return EINVAL;
452 if (vap->va_flags & SF_ARCHIVED)
453 dep->de_Attributes &= ~ATTR_ARCHIVE;
454 else if (!(dep->de_Attributes & ATTR_DIRECTORY))
455 dep->de_Attributes |= ATTR_ARCHIVE;
456 dep->de_flag |= DE_MODIFIED;
457 }
458
414 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (uid_t)VNOVAL) {
459 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
460 uid_t uid;
461 gid_t gid;
462
415 if (vp->v_mount->mnt_flag & MNT_RDONLY)
416 return (EROFS);
463 if (vp->v_mount->mnt_flag & MNT_RDONLY)
464 return (EROFS);
417 if ((cred->cr_uid != dep->de_pmp->pm_uid ||
418 vap->va_uid != dep->de_pmp->pm_uid ||
419 (vap->va_gid != dep->de_pmp->pm_gid &&
420 !groupmember(vap->va_gid, cred))) &&
465 uid = vap->va_uid;
466 if (uid == (uid_t)VNOVAL)
467 uid = pmp->pm_uid;
468 gid = vap->va_gid;
469 if (gid == (gid_t)VNOVAL)
470 gid = pmp->pm_gid;
471 if ((cred->cr_uid != pmp->pm_uid || uid != pmp->pm_uid ||
472 (gid != pmp->pm_gid && !groupmember(gid, cred))) &&
421 (error = suser(cred, &ap->a_p->p_acflag)))
422 return error;
473 (error = suser(cred, &ap->a_p->p_acflag)))
474 return error;
423 if (vap->va_uid != dep->de_pmp->pm_uid ||
424 vap->va_gid != dep->de_pmp->pm_gid)
475 if (uid != pmp->pm_uid || gid != pmp->pm_gid)
425 return EINVAL;
426 }
476 return EINVAL;
477 }
478
427 if (vap->va_size != VNOVAL) {
428 /*
429 * Disallow write attempts on read-only file systems;
430 * unless the file is a socket, fifo, or a block or
431 * character device resident on the file system.
432 */
433 switch (vp->v_type) {
434 case VDIR:
435 return (EISDIR);
436 case VLNK:
437 case VREG:
438 if (vp->v_mount->mnt_flag & MNT_RDONLY)
439 return (EROFS);
440 break;
441 }
442 error = detrunc(dep, vap->va_size, 0, cred, ap->a_p);
443 if (error)
444 return error;
445 }
479 if (vap->va_size != VNOVAL) {
480 /*
481 * Disallow write attempts on read-only file systems;
482 * unless the file is a socket, fifo, or a block or
483 * character device resident on the file system.
484 */
485 switch (vp->v_type) {
486 case VDIR:
487 return (EISDIR);
488 case VLNK:
489 case VREG:
490 if (vp->v_mount->mnt_flag & MNT_RDONLY)
491 return (EROFS);
492 break;
493 }
494 error = detrunc(dep, vap->va_size, 0, cred, ap->a_p);
495 if (error)
496 return error;
497 }
446 if (vap->va_mtime.tv_sec != VNOVAL) {
498 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
447 if (vp->v_mount->mnt_flag & MNT_RDONLY)
448 return (EROFS);
499 if (vp->v_mount->mnt_flag & MNT_RDONLY)
500 return (EROFS);
449 if (cred->cr_uid != dep->de_pmp->pm_uid &&
501 if (cred->cr_uid != pmp->pm_uid &&
450 (error = suser(cred, &ap->a_p->p_acflag)) &&
451 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
502 (error = suser(cred, &ap->a_p->p_acflag)) &&
503 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
452 (error = VOP_ACCESS(vp, VWRITE, cred, ap->a_p))))
453 return error;
454 dep->de_flag |= DE_UPDATE;
455 error = deupdat(dep, &vap->va_mtime, 1);
456 if (error)
457 return error;
504 (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
505 return (error);
506 if (vp->v_type != VDIR) {
507 if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
508 vap->va_atime.tv_sec != VNOVAL)
509 unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
510 if (vap->va_mtime.tv_sec != VNOVAL)
511 unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
512 dep->de_Attributes |= ATTR_ARCHIVE;
513 dep->de_flag |= DE_MODIFIED;
514 }
458 }
515 }
459
460 /*
461 * DOS files only have the ability to have their writability
462 * attribute set, so we use the owner write bit to set the readonly
463 * attribute.
464 */
516 /*
517 * DOS files only have the ability to have their writability
518 * attribute set, so we use the owner write bit to set the readonly
519 * attribute.
520 */
465 error = 0;
466 if (vap->va_mode != (u_short) VNOVAL) {
521 if (vap->va_mode != (mode_t)VNOVAL) {
467 if (vp->v_mount->mnt_flag & MNT_RDONLY)
468 return (EROFS);
522 if (vp->v_mount->mnt_flag & MNT_RDONLY)
523 return (EROFS);
469 if (cred->cr_uid != dep->de_pmp->pm_uid &&
524 if (cred->cr_uid != pmp->pm_uid &&
470 (error = suser(cred, &ap->a_p->p_acflag)))
525 (error = suser(cred, &ap->a_p->p_acflag)))
471 return error;
472
473 /* We ignore the read and execute bits */
474 if (vap->va_mode & VWRITE)
475 dep->de_Attributes &= ~ATTR_READONLY;
476 else
477 dep->de_Attributes |= ATTR_READONLY;
478 dep->de_flag |= DE_MODIFIED;
526 return (error);
527 if (vp->v_type != VDIR) {
528 /* We ignore the read and execute bits. */
529 if (vap->va_mode & VWRITE)
530 dep->de_Attributes &= ~ATTR_READONLY;
531 else
532 dep->de_Attributes |= ATTR_READONLY;
533 dep->de_flag |= DE_MODIFIED;
534 }
479 }
535 }
480 return error;
536 return (deupdat(dep, 1));
481}
482
483static int
484msdosfs_read(ap)
485 struct vop_read_args /* {
486 struct vnode *a_vp;
487 struct uio *a_uio;
488 int a_ioflag;
489 struct ucred *a_cred;
490 } */ *ap;
491{
492 int error = 0;
493 int diff;
537}
538
539static int
540msdosfs_read(ap)
541 struct vop_read_args /* {
542 struct vnode *a_vp;
543 struct uio *a_uio;
544 int a_ioflag;
545 struct ucred *a_cred;
546 } */ *ap;
547{
548 int error = 0;
549 int diff;
550 int blsize;
494 int isadir;
495 long n;
496 long on;
497 daddr_t lbn;
551 int isadir;
552 long n;
553 long on;
554 daddr_t lbn;
498 daddr_t rablock;
555 daddr_t rablock, rablock1;
499 int rasize;
500 struct buf *bp;
501 struct vnode *vp = ap->a_vp;
502 struct denode *dep = VTODE(vp);
503 struct msdosfsmount *pmp = dep->de_pmp;
504 struct uio *uio = ap->a_uio;
505
506 /*
507 * If they didn't ask for any data, then we are done.
508 */
509 if (uio->uio_resid == 0)
556 int rasize;
557 struct buf *bp;
558 struct vnode *vp = ap->a_vp;
559 struct denode *dep = VTODE(vp);
560 struct msdosfsmount *pmp = dep->de_pmp;
561 struct uio *uio = ap->a_uio;
562
563 /*
564 * If they didn't ask for any data, then we are done.
565 */
566 if (uio->uio_resid == 0)
510 return 0;
567 return (0);
511 if (uio->uio_offset < 0)
568 if (uio->uio_offset < 0)
512 return EINVAL;
569 return (EINVAL);
513
514 isadir = dep->de_Attributes & ATTR_DIRECTORY;
515 do {
570
571 isadir = dep->de_Attributes & ATTR_DIRECTORY;
572 do {
516 lbn = uio->uio_offset >> pmp->pm_cnshift;
573 lbn = de_cluster(pmp, uio->uio_offset);
517 on = uio->uio_offset & pmp->pm_crbomask;
518 n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
519 diff = dep->de_FileSize - uio->uio_offset;
520 if (diff <= 0)
574 on = uio->uio_offset & pmp->pm_crbomask;
575 n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
576 diff = dep->de_FileSize - uio->uio_offset;
577 if (diff <= 0)
521 return 0;
578 return (0);
579 if (diff < n)
580 n = diff;
522 /* convert cluster # to block # if a directory */
523 if (isadir) {
581 /* convert cluster # to block # if a directory */
582 if (isadir) {
524 error = pcbmap(dep, lbn, &lbn, 0);
583 error = pcbmap(dep, lbn, &lbn, 0, &blsize);
525 if (error)
584 if (error)
526 return error;
585 return (error);
527 }
586 }
528 if (diff < n)
529 n = diff;
530 /*
531 * If we are operating on a directory file then be sure to
532 * do i/o with the vnode for the filesystem instead of the
533 * vnode for the directory.
534 */
535 if (isadir) {
587 /*
588 * If we are operating on a directory file then be sure to
589 * do i/o with the vnode for the filesystem instead of the
590 * vnode for the directory.
591 */
592 if (isadir) {
536 error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
537 NOCRED, &bp);
593 error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
538 } else {
539 rablock = lbn + 1;
540#ifdef PC98
541 /*
542 * 1024byte/sector support
543 */
544 if (pmp->pm_BytesPerSec == 1024)
545 vp->v_flag |= 0x10000;
546#endif
547 if (vp->v_lastr + 1 == lbn &&
594 } else {
595 rablock = lbn + 1;
596#ifdef PC98
597 /*
598 * 1024byte/sector support
599 */
600 if (pmp->pm_BytesPerSec == 1024)
601 vp->v_flag |= 0x10000;
602#endif
603 if (vp->v_lastr + 1 == lbn &&
548 rablock * pmp->pm_bpcluster < dep->de_FileSize) {
604 de_cn2off(pmp, rablock) < dep->de_FileSize) {
605 rablock1 = de_cn2bn(pmp, rablock);
549 rasize = pmp->pm_bpcluster;
606 rasize = pmp->pm_bpcluster;
550 error = breadn(vp, lbn, pmp->pm_bpcluster,
551 &rablock, &rasize, 1,
552 NOCRED, &bp);
553 } else {
554 error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
555 &bp);
556 }
607 error = breadn(vp, de_cn2bn(pmp, lbn),
608 pmp->pm_bpcluster, &rablock1, &rasize, 1,
609 NOCRED, &bp);
610 } else
611 error = bread(vp, de_cn2bn(pmp, lbn),
612 pmp->pm_bpcluster, NOCRED, &bp);
557 vp->v_lastr = lbn;
558 }
559 n = min(n, pmp->pm_bpcluster - bp->b_resid);
560 if (error) {
561 brelse(bp);
613 vp->v_lastr = lbn;
614 }
615 n = min(n, pmp->pm_bpcluster - bp->b_resid);
616 if (error) {
617 brelse(bp);
562 return error;
618 return (error);
563 }
564 error = uiomove(bp->b_data + on, (int) n, uio);
619 }
620 error = uiomove(bp->b_data + on, (int) n, uio);
565 /*
566 * If we have read everything from this block or have read
567 * to end of file then we are done with this block. Mark
568 * it to say the buffer can be reused if need be.
569 */
570#if 0
571 if (n + on == pmp->pm_bpcluster ||
572 uio->uio_offset == dep->de_FileSize)
573 bp->b_flags |= B_AGE;
574#endif
621 if (!isadir)
622 dep->de_flag |= DE_ACCESS;
575 brelse(bp);
576 } while (error == 0 && uio->uio_resid > 0 && n != 0);
623 brelse(bp);
624 } while (error == 0 && uio->uio_resid > 0 && n != 0);
577 return error;
625 return (error);
578}
579
580/*
581 * Write data to a file or directory.
582 */
583static int
584msdosfs_write(ap)
585 struct vop_write_args /* {
586 struct vnode *a_vp;
587 struct uio *a_uio;
588 int a_ioflag;
589 struct ucred *a_cred;
590 } */ *ap;
591{
592 int n;
626}
627
628/*
629 * Write data to a file or directory.
630 */
631static int
632msdosfs_write(ap)
633 struct vop_write_args /* {
634 struct vnode *a_vp;
635 struct uio *a_uio;
636 int a_ioflag;
637 struct ucred *a_cred;
638 } */ *ap;
639{
640 int n;
593 int isadir;
594 int croffset;
595 int resid;
641 int croffset;
642 int resid;
596 int osize;
643 u_long osize;
597 int error = 0;
598 u_long count;
599 daddr_t bn, lastcn;
600 struct buf *bp;
601 int ioflag = ap->a_ioflag;
602 struct uio *uio = ap->a_uio;
603 struct proc *p = uio->uio_procp;
604 struct vnode *vp = ap->a_vp;
605 struct vnode *thisvp;
606 struct denode *dep = VTODE(vp);
607 struct msdosfsmount *pmp = dep->de_pmp;
608 struct ucred *cred = ap->a_cred;
644 int error = 0;
645 u_long count;
646 daddr_t bn, lastcn;
647 struct buf *bp;
648 int ioflag = ap->a_ioflag;
649 struct uio *uio = ap->a_uio;
650 struct proc *p = uio->uio_procp;
651 struct vnode *vp = ap->a_vp;
652 struct vnode *thisvp;
653 struct denode *dep = VTODE(vp);
654 struct msdosfsmount *pmp = dep->de_pmp;
655 struct ucred *cred = ap->a_cred;
609 struct timespec ts;
610
611#ifdef MSDOSFS_DEBUG
656
657#ifdef MSDOSFS_DEBUG
612 printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
613 vp, uio, ioflag, cred);
614 printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
615 dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
658 printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
659 vp, uio, ioflag, cred);
660 printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
661 dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
616#endif
617
618 switch (vp->v_type) {
619 case VREG:
620 if (ioflag & IO_APPEND)
621 uio->uio_offset = dep->de_FileSize;
662#endif
663
664 switch (vp->v_type) {
665 case VREG:
666 if (ioflag & IO_APPEND)
667 uio->uio_offset = dep->de_FileSize;
622 isadir = 0;
623 thisvp = vp;
624 break;
668 thisvp = vp;
669 break;
625
626 case VDIR:
670 case VDIR:
627 if ((ioflag & IO_SYNC) == 0)
628 panic("msdosfs_write(): non-sync directory update");
629 isadir = 1;
630 thisvp = pmp->pm_devvp;
631 break;
632
671 return EISDIR;
633 default:
634 panic("msdosfs_write(): bad file type");
672 default:
673 panic("msdosfs_write(): bad file type");
635 break;
636 }
637
638 if (uio->uio_offset < 0)
674 }
675
676 if (uio->uio_offset < 0)
639 return EINVAL;
677 return (EINVAL);
640
641 if (uio->uio_resid == 0)
678
679 if (uio->uio_resid == 0)
642 return 0;
680 return (0);
643
644 /*
645 * If they've exceeded their filesize limit, tell them about it.
646 */
681
682 /*
683 * If they've exceeded their filesize limit, tell them about it.
684 */
647 if (vp->v_type == VREG && p &&
685 if (p &&
648 ((uio->uio_offset + uio->uio_resid) >
686 ((uio->uio_offset + uio->uio_resid) >
649 p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
687 p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
650 psignal(p, SIGXFSZ);
688 psignal(p, SIGXFSZ);
651 return EFBIG;
689 return (EFBIG);
652 }
653
654 /*
690 }
691
692 /*
655 * If attempting to write beyond the end of the root directory we
656 * stop that here because the root directory can not grow.
657 */
658 if ((dep->de_Attributes & ATTR_DIRECTORY) &&
659 dep->de_StartCluster == MSDOSFSROOT &&
660 (uio->uio_offset + uio->uio_resid) > dep->de_FileSize)
661 return ENOSPC;
662
663 /*
664 * If the offset we are starting the write at is beyond the end of
665 * the file, then they've done a seek. Unix filesystems allow
666 * files with holes in them, DOS doesn't so we must fill the hole
667 * with zeroed blocks.
668 */
669 if (uio->uio_offset > dep->de_FileSize) {
670 error = deextend(dep, uio->uio_offset, cred);
671 if (error)
693 * If the offset we are starting the write at is beyond the end of
694 * the file, then they've done a seek. Unix filesystems allow
695 * files with holes in them, DOS doesn't so we must fill the hole
696 * with zeroed blocks.
697 */
698 if (uio->uio_offset > dep->de_FileSize) {
699 error = deextend(dep, uio->uio_offset, cred);
700 if (error)
672 return error;
701 return (error);
673 }
674
675 /*
676 * Remember some values in case the write fails.
677 */
678 resid = uio->uio_resid;
679 osize = dep->de_FileSize;
680
702 }
703
704 /*
705 * Remember some values in case the write fails.
706 */
707 resid = uio->uio_resid;
708 osize = dep->de_FileSize;
709
681
682#ifdef PC98
683 /*
684 * 1024byte/sector support
685 */
686 if (pmp->pm_BytesPerSec == 1024)
687 thisvp->v_flag |= 0x10000;
688#endif
689 /*
690 * If we write beyond the end of the file, extend it to its ultimate
691 * size ahead of the time to hopefully get a contiguous area.
692 */
693 if (uio->uio_offset + resid > osize) {
710#ifdef PC98
711 /*
712 * 1024byte/sector support
713 */
714 if (pmp->pm_BytesPerSec == 1024)
715 thisvp->v_flag |= 0x10000;
716#endif
717 /*
718 * If we write beyond the end of the file, extend it to its ultimate
719 * size ahead of the time to hopefully get a contiguous area.
720 */
721 if (uio->uio_offset + resid > osize) {
694 count = de_clcount(pmp, uio->uio_offset + resid) - de_clcount(pmp, osize);
695 if ((error = extendfile(dep, count, NULL, NULL, 0))
696 && (error != ENOSPC || (ioflag & IO_UNIT)))
722 count = de_clcount(pmp, uio->uio_offset + resid) -
723 de_clcount(pmp, osize);
724 error = extendfile(dep, count, NULL, NULL, 0);
725 if (error && (error != ENOSPC || (ioflag & IO_UNIT)))
697 goto errexit;
698 lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
699 } else
700 lastcn = de_clcount(pmp, osize) - 1;
701
702 do {
726 goto errexit;
727 lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
728 } else
729 lastcn = de_clcount(pmp, osize) - 1;
730
731 do {
703 bn = de_blk(pmp, uio->uio_offset);
704 if (isadir) {
705 error = pcbmap(dep, bn, &bn, 0);
706 if (error)
707 break;
708 } else if (bn > lastcn) {
732 if (de_cluster(pmp, uio->uio_offset) > lastcn) {
709 error = ENOSPC;
710 break;
711 }
712
713 croffset = uio->uio_offset & pmp->pm_crbomask;
714 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
715 if (uio->uio_offset + n > dep->de_FileSize) {
716 dep->de_FileSize = uio->uio_offset + n;
717 /* The object size needs to be set before buffer is allocated */
718 vnode_pager_setsize(vp, dep->de_FileSize);
719 }
720
733 error = ENOSPC;
734 break;
735 }
736
737 croffset = uio->uio_offset & pmp->pm_crbomask;
738 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
739 if (uio->uio_offset + n > dep->de_FileSize) {
740 dep->de_FileSize = uio->uio_offset + n;
741 /* The object size needs to be set before buffer is allocated */
742 vnode_pager_setsize(vp, dep->de_FileSize);
743 }
744
745 bn = de_blk(pmp, uio->uio_offset);
721 if ((uio->uio_offset & pmp->pm_crbomask) == 0
722 && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
723 || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
724 /*
725 * If either the whole cluster gets written,
726 * or we write the cluster from its start beyond EOF,
727 * then no need to read data from disk.
728 */
729 bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
730 clrbuf(bp);
731 /*
732 * Do the bmap now, since pcbmap needs buffers
733 * for the fat table. (see msdosfs_strategy)
734 */
746 if ((uio->uio_offset & pmp->pm_crbomask) == 0
747 && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
748 || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
749 /*
750 * If either the whole cluster gets written,
751 * or we write the cluster from its start beyond EOF,
752 * then no need to read data from disk.
753 */
754 bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
755 clrbuf(bp);
756 /*
757 * Do the bmap now, since pcbmap needs buffers
758 * for the fat table. (see msdosfs_strategy)
759 */
735 if (!isadir) {
736 if (bp->b_blkno == bp->b_lblkno) {
737 error = pcbmap(dep, bp->b_lblkno,
738 &bp->b_blkno, 0);
739 if (error)
740 bp->b_blkno = -1;
741 }
742 if (bp->b_blkno == -1) {
743 brelse(bp);
744 if (!error)
745 error = EIO; /* XXX */
746 break;
747 }
760 if (bp->b_blkno == bp->b_lblkno) {
761 error = pcbmap(dep,
762 de_bn2cn(pmp, bp->b_lblkno),
763 &bp->b_blkno, 0, 0);
764 if (error)
765 bp->b_blkno = -1;
748 }
766 }
767 if (bp->b_blkno == -1) {
768 brelse(bp);
769 if (!error)
770 error = EIO; /* XXX */
771 break;
772 }
749 } else {
750 /*
751 * The block we need to write into exists, so read it in.
752 */
753 error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
773 } else {
774 /*
775 * The block we need to write into exists, so read it in.
776 */
777 error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
754 if (error)
778 if (error) {
779 brelse(bp);
755 break;
780 break;
781 }
756 }
757
758 /*
759 * Should these vnode_pager_* functions be done on dir
760 * files?
761 */
762
763 /*

--- 5 unchanged lines hidden (view full) ---

769 * If they want this synchronous then write it and wait for
770 * it. Otherwise, if on a cluster boundary write it
771 * asynchronously so we can move on to the next block
772 * without delay. Otherwise do a delayed write because we
773 * may want to write somemore into the block later.
774 */
775 if (ioflag & IO_SYNC)
776 (void) bwrite(bp);
782 }
783
784 /*
785 * Should these vnode_pager_* functions be done on dir
786 * files?
787 */
788
789 /*

--- 5 unchanged lines hidden (view full) ---

795 * If they want this synchronous then write it and wait for
796 * it. Otherwise, if on a cluster boundary write it
797 * asynchronously so we can move on to the next block
798 * without delay. Otherwise do a delayed write because we
799 * may want to write somemore into the block later.
800 */
801 if (ioflag & IO_SYNC)
802 (void) bwrite(bp);
777 else if (n + croffset == pmp->pm_bpcluster) {
803 else if (n + croffset == pmp->pm_bpcluster)
778 bawrite(bp);
804 bawrite(bp);
779 } else
805 else
780 bdwrite(bp);
781 dep->de_flag |= DE_UPDATE;
782 } while (error == 0 && uio->uio_resid > 0);
783
784 /*
785 * If the write failed and they want us to, truncate the file back
786 * to the size it was before the write was attempted.
787 */
788errexit:
789 if (error) {
790 if (ioflag & IO_UNIT) {
791 detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
792 uio->uio_offset -= resid - uio->uio_resid;
793 uio->uio_resid = resid;
794 } else {
795 detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
796 if (uio->uio_resid != resid)
797 error = 0;
798 }
806 bdwrite(bp);
807 dep->de_flag |= DE_UPDATE;
808 } while (error == 0 && uio->uio_resid > 0);
809
810 /*
811 * If the write failed and they want us to, truncate the file back
812 * to the size it was before the write was attempted.
813 */
814errexit:
815 if (error) {
816 if (ioflag & IO_UNIT) {
817 detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
818 uio->uio_offset -= resid - uio->uio_resid;
819 uio->uio_resid = resid;
820 } else {
821 detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
822 if (uio->uio_resid != resid)
823 error = 0;
824 }
799 } else if (ioflag & IO_SYNC) {
800 TIMEVAL_TO_TIMESPEC(&time, &ts);
801 error = deupdat(dep, &ts, 1);
802 }
803 return error;
825 } else if (ioflag & IO_SYNC)
826 error = deupdat(dep, 1);
827 return (error);
804}
805
806/*
807 * Flush the blocks of a file to disk.
808 *
809 * This function is worthless for vnodes that represent directories. Maybe we
810 * could just do a sync if they try an fsync on a directory file.
811 */
812static int
813msdosfs_fsync(ap)
814 struct vop_fsync_args /* {
815 struct vnode *a_vp;
816 struct ucred *a_cred;
817 int a_waitfor;
818 struct proc *a_p;
819 } */ *ap;
820{
828}
829
830/*
831 * Flush the blocks of a file to disk.
832 *
833 * This function is worthless for vnodes that represent directories. Maybe we
834 * could just do a sync if they try an fsync on a directory file.
835 */
836static int
837msdosfs_fsync(ap)
838 struct vop_fsync_args /* {
839 struct vnode *a_vp;
840 struct ucred *a_cred;
841 int a_waitfor;
842 struct proc *a_p;
843 } */ *ap;
844{
821 register struct vnode *vp = ap->a_vp;
822 register struct buf *bp;
823 int wait = ap->a_waitfor == MNT_WAIT;
824 struct timespec ts;
825 struct buf *nbp;
845 struct vnode *vp = ap->a_vp;
826 int s;
846 int s;
847 struct buf *bp, *nbp;
827
828 /*
829 * Flush all dirty buffers associated with a vnode.
830 */
831loop:
832 s = splbio();
833 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
834 nbp = bp->b_vnbufs.le_next;

--- 13 unchanged lines hidden (view full) ---

848 }
849#ifdef DIAGNOSTIC
850 if (vp->v_dirtyblkhd.lh_first) {
851 vprint("msdosfs_fsync: dirty", vp);
852 goto loop;
853 }
854#endif
855 splx(s);
848
849 /*
850 * Flush all dirty buffers associated with a vnode.
851 */
852loop:
853 s = splbio();
854 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
855 nbp = bp->b_vnbufs.le_next;

--- 13 unchanged lines hidden (view full) ---

869 }
870#ifdef DIAGNOSTIC
871 if (vp->v_dirtyblkhd.lh_first) {
872 vprint("msdosfs_fsync: dirty", vp);
873 goto loop;
874 }
875#endif
876 splx(s);
856 TIMEVAL_TO_TIMESPEC(&time, &ts);
857 return deupdat(VTODE(vp), &ts, wait);
877 return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
858}
859
860static int
861msdosfs_remove(ap)
862 struct vop_remove_args /* {
863 struct vnode *a_dvp;
864 struct vnode *a_vp;
865 struct componentname *a_cnp;
866 } */ *ap;
867{
868 int error;
869 struct denode *dep = VTODE(ap->a_vp);
870 struct denode *ddep = VTODE(ap->a_dvp);
871
878}
879
880static int
881msdosfs_remove(ap)
882 struct vop_remove_args /* {
883 struct vnode *a_dvp;
884 struct vnode *a_vp;
885 struct componentname *a_cnp;
886 } */ *ap;
887{
888 int error;
889 struct denode *dep = VTODE(ap->a_vp);
890 struct denode *ddep = VTODE(ap->a_dvp);
891
872 error = removede(ddep,dep);
892 if (ap->a_vp->v_type == VDIR)
893 error = EPERM;
894 else
895 error = removede(ddep, dep);
873#ifdef MSDOSFS_DEBUG
896#ifdef MSDOSFS_DEBUG
874 printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
897 printf("msdosfs_remove(), dep %p, v_usecount %d\n", dep, ap->a_vp->v_usecount);
875#endif
876 if (ddep == dep)
877 vrele(ap->a_vp);
878 else
879 vput(ap->a_vp); /* causes msdosfs_inactive() to be called
880 * via vrele() */
881 vput(ap->a_dvp);
898#endif
899 if (ddep == dep)
900 vrele(ap->a_vp);
901 else
902 vput(ap->a_vp); /* causes msdosfs_inactive() to be called
903 * via vrele() */
904 vput(ap->a_dvp);
882 return error;
905 return (error);
883}
884
885/*
886 * DOS filesystems don't know what links are. But since we already called
887 * msdosfs_lookup() with create and lockparent, the parent is locked so we
888 * have to free it before we return the error.
889 */
890static int

--- 66 unchanged lines hidden (view full) ---

957 struct vnode *a_fdvp;
958 struct vnode *a_fvp;
959 struct componentname *a_fcnp;
960 struct vnode *a_tdvp;
961 struct vnode *a_tvp;
962 struct componentname *a_tcnp;
963 } */ *ap;
964{
906}
907
908/*
909 * DOS filesystems don't know what links are. But since we already called
910 * msdosfs_lookup() with create and lockparent, the parent is locked so we
911 * have to free it before we return the error.
912 */
913static int

--- 66 unchanged lines hidden (view full) ---

980 struct vnode *a_fdvp;
981 struct vnode *a_fvp;
982 struct componentname *a_fcnp;
983 struct vnode *a_tdvp;
984 struct vnode *a_tvp;
985 struct componentname *a_tcnp;
986 } */ *ap;
987{
965 u_char toname[11];
966 int error;
967 int newparent = 0;
968 int sourceisadirectory = 0;
969 u_long cn;
970 daddr_t bn;
988 struct vnode *tdvp = ap->a_tdvp;
989 struct vnode *fvp = ap->a_fvp;
990 struct vnode *fdvp = ap->a_fdvp;
971 struct vnode *tvp = ap->a_tvp;
991 struct vnode *tvp = ap->a_tvp;
992 struct componentname *tcnp = ap->a_tcnp;
972 struct componentname *fcnp = ap->a_fcnp;
973 struct proc *p = fcnp->cn_proc;
993 struct componentname *fcnp = ap->a_fcnp;
994 struct proc *p = fcnp->cn_proc;
995 struct denode *ip, *xp, *dp, *zp;
996 u_char toname[11], oldname[11];
997 u_long from_diroffset, to_diroffset;
998 u_char to_count;
999 int doingdirectory = 0, newparent = 0;
1000 int error;
1001 u_long cn;
1002 daddr_t bn;
974 struct denode *fddep; /* from file's parent directory */
975 struct denode *fdep; /* from file or directory */
976 struct denode *tddep; /* to file's parent directory */
977 struct denode *tdep; /* to file or directory */
978 struct msdosfsmount *pmp;
979 struct direntry *dotdotp;
1003 struct denode *fddep; /* from file's parent directory */
1004 struct denode *fdep; /* from file or directory */
1005 struct denode *tddep; /* to file's parent directory */
1006 struct denode *tdep; /* to file or directory */
1007 struct msdosfsmount *pmp;
1008 struct direntry *dotdotp;
980 struct direntry *ep;
981 struct buf *bp;
982
983 fddep = VTODE(ap->a_fdvp);
984 fdep = VTODE(ap->a_fvp);
985 tddep = VTODE(ap->a_tdvp);
986 tdep = tvp ? VTODE(tvp) : NULL;
987 pmp = fddep->de_pmp;
988
1009 struct buf *bp;
1010
1011 fddep = VTODE(ap->a_fdvp);
1012 fdep = VTODE(ap->a_fvp);
1013 tddep = VTODE(ap->a_tdvp);
1014 tdep = tvp ? VTODE(tvp) : NULL;
1015 pmp = fddep->de_pmp;
1016
989 /* Check for cross-device rename */
990 if ((ap->a_fvp->v_mount != ap->a_tdvp->v_mount) ||
991 (tvp && (ap->a_fvp->v_mount != tvp->v_mount))) {
992 error = EXDEV;
993 goto bad;
994 }
1017 pmp = VFSTOMSDOSFS(fdvp->v_mount);
995
1018
1019#ifdef DIAGNOSTIC
1020 if ((tcnp->cn_flags & HASBUF) == 0 ||
1021 (fcnp->cn_flags & HASBUF) == 0)
1022 panic("msdosfs_rename: no name");
1023#endif
996 /*
1024 /*
997 * Convert the filename in tcnp into a dos filename. We copy this
998 * into the denode and directory entry for the destination
999 * file/directory.
1025 * Check for cross-device rename.
1000 */
1026 */
1001 unix2dosfn((u_char *) ap->a_tcnp->cn_nameptr,
1002 toname, ap->a_tcnp->cn_namelen);
1027 if ((fvp->v_mount != tdvp->v_mount) ||
1028 (tvp && (fvp->v_mount != tvp->v_mount))) {
1029 error = EXDEV;
1030abortit:
1031 VOP_ABORTOP(tdvp, tcnp);
1032 if (tdvp == tvp)
1033 vrele(tdvp);
1034 else
1035 vput(tdvp);
1036 if (tvp)
1037 vput(tvp);
1038 VOP_ABORTOP(fdvp, fcnp);
1039 vrele(fdvp);
1040 vrele(fvp);
1041 return (error);
1042 }
1003
1004 /*
1043
1044 /*
1005 * At this point this is the lock state of the denodes:
1006 * fddep referenced
1007 * fdep referenced
1008 * tddep locked
1009 * tdep locked if it exists
1045 * If source and dest are the same, do nothing.
1010 */
1046 */
1047 if (tvp == fvp) {
1048 error = 0;
1049 goto abortit;
1050 }
1011
1051
1052 error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
1053 if (error)
1054 goto abortit;
1055 dp = VTODE(fdvp);
1056 ip = VTODE(fvp);
1057
1012 /*
1013 * Be sure we are not renaming ".", "..", or an alias of ".". This
1014 * leads to a crippled directory tree. It's pretty tough to do a
1015 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
1016 * doesn't work if the ".." entry is missing.
1017 */
1058 /*
1059 * Be sure we are not renaming ".", "..", or an alias of ".". This
1060 * leads to a crippled directory tree. It's pretty tough to do a
1061 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
1062 * doesn't work if the ".." entry is missing.
1063 */
1018 if (fdep->de_Attributes & ATTR_DIRECTORY) {
1019 if ((ap->a_fcnp->cn_namelen == 1
1020 && ap->a_fcnp->cn_nameptr[0] == '.')
1021 || fddep == fdep
1022 || (ap->a_fcnp->cn_flags | ap->a_tcnp->cn_flags)
1023 & ISDOTDOT) {
1024 VOP_ABORTOP(ap->a_tdvp, ap->a_tcnp);
1025 vput(ap->a_tdvp);
1026 if (tvp)
1027 vput(tvp);
1028 VOP_ABORTOP(ap->a_fdvp, ap->a_fcnp);
1029 vrele(ap->a_fdvp);
1030 vrele(ap->a_fvp);
1031 return EINVAL;
1064 if (ip->de_Attributes & ATTR_DIRECTORY) {
1065 /*
1066 * Avoid ".", "..", and aliases of "." for obvious reasons.
1067 */
1068 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1069 dp == ip ||
1070 (fcnp->cn_flags & ISDOTDOT) ||
1071 (tcnp->cn_flags & ISDOTDOT) ||
1072 (ip->de_flag & DE_RENAME)) {
1073 VOP_UNLOCK(fvp, 0, p);
1074 error = EINVAL;
1075 goto abortit;
1032 }
1076 }
1033 sourceisadirectory = 1;
1077 ip->de_flag |= DE_RENAME;
1078 doingdirectory++;
1034 }
1035
1036 /*
1079 }
1080
1081 /*
1037 * If we are renaming a directory, and the directory is being moved
1038 * to another directory, then we must be sure the destination
1039 * directory is not in the subtree of the source directory. This
1040 * could orphan everything under the source directory.
1041 * doscheckpath() unlocks the destination's parent directory so we
1042 * must look it up again to relock it.
1082 * When the target exists, both the directory
1083 * and target vnodes are returned locked.
1043 */
1084 */
1044 if (fddep->de_StartCluster != tddep->de_StartCluster)
1085 dp = VTODE(tdvp);
1086 xp = tvp ? VTODE(tvp) : NULL;
1087 /*
1088 * Remember direntry place to use for destination
1089 */
1090 to_diroffset = dp->de_fndoffset;
1091 to_count = dp->de_fndcnt;
1092
1093 /*
1094 * If ".." must be changed (ie the directory gets a new
1095 * parent) then the source directory must not be in the
1096 * directory heirarchy above the target, as this would
1097 * orphan everything below the source directory. Also
1098 * the user must have write permission in the source so
1099 * as to be able to change "..". We must repeat the call
1100 * to namei, as the parent directory is unlocked by the
1101 * call to doscheckpath().
1102 */
1103 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
1104 VOP_UNLOCK(fvp, 0, p);
1105 if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
1045 newparent = 1;
1106 newparent = 1;
1046 if (sourceisadirectory && newparent) {
1047 if (tdep) {
1048 vput(ap->a_tvp);
1049 tdep = NULL;
1050 }
1051 /* doscheckpath() vput()'s tddep */
1052 error = doscheckpath(fdep, tddep);
1053 tddep = NULL;
1054 if (error)
1107 vrele(fdvp);
1108 if (doingdirectory && newparent) {
1109 if (error) /* write access check above */
1055 goto bad;
1110 goto bad;
1056 if ((ap->a_tcnp->cn_flags & SAVESTART) == 0)
1057 panic("msdosfs_rename(): lost to startdir");
1058 error = relookup(ap->a_tdvp, &tvp, ap->a_tcnp);
1111 if (xp != NULL)
1112 vput(tvp);
1113 /*
1114 * doscheckpath() vput()'s dp,
1115 * so we have to do a relookup afterwards
1116 */
1117 error = doscheckpath(ip, dp);
1059 if (error)
1118 if (error)
1060 goto bad;
1061 tddep = VTODE(ap->a_tdvp);
1062 tdep = tvp ? VTODE(tvp) : NULL;
1119 goto out;
1120 if ((tcnp->cn_flags & SAVESTART) == 0)
1121 panic("msdosfs_rename: lost to startdir");
1122 error = relookup(tdvp, &tvp, tcnp);
1123 if (error)
1124 goto out;
1125 dp = VTODE(tdvp);
1126 xp = tvp ? VTODE(tvp) : NULL;
1063 }
1064
1127 }
1128
1065 /*
1066 * If the destination exists, then be sure its type (file or dir)
1067 * matches that of the source. And, if it is a directory make sure
1068 * it is empty. Then delete the destination.
1069 */
1070 if (tdep) {
1071 if (tdep->de_Attributes & ATTR_DIRECTORY) {
1072 if (!sourceisadirectory) {
1073 error = ENOTDIR;
1074 goto bad;
1075 }
1076 if (!dosdirempty(tdep)) {
1129 if (xp != NULL) {
1130 /*
1131 * Target must be empty if a directory and have no links
1132 * to it. Also, ensure source and target are compatible
1133 * (both directories, or both not directories).
1134 */
1135 if (xp->de_Attributes & ATTR_DIRECTORY) {
1136 if (!dosdirempty(xp)) {
1077 error = ENOTEMPTY;
1078 goto bad;
1079 }
1137 error = ENOTEMPTY;
1138 goto bad;
1139 }
1080 cache_purge(DETOV(tddep));
1081 } else { /* destination is file */
1082 if (sourceisadirectory) {
1083 error = EISDIR;
1140 if (!doingdirectory) {
1141 error = ENOTDIR;
1084 goto bad;
1085 }
1142 goto bad;
1143 }
1144 cache_purge(tdvp);
1145 } else if (doingdirectory) {
1146 error = EISDIR;
1147 goto bad;
1086 }
1148 }
1087 error = removede(tddep,tdep);
1149 error = removede(dp, xp);
1088 if (error)
1089 goto bad;
1150 if (error)
1151 goto bad;
1090 vput(ap->a_tvp);
1091 tdep = NULL;
1152 vput(tvp);
1153 xp = NULL;
1092 }
1093
1094 /*
1154 }
1155
1156 /*
1095 * If the source and destination are in the same directory then
1096 * just read in the directory entry, change the name in the
1097 * directory entry and write it back to disk.
1157 * Convert the filename in tcnp into a dos filename. We copy this
1158 * into the denode and directory entry for the destination
1159 * file/directory.
1098 */
1160 */
1099 if (newparent == 0) {
1100 /* tddep and fddep point to the same denode here */
1101 vn_lock(ap->a_fvp, LK_EXCLUSIVE, p); /* ap->a_fdvp is already locked */
1102 error = readep(fddep->de_pmp, fdep->de_dirclust,
1103 fdep->de_diroffset, &bp, &ep);
1104 if (error) {
1105 VOP_UNLOCK(ap->a_fvp, 0, p);
1106 goto bad;
1107 }
1108 bcopy(toname, ep->deName, 11);
1109 error = bwrite(bp);
1110 if (error) {
1111 VOP_UNLOCK(ap->a_fvp, 0, p);
1112 goto bad;
1113 }
1114 bcopy(toname, fdep->de_Name, 11); /* update denode */
1161 error = uniqdosname(VTODE(tdvp), tcnp, toname);
1162 if (error)
1163 goto abortit;
1164
1165 /*
1166 * Since from wasn't locked at various places above,
1167 * have to do a relookup here.
1168 */
1169 fcnp->cn_flags &= ~MODMASK;
1170 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1171 if ((fcnp->cn_flags & SAVESTART) == 0)
1172 panic("msdosfs_rename: lost from startdir");
1173 if (!newparent)
1174 VOP_UNLOCK(tdvp, 0, p);
1175 (void) relookup(fdvp, &fvp, fcnp);
1176 if (fvp == NULL) {
1115 /*
1177 /*
1116 * fdep locked fddep and tddep point to the same denode
1117 * which is locked tdep is NULL
1178 * From name has disappeared.
1118 */
1179 */
1180 if (doingdirectory)
1181 panic("rename: lost dir entry");
1182 vrele(ap->a_fvp);
1183 if (newparent)
1184 VOP_UNLOCK(tdvp, 0, p);
1185 vrele(tdvp);
1186 return 0;
1187 }
1188 xp = VTODE(fvp);
1189 zp = VTODE(fdvp);
1190 from_diroffset = zp->de_fndoffset;
1191
1192 /*
1193 * Ensure that the directory entry still exists and has not
1194 * changed till now. If the source is a file the entry may
1195 * have been unlinked or renamed. In either case there is
1196 * no further work to be done. If the source is a directory
1197 * then it cannot have been rmdir'ed or renamed; this is
1198 * prohibited by the DE_RENAME flag.
1199 */
1200 if (xp != ip) {
1201 if (doingdirectory)
1202 panic("rename: lost dir entry");
1203 vrele(ap->a_fvp);
1204 VOP_UNLOCK(fvp, 0, p);
1205 if (newparent)
1206 VOP_UNLOCK(fdvp, 0, p);
1207 xp = NULL;
1119 } else {
1208 } else {
1120 u_long dirsize = 0L;
1209 vrele(fvp);
1210 xp = NULL;
1121
1122 /*
1211
1212 /*
1123 * If the source and destination are in different
1124 * directories, then mark the entry in the source directory
1125 * as deleted and write a new entry in the destination
1126 * directory. Then move the denode to the correct hash
1213 * First write a new entry in the destination
1214 * directory and mark the entry in the source directory
1215 * as deleted. Then move the denode to the correct hash
1127 * chain for its new location in the filesystem. And, if
1128 * we moved a directory, then update its .. entry to point
1216 * chain for its new location in the filesystem. And, if
1217 * we moved a directory, then update its .. entry to point
1129 * to the new parent directory. If we moved a directory
1130 * will also insure that the directory entry on disk has a
1131 * filesize of zero.
1218 * to the new parent directory.
1132 */
1219 */
1133 vn_lock(ap->a_fvp, LK_EXCLUSIVE, p);
1134 bcopy(toname, fdep->de_Name, 11); /* update denode */
1135 if (fdep->de_Attributes & ATTR_DIRECTORY) {
1136 dirsize = fdep->de_FileSize;
1137 fdep->de_FileSize = 0;
1138 }
1139 error = createde(fdep, tddep, (struct denode **) 0);
1140 if (fdep->de_Attributes & ATTR_DIRECTORY) {
1141 fdep->de_FileSize = dirsize;
1142 }
1220 bcopy(ip->de_Name, oldname, 11);
1221 bcopy(toname, ip->de_Name, 11); /* update denode */
1222 dp->de_fndoffset = to_diroffset;
1223 dp->de_fndcnt = to_count;
1224 error = createde(ip, dp, (struct denode **)0, tcnp);
1143 if (error) {
1225 if (error) {
1144 /* should put back filename */
1145 VOP_UNLOCK(ap->a_fvp, 0, p);
1226 bcopy(oldname, ip->de_Name, 11);
1227 if (newparent)
1228 VOP_UNLOCK(fdvp, 0, p);
1229 VOP_UNLOCK(fvp, 0, p);
1146 goto bad;
1147 }
1230 goto bad;
1231 }
1148 vn_lock(ap->a_fdvp, LK_EXCLUSIVE, p);
1149 error = readep(fddep->de_pmp, fddep->de_fndclust,
1150 fddep->de_fndoffset, &bp, &ep);
1232 ip->de_refcnt++;
1233 zp->de_fndoffset = from_diroffset;
1234 error = removede(zp, ip);
1151 if (error) {
1235 if (error) {
1152 VOP_UNLOCK(ap->a_fvp, 0, p);
1153 VOP_UNLOCK(ap->a_fdvp, 0, p);
1236 /* XXX should really panic here, fs is corrupt */
1237 if (newparent)
1238 VOP_UNLOCK(fdvp, 0, p);
1239 VOP_UNLOCK(fvp, 0, p);
1154 goto bad;
1155 }
1240 goto bad;
1241 }
1156 ep->deName[0] = SLOT_DELETED;
1157 error = bwrite(bp);
1158 if (error) {
1159 VOP_UNLOCK(ap->a_fvp, 0, p);
1160 VOP_UNLOCK(ap->a_fdvp, 0, p);
1161 goto bad;
1242 if (!doingdirectory) {
1243 error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
1244 &ip->de_dirclust, 0);
1245 if (error) {
1246 /* XXX should really panic here, fs is corrupt */
1247 if (newparent)
1248 VOP_UNLOCK(fdvp, 0, p);
1249 VOP_UNLOCK(fvp, 0, p);
1250 goto bad;
1251 }
1252 if (ip->de_dirclust != MSDOSFSROOT)
1253 ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
1162 }
1254 }
1163 if (!sourceisadirectory) {
1164 fdep->de_dirclust = tddep->de_fndclust;
1165 fdep->de_diroffset = tddep->de_fndoffset;
1166 reinsert(fdep);
1167 }
1168 VOP_UNLOCK(ap->a_fdvp, 0, p);
1255 reinsert(ip);
1256 if (newparent)
1257 VOP_UNLOCK(fdvp, 0, p);
1169 }
1258 }
1170 /* fdep is still locked here */
1171
1172 /*
1173 * If we moved a directory to a new parent directory, then we must
1174 * fixup the ".." entry in the moved directory.
1175 */
1259
1260 /*
1261 * If we moved a directory to a new parent directory, then we must
1262 * fixup the ".." entry in the moved directory.
1263 */
1176 if (sourceisadirectory && newparent) {
1177 cn = fdep->de_StartCluster;
1264 if (doingdirectory && newparent) {
1265 cn = ip->de_StartCluster;
1178 if (cn == MSDOSFSROOT) {
1179 /* this should never happen */
1180 panic("msdosfs_rename(): updating .. in root directory?");
1266 if (cn == MSDOSFSROOT) {
1267 /* this should never happen */
1268 panic("msdosfs_rename(): updating .. in root directory?");
1181 } else {
1269 } else
1182 bn = cntobn(pmp, cn);
1270 bn = cntobn(pmp, cn);
1183 }
1184 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
1185 NOCRED, &bp);
1186 if (error) {
1271 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
1272 NOCRED, &bp);
1273 if (error) {
1187 /* should really panic here, fs is corrupt */
1188 VOP_UNLOCK(ap->a_fvp, 0, p);
1274 /* XXX should really panic here, fs is corrupt */
1275 brelse(bp);
1276 VOP_UNLOCK(fvp, 0, p);
1189 goto bad;
1190 }
1277 goto bad;
1278 }
1191 dotdotp = (struct direntry *) bp->b_data + 1;
1192 putushort(dotdotp->deStartCluster, tddep->de_StartCluster);
1279 dotdotp = (struct direntry *)bp->b_data + 1;
1280 putushort(dotdotp->deStartCluster, dp->de_StartCluster);
1281 if (FAT32(pmp))
1282 putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16);
1193 error = bwrite(bp);
1283 error = bwrite(bp);
1194 VOP_UNLOCK(ap->a_fvp, 0, p);
1195 if (error) {
1284 if (error) {
1196 /* should really panic here, fs is corrupt */
1285 /* XXX should really panic here, fs is corrupt */
1286 VOP_UNLOCK(fvp, 0, p);
1197 goto bad;
1198 }
1287 goto bad;
1288 }
1199 } else
1200 VOP_UNLOCK(ap->a_fvp, 0, p);
1201bad: ;
1202 vrele(DETOV(fdep));
1203 vrele(DETOV(fddep));
1204 if (tdep)
1205 vput(DETOV(tdep));
1206 if (tddep)
1207 vput(DETOV(tddep));
1208 return error;
1289 }
1290
1291 VOP_UNLOCK(fvp, 0, p);
1292bad:
1293 if (xp)
1294 vput(tvp);
1295 vput(tdvp);
1296out:
1297 ip->de_flag &= ~DE_RENAME;
1298 vrele(fdvp);
1299 vrele(fvp);
1300 return (error);
1301
1209}
1210
1211static struct {
1212 struct direntry dot;
1213 struct direntry dotdot;
1302}
1303
1304static struct {
1305 struct direntry dot;
1306 struct direntry dotdot;
1214} dosdirtemplate = {
1215 {
1216 ". ", " ", /* the . entry */
1217 ATTR_DIRECTORY, /* file attribute */
1218 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
1219 {210, 4}, {210, 4}, /* time and date */
1220 {0, 0}, /* startcluster */
1221 {0, 0, 0, 0}, /* filesize */
1222 },{
1223 ".. ", " ", /* the .. entry */
1224 ATTR_DIRECTORY, /* file attribute */
1225 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
1226 {210, 4}, {210, 4}, /* time and date */
1227 {0, 0}, /* startcluster */
1228 {0, 0, 0, 0}, /* filesize */
1229 }
1307} dosdirtemplate = {
1308 { ". ", " ", /* the . entry */
1309 ATTR_DIRECTORY, /* file attribute */
1310 0, /* reserved */
1311 0, { 0, 0 }, { 0, 0 }, /* create time & date */
1312 { 0, 0 }, /* access date */
1313 { 0, 0 }, /* high bits of start cluster */
1314 { 210, 4 }, { 210, 4 }, /* modify time & date */
1315 { 0, 0 }, /* startcluster */
1316 { 0, 0, 0, 0 } /* filesize */
1317 },
1318 { ".. ", " ", /* the .. entry */
1319 ATTR_DIRECTORY, /* file attribute */
1320 0, /* reserved */
1321 0, { 0, 0 }, { 0, 0 }, /* create time & date */
1322 { 0, 0 }, /* access date */
1323 { 0, 0 }, /* high bits of start cluster */
1324 { 210, 4 }, { 210, 4 }, /* modify time & date */
1325 { 0, 0 }, /* startcluster */
1326 { 0, 0, 0, 0 } /* filesize */
1327 }
1230};
1231
1232static int
1233msdosfs_mkdir(ap)
1234 struct vop_mkdir_args /* {
1235 struct vnode *a_dvp;
1236 struvt vnode **a_vpp;
1237 struvt componentname *a_cnp;
1238 struct vattr *a_vap;
1239 } */ *ap;
1240{
1328};
1329
1330static int
1331msdosfs_mkdir(ap)
1332 struct vop_mkdir_args /* {
1333 struct vnode *a_dvp;
1334 struvt vnode **a_vpp;
1335 struvt componentname *a_cnp;
1336 struct vattr *a_vap;
1337 } */ *ap;
1338{
1241 int bn;
1339 struct componentname *cnp = ap->a_cnp;
1340 struct denode ndirent;
1341 struct denode *dep;
1342 struct denode *pdep = VTODE(ap->a_dvp);
1242 int error;
1343 int error;
1243 u_long newcluster;
1244 struct denode *pdep;
1245 struct denode *ndep;
1344 int bn;
1345 u_long newcluster, pcl;
1246 struct direntry *denp;
1346 struct direntry *denp;
1247 struct denode ndirent;
1248 struct msdosfsmount *pmp;
1347 struct msdosfsmount *pmp = pdep->de_pmp;
1249 struct buf *bp;
1250 struct timespec ts;
1348 struct buf *bp;
1349 struct timespec ts;
1251 u_short dDate, dTime;
1252
1350
1253 pdep = VTODE(ap->a_dvp);
1254
1255 /*
1256 * If this is the root directory and there is no space left we
1257 * can't do anything. This is because the root directory can not
1258 * change size.
1259 */
1351 /*
1352 * If this is the root directory and there is no space left we
1353 * can't do anything. This is because the root directory can not
1354 * change size.
1355 */
1260 if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndclust == (u_long)-1) {
1261 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1262 vput(ap->a_dvp);
1263 return ENOSPC;
1356 if (pdep->de_StartCluster == MSDOSFSROOT
1357 && pdep->de_fndoffset >= pdep->de_FileSize) {
1358 error = ENOSPC;
1359 goto bad2;
1264 }
1265
1360 }
1361
1266 pmp = pdep->de_pmp;
1267
1268 /*
1269 * Allocate a cluster to hold the about to be created directory.
1270 */
1271 error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
1362 /*
1363 * Allocate a cluster to hold the about to be created directory.
1364 */
1365 error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
1272 if (error) {
1273 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1274 vput(ap->a_dvp);
1275 return error;
1276 }
1366 if (error)
1367 goto bad2;
1277
1368
1369 bzero(&ndirent, sizeof(ndirent));
1370 ndirent.de_pmp = pmp;
1371 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
1372 TIMEVAL_TO_TIMESPEC(&time, &ts);
1373 DETIMES(&ndirent, &ts, &ts, &ts);
1374
1278 /*
1279 * Now fill the cluster with the "." and ".." entries. And write
1280 * the cluster to disk. This way it is there for the parent
1281 * directory to be pointing at if there were a crash.
1282 */
1283 bn = cntobn(pmp, newcluster);
1284 /* always succeeds */
1285 bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
1286 bzero(bp->b_data, pmp->pm_bpcluster);
1287 bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
1375 /*
1376 * Now fill the cluster with the "." and ".." entries. And write
1377 * the cluster to disk. This way it is there for the parent
1378 * directory to be pointing at if there were a crash.
1379 */
1380 bn = cntobn(pmp, newcluster);
1381 /* always succeeds */
1382 bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
1383 bzero(bp->b_data, pmp->pm_bpcluster);
1384 bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
1288 denp = (struct direntry *) bp->b_data;
1289 putushort(denp->deStartCluster, newcluster);
1290 TIMEVAL_TO_TIMESPEC(&time, &ts);
1291 unix2dostime(&ts, &dDate, &dTime);
1292 putushort(denp->deDate, dDate);
1293 putushort(denp->deTime, dTime);
1294 denp++;
1295 putushort(denp->deStartCluster, pdep->de_StartCluster);
1296 putushort(denp->deDate, dDate);
1297 putushort(denp->deTime, dTime);
1298 error = bwrite(bp);
1299 if (error) {
1300 clusterfree(pmp, newcluster, NULL);
1301 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1302 vput(ap->a_dvp);
1303 return error;
1385 denp = (struct direntry *)bp->b_data;
1386 putushort(denp[0].deStartCluster, newcluster);
1387 putushort(denp[0].deCDate, ndirent.de_CDate);
1388 putushort(denp[0].deCTime, ndirent.de_CTime);
1389 denp[0].deCHundredth = ndirent.de_CHun;
1390 putushort(denp[0].deADate, ndirent.de_ADate);
1391 putushort(denp[0].deMDate, ndirent.de_MDate);
1392 putushort(denp[0].deMTime, ndirent.de_MTime);
1393 pcl = pdep->de_StartCluster;
1394 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
1395 pcl = 0;
1396 putushort(denp[1].deStartCluster, pcl);
1397 putushort(denp[1].deCDate, ndirent.de_CDate);
1398 putushort(denp[1].deCTime, ndirent.de_CTime);
1399 denp[1].deCHundredth = ndirent.de_CHun;
1400 putushort(denp[1].deADate, ndirent.de_ADate);
1401 putushort(denp[1].deMDate, ndirent.de_MDate);
1402 putushort(denp[1].deMTime, ndirent.de_MTime);
1403 if (FAT32(pmp)) {
1404 putushort(denp[0].deHighClust, newcluster >> 16);
1405 putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
1304 }
1305
1406 }
1407
1408 error = bwrite(bp);
1409 if (error)
1410 goto bad;
1411
1306 /*
1307 * Now build up a directory entry pointing to the newly allocated
1308 * cluster. This will be written to an empty slot in the parent
1309 * directory.
1310 */
1412 /*
1413 * Now build up a directory entry pointing to the newly allocated
1414 * cluster. This will be written to an empty slot in the parent
1415 * directory.
1416 */
1311 ndep = &ndirent;
1312 bzero(ndep, sizeof(*ndep));
1313 unix2dosfn((u_char *)ap->a_cnp->cn_nameptr,
1314 ndep->de_Name, ap->a_cnp->cn_namelen);
1315 TIMEVAL_TO_TIMESPEC(&time, &ts);
1316 unix2dostime(&ts, &ndep->de_Date, &ndep->de_Time);
1317 ndep->de_StartCluster = newcluster;
1318 ndep->de_Attributes = ATTR_DIRECTORY;
1319
1320 error = createde(ndep, pdep, &ndep);
1321 if (error) {
1322 clusterfree(pmp, newcluster, NULL);
1323 } else {
1324 *ap->a_vpp = DETOV(ndep);
1325 }
1326 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1327#ifdef MSDOSFS_DEBUG
1328 printf("msdosfs_mkdir(): vput(%08x)\n", ap->a_dvp);
1417#ifdef DIAGNOSTIC
1418 if ((cnp->cn_flags & HASBUF) == 0)
1419 panic("msdosfs_mkdir: no name");
1329#endif
1420#endif
1421 error = uniqdosname(pdep, cnp, ndirent.de_Name);
1422 if (error)
1423 goto bad;
1424
1425 ndirent.de_Attributes = ATTR_DIRECTORY;
1426 ndirent.de_StartCluster = newcluster;
1427 ndirent.de_FileSize = 0;
1428 ndirent.de_dev = pdep->de_dev;
1429 ndirent.de_devvp = pdep->de_devvp;
1430 error = createde(&ndirent, pdep, &dep, cnp);
1431 if (error)
1432 goto bad;
1433 if ((cnp->cn_flags & SAVESTART) == 0)
1434 zfree(namei_zone, cnp->cn_pnbuf);
1330 vput(ap->a_dvp);
1435 vput(ap->a_dvp);
1331 return error;
1436 *ap->a_vpp = DETOV(dep);
1437 return (0);
1438
1439bad:
1440 clusterfree(pmp, newcluster, NULL);
1441bad2:
1442 zfree(namei_zone, cnp->cn_pnbuf);
1443 vput(ap->a_dvp);
1444 return (error);
1332}
1333
1334static int
1335msdosfs_rmdir(ap)
1336 struct vop_rmdir_args /* {
1337 struct vnode *a_dvp;
1338 struct vnode *a_vp;
1339 struct componentname *a_cnp;
1340 } */ *ap;
1341{
1445}
1446
1447static int
1448msdosfs_rmdir(ap)
1449 struct vop_rmdir_args /* {
1450 struct vnode *a_dvp;
1451 struct vnode *a_vp;
1452 struct componentname *a_cnp;
1453 } */ *ap;
1454{
1342 struct denode *ddep;
1343 struct denode *dep;
1344 int error = 0;
1455 register struct vnode *vp = ap->a_vp;
1456 register struct vnode *dvp = ap->a_dvp;
1457 register struct componentname *cnp = ap->a_cnp;
1458 register struct denode *ip, *dp;
1459 int error;
1460
1461 ip = VTODE(vp);
1462 dp = VTODE(dvp);
1345
1463
1346 ddep = VTODE(ap->a_dvp); /* parent dir of dir to delete */
1347 dep = VTODE(ap->a_vp);/* directory to delete */
1348
1349 /*
1464 /*
1350 * Be sure the directory being deleted is empty.
1465 * Verify the directory is empty (and valid).
1466 * (Rmdir ".." won't be valid since
1467 * ".." will contain a reference to
1468 * the current directory and thus be
1469 * non-empty.)
1351 */
1470 */
1352 if (dosdirempty(dep) == 0) {
1471 error = 0;
1472 if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
1353 error = ENOTEMPTY;
1354 goto out;
1355 }
1473 error = ENOTEMPTY;
1474 goto out;
1475 }
1356
1357 /*
1358 * Delete the entry from the directory. For dos filesystems this
1359 * gets rid of the directory entry on disk, the in memory copy
1360 * still exists but the de_refcnt is <= 0. This prevents it from
1361 * being found by deget(). When the vput() on dep is done we give
1362 * up access and eventually msdosfs_reclaim() will be called which
1363 * will remove it from the denode cache.
1364 */
1476 /*
1477 * Delete the entry from the directory. For dos filesystems this
1478 * gets rid of the directory entry on disk, the in memory copy
1479 * still exists but the de_refcnt is <= 0. This prevents it from
1480 * being found by deget(). When the vput() on dep is done we give
1481 * up access and eventually msdosfs_reclaim() will be called which
1482 * will remove it from the denode cache.
1483 */
1365 error = removede(ddep,dep);
1484 error = removede(dp, ip);
1366 if (error)
1367 goto out;
1485 if (error)
1486 goto out;
1368
1369 /*
1370 * This is where we decrement the link count in the parent
1371 * directory. Since dos filesystems don't do this we just purge
1372 * the name cache and let go of the parent directory denode.
1373 */
1487 /*
1488 * This is where we decrement the link count in the parent
1489 * directory. Since dos filesystems don't do this we just purge
1490 * the name cache and let go of the parent directory denode.
1491 */
1374 cache_purge(DETOV(ddep));
1375 vput(ap->a_dvp);
1376 ap->a_dvp = NULL;
1377
1492 cache_purge(dvp);
1493 vput(dvp);
1494 dvp = NULL;
1378 /*
1379 * Truncate the directory that is being deleted.
1380 */
1495 /*
1496 * Truncate the directory that is being deleted.
1497 */
1381 error = detrunc(dep, (u_long) 0, IO_SYNC, NOCRED, NULL);
1382 cache_purge(DETOV(dep));
1383
1384out: ;
1385 if (ap->a_dvp)
1386 vput(ap->a_dvp);
1387 vput(ap->a_vp);
1388 return error;
1498 error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
1499 cache_purge(vp);
1500out:
1501 if (dvp)
1502 vput(dvp);
1503 vput(vp);
1504 return (error);
1389}
1390
1391/*
1392 * DOS filesystems don't know what symlinks are.
1393 */
1394static int
1395msdosfs_symlink(ap)
1396 struct vop_symlink_args /* {
1397 struct vnode *a_dvp;
1398 struct vnode **a_vpp;
1399 struct componentname *a_cnp;
1400 struct vattr *a_vap;
1401 char *a_target;
1402 } */ *ap;
1403{
1404 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1505}
1506
1507/*
1508 * DOS filesystems don't know what symlinks are.
1509 */
1510static int
1511msdosfs_symlink(ap)
1512 struct vop_symlink_args /* {
1513 struct vnode *a_dvp;
1514 struct vnode **a_vpp;
1515 struct componentname *a_cnp;
1516 struct vattr *a_vap;
1517 char *a_target;
1518 } */ *ap;
1519{
1520 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1521 /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
1405 vput(ap->a_dvp);
1522 vput(ap->a_dvp);
1406 return EINVAL;
1523 return (EOPNOTSUPP);
1407}
1408
1524}
1525
1409/*
1410 * Dummy dirents to simulate the "." and ".." entries of the root directory
1411 * in a dos filesystem. Dos doesn't provide these. Note that each entry
1412 * must be the same size as a dos directory entry (32 bytes).
1413 */
1414static struct dos_dirent {
1415 u_long d_fileno;
1416 u_short d_reclen;
1417 u_char d_type;
1418 u_char d_namlen;
1419 u_char d_name[24];
1420} rootdots[2] = {
1421
1422 {
1423 1, /* d_fileno */
1424 sizeof(struct direntry), /* d_reclen */
1425 DT_DIR, /* d_type */
1426 1, /* d_namlen */
1427 "." /* d_name */
1428 },
1429 {
1430 1, /* d_fileno */
1431 sizeof(struct direntry), /* d_reclen */
1432 DT_DIR, /* d_type */
1433 2, /* d_namlen */
1434 ".." /* d_name */
1435 }
1436};
1437
1438static int
1439msdosfs_readdir(ap)
1440 struct vop_readdir_args /* {
1441 struct vnode *a_vp;
1442 struct uio *a_uio;
1443 struct ucred *a_cred;
1444 int *a_eofflag;
1445 int *a_ncookies;
1446 u_long **a_cookies;
1447 } */ *ap;
1448{
1449 int error = 0;
1450 int diff;
1526static int
1527msdosfs_readdir(ap)
1528 struct vop_readdir_args /* {
1529 struct vnode *a_vp;
1530 struct uio *a_uio;
1531 struct ucred *a_cred;
1532 int *a_eofflag;
1533 int *a_ncookies;
1534 u_long **a_cookies;
1535 } */ *ap;
1536{
1537 int error = 0;
1538 int diff;
1451 char pushout;
1452 long n;
1539 long n;
1540 int blsize;
1453 long on;
1454 long lost;
1455 long count;
1456 u_long cn;
1457 u_long fileno;
1541 long on;
1542 long lost;
1543 long count;
1544 u_long cn;
1545 u_long fileno;
1546 u_long dirsperblk;
1458 long bias = 0;
1547 long bias = 0;
1459 daddr_t bn;
1460 daddr_t lbn;
1548 daddr_t bn, lbn;
1461 struct buf *bp;
1462 struct denode *dep = VTODE(ap->a_vp);
1463 struct msdosfsmount *pmp = dep->de_pmp;
1464 struct direntry *dentp;
1549 struct buf *bp;
1550 struct denode *dep = VTODE(ap->a_vp);
1551 struct msdosfsmount *pmp = dep->de_pmp;
1552 struct direntry *dentp;
1465 struct dirent *prev;
1466 struct dirent *crnt;
1467 u_char dirbuf[512]; /* holds converted dos directories */
1553 struct dirent dirbuf;
1468 struct uio *uio = ap->a_uio;
1554 struct uio *uio = ap->a_uio;
1469 off_t off;
1555 u_long *cookies = NULL;
1470 int ncookies = 0;
1556 int ncookies = 0;
1557 off_t offset, off;
1558 int chksum = -1;
1471
1472#ifdef MSDOSFS_DEBUG
1559
1560#ifdef MSDOSFS_DEBUG
1473 printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
1474 ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
1561 printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
1562 ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
1475#endif
1476
1477 /*
1478 * msdosfs_readdir() won't operate properly on regular files since
1479 * it does i/o only with the the filesystem vnode, and hence can
1480 * retrieve the wrong block from the buffer cache for a plain file.
1481 * So, fail attempts to readdir() on a plain file.
1482 */
1483 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
1563#endif
1564
1565 /*
1566 * msdosfs_readdir() won't operate properly on regular files since
1567 * it does i/o only with the the filesystem vnode, and hence can
1568 * retrieve the wrong block from the buffer cache for a plain file.
1569 * So, fail attempts to readdir() on a plain file.
1570 */
1571 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
1484 return ENOTDIR;
1572 return (ENOTDIR);
1485
1486 /*
1573
1574 /*
1575 * To be safe, initialize dirbuf
1576 */
1577 bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
1578
1579 /*
1487 * If the user buffer is smaller than the size of one dos directory
1488 * entry or the file offset is not a multiple of the size of a
1489 * directory entry, then we fail the read.
1490 */
1491 count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
1580 * If the user buffer is smaller than the size of one dos directory
1581 * entry or the file offset is not a multiple of the size of a
1582 * directory entry, then we fail the read.
1583 */
1584 count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
1492 lost = uio->uio_resid - count;
1585 offset = uio->uio_offset;
1493 if (count < sizeof(struct direntry) ||
1586 if (count < sizeof(struct direntry) ||
1494 (uio->uio_offset & (sizeof(struct direntry) - 1)))
1495 return EINVAL;
1587 (offset & (sizeof(struct direntry) - 1)))
1588 return (EINVAL);
1589 lost = uio->uio_resid - count;
1496 uio->uio_resid = count;
1590 uio->uio_resid = count;
1497 uio->uio_iov->iov_len = count;
1498 off = uio->uio_offset;
1499
1591
1592 if (ap->a_ncookies) {
1593 ncookies = uio->uio_resid / 16;
1594 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1595 M_WAITOK);
1596 *ap->a_cookies = cookies;
1597 *ap->a_ncookies = ncookies;
1598 }
1599
1600 dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
1601
1500 /*
1501 * If they are reading from the root directory then, we simulate
1502 * the . and .. entries since these don't exist in the root
1503 * directory. We also set the offset bias to make up for having to
1504 * simulate these entries. By this I mean that at file offset 64 we
1505 * read the first entry in the root directory that lives on disk.
1506 */
1602 /*
1603 * If they are reading from the root directory then, we simulate
1604 * the . and .. entries since these don't exist in the root
1605 * directory. We also set the offset bias to make up for having to
1606 * simulate these entries. By this I mean that at file offset 64 we
1607 * read the first entry in the root directory that lives on disk.
1608 */
1507 if (dep->de_StartCluster == MSDOSFSROOT) {
1508 /*
1509 * printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
1510 * uio->uio_offset);
1511 */
1609 if (dep->de_StartCluster == MSDOSFSROOT
1610 || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
1611#if 0
1612 printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
1613 offset);
1614#endif
1512 bias = 2 * sizeof(struct direntry);
1615 bias = 2 * sizeof(struct direntry);
1513 if (uio->uio_offset < 2 * sizeof(struct direntry)) {
1514 if (uio->uio_offset
1515 && uio->uio_offset != sizeof(struct direntry)) {
1516 error = EINVAL;
1517 goto out;
1616 if (offset < bias) {
1617 for (n = (int)offset / sizeof(struct direntry);
1618 n < 2; n++) {
1619 if (FAT32(pmp))
1620 dirbuf.d_fileno = cntobn(pmp,
1621 pmp->pm_rootdirblk)
1622 * dirsperblk;
1623 else
1624 dirbuf.d_fileno = 1;
1625 dirbuf.d_type = DT_DIR;
1626 switch (n) {
1627 case 0:
1628 dirbuf.d_namlen = 1;
1629 strcpy(dirbuf.d_name, ".");
1630 break;
1631 case 1:
1632 dirbuf.d_namlen = 2;
1633 strcpy(dirbuf.d_name, "..");
1634 break;
1635 }
1636 dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
1637 if (uio->uio_resid < dirbuf.d_reclen)
1638 goto out;
1639 error = uiomove((caddr_t) &dirbuf,
1640 dirbuf.d_reclen, uio);
1641 if (error)
1642 goto out;
1643 if (cookies) {
1644 *cookies++ = offset;
1645 if (--ncookies <= 0)
1646 goto out;
1647 }
1648 offset += sizeof(struct direntry);
1518 }
1649 }
1519 n = 1;
1520 if (!uio->uio_offset) {
1521 n = 2;
1522 ncookies++;
1523 }
1524 ncookies++;
1525 error = uiomove((char *) rootdots + uio->uio_offset,
1526 n * sizeof(struct direntry), uio);
1527 }
1528 }
1650 }
1651 }
1529 while (!error && uio->uio_resid > 0) {
1530 lbn = (uio->uio_offset - bias) >> pmp->pm_cnshift;
1531 on = (uio->uio_offset - bias) & pmp->pm_crbomask;
1532 n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
1533 diff = dep->de_FileSize - (uio->uio_offset - bias);
1652
1653 off = offset;
1654 while (uio->uio_resid > 0) {
1655 lbn = de_cluster(pmp, offset - bias);
1656 on = (offset - bias) & pmp->pm_crbomask;
1657 n = min(pmp->pm_bpcluster - on, uio->uio_resid);
1658 diff = dep->de_FileSize - (offset - bias);
1534 if (diff <= 0)
1535 break;
1659 if (diff <= 0)
1660 break;
1536 if (diff < n)
1537 n = diff;
1538 error = pcbmap(dep, lbn, &bn, &cn);
1661 n = min(n, diff);
1662 error = pcbmap(dep, lbn, &bn, &cn, &blsize);
1539 if (error)
1540 break;
1663 if (error)
1664 break;
1541 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
1542 n = min(n, pmp->pm_bpcluster - bp->b_resid);
1665 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
1543 if (error) {
1544 brelse(bp);
1666 if (error) {
1667 brelse(bp);
1545 return error;
1668 return (error);
1546 }
1669 }
1670 n = min(n, blsize - bp->b_resid);
1547
1548 /*
1671
1672 /*
1549 * code to convert from dos directory entries to ufs
1550 * directory entries
1673 * Convert from dos directory entries to fs-independent
1674 * directory entries.
1551 */
1675 */
1552 pushout = 0;
1553 dentp = (struct direntry *)(bp->b_data + on);
1554 prev = 0;
1555 crnt = (struct dirent *) dirbuf;
1556 while ((char *) dentp < bp->b_data + on + n) {
1676 for (dentp = (struct direntry *)(bp->b_data + on);
1677 (char *)dentp < bp->b_data + on + n;
1678 dentp++, offset += sizeof(struct direntry)) {
1679#if 0
1680 printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
1681 dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
1682#endif
1557 /*
1683 /*
1558 * printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
1559 * dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
1684 * If this is an unused entry, we can stop.
1560 */
1685 */
1686 if (dentp->deName[0] == SLOT_EMPTY) {
1687 brelse(bp);
1688 goto out;
1689 }
1561 /*
1690 /*
1562 * If we have an empty entry or a slot from a
1563 * deleted file, or a volume label entry just
1564 * concatenate its space onto the end of the
1565 * previous entry or, manufacture an empty entry if
1566 * there is no previous entry.
1691 * Skip deleted entries.
1567 */
1692 */
1568 if (dentp->deName[0] == SLOT_EMPTY ||
1569 dentp->deName[0] == SLOT_DELETED ||
1570 (dentp->deAttributes & ATTR_VOLUME)) {
1571 if (prev) {
1572 prev->d_reclen += sizeof(struct direntry);
1573 } else {
1574 prev = crnt;
1575 prev->d_fileno = 0;
1576 prev->d_reclen = sizeof(struct direntry);
1577 prev->d_type = DT_UNKNOWN;
1578 prev->d_namlen = 0;
1579 prev->d_name[0] = 0;
1580 ncookies++;
1581 }
1582 } else {
1583 /*
1584 * this computation of d_fileno must match
1585 * the computation of va_fileid in
1586 * msdosfs_getattr
1587 */
1588 if (dentp->deAttributes & ATTR_DIRECTORY) {
1589 /* if this is the root directory */
1590 fileno = getushort(dentp->deStartCluster);
1591 if (fileno == MSDOSFSROOT)
1592 fileno = 1;
1593 } else {
1594 /*
1595 * if the file's dirent lives in
1596 * root dir
1597 */
1598 if ((fileno = cn) == MSDOSFSROOT)
1599 fileno = 1;
1600 fileno = (fileno << 16) |
1601 ((dentp - (struct direntry *) bp->b_data) & 0xffff);
1602 }
1603 crnt->d_fileno = fileno;
1604 crnt->d_reclen = sizeof(struct direntry);
1605 crnt->d_type = (dentp->deAttributes & ATTR_DIRECTORY)
1606 ? DT_DIR : DT_REG;
1607 crnt->d_namlen = dos2unixfn(dentp->deName,
1608 (u_char *)crnt->d_name);
1609 /*
1610 * printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n",
1611 * crnt->d_name, crnt->d_fileno, dentp->deAttributes,
1612 * dentp->deStartCluster);
1613 */
1614 prev = crnt;
1615 ncookies++;
1693 if (dentp->deName[0] == SLOT_DELETED) {
1694 chksum = -1;
1695 continue;
1616 }
1696 }
1617 dentp++;
1618
1697
1619 crnt = (struct dirent *) ((char *) crnt + sizeof(struct direntry));
1620 pushout = 1;
1698 /*
1699 * Handle Win95 long directory entries
1700 */
1701 if (dentp->deAttributes == ATTR_WIN95) {
1702 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
1703 continue;
1704 chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum);
1705 continue;
1706 }
1621
1622 /*
1707
1708 /*
1623 * If our intermediate buffer is full then copy its
1624 * contents to user space. I would just use the
1625 * buffer the buf header points to but, I'm afraid
1626 * that when we brelse() it someone else might find
1627 * it in the cache and think its contents are
1628 * valid. Maybe there is a way to invalidate the
1629 * buffer before brelse()'ing it.
1709 * Skip volume labels
1630 */
1710 */
1631 if ((u_char *) crnt >= &dirbuf[sizeof dirbuf]) {
1632 pushout = 0;
1633 error = uiomove(dirbuf, sizeof(dirbuf), uio);
1634 if (error)
1635 break;
1636 prev = 0;
1637 crnt = (struct dirent *) dirbuf;
1711 if (dentp->deAttributes & ATTR_VOLUME) {
1712 chksum = -1;
1713 continue;
1638 }
1714 }
1715 /*
1716 * This computation of d_fileno must match
1717 * the computation of va_fileid in
1718 * msdosfs_getattr.
1719 */
1720 if (dentp->deAttributes & ATTR_DIRECTORY) {
1721 fileno = getushort(dentp->deStartCluster);
1722 if (FAT32(pmp))
1723 fileno |= getushort(dentp->deHighClust) << 16;
1724 /* if this is the root directory */
1725 if (fileno == MSDOSFSROOT)
1726 if (FAT32(pmp))
1727 fileno = cntobn(pmp,
1728 pmp->pm_rootdirblk)
1729 * dirsperblk;
1730 else
1731 fileno = 1;
1732 else
1733 fileno = cntobn(pmp, fileno) * dirsperblk;
1734 dirbuf.d_fileno = fileno;
1735 dirbuf.d_type = DT_DIR;
1736 } else {
1737 dirbuf.d_fileno = offset / sizeof(struct direntry);
1738 dirbuf.d_type = DT_REG;
1739 }
1740 if (chksum != winChksum(dentp->deName))
1741 dirbuf.d_namlen = dos2unixfn(dentp->deName,
1742 (u_char *)dirbuf.d_name,
1743 pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
1744 else
1745 dirbuf.d_name[dirbuf.d_namlen] = 0;
1746 chksum = -1;
1747 dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
1748 if (uio->uio_resid < dirbuf.d_reclen) {
1749 brelse(bp);
1750 goto out;
1751 }
1752 error = uiomove((caddr_t) &dirbuf,
1753 dirbuf.d_reclen, uio);
1754 if (error) {
1755 brelse(bp);
1756 goto out;
1757 }
1758 if (cookies) {
1759 *cookies++ = off;
1760 off = offset + sizeof(struct direntry);
1761 if (--ncookies <= 0) {
1762 brelse(bp);
1763 goto out;
1764 }
1765 }
1639 }
1766 }
1640 if (pushout) {
1641 pushout = 0;
1642 error = uiomove(dirbuf, (char *) crnt - (char *) dirbuf,
1643 uio);
1644 }
1645
1646#if 0
1647 /*
1648 * If we have read everything from this block or have read
1649 * to end of file then we are done with this block. Mark
1650 * it to say the buffer can be reused if need be.
1651 */
1652 if (n + on == pmp->pm_bpcluster ||
1653 (uio->uio_offset - bias) == dep->de_FileSize)
1654 bp->b_flags |= B_AGE;
1655#endif /* if 0 */
1656 brelse(bp);
1767 brelse(bp);
1657 if (n == 0)
1658 break;
1659 }
1768 }
1660out: ;
1769out:
1770 /* Subtract unused cookies */
1771 if (ap->a_ncookies)
1772 *ap->a_ncookies -= ncookies;
1773
1774 uio->uio_offset = offset;
1661 uio->uio_resid += lost;
1775 uio->uio_resid += lost;
1662 if (!error && ap->a_ncookies != NULL) {
1663 struct dirent* dpStart;
1664 struct dirent* dpEnd;
1665 struct dirent* dp;
1666 u_long *cookies;
1667 u_long *cookiep;
1668
1776
1669 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1670 panic("msdosfs_readdir: unexpected uio from NFS server");
1671 dpStart = (struct dirent *)
1672 (uio->uio_iov->iov_base - (uio->uio_offset - off));
1673 dpEnd = (struct dirent *) uio->uio_iov->iov_base;
1674 cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
1675 for (dp = dpStart, cookiep = cookies;
1676 dp < dpEnd;
1677 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
1678 off += dp->d_reclen;
1679 *cookiep++ = (u_long) off;
1680 }
1681 *ap->a_ncookies = ncookies;
1682 *ap->a_cookies = cookies;
1683 }
1684
1685 /*
1686 * Set the eofflag (NFS uses it)
1687 */
1688 if (ap->a_eofflag)
1777 /*
1778 * Set the eofflag (NFS uses it)
1779 */
1780 if (ap->a_eofflag)
1689 if (dep->de_FileSize - (uio->uio_offset - bias) <= 0)
1781 if (dep->de_FileSize - (offset - bias) <= 0)
1690 *ap->a_eofflag = 1;
1691 else
1692 *ap->a_eofflag = 0;
1693
1782 *ap->a_eofflag = 1;
1783 else
1784 *ap->a_eofflag = 0;
1785
1694 return error;
1786 return (error);
1695}
1696
1697static int
1698msdosfs_abortop(ap)
1699 struct vop_abortop_args /* {
1700 struct vnode *a_dvp;
1701 struct componentname *a_cnp;
1702 } */ *ap;
1703{
1704 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1705 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1787}
1788
1789static int
1790msdosfs_abortop(ap)
1791 struct vop_abortop_args /* {
1792 struct vnode *a_dvp;
1793 struct componentname *a_cnp;
1794 } */ *ap;
1795{
1796 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1797 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1706 return 0;
1798 return (0);
1707}
1708
1709/*
1710 * vp - address of vnode file the file
1711 * bn - which cluster we are interested in mapping to a filesystem block number.
1712 * vpp - returns the vnode for the block special file holding the filesystem
1713 * containing the file of interest
1714 * bnp - address of where to return the filesystem relative block number

--- 5 unchanged lines hidden (view full) ---

1720 daddr_t a_bn;
1721 struct vnode **a_vpp;
1722 daddr_t *a_bnp;
1723 int *a_runp;
1724 int *a_runb;
1725 } */ *ap;
1726{
1727 struct denode *dep = VTODE(ap->a_vp);
1799}
1800
1801/*
1802 * vp - address of vnode file the file
1803 * bn - which cluster we are interested in mapping to a filesystem block number.
1804 * vpp - returns the vnode for the block special file holding the filesystem
1805 * containing the file of interest
1806 * bnp - address of where to return the filesystem relative block number

--- 5 unchanged lines hidden (view full) ---

1812 daddr_t a_bn;
1813 struct vnode **a_vpp;
1814 daddr_t *a_bnp;
1815 int *a_runp;
1816 int *a_runb;
1817 } */ *ap;
1818{
1819 struct denode *dep = VTODE(ap->a_vp);
1820 struct msdosfsmount *pmp = dep->de_pmp;
1728
1729 if (ap->a_vpp != NULL)
1730 *ap->a_vpp = dep->de_devvp;
1731 if (ap->a_bnp == NULL)
1821
1822 if (ap->a_vpp != NULL)
1823 *ap->a_vpp = dep->de_devvp;
1824 if (ap->a_bnp == NULL)
1732 return 0;
1825 return (0);
1733 if (ap->a_runp) {
1734 /*
1735 * Sequential clusters should be counted here.
1736 */
1737 *ap->a_runp = 0;
1738 }
1739 if (ap->a_runb) {
1740 *ap->a_runb = 0;
1741 }
1826 if (ap->a_runp) {
1827 /*
1828 * Sequential clusters should be counted here.
1829 */
1830 *ap->a_runp = 0;
1831 }
1832 if (ap->a_runb) {
1833 *ap->a_runb = 0;
1834 }
1742 return pcbmap(dep, ap->a_bn, ap->a_bnp, 0);
1835 return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
1743}
1744
1745static int
1746msdosfs_strategy(ap)
1747 struct vop_strategy_args /* {
1748 struct buf *a_bp;
1749 } */ *ap;
1750{

--- 6 unchanged lines hidden (view full) ---

1757 panic("msdosfs_strategy: spec");
1758 /*
1759 * If we don't already know the filesystem relative block number
1760 * then get it using pcbmap(). If pcbmap() returns the block
1761 * number as -1 then we've got a hole in the file. DOS filesystems
1762 * don't allow files with holes, so we shouldn't ever see this.
1763 */
1764 if (bp->b_blkno == bp->b_lblkno) {
1836}
1837
1838static int
1839msdosfs_strategy(ap)
1840 struct vop_strategy_args /* {
1841 struct buf *a_bp;
1842 } */ *ap;
1843{

--- 6 unchanged lines hidden (view full) ---

1850 panic("msdosfs_strategy: spec");
1851 /*
1852 * If we don't already know the filesystem relative block number
1853 * then get it using pcbmap(). If pcbmap() returns the block
1854 * number as -1 then we've got a hole in the file. DOS filesystems
1855 * don't allow files with holes, so we shouldn't ever see this.
1856 */
1857 if (bp->b_blkno == bp->b_lblkno) {
1765 error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0);
1766 if (error)
1767 bp->b_blkno = -1;
1768 if (bp->b_blkno == -1)
1769 clrbuf(bp);
1858 error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
1859 &bp->b_blkno, 0, 0);
1860 if (error) {
1861 bp->b_error = error;
1862 bp->b_flags |= B_ERROR;
1863 biodone(bp);
1864 return (error);
1865 }
1866 if ((long)bp->b_blkno == -1)
1867 vfs_bio_clrbuf(bp);
1770 }
1771 if (bp->b_blkno == -1) {
1772 biodone(bp);
1868 }
1869 if (bp->b_blkno == -1) {
1870 biodone(bp);
1773 return error;
1871 return (0);
1774 }
1872 }
1775#ifdef DIAGNOSTIC
1776#endif
1777 /*
1778 * Read/write the block from/to the disk that contains the desired
1779 * file block.
1780 */
1781 vp = dep->de_devvp;
1782 bp->b_dev = vp->v_rdev;
1783 VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
1873 /*
1874 * Read/write the block from/to the disk that contains the desired
1875 * file block.
1876 */
1877 vp = dep->de_devvp;
1878 bp->b_dev = vp->v_rdev;
1879 VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
1784 return 0;
1880 return (0);
1785}
1786
1787static int
1788msdosfs_print(ap)
1789 struct vop_print_args /* {
1790 struct vnode *vp;
1791 } */ *ap;
1792{
1793 struct denode *dep = VTODE(ap->a_vp);
1794
1795 printf(
1796 "tag VT_MSDOSFS, startcluster %d, dircluster %ld, diroffset %ld ",
1797 dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
1798 printf(" dev %d, %d", major(dep->de_dev), minor(dep->de_dev));
1799 lockmgr_printinfo(&dep->de_lock);
1800 printf("\n");
1881}
1882
1883static int
1884msdosfs_print(ap)
1885 struct vop_print_args /* {
1886 struct vnode *vp;
1887 } */ *ap;
1888{
1889 struct denode *dep = VTODE(ap->a_vp);
1890
1891 printf(
1892 "tag VT_MSDOSFS, startcluster %d, dircluster %ld, diroffset %ld ",
1893 dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
1894 printf(" dev %d, %d", major(dep->de_dev), minor(dep->de_dev));
1895 lockmgr_printinfo(&dep->de_lock);
1896 printf("\n");
1801 return 0;
1897 return (0);
1802}
1803
1804static int
1805msdosfs_pathconf(ap)
1806 struct vop_pathconf_args /* {
1807 struct vnode *a_vp;
1808 int a_name;
1809 int *a_retval;
1810 } */ *ap;
1811{
1898}
1899
1900static int
1901msdosfs_pathconf(ap)
1902 struct vop_pathconf_args /* {
1903 struct vnode *a_vp;
1904 int a_name;
1905 int *a_retval;
1906 } */ *ap;
1907{
1908 struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
1909
1812 switch (ap->a_name) {
1813 case _PC_LINK_MAX:
1814 *ap->a_retval = 1;
1910 switch (ap->a_name) {
1911 case _PC_LINK_MAX:
1912 *ap->a_retval = 1;
1815 return 0;
1913 return (0);
1816 case _PC_NAME_MAX:
1914 case _PC_NAME_MAX:
1817 *ap->a_retval = 12;
1818 return 0;
1915 *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
1916 return (0);
1819 case _PC_PATH_MAX:
1917 case _PC_PATH_MAX:
1820 *ap->a_retval = PATH_MAX; /* 255? */
1821 return 0;
1918 *ap->a_retval = PATH_MAX;
1919 return (0);
1822 case _PC_CHOWN_RESTRICTED:
1823 *ap->a_retval = 1;
1920 case _PC_CHOWN_RESTRICTED:
1921 *ap->a_retval = 1;
1824 return 0;
1922 return (0);
1825 case _PC_NO_TRUNC:
1826 *ap->a_retval = 0;
1923 case _PC_NO_TRUNC:
1924 *ap->a_retval = 0;
1827 return 0;
1925 return (0);
1828 default:
1926 default:
1829 return EINVAL;
1927 return (EINVAL);
1830 }
1928 }
1929 /* NOTREACHED */
1831}
1832
1833/* Global vfs data structures for msdosfs */
1834vop_t **msdosfs_vnodeop_p;
1835static struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
1836 { &vop_default_desc, (vop_t *) vop_defaultop },
1837 { &vop_abortop_desc, (vop_t *) msdosfs_abortop },
1838 { &vop_access_desc, (vop_t *) msdosfs_access },

--- 32 unchanged lines hidden ---
1930}
1931
1932/* Global vfs data structures for msdosfs */
1933vop_t **msdosfs_vnodeop_p;
1934static struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
1935 { &vop_default_desc, (vop_t *) vop_defaultop },
1936 { &vop_abortop_desc, (vop_t *) msdosfs_abortop },
1937 { &vop_access_desc, (vop_t *) msdosfs_access },

--- 32 unchanged lines hidden ---