aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namei.c52
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 */
1389static 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)