diff options
-rw-r--r-- | fs/namei.c | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/fs/namei.c b/fs/namei.c index ec72fa1acb14..71807dc7e402 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1383,6 +1383,25 @@ unsigned int full_name_hash(const unsigned char *name, unsigned int len) | |||
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | /* | 1385 | /* |
1386 | * We know there's a real path component here of at least | ||
1387 | * one character. | ||
1388 | */ | ||
1389 | static inline unsigned long hash_name(const char *name, unsigned int *hashp) | ||
1390 | { | ||
1391 | unsigned long hash = init_name_hash(); | ||
1392 | unsigned long len = 0, c; | ||
1393 | |||
1394 | c = (unsigned char)*name; | ||
1395 | do { | ||
1396 | len++; | ||
1397 | hash = partial_name_hash(c, hash); | ||
1398 | c = (unsigned char)name[len]; | ||
1399 | } while (c && c != '/'); | ||
1400 | *hashp = end_name_hash(hash); | ||
1401 | return len; | ||
1402 | } | ||
1403 | |||
1404 | /* | ||
1386 | * Name resolution. | 1405 | * Name resolution. |
1387 | * This is the basic name resolution function, turning a pathname into | 1406 | * This is the basic name resolution function, turning a pathname into |
1388 | * the final dentry. We expect 'base' to be positive and a directory. | 1407 | * the final dentry. We expect 'base' to be positive and a directory. |
@@ -1402,31 +1421,22 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1402 | 1421 | ||
1403 | /* At this point we know we have a real path component. */ | 1422 | /* At this point we know we have a real path component. */ |
1404 | for(;;) { | 1423 | for(;;) { |
1405 | unsigned long hash; | ||
1406 | struct qstr this; | 1424 | struct qstr this; |
1407 | unsigned int c; | 1425 | long len; |
1408 | int type; | 1426 | int type; |
1409 | 1427 | ||
1410 | err = may_lookup(nd); | 1428 | err = may_lookup(nd); |
1411 | if (err) | 1429 | if (err) |
1412 | break; | 1430 | break; |
1413 | 1431 | ||
1432 | len = hash_name(name, &this.hash); | ||
1414 | this.name = name; | 1433 | this.name = name; |
1415 | c = *(const unsigned char *)name; | 1434 | this.len = len; |
1416 | |||
1417 | hash = init_name_hash(); | ||
1418 | do { | ||
1419 | name++; | ||
1420 | hash = partial_name_hash(c, hash); | ||
1421 | c = *(const unsigned char *)name; | ||
1422 | } while (c && (c != '/')); | ||
1423 | this.len = name - (const char *) this.name; | ||
1424 | this.hash = end_name_hash(hash); | ||
1425 | 1435 | ||
1426 | type = LAST_NORM; | 1436 | type = LAST_NORM; |
1427 | if (this.name[0] == '.') switch (this.len) { | 1437 | if (name[0] == '.') switch (len) { |
1428 | case 2: | 1438 | case 2: |
1429 | if (this.name[1] == '.') { | 1439 | if (name[1] == '.') { |
1430 | type = LAST_DOTDOT; | 1440 | type = LAST_DOTDOT; |
1431 | nd->flags |= LOOKUP_JUMPED; | 1441 | nd->flags |= LOOKUP_JUMPED; |
1432 | } | 1442 | } |
@@ -1445,12 +1455,18 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1445 | } | 1455 | } |
1446 | } | 1456 | } |
1447 | 1457 | ||
1448 | /* remove trailing slashes? */ | 1458 | if (!name[len]) |
1449 | if (!c) | ||
1450 | goto last_component; | 1459 | goto last_component; |
1451 | while (*++name == '/'); | 1460 | /* |
1452 | if (!*name) | 1461 | * If it wasn't NUL, we know it was '/'. Skip that |
1462 | * slash, and continue until no more slashes. | ||
1463 | */ | ||
1464 | do { | ||
1465 | len++; | ||
1466 | } while (unlikely(name[len] == '/')); | ||
1467 | if (!name[len]) | ||
1453 | goto last_component; | 1468 | goto last_component; |
1469 | name += len; | ||
1454 | 1470 | ||
1455 | err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); | 1471 | err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); |
1456 | if (err < 0) | 1472 | if (err < 0) |