| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: vfs_lookup.c,v 1.136 2011/04/11 01:36:28 dholland Exp $ */ | | 1 | /* $NetBSD: vfs_lookup.c,v 1.137 2011/04/11 01:36:59 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.136 2011/04/11 01:36:28 dholland Exp $"); | | 40 | __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.137 2011/04/11 01:36:59 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> |
| @@ -403,26 +403,28 @@ struct namei_state { | | | @@ -403,26 +403,28 @@ struct namei_state { |
403 | struct nameidata *ndp; | | 403 | struct nameidata *ndp; |
404 | struct componentname *cnp; | | 404 | struct componentname *cnp; |
405 | | | 405 | |
406 | /* used by the pieces of namei */ | | 406 | /* used by the pieces of namei */ |
407 | struct vnode *namei_startdir; /* The directory namei() starts from. */ | | 407 | struct vnode *namei_startdir; /* The directory namei() starts from. */ |
408 | | | 408 | |
409 | /* used by the pieces of lookup */ | | 409 | /* used by the pieces of lookup */ |
410 | int lookup_alldone; | | 410 | int lookup_alldone; |
411 | | | 411 | |
412 | int docache; /* == 0 do not cache last component */ | | 412 | int docache; /* == 0 do not cache last component */ |
413 | int rdonly; /* lookup read-only flag bit */ | | 413 | int rdonly; /* lookup read-only flag bit */ |
414 | struct vnode *dp; /* the directory we are searching */ | | 414 | struct vnode *dp; /* the directory we are searching */ |
415 | int slashes; | | 415 | int slashes; |
| | | 416 | |
| | | 417 | unsigned attempt_retry:1; /* true if error allows emul retry */ |
416 | }; | | 418 | }; |
417 | | | 419 | |
418 | | | 420 | |
419 | /* | | 421 | /* |
420 | * Initialize the namei working state. | | 422 | * Initialize the namei working state. |
421 | */ | | 423 | */ |
422 | static void | | 424 | static void |
423 | namei_init(struct namei_state *state, struct nameidata *ndp) | | 425 | namei_init(struct namei_state *state, struct nameidata *ndp) |
424 | { | | 426 | { |
425 | state->ndp = ndp; | | 427 | state->ndp = ndp; |
426 | state->cnp = &ndp->ni_cnd; | | 428 | state->cnp = &ndp->ni_cnd; |
427 | KASSERT((state->cnp->cn_flags & INRELOOKUP) == 0); | | 429 | KASSERT((state->cnp->cn_flags & INRELOOKUP) == 0); |
428 | | | 430 | |
| @@ -1223,151 +1225,171 @@ terminal: | | | @@ -1223,151 +1225,171 @@ terminal: |
1223 | if ((cnp->cn_flags & LOCKLEAF) == 0) { | | 1225 | if ((cnp->cn_flags & LOCKLEAF) == 0) { |
1224 | VOP_UNLOCK(state->dp); | | 1226 | VOP_UNLOCK(state->dp); |
1225 | } | | 1227 | } |
1226 | return (0); | | 1228 | return (0); |
1227 | | | 1229 | |
1228 | bad: | | 1230 | bad: |
1229 | ndp->ni_vp = NULL; | | 1231 | ndp->ni_vp = NULL; |
1230 | return (error); | | 1232 | return (error); |
1231 | } | | 1233 | } |
1232 | | | 1234 | |
1233 | ////////////////////////////// | | 1235 | ////////////////////////////// |
1234 | | | 1236 | |
1235 | static int | | 1237 | static int |
1236 | do_namei(struct namei_state *state, struct vnode *forcecwd, | | 1238 | namei_oneroot(struct namei_state *state, struct vnode *forcecwd, |
1237 | int neverfollow, int inhibitmagic) | | 1239 | int neverfollow, int inhibitmagic) |
1238 | { | | 1240 | { |
1239 | int error; | | | |
1240 | | | | |
1241 | struct nameidata *ndp = state->ndp; | | 1241 | struct nameidata *ndp = state->ndp; |
1242 | struct componentname *cnp = state->cnp; | | 1242 | struct componentname *cnp = state->cnp; |
1243 | const char *savepath = NULL; | | 1243 | int error; |
1244 | | | | |
1245 | KASSERT(cnp == &ndp->ni_cnd); | | | |
1246 | | | | |
1247 | if (cnp->cn_flags & TRYEMULROOT) { | | | |
1248 | savepath = pathbuf_stringcopy_get(ndp->ni_pathbuf); | | | |
1249 | } | | | |
1250 | | | | |
1251 | emul_retry: | | | |
1252 | | | | |
1253 | if (savepath != NULL) { | | | |
1254 | /* kinda gross */ | | | |
1255 | strcpy(ndp->ni_pathbuf->pb_path, savepath); | | | |
1256 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | | |
1257 | savepath = NULL; | | | |
1258 | } | | | |
1259 | | | 1244 | |
1260 | error = namei_start(state, forcecwd); | | 1245 | error = namei_start(state, forcecwd); |
1261 | if (error) { | | 1246 | if (error) { |
1262 | if (savepath != NULL) { | | | |
1263 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | | |
1264 | } | | | |
1265 | return error; | | 1247 | return error; |
1266 | } | | 1248 | } |
1267 | | | 1249 | |
1268 | /* | | 1250 | /* |
1269 | * Keep going until we run out of path components. | | 1251 | * Keep going until we run out of path components. |
1270 | */ | | 1252 | */ |
1271 | for (;;) { | | 1253 | for (;;) { |
1272 | | | 1254 | |
1273 | /* | | 1255 | /* |
1274 | * If the directory we're on is unmounted, bail out. | | 1256 | * If the directory we're on is unmounted, bail out. |
1275 | * XXX: should this also check if it's unlinked? | | 1257 | * XXX: should this also check if it's unlinked? |
1276 | */ | | 1258 | */ |
1277 | if (state->namei_startdir->v_mount == NULL) { | | 1259 | if (state->namei_startdir->v_mount == NULL) { |
1278 | if (savepath != NULL) { | | | |
1279 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | | |
1280 | } | | | |
1281 | namei_end(state); | | 1260 | namei_end(state); |
1282 | return (ENOENT); | | 1261 | return (ENOENT); |
1283 | } | | 1262 | } |
1284 | | | 1263 | |
1285 | /* | | 1264 | /* |
1286 | * Look up the next path component. | | 1265 | * Look up the next path component. |
1287 | * (currently, this may consume more than one) | | 1266 | * (currently, this may consume more than one) |
1288 | */ | | 1267 | */ |
1289 | error = do_lookup(state, state->namei_startdir); | | 1268 | error = do_lookup(state, state->namei_startdir); |
1290 | if (error != 0) { | | 1269 | if (error != 0) { |
1291 | /* XXX this should use namei_end() */ | | 1270 | /* XXX this should use namei_end() */ |
1292 | if (ndp->ni_dvp) { | | 1271 | if (ndp->ni_dvp) { |
1293 | vput(ndp->ni_dvp); | | 1272 | vput(ndp->ni_dvp); |
1294 | } | | 1273 | } |
1295 | if (ndp->ni_erootdir != NULL) { | | 1274 | /* |
1296 | /* Retry the whole thing from the normal root */ | | 1275 | * Note that if we're doing TRYEMULROOT we can |
1297 | cnp->cn_flags &= ~TRYEMULROOT; | | 1276 | * retry with the normal root. Setting this |
1298 | goto emul_retry; | | 1277 | * here matches previous practice, but the |
1299 | } | | 1278 | * previous practice didn't make much sense |
1300 | KASSERT(savepath == NULL); | | 1279 | * and somebody should sit down and figure out |
| | | 1280 | * which cases should cause retry and which |
| | | 1281 | * shouldn't. XXX. |
| | | 1282 | */ |
| | | 1283 | state->attempt_retry = 1; |
1301 | return (error); | | 1284 | return (error); |
1302 | } | | 1285 | } |
1303 | | | 1286 | |
1304 | /* | | 1287 | /* |
1305 | * If we've reached a symbolic link, follow it, unless we | | 1288 | * If we've reached a symbolic link, follow it, unless we |
1306 | * aren't supposed to. | | 1289 | * aren't supposed to. |
1307 | */ | | 1290 | */ |
1308 | if (namei_atsymlink(state)) { | | 1291 | if (namei_atsymlink(state)) { |
1309 | if (neverfollow) { | | 1292 | if (neverfollow) { |
1310 | error = EINVAL; | | 1293 | error = EINVAL; |
1311 | } else { | | 1294 | } else { |
1312 | error = namei_follow(state, inhibitmagic); | | 1295 | error = namei_follow(state, inhibitmagic); |
1313 | } | | 1296 | } |
1314 | if (error) { | | 1297 | if (error) { |
1315 | KASSERT(ndp->ni_dvp != ndp->ni_vp); | | 1298 | KASSERT(ndp->ni_dvp != ndp->ni_vp); |
1316 | vput(ndp->ni_dvp); | | 1299 | vput(ndp->ni_dvp); |
1317 | vput(ndp->ni_vp); | | 1300 | vput(ndp->ni_vp); |
1318 | ndp->ni_vp = NULL; | | 1301 | ndp->ni_vp = NULL; |
1319 | if (savepath != NULL) { | | | |
1320 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | | |
1321 | } | | | |
1322 | return error; | | 1302 | return error; |
1323 | } | | 1303 | } |
1324 | } | | 1304 | } |
1325 | else { | | 1305 | else { |
1326 | break; | | 1306 | break; |
1327 | } | | 1307 | } |
1328 | } | | 1308 | } |
1329 | | | 1309 | |
1330 | /* | | 1310 | /* |
1331 | * Done. | | 1311 | * Done. |
1332 | */ | | 1312 | */ |
1333 | | | 1313 | |
1334 | /* | | 1314 | /* |
1335 | * If LOCKPARENT is not set, the parent directory isn't returned. | | 1315 | * If LOCKPARENT is not set, the parent directory isn't returned. |
1336 | */ | | 1316 | */ |
1337 | if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != NULL) { | | 1317 | if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != NULL) { |
1338 | if (ndp->ni_dvp == ndp->ni_vp) { | | 1318 | if (ndp->ni_dvp == ndp->ni_vp) { |
1339 | vrele(ndp->ni_dvp); | | 1319 | vrele(ndp->ni_dvp); |
1340 | } else { | | 1320 | } else { |
1341 | vput(ndp->ni_dvp); | | 1321 | vput(ndp->ni_dvp); |
1342 | } | | 1322 | } |
1343 | ndp->ni_dvp = NULL; | | 1323 | ndp->ni_dvp = NULL; |
1344 | } | | 1324 | } |
1345 | | | 1325 | |
| | | 1326 | return 0; |
| | | 1327 | } |
| | | 1328 | |
| | | 1329 | static int |
| | | 1330 | namei_tryemulroot(struct namei_state *state, struct vnode *forcecwd, |
| | | 1331 | int neverfollow, int inhibitmagic) |
| | | 1332 | { |
| | | 1333 | int error; |
| | | 1334 | |
| | | 1335 | struct nameidata *ndp = state->ndp; |
| | | 1336 | struct componentname *cnp = state->cnp; |
| | | 1337 | const char *savepath = NULL; |
| | | 1338 | |
| | | 1339 | KASSERT(cnp == &ndp->ni_cnd); |
| | | 1340 | |
| | | 1341 | if (cnp->cn_flags & TRYEMULROOT) { |
| | | 1342 | savepath = pathbuf_stringcopy_get(ndp->ni_pathbuf); |
| | | 1343 | } |
| | | 1344 | |
| | | 1345 | emul_retry: |
| | | 1346 | state->attempt_retry = 0; |
| | | 1347 | |
| | | 1348 | error = namei_oneroot(state, forcecwd, neverfollow, inhibitmagic); |
| | | 1349 | if (error) { |
| | | 1350 | /* |
| | | 1351 | * Once namei has started up, the existence of ni_erootdir |
| | | 1352 | * tells us whether we're working from an emulation root. |
| | | 1353 | * The TRYEMULROOT flag isn't necessarily authoritative. |
| | | 1354 | */ |
| | | 1355 | if (ndp->ni_erootdir != NULL && state->attempt_retry) { |
| | | 1356 | /* Retry the whole thing using the normal root */ |
| | | 1357 | cnp->cn_flags &= ~TRYEMULROOT; |
| | | 1358 | state->attempt_retry = 0; |
| | | 1359 | |
| | | 1360 | /* kinda gross */ |
| | | 1361 | strcpy(ndp->ni_pathbuf->pb_path, savepath); |
| | | 1362 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); |
| | | 1363 | savepath = NULL; |
| | | 1364 | |
| | | 1365 | goto emul_retry; |
| | | 1366 | } |
| | | 1367 | } |
1346 | if (savepath != NULL) { | | 1368 | if (savepath != NULL) { |
1347 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); | | 1369 | pathbuf_stringcopy_put(ndp->ni_pathbuf, savepath); |
1348 | } | | 1370 | } |
1349 | | | 1371 | return error; |
1350 | return 0; | | | |
1351 | } | | 1372 | } |
1352 | | | 1373 | |
1353 | int | | 1374 | int |
1354 | namei(struct nameidata *ndp) | | 1375 | namei(struct nameidata *ndp) |
1355 | { | | 1376 | { |
1356 | struct namei_state state; | | 1377 | struct namei_state state; |
1357 | int error; | | 1378 | int error; |
1358 | | | 1379 | |
1359 | namei_init(&state, ndp); | | 1380 | namei_init(&state, ndp); |
1360 | error = do_namei(&state, NULL, 0/*!neverfollow*/, 0/*!inhibitmagic*/); | | 1381 | error = namei_tryemulroot(&state, NULL, |
| | | 1382 | 0/*!neverfollow*/, 0/*!inhibitmagic*/); |
1361 | namei_cleanup(&state); | | 1383 | namei_cleanup(&state); |
1362 | | | 1384 | |
1363 | return error; | | 1385 | return error; |
1364 | } | | 1386 | } |
1365 | | | 1387 | |
1366 | //////////////////////////////////////////////////////////// | | 1388 | //////////////////////////////////////////////////////////// |
1367 | | | 1389 | |
1368 | /* | | 1390 | /* |
1369 | * Externally visible interfaces used by nfsd (bletch, yuk, XXX) | | 1391 | * Externally visible interfaces used by nfsd (bletch, yuk, XXX) |
1370 | * | | 1392 | * |
1371 | * The "index" version differs from the "main" version in that it's | | 1393 | * The "index" version differs from the "main" version in that it's |
1372 | * called from a different place in a different context. For now I | | 1394 | * called from a different place in a different context. For now I |
1373 | * want to be able to shuffle code in from one call site without | | 1395 | * want to be able to shuffle code in from one call site without |
| @@ -1376,27 +1398,28 @@ namei(struct nameidata *ndp) | | | @@ -1376,27 +1398,28 @@ namei(struct nameidata *ndp) |
1376 | * It turns out that the "main" version was a cut and pasted copy of | | 1398 | * It turns out that the "main" version was a cut and pasted copy of |
1377 | * namei with a few changes; the "index" version on the other hand | | 1399 | * namei with a few changes; the "index" version on the other hand |
1378 | * always takes a single component and is an elaborate form of calling | | 1400 | * always takes a single component and is an elaborate form of calling |
1379 | * VOP_LOOKUP once. | | 1401 | * VOP_LOOKUP once. |
1380 | */ | | 1402 | */ |
1381 | | | 1403 | |
1382 | int | | 1404 | int |
1383 | lookup_for_nfsd(struct nameidata *ndp, struct vnode *forcecwd, int neverfollow) | | 1405 | lookup_for_nfsd(struct nameidata *ndp, struct vnode *forcecwd, int neverfollow) |
1384 | { | | 1406 | { |
1385 | struct namei_state state; | | 1407 | struct namei_state state; |
1386 | int error; | | 1408 | int error; |
1387 | | | 1409 | |
1388 | namei_init(&state, ndp); | | 1410 | namei_init(&state, ndp); |
1389 | error = do_namei(&state, forcecwd, neverfollow, 1/*inhibitmagic*/); | | 1411 | error = namei_tryemulroot(&state, forcecwd, |
| | | 1412 | neverfollow, 1/*inhibitmagic*/); |
1390 | namei_cleanup(&state); | | 1413 | namei_cleanup(&state); |
1391 | | | 1414 | |
1392 | return error; | | 1415 | return error; |
1393 | } | | 1416 | } |
1394 | | | 1417 | |
1395 | static int | | 1418 | static int |
1396 | do_lookup_for_nfsd_index(struct namei_state *state, struct vnode *startdir) | | 1419 | do_lookup_for_nfsd_index(struct namei_state *state, struct vnode *startdir) |
1397 | { | | 1420 | { |
1398 | int error = 0; | | 1421 | int error = 0; |
1399 | | | 1422 | |
1400 | struct componentname *cnp = state->cnp; | | 1423 | struct componentname *cnp = state->cnp; |
1401 | struct nameidata *ndp = state->ndp; | | 1424 | struct nameidata *ndp = state->ndp; |
1402 | const char *cp; /* pointer into pathname argument */ | | 1425 | const char *cp; /* pointer into pathname argument */ |