| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: vfs_lookup.c,v 1.150 2011/04/11 02:12:58 dholland Exp $ */ | | 1 | /* $NetBSD: vfs_lookup.c,v 1.151 2011/04/11 02:13:10 dholland Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1982, 1986, 1989, 1993 | | 4 | * Copyright (c) 1982, 1986, 1989, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * (c) UNIX System Laboratories, Inc. | | 6 | * (c) UNIX System Laboratories, Inc. |
7 | * All or some portions of this file are derived from material licensed | | 7 | * All or some portions of this file are derived from material licensed |
8 | * to the University of California by American Telephone and Telegraph | | 8 | * to the University of California by American Telephone and Telegraph |
9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | | 9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
10 | * the permission of UNIX System Laboratories, Inc. | | 10 | * the permission of UNIX System Laboratories, Inc. |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
| @@ -27,27 +27,27 @@ | | | @@ -27,27 +27,27 @@ |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. | | 34 | * SUCH DAMAGE. |
35 | * | | 35 | * |
36 | * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 | | 36 | * @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95 |
37 | */ | | 37 | */ |
38 | | | 38 | |
39 | #include <sys/cdefs.h> | | 39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.150 2011/04/11 02:12:58 dholland Exp $"); | | 40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.151 2011/04/11 02:13:10 dholland Exp $"); |
41 | | | 41 | |
42 | #include "opt_magiclinks.h" | | 42 | #include "opt_magiclinks.h" |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/kernel.h> | | 46 | #include <sys/kernel.h> |
47 | #include <sys/syslimits.h> | | 47 | #include <sys/syslimits.h> |
48 | #include <sys/time.h> | | 48 | #include <sys/time.h> |
49 | #include <sys/namei.h> | | 49 | #include <sys/namei.h> |
50 | #include <sys/vnode.h> | | 50 | #include <sys/vnode.h> |
51 | #include <sys/mount.h> | | 51 | #include <sys/mount.h> |
52 | #include <sys/errno.h> | | 52 | #include <sys/errno.h> |
53 | #include <sys/filedesc.h> | | 53 | #include <sys/filedesc.h> |
| @@ -616,35 +616,26 @@ namei_start(struct namei_state *state, s | | | @@ -616,35 +616,26 @@ namei_start(struct namei_state *state, s |
616 | /* no ktrace */ | | 616 | /* no ktrace */ |
617 | } else { | | 617 | } else { |
618 | startdir = namei_getstartdir(state); | | 618 | startdir = namei_getstartdir(state); |
619 | namei_ktrace(state); | | 619 | namei_ktrace(state); |
620 | } | | 620 | } |
621 | | | 621 | |
622 | vn_lock(startdir, LK_EXCLUSIVE | LK_RETRY); | | 622 | vn_lock(startdir, LK_EXCLUSIVE | LK_RETRY); |
623 | | | 623 | |
624 | *startdir_ret = startdir; | | 624 | *startdir_ret = startdir; |
625 | return 0; | | 625 | return 0; |
626 | } | | 626 | } |
627 | | | 627 | |
628 | /* | | 628 | /* |
629 | * Undo namei_start: unlock and release the current lookup directory. | | | |
630 | */ | | | |
631 | static void | | | |
632 | namei_end(struct namei_state *state) | | | |
633 | { | | | |
634 | vput(state->namei_startdir); | | | |
635 | } | | | |
636 | | | | |
637 | /* | | | |
638 | * Check for being at a symlink. | | 629 | * Check for being at a symlink. |
639 | */ | | 630 | */ |
640 | static inline int | | 631 | static inline int |
641 | namei_atsymlink(struct namei_state *state, struct vnode *foundobj) | | 632 | namei_atsymlink(struct namei_state *state, struct vnode *foundobj) |
642 | { | | 633 | { |
643 | return (foundobj->v_type == VLNK) && | | 634 | return (foundobj->v_type == VLNK) && |
644 | (state->cnp->cn_flags & (FOLLOW|REQUIREDIR)); | | 635 | (state->cnp->cn_flags & (FOLLOW|REQUIREDIR)); |
645 | } | | 636 | } |
646 | | | 637 | |
647 | /* | | 638 | /* |
648 | * Follow a symlink. | | 639 | * Follow a symlink. |
649 | */ | | 640 | */ |
650 | static inline int | | 641 | static inline int |
| @@ -1067,27 +1058,27 @@ namei_oneroot(struct namei_state *state, | | | @@ -1067,27 +1058,27 @@ namei_oneroot(struct namei_state *state, |
1067 | state->rdonly = cnp->cn_flags & RDONLY; | | 1058 | state->rdonly = cnp->cn_flags & RDONLY; |
1068 | | | 1059 | |
1069 | /* | | 1060 | /* |
1070 | * Keep going until we run out of path components. | | 1061 | * Keep going until we run out of path components. |
1071 | */ | | 1062 | */ |
1072 | cnp->cn_nameptr = ndp->ni_pnbuf; | | 1063 | cnp->cn_nameptr = ndp->ni_pnbuf; |
1073 | for (;;) { | | 1064 | for (;;) { |
1074 | | | 1065 | |
1075 | /* | | 1066 | /* |
1076 | * If the directory we're on is unmounted, bail out. | | 1067 | * If the directory we're on is unmounted, bail out. |
1077 | * XXX: should this also check if it's unlinked? | | 1068 | * XXX: should this also check if it's unlinked? |
1078 | */ | | 1069 | */ |
1079 | if (state->namei_startdir->v_mount == NULL) { | | 1070 | if (state->namei_startdir->v_mount == NULL) { |
1080 | namei_end(state); | | 1071 | vput(state->namei_startdir); |
1081 | return (ENOENT); | | 1072 | return (ENOENT); |
1082 | } | | 1073 | } |
1083 | | | 1074 | |
1084 | /* | | 1075 | /* |
1085 | * Look up the next path component. | | 1076 | * Look up the next path component. |
1086 | * (currently, this may consume more than one) | | 1077 | * (currently, this may consume more than one) |
1087 | */ | | 1078 | */ |
1088 | | | 1079 | |
1089 | state->lookup_alldone = 0; | | 1080 | state->lookup_alldone = 0; |
1090 | | | 1081 | |
1091 | ndp->ni_dvp = NULL; | | 1082 | ndp->ni_dvp = NULL; |
1092 | cnp->cn_flags &= ~ISSYMLINK; | | 1083 | cnp->cn_flags &= ~ISSYMLINK; |
1093 | searchdir = state->namei_startdir; | | 1084 | searchdir = state->namei_startdir; |
| @@ -1099,66 +1090,63 @@ namei_oneroot(struct namei_state *state, | | | @@ -1099,66 +1090,63 @@ namei_oneroot(struct namei_state *state, |
1099 | * directory. | | 1090 | * directory. |
1100 | */ | | 1091 | */ |
1101 | cp = cnp->cn_nameptr; | | 1092 | cp = cnp->cn_nameptr; |
1102 | if (*cp == '/') { | | 1093 | if (*cp == '/') { |
1103 | do { | | 1094 | do { |
1104 | cp++; | | 1095 | cp++; |
1105 | } while (*cp == '/'); | | 1096 | } while (*cp == '/'); |
1106 | ndp->ni_pathlen -= cp - cnp->cn_nameptr; | | 1097 | ndp->ni_pathlen -= cp - cnp->cn_nameptr; |
1107 | cnp->cn_nameptr = cp; | | 1098 | cnp->cn_nameptr = cp; |
1108 | | | 1099 | |
1109 | if (searchdir->v_type != VDIR) { | | 1100 | if (searchdir->v_type != VDIR) { |
1110 | vput(searchdir); | | 1101 | vput(searchdir); |
1111 | ndp->ni_vp = NULL; | | 1102 | ndp->ni_vp = NULL; |
1112 | /* XXX this should use namei_end() */ | | | |
1113 | if (ndp->ni_dvp) { | | 1103 | if (ndp->ni_dvp) { |
1114 | vput(ndp->ni_dvp); | | 1104 | vput(ndp->ni_dvp); |
1115 | } | | 1105 | } |
1116 | state->attempt_retry = 1; | | 1106 | state->attempt_retry = 1; |
1117 | return ENOTDIR; | | 1107 | return ENOTDIR; |
1118 | } | | 1108 | } |
1119 | } | | 1109 | } |
1120 | | | 1110 | |
1121 | /* | | 1111 | /* |
1122 | * If we've exhausted the path name, then just return the | | 1112 | * If we've exhausted the path name, then just return the |
1123 | * current node. | | 1113 | * current node. |
1124 | */ | | 1114 | */ |
1125 | if (cnp->cn_nameptr[0] == '\0') { | | 1115 | if (cnp->cn_nameptr[0] == '\0') { |
1126 | foundobj = searchdir; | | 1116 | foundobj = searchdir; |
1127 | ndp->ni_vp = foundobj; | | 1117 | ndp->ni_vp = foundobj; |
1128 | cnp->cn_flags |= ISLASTCN; | | 1118 | cnp->cn_flags |= ISLASTCN; |
1129 | | | 1119 | |
1130 | /* bleh */ | | 1120 | /* bleh */ |
1131 | goto terminal; | | 1121 | goto terminal; |
1132 | } | | 1122 | } |
1133 | | | 1123 | |
1134 | error = lookup_parsepath(state); | | 1124 | error = lookup_parsepath(state); |
1135 | if (error) { | | 1125 | if (error) { |
1136 | vput(searchdir); | | 1126 | vput(searchdir); |
1137 | ndp->ni_dvp = NULL; | | 1127 | ndp->ni_dvp = NULL; |
1138 | ndp->ni_vp = NULL; | | 1128 | ndp->ni_vp = NULL; |
1139 | /* XXX this should use namei_end() */ | | | |
1140 | if (ndp->ni_dvp) { | | 1129 | if (ndp->ni_dvp) { |
1141 | vput(ndp->ni_dvp); | | 1130 | vput(ndp->ni_dvp); |
1142 | } | | 1131 | } |
1143 | state->attempt_retry = 1; | | 1132 | state->attempt_retry = 1; |
1144 | return (error); | | 1133 | return (error); |
1145 | } | | 1134 | } |
1146 | | | 1135 | |
1147 | error = lookup_once(state, searchdir, &searchdir, &foundobj); | | 1136 | error = lookup_once(state, searchdir, &searchdir, &foundobj); |
1148 | ndp->ni_dvp = searchdir; | | 1137 | ndp->ni_dvp = searchdir; |
1149 | if (error) { | | 1138 | if (error) { |
1150 | ndp->ni_vp = NULL; | | 1139 | ndp->ni_vp = NULL; |
1151 | /* XXX this should use namei_end() */ | | | |
1152 | if (ndp->ni_dvp) { | | 1140 | if (ndp->ni_dvp) { |
1153 | vput(ndp->ni_dvp); | | 1141 | vput(ndp->ni_dvp); |
1154 | } | | 1142 | } |
1155 | /* | | 1143 | /* |
1156 | * Note that if we're doing TRYEMULROOT we can | | 1144 | * Note that if we're doing TRYEMULROOT we can |
1157 | * retry with the normal root. Where this is | | 1145 | * retry with the normal root. Where this is |
1158 | * currently set matches previous practice, | | 1146 | * currently set matches previous practice, |
1159 | * but the previous practice didn't make much | | 1147 | * but the previous practice didn't make much |
1160 | * sense and somebody should sit down and | | 1148 | * sense and somebody should sit down and |
1161 | * figure out which cases should cause retry | | 1149 | * figure out which cases should cause retry |
1162 | * and which shouldn't. XXX. | | 1150 | * and which shouldn't. XXX. |
1163 | */ | | 1151 | */ |
1164 | state->attempt_retry = 1; | | 1152 | state->attempt_retry = 1; |
| @@ -1199,27 +1187,26 @@ namei_oneroot(struct namei_state *state, | | | @@ -1199,27 +1187,26 @@ namei_oneroot(struct namei_state *state, |
1199 | } | | 1187 | } |
1200 | cnp->cn_nameptr = ndp->ni_pnbuf; | | 1188 | cnp->cn_nameptr = ndp->ni_pnbuf; |
1201 | continue; | | 1189 | continue; |
1202 | } | | 1190 | } |
1203 | | | 1191 | |
1204 | /* | | 1192 | /* |
1205 | * Check for directory, if the component was | | 1193 | * Check for directory, if the component was |
1206 | * followed by a series of slashes. | | 1194 | * followed by a series of slashes. |
1207 | */ | | 1195 | */ |
1208 | if ((foundobj->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { | | 1196 | if ((foundobj->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) { |
1209 | KASSERT(foundobj != ndp->ni_dvp); | | 1197 | KASSERT(foundobj != ndp->ni_dvp); |
1210 | vput(foundobj); | | 1198 | vput(foundobj); |
1211 | ndp->ni_vp = NULL; | | 1199 | ndp->ni_vp = NULL; |
1212 | /* XXX this should use namei_end() */ | | | |
1213 | if (ndp->ni_dvp) { | | 1200 | if (ndp->ni_dvp) { |
1214 | vput(ndp->ni_dvp); | | 1201 | vput(ndp->ni_dvp); |
1215 | } | | 1202 | } |
1216 | state->attempt_retry = 1; | | 1203 | state->attempt_retry = 1; |
1217 | return ENOTDIR; | | 1204 | return ENOTDIR; |
1218 | } | | 1205 | } |
1219 | | | 1206 | |
1220 | /* | | 1207 | /* |
1221 | * Not a symbolic link. If this was not the | | 1208 | * Not a symbolic link. If this was not the |
1222 | * last component, then continue at the next | | 1209 | * last component, then continue at the next |
1223 | * component, else return. | | 1210 | * component, else return. |
1224 | */ | | 1211 | */ |
1225 | if (!(cnp->cn_flags & ISLASTCN)) { | | 1212 | if (!(cnp->cn_flags & ISLASTCN)) { |
| @@ -1267,46 +1254,44 @@ namei_oneroot(struct namei_state *state, | | | @@ -1267,46 +1254,44 @@ namei_oneroot(struct namei_state *state, |
1267 | switch (cnp->cn_nameiop) { | | 1254 | switch (cnp->cn_nameiop) { |
1268 | case CREATE: | | 1255 | case CREATE: |
1269 | error = EEXIST; | | 1256 | error = EEXIST; |
1270 | break; | | 1257 | break; |
1271 | case DELETE: | | 1258 | case DELETE: |
1272 | case RENAME: | | 1259 | case RENAME: |
1273 | error = EBUSY; | | 1260 | error = EBUSY; |
1274 | break; | | 1261 | break; |
1275 | default: | | 1262 | default: |
1276 | KASSERT(0); | | 1263 | KASSERT(0); |
1277 | } | | 1264 | } |
1278 | vput(foundobj); | | 1265 | vput(foundobj); |
1279 | foundobj = NULL; | | 1266 | foundobj = NULL; |
1280 | /* XXX this should use namei_end() */ | | | |
1281 | if (ndp->ni_dvp) { | | 1267 | if (ndp->ni_dvp) { |
1282 | vput(ndp->ni_dvp); | | 1268 | vput(ndp->ni_dvp); |
1283 | } | | 1269 | } |
1284 | state->attempt_retry = 1; | | 1270 | state->attempt_retry = 1; |
1285 | return (error); | | 1271 | return (error); |
1286 | } | | 1272 | } |
1287 | | | 1273 | |
1288 | /* | | 1274 | /* |
1289 | * Disallow directory write attempts on read-only lookups. | | 1275 | * Disallow directory write attempts on read-only lookups. |
1290 | * Prefers EEXIST over EROFS for the CREATE case. | | 1276 | * Prefers EEXIST over EROFS for the CREATE case. |
1291 | */ | | 1277 | */ |
1292 | if (state->rdonly && | | 1278 | if (state->rdonly && |
1293 | (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { | | 1279 | (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { |
1294 | error = EROFS; | | 1280 | error = EROFS; |
1295 | if (foundobj != ndp->ni_dvp) { | | 1281 | if (foundobj != ndp->ni_dvp) { |
1296 | vput(foundobj); | | 1282 | vput(foundobj); |
1297 | } | | 1283 | } |
1298 | ndp->ni_vp = NULL; | | 1284 | ndp->ni_vp = NULL; |
1299 | /* XXX this should use namei_end() */ | | | |
1300 | if (ndp->ni_dvp) { | | 1285 | if (ndp->ni_dvp) { |
1301 | vput(ndp->ni_dvp); | | 1286 | vput(ndp->ni_dvp); |
1302 | } | | 1287 | } |
1303 | state->attempt_retry = 1; | | 1288 | state->attempt_retry = 1; |
1304 | return (error); | | 1289 | return (error); |
1305 | } | | 1290 | } |
1306 | if ((cnp->cn_flags & LOCKLEAF) == 0) { | | 1291 | if ((cnp->cn_flags & LOCKLEAF) == 0) { |
1307 | VOP_UNLOCK(foundobj); | | 1292 | VOP_UNLOCK(foundobj); |
1308 | } | | 1293 | } |
1309 | | | 1294 | |
1310 | break; | | 1295 | break; |
1311 | } | | 1296 | } |
1312 | | | 1297 | |