diff options
-rw-r--r-- | fs/namei.c | 48 |
1 files changed, 22 insertions, 26 deletions
diff --git a/fs/namei.c b/fs/namei.c index b9e537980ef5..4521b5ff7c93 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1362,6 +1362,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1362 | unsigned long hash; | 1362 | unsigned long hash; |
1363 | struct qstr this; | 1363 | struct qstr this; |
1364 | unsigned int c; | 1364 | unsigned int c; |
1365 | int type; | ||
1365 | 1366 | ||
1366 | nd->flags |= LOOKUP_CONTINUE; | 1367 | nd->flags |= LOOKUP_CONTINUE; |
1367 | 1368 | ||
@@ -1381,6 +1382,16 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1381 | this.len = name - (const char *) this.name; | 1382 | this.len = name - (const char *) this.name; |
1382 | this.hash = end_name_hash(hash); | 1383 | this.hash = end_name_hash(hash); |
1383 | 1384 | ||
1385 | type = LAST_NORM; | ||
1386 | if (this.name[0] == '.') switch (this.len) { | ||
1387 | case 2: | ||
1388 | if (this.name[1] == '.') | ||
1389 | type = LAST_DOTDOT; | ||
1390 | break; | ||
1391 | case 1: | ||
1392 | type = LAST_DOT; | ||
1393 | } | ||
1394 | |||
1384 | /* remove trailing slashes? */ | 1395 | /* remove trailing slashes? */ |
1385 | if (!c) | 1396 | if (!c) |
1386 | goto last_component; | 1397 | goto last_component; |
@@ -1393,21 +1404,17 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1393 | * to be able to know about the current root directory and | 1404 | * to be able to know about the current root directory and |
1394 | * parent relationships. | 1405 | * parent relationships. |
1395 | */ | 1406 | */ |
1396 | if (this.name[0] == '.') switch (this.len) { | 1407 | if (unlikely(type != LAST_NORM)) { |
1397 | default: | 1408 | if (type == LAST_DOTDOT) { |
1398 | break; | ||
1399 | case 2: | ||
1400 | if (this.name[1] != '.') | ||
1401 | break; | ||
1402 | if (nd->flags & LOOKUP_RCU) { | 1409 | if (nd->flags & LOOKUP_RCU) { |
1403 | if (follow_dotdot_rcu(nd)) | 1410 | if (follow_dotdot_rcu(nd)) |
1404 | return -ECHILD; | 1411 | return -ECHILD; |
1405 | } else | 1412 | } else |
1406 | follow_dotdot(nd); | 1413 | follow_dotdot(nd); |
1407 | /* fallthrough */ | 1414 | } |
1408 | case 1: | 1415 | continue; |
1409 | continue; | ||
1410 | } | 1416 | } |
1417 | |||
1411 | /* This does the actual lookups.. */ | 1418 | /* This does the actual lookups.. */ |
1412 | err = do_lookup(nd, &this, &next, &inode); | 1419 | err = do_lookup(nd, &this, &next, &inode); |
1413 | if (err) | 1420 | if (err) |
@@ -1441,20 +1448,15 @@ last_component: | |||
1441 | nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; | 1448 | nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; |
1442 | if (lookup_flags & LOOKUP_PARENT) | 1449 | if (lookup_flags & LOOKUP_PARENT) |
1443 | goto lookup_parent; | 1450 | goto lookup_parent; |
1444 | if (this.name[0] == '.') switch (this.len) { | 1451 | if (unlikely(type != LAST_NORM)) { |
1445 | default: | 1452 | if (type == LAST_DOTDOT) { |
1446 | break; | ||
1447 | case 2: | ||
1448 | if (this.name[1] != '.') | ||
1449 | break; | ||
1450 | if (nd->flags & LOOKUP_RCU) { | 1453 | if (nd->flags & LOOKUP_RCU) { |
1451 | if (follow_dotdot_rcu(nd)) | 1454 | if (follow_dotdot_rcu(nd)) |
1452 | return -ECHILD; | 1455 | return -ECHILD; |
1453 | } else | 1456 | } else |
1454 | follow_dotdot(nd); | 1457 | follow_dotdot(nd); |
1455 | /* fallthrough */ | 1458 | } |
1456 | case 1: | 1459 | goto return_reval; |
1457 | goto return_reval; | ||
1458 | } | 1460 | } |
1459 | err = do_lookup(nd, &this, &next, &inode); | 1461 | err = do_lookup(nd, &this, &next, &inode); |
1460 | if (err) | 1462 | if (err) |
@@ -1480,14 +1482,8 @@ last_component: | |||
1480 | goto return_base; | 1482 | goto return_base; |
1481 | lookup_parent: | 1483 | lookup_parent: |
1482 | nd->last = this; | 1484 | nd->last = this; |
1483 | nd->last_type = LAST_NORM; | 1485 | nd->last_type = type; |
1484 | if (this.name[0] != '.') | 1486 | if (type == LAST_NORM) |
1485 | goto return_base; | ||
1486 | if (this.len == 1) | ||
1487 | nd->last_type = LAST_DOT; | ||
1488 | else if (this.len == 2 && this.name[1] == '.') | ||
1489 | nd->last_type = LAST_DOTDOT; | ||
1490 | else | ||
1491 | goto return_base; | 1487 | goto return_base; |
1492 | return_reval: | 1488 | return_reval: |
1493 | /* | 1489 | /* |