| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: msdosfs_vnops.c,v 1.86 2013/03/18 19:35:37 plunky Exp $ */ | | 1 | /* $NetBSD: msdosfs_vnops.c,v 1.87 2013/11/02 10:30:18 hannken Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. | | 4 | * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. |
5 | * Copyright (C) 1994, 1995, 1997 TooLs GmbH. | | 5 | * Copyright (C) 1994, 1995, 1997 TooLs GmbH. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). | | 7 | * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -38,27 +38,27 @@ | | | @@ -38,27 +38,27 @@ |
38 | * it, and don't remove this notice. | | 38 | * it, and don't remove this notice. |
39 | * | | 39 | * |
40 | * This software is provided "as is". | | 40 | * This software is provided "as is". |
41 | * | | 41 | * |
42 | * The author supplies this software to be publicly redistributed on the | | 42 | * The author supplies this software to be publicly redistributed on the |
43 | * understanding that the author is not responsible for the correct | | 43 | * understanding that the author is not responsible for the correct |
44 | * functioning of this software in any circumstances and is not liable for | | 44 | * functioning of this software in any circumstances and is not liable for |
45 | * any damages caused by this software. | | 45 | * any damages caused by this software. |
46 | * | | 46 | * |
47 | * October 1992 | | 47 | * October 1992 |
48 | */ | | 48 | */ |
49 | | | 49 | |
50 | #include <sys/cdefs.h> | | 50 | #include <sys/cdefs.h> |
51 | __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.86 2013/03/18 19:35:37 plunky Exp $"); | | 51 | __KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.87 2013/11/02 10:30:18 hannken Exp $"); |
52 | | | 52 | |
53 | #include <sys/param.h> | | 53 | #include <sys/param.h> |
54 | #include <sys/systm.h> | | 54 | #include <sys/systm.h> |
55 | #include <sys/namei.h> | | 55 | #include <sys/namei.h> |
56 | #include <sys/resourcevar.h> /* defines plimit structure in proc struct */ | | 56 | #include <sys/resourcevar.h> /* defines plimit structure in proc struct */ |
57 | #include <sys/kernel.h> | | 57 | #include <sys/kernel.h> |
58 | #include <sys/file.h> /* define FWRITE ... */ | | 58 | #include <sys/file.h> /* define FWRITE ... */ |
59 | #include <sys/stat.h> | | 59 | #include <sys/stat.h> |
60 | #include <sys/buf.h> | | 60 | #include <sys/buf.h> |
61 | #include <sys/proc.h> | | 61 | #include <sys/proc.h> |
62 | #include <sys/mount.h> | | 62 | #include <sys/mount.h> |
63 | #include <sys/fstrans.h> | | 63 | #include <sys/fstrans.h> |
64 | #include <sys/vnode.h> | | 64 | #include <sys/vnode.h> |
| @@ -819,26 +819,27 @@ msdosfs_rename(void *v) | | | @@ -819,26 +819,27 @@ msdosfs_rename(void *v) |
819 | { | | 819 | { |
820 | struct vop_rename_args /* { | | 820 | struct vop_rename_args /* { |
821 | struct vnode *a_fdvp; | | 821 | struct vnode *a_fdvp; |
822 | struct vnode *a_fvp; | | 822 | struct vnode *a_fvp; |
823 | struct componentname *a_fcnp; | | 823 | struct componentname *a_fcnp; |
824 | struct vnode *a_tdvp; | | 824 | struct vnode *a_tdvp; |
825 | struct vnode *a_tvp; | | 825 | struct vnode *a_tvp; |
826 | struct componentname *a_tcnp; | | 826 | struct componentname *a_tcnp; |
827 | } */ *ap = v; | | 827 | } */ *ap = v; |
828 | struct vnode *tvp = ap->a_tvp; | | 828 | struct vnode *tvp = ap->a_tvp; |
829 | struct vnode *tdvp = ap->a_tdvp; | | 829 | struct vnode *tdvp = ap->a_tdvp; |
830 | struct vnode *fvp = ap->a_fvp; | | 830 | struct vnode *fvp = ap->a_fvp; |
831 | struct vnode *fdvp = ap->a_fdvp; | | 831 | struct vnode *fdvp = ap->a_fdvp; |
| | | 832 | struct mount *mp = fdvp->v_mount; |
832 | struct componentname *tcnp = ap->a_tcnp; | | 833 | struct componentname *tcnp = ap->a_tcnp; |
833 | struct componentname *fcnp = ap->a_fcnp; | | 834 | struct componentname *fcnp = ap->a_fcnp; |
834 | struct denode *ip, *xp, *dp, *zp; | | 835 | struct denode *ip, *xp, *dp, *zp; |
835 | u_char toname[12], oldname[12]; | | 836 | u_char toname[12], oldname[12]; |
836 | u_long from_diroffset, to_diroffset; | | 837 | u_long from_diroffset, to_diroffset; |
837 | u_char to_count; | | 838 | u_char to_count; |
838 | int doingdirectory = 0, newparent = 0; | | 839 | int doingdirectory = 0, newparent = 0; |
839 | int error; | | 840 | int error; |
840 | u_long cn; | | 841 | u_long cn; |
841 | daddr_t bn; | | 842 | daddr_t bn; |
842 | struct msdosfsmount *pmp; | | 843 | struct msdosfsmount *pmp; |
843 | struct direntry *dotdotp; | | 844 | struct direntry *dotdotp; |
844 | struct buf *bp; | | 845 | struct buf *bp; |
| @@ -896,27 +897,27 @@ abortit: | | | @@ -896,27 +897,27 @@ abortit: |
896 | dp == ip || | | 897 | dp == ip || |
897 | (fcnp->cn_flags & ISDOTDOT) || | | 898 | (fcnp->cn_flags & ISDOTDOT) || |
898 | (tcnp->cn_flags & ISDOTDOT) || | | 899 | (tcnp->cn_flags & ISDOTDOT) || |
899 | (ip->de_flag & DE_RENAME)) { | | 900 | (ip->de_flag & DE_RENAME)) { |
900 | VOP_UNLOCK(fvp); | | 901 | VOP_UNLOCK(fvp); |
901 | error = EINVAL; | | 902 | error = EINVAL; |
902 | goto abortit; | | 903 | goto abortit; |
903 | } | | 904 | } |
904 | ip->de_flag |= DE_RENAME; | | 905 | ip->de_flag |= DE_RENAME; |
905 | doingdirectory++; | | 906 | doingdirectory++; |
906 | } | | 907 | } |
907 | VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */ | | 908 | VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */ |
908 | | | 909 | |
909 | fstrans_start(fdvp->v_mount, FSTRANS_SHARED); | | 910 | fstrans_start(mp, FSTRANS_SHARED); |
910 | /* | | 911 | /* |
911 | * When the target exists, both the directory | | 912 | * When the target exists, both the directory |
912 | * and target vnodes are returned locked. | | 913 | * and target vnodes are returned locked. |
913 | */ | | 914 | */ |
914 | dp = VTODE(tdvp); | | 915 | dp = VTODE(tdvp); |
915 | xp = tvp ? VTODE(tvp) : NULL; | | 916 | xp = tvp ? VTODE(tvp) : NULL; |
916 | /* | | 917 | /* |
917 | * Remember direntry place to use for destination | | 918 | * Remember direntry place to use for destination |
918 | */ | | 919 | */ |
919 | to_diroffset = dp->de_fndoffset; | | 920 | to_diroffset = dp->de_fndoffset; |
920 | to_count = dp->de_fndcnt; | | 921 | to_count = dp->de_fndcnt; |
921 | | | 922 | |
922 | /* | | 923 | /* |
| @@ -983,55 +984,55 @@ abortit: | | | @@ -983,55 +984,55 @@ abortit: |
983 | VN_KNOTE(tvp, NOTE_DELETE); | | 984 | VN_KNOTE(tvp, NOTE_DELETE); |
984 | cache_purge(tvp); | | 985 | cache_purge(tvp); |
985 | vput(tvp); | | 986 | vput(tvp); |
986 | tvp = NULL; | | 987 | tvp = NULL; |
987 | xp = NULL; | | 988 | xp = NULL; |
988 | } | | 989 | } |
989 | | | 990 | |
990 | /* | | 991 | /* |
991 | * Convert the filename in tcnp into a dos filename. We copy this | | 992 | * Convert the filename in tcnp into a dos filename. We copy this |
992 | * into the denode and directory entry for the destination | | 993 | * into the denode and directory entry for the destination |
993 | * file/directory. | | 994 | * file/directory. |
994 | */ | | 995 | */ |
995 | if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) { | | 996 | if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) { |
996 | fstrans_done(fdvp->v_mount); | | 997 | fstrans_done(mp); |
997 | goto abortit; | | 998 | goto abortit; |
998 | } | | 999 | } |
999 | | | 1000 | |
1000 | /* | | 1001 | /* |
1001 | * Since from wasn't locked at various places above, | | 1002 | * Since from wasn't locked at various places above, |
1002 | * have to do a relookup here. | | 1003 | * have to do a relookup here. |
1003 | */ | | 1004 | */ |
1004 | fcnp->cn_flags &= ~MODMASK; | | 1005 | fcnp->cn_flags &= ~MODMASK; |
1005 | fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; | | 1006 | fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; |
1006 | VOP_UNLOCK(tdvp); | | 1007 | VOP_UNLOCK(tdvp); |
1007 | vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); | | 1008 | vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); |
1008 | if ((error = relookup(fdvp, &fvp, fcnp, 0))) { | | 1009 | if ((error = relookup(fdvp, &fvp, fcnp, 0))) { |
1009 | VOP_UNLOCK(fdvp); | | 1010 | VOP_UNLOCK(fdvp); |
1010 | vrele(ap->a_fvp); | | 1011 | vrele(ap->a_fvp); |
1011 | vrele(tdvp); | | 1012 | vrele(tdvp); |
1012 | fstrans_done(fdvp->v_mount); | | 1013 | fstrans_done(mp); |
1013 | return (error); | | 1014 | return (error); |
1014 | } | | 1015 | } |
1015 | if (fvp == NULL) { | | 1016 | if (fvp == NULL) { |
1016 | /* | | 1017 | /* |
1017 | * From name has disappeared. | | 1018 | * From name has disappeared. |
1018 | */ | | 1019 | */ |
1019 | if (doingdirectory) | | 1020 | if (doingdirectory) |
1020 | panic("rename: lost dir entry"); | | 1021 | panic("rename: lost dir entry"); |
1021 | vput(fdvp); | | 1022 | vput(fdvp); |
1022 | vrele(ap->a_fvp); | | 1023 | vrele(ap->a_fvp); |
1023 | vrele(tdvp); | | 1024 | vrele(tdvp); |
1024 | fstrans_done(fdvp->v_mount); | | 1025 | fstrans_done(mp); |
1025 | return 0; | | 1026 | return 0; |
1026 | } | | 1027 | } |
1027 | VOP_UNLOCK(fdvp); | | 1028 | VOP_UNLOCK(fdvp); |
1028 | xp = VTODE(fvp); | | 1029 | xp = VTODE(fvp); |
1029 | zp = VTODE(fdvp); | | 1030 | zp = VTODE(fdvp); |
1030 | from_diroffset = zp->de_fndoffset; | | 1031 | from_diroffset = zp->de_fndoffset; |
1031 | | | 1032 | |
1032 | /* | | 1033 | /* |
1033 | * Ensure that the directory entry still exists and has not | | 1034 | * Ensure that the directory entry still exists and has not |
1034 | * changed till now. If the source is a file the entry may | | 1035 | * changed till now. If the source is a file the entry may |
1035 | * have been unlinked or renamed. In either case there is | | 1036 | * have been unlinked or renamed. In either case there is |
1036 | * no further work to be done. If the source is a directory | | 1037 | * no further work to be done. If the source is a directory |
1037 | * then it cannot have been rmdir'ed or renamed; this is | | 1038 | * then it cannot have been rmdir'ed or renamed; this is |
| @@ -1119,27 +1120,27 @@ abortit: | | | @@ -1119,27 +1120,27 @@ abortit: |
1119 | goto bad; | | 1120 | goto bad; |
1120 | } | | 1121 | } |
1121 | } | | 1122 | } |
1122 | | | 1123 | |
1123 | VN_KNOTE(fvp, NOTE_RENAME); | | 1124 | VN_KNOTE(fvp, NOTE_RENAME); |
1124 | VOP_UNLOCK(fvp); | | 1125 | VOP_UNLOCK(fvp); |
1125 | bad: | | 1126 | bad: |
1126 | if (tvp) | | 1127 | if (tvp) |
1127 | vput(tvp); | | 1128 | vput(tvp); |
1128 | vrele(tdvp); | | 1129 | vrele(tdvp); |
1129 | ip->de_flag &= ~DE_RENAME; | | 1130 | ip->de_flag &= ~DE_RENAME; |
1130 | vrele(fdvp); | | 1131 | vrele(fdvp); |
1131 | vrele(fvp); | | 1132 | vrele(fvp); |
1132 | fstrans_done(fdvp->v_mount); | | 1133 | fstrans_done(mp); |
1133 | return (error); | | 1134 | return (error); |
1134 | | | 1135 | |
1135 | /* XXX: uuuh */ | | 1136 | /* XXX: uuuh */ |
1136 | tdvpbad: | | 1137 | tdvpbad: |
1137 | VOP_UNLOCK(tdvp); | | 1138 | VOP_UNLOCK(tdvp); |
1138 | goto bad; | | 1139 | goto bad; |
1139 | } | | 1140 | } |
1140 | | | 1141 | |
1141 | static const struct { | | 1142 | static const struct { |
1142 | struct direntry dot; | | 1143 | struct direntry dot; |
1143 | struct direntry dotdot; | | 1144 | struct direntry dotdot; |
1144 | } dosdirtemplate = { | | 1145 | } dosdirtemplate = { |
1145 | { ". ", " ", /* the . entry */ | | 1146 | { ". ", " ", /* the . entry */ |
| @@ -1281,41 +1282,42 @@ bad2: | | | @@ -1281,41 +1282,42 @@ bad2: |
1281 | return (error); | | 1282 | return (error); |
1282 | } | | 1283 | } |
1283 | | | 1284 | |
1284 | int | | 1285 | int |
1285 | msdosfs_rmdir(void *v) | | 1286 | msdosfs_rmdir(void *v) |
1286 | { | | 1287 | { |
1287 | struct vop_rmdir_args /* { | | 1288 | struct vop_rmdir_args /* { |
1288 | struct vnode *a_dvp; | | 1289 | struct vnode *a_dvp; |
1289 | struct vnode *a_vp; | | 1290 | struct vnode *a_vp; |
1290 | struct componentname *a_cnp; | | 1291 | struct componentname *a_cnp; |
1291 | } */ *ap = v; | | 1292 | } */ *ap = v; |
1292 | struct vnode *vp = ap->a_vp; | | 1293 | struct vnode *vp = ap->a_vp; |
1293 | struct vnode *dvp = ap->a_dvp; | | 1294 | struct vnode *dvp = ap->a_dvp; |
| | | 1295 | struct mount *mp = dvp->v_mount; |
1294 | struct componentname *cnp = ap->a_cnp; | | 1296 | struct componentname *cnp = ap->a_cnp; |
1295 | struct denode *ip, *dp; | | 1297 | struct denode *ip, *dp; |
1296 | int error; | | 1298 | int error; |
1297 | | | 1299 | |
1298 | ip = VTODE(vp); | | 1300 | ip = VTODE(vp); |
1299 | dp = VTODE(dvp); | | 1301 | dp = VTODE(dvp); |
1300 | /* | | 1302 | /* |
1301 | * No rmdir "." please. | | 1303 | * No rmdir "." please. |
1302 | */ | | 1304 | */ |
1303 | if (dp == ip) { | | 1305 | if (dp == ip) { |
1304 | vrele(dvp); | | 1306 | vrele(dvp); |
1305 | vput(vp); | | 1307 | vput(vp); |
1306 | return (EINVAL); | | 1308 | return (EINVAL); |
1307 | } | | 1309 | } |
1308 | fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); | | 1310 | fstrans_start(mp, FSTRANS_SHARED); |
1309 | /* | | 1311 | /* |
1310 | * Verify the directory is empty (and valid). | | 1312 | * Verify the directory is empty (and valid). |
1311 | * (Rmdir ".." won't be valid since | | 1313 | * (Rmdir ".." won't be valid since |
1312 | * ".." will contain a reference to | | 1314 | * ".." will contain a reference to |
1313 | * the current directory and thus be | | 1315 | * the current directory and thus be |
1314 | * non-empty.) | | 1316 | * non-empty.) |
1315 | */ | | 1317 | */ |
1316 | error = 0; | | 1318 | error = 0; |
1317 | if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) { | | 1319 | if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) { |
1318 | error = ENOTEMPTY; | | 1320 | error = ENOTEMPTY; |
1319 | goto out; | | 1321 | goto out; |
1320 | } | | 1322 | } |
1321 | /* | | 1323 | /* |
| @@ -1337,27 +1339,27 @@ msdosfs_rmdir(void *v) | | | @@ -1337,27 +1339,27 @@ msdosfs_rmdir(void *v) |
1337 | cache_purge(dvp); | | 1339 | cache_purge(dvp); |
1338 | vput(dvp); | | 1340 | vput(dvp); |
1339 | dvp = NULL; | | 1341 | dvp = NULL; |
1340 | /* | | 1342 | /* |
1341 | * Truncate the directory that is being deleted. | | 1343 | * Truncate the directory that is being deleted. |
1342 | */ | | 1344 | */ |
1343 | error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred); | | 1345 | error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred); |
1344 | cache_purge(vp); | | 1346 | cache_purge(vp); |
1345 | out: | | 1347 | out: |
1346 | VN_KNOTE(vp, NOTE_DELETE); | | 1348 | VN_KNOTE(vp, NOTE_DELETE); |
1347 | if (dvp) | | 1349 | if (dvp) |
1348 | vput(dvp); | | 1350 | vput(dvp); |
1349 | vput(vp); | | 1351 | vput(vp); |
1350 | fstrans_done(ap->a_dvp->v_mount); | | 1352 | fstrans_done(mp); |
1351 | return (error); | | 1353 | return (error); |
1352 | } | | 1354 | } |
1353 | | | 1355 | |
1354 | int | | 1356 | int |
1355 | msdosfs_readdir(void *v) | | 1357 | msdosfs_readdir(void *v) |
1356 | { | | 1358 | { |
1357 | struct vop_readdir_args /* { | | 1359 | struct vop_readdir_args /* { |
1358 | struct vnode *a_vp; | | 1360 | struct vnode *a_vp; |
1359 | struct uio *a_uio; | | 1361 | struct uio *a_uio; |
1360 | kauth_cred_t a_cred; | | 1362 | kauth_cred_t a_cred; |
1361 | int *a_eofflag; | | 1363 | int *a_eofflag; |
1362 | off_t **a_cookies; | | 1364 | off_t **a_cookies; |
1363 | int *a_ncookies; | | 1365 | int *a_ncookies; |