aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c66
1 files changed, 44 insertions, 22 deletions
diff --git a/fs/namei.c b/fs/namei.c
index a780ea515c47..e2ba62820a0f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1374,6 +1374,34 @@ static inline int can_lookup(struct inode *inode)
1374 return 1; 1374 return 1;
1375} 1375}
1376 1376
1377unsigned int full_name_hash(const unsigned char *name, unsigned int len)
1378{
1379 unsigned long hash = init_name_hash();
1380 while (len--)
1381 hash = partial_name_hash(*name++, hash);
1382 return end_name_hash(hash);
1383}
1384EXPORT_SYMBOL(full_name_hash);
1385
1386/*
1387 * We know there's a real path component here of at least
1388 * one character.
1389 */
1390static inline unsigned long hash_name(const char *name, unsigned int *hashp)
1391{
1392 unsigned long hash = init_name_hash();
1393 unsigned long len = 0, c;
1394
1395 c = (unsigned char)*name;
1396 do {
1397 len++;
1398 hash = partial_name_hash(c, hash);
1399 c = (unsigned char)name[len];
1400 } while (c && c != '/');
1401 *hashp = end_name_hash(hash);
1402 return len;
1403}
1404
1377/* 1405/*
1378 * Name resolution. 1406 * Name resolution.
1379 * This is the basic name resolution function, turning a pathname into 1407 * This is the basic name resolution function, turning a pathname into
@@ -1394,31 +1422,22 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1394 1422
1395 /* At this point we know we have a real path component. */ 1423 /* At this point we know we have a real path component. */
1396 for(;;) { 1424 for(;;) {
1397 unsigned long hash;
1398 struct qstr this; 1425 struct qstr this;
1399 unsigned int c; 1426 long len;
1400 int type; 1427 int type;
1401 1428
1402 err = may_lookup(nd); 1429 err = may_lookup(nd);
1403 if (err) 1430 if (err)
1404 break; 1431 break;
1405 1432
1433 len = hash_name(name, &this.hash);
1406 this.name = name; 1434 this.name = name;
1407 c = *(const unsigned char *)name; 1435 this.len = len;
1408
1409 hash = init_name_hash();
1410 do {
1411 name++;
1412 hash = partial_name_hash(c, hash);
1413 c = *(const unsigned char *)name;
1414 } while (c && (c != '/'));
1415 this.len = name - (const char *) this.name;
1416 this.hash = end_name_hash(hash);
1417 1436
1418 type = LAST_NORM; 1437 type = LAST_NORM;
1419 if (this.name[0] == '.') switch (this.len) { 1438 if (name[0] == '.') switch (len) {
1420 case 2: 1439 case 2:
1421 if (this.name[1] == '.') { 1440 if (name[1] == '.') {
1422 type = LAST_DOTDOT; 1441 type = LAST_DOTDOT;
1423 nd->flags |= LOOKUP_JUMPED; 1442 nd->flags |= LOOKUP_JUMPED;
1424 } 1443 }
@@ -1437,12 +1456,18 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1437 } 1456 }
1438 } 1457 }
1439 1458
1440 /* remove trailing slashes? */ 1459 if (!name[len])
1441 if (!c)
1442 goto last_component; 1460 goto last_component;
1443 while (*++name == '/'); 1461 /*
1444 if (!*name) 1462 * If it wasn't NUL, we know it was '/'. Skip that
1463 * slash, and continue until no more slashes.
1464 */
1465 do {
1466 len++;
1467 } while (unlikely(name[len] == '/'));
1468 if (!name[len])
1445 goto last_component; 1469 goto last_component;
1470 name += len;
1446 1471
1447 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW); 1472 err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
1448 if (err < 0) 1473 if (err < 0)
@@ -1775,24 +1800,21 @@ static struct dentry *lookup_hash(struct nameidata *nd)
1775struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) 1800struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
1776{ 1801{
1777 struct qstr this; 1802 struct qstr this;
1778 unsigned long hash;
1779 unsigned int c; 1803 unsigned int c;
1780 1804
1781 WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex)); 1805 WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
1782 1806
1783 this.name = name; 1807 this.name = name;
1784 this.len = len; 1808 this.len = len;
1809 this.hash = full_name_hash(name, len);
1785 if (!len) 1810 if (!len)
1786 return ERR_PTR(-EACCES); 1811 return ERR_PTR(-EACCES);
1787 1812
1788 hash = init_name_hash();
1789 while (len--) { 1813 while (len--) {
1790 c = *(const unsigned char *)name++; 1814 c = *(const unsigned char *)name++;
1791 if (c == '/' || c == '\0') 1815 if (c == '/' || c == '\0')
1792 return ERR_PTR(-EACCES); 1816 return ERR_PTR(-EACCES);
1793 hash = partial_name_hash(c, hash);
1794 } 1817 }
1795 this.hash = end_name_hash(hash);
1796 /* 1818 /*
1797 * See if the low-level filesystem might want 1819 * See if the low-level filesystem might want
1798 * to use its own hash.. 1820 * to use its own hash..