diff options
-rw-r--r-- | fs/dcache.c | 90 | ||||
-rw-r--r-- | fs/seq_file.c | 65 | ||||
-rw-r--r-- | include/linux/dcache.h | 1 | ||||
-rw-r--r-- | include/linux/seq_file.h | 2 |
4 files changed, 118 insertions, 40 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 43455776711e..635c2aa427ed 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1746,6 +1746,17 @@ shouldnt_be_hashed: | |||
1746 | goto shouldnt_be_hashed; | 1746 | goto shouldnt_be_hashed; |
1747 | } | 1747 | } |
1748 | 1748 | ||
1749 | static int prepend(char **buffer, int *buflen, const char *str, | ||
1750 | int namelen) | ||
1751 | { | ||
1752 | *buflen -= namelen; | ||
1753 | if (*buflen < 0) | ||
1754 | return -ENAMETOOLONG; | ||
1755 | *buffer -= namelen; | ||
1756 | memcpy(*buffer, str, namelen); | ||
1757 | return 0; | ||
1758 | } | ||
1759 | |||
1749 | /** | 1760 | /** |
1750 | * d_path - return the path of a dentry | 1761 | * d_path - return the path of a dentry |
1751 | * @dentry: dentry to report | 1762 | * @dentry: dentry to report |
@@ -1767,17 +1778,11 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1767 | { | 1778 | { |
1768 | char * end = buffer+buflen; | 1779 | char * end = buffer+buflen; |
1769 | char * retval; | 1780 | char * retval; |
1770 | int namelen; | 1781 | |
1771 | 1782 | prepend(&end, &buflen, "\0", 1); | |
1772 | *--end = '\0'; | 1783 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && |
1773 | buflen--; | 1784 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
1774 | if (!IS_ROOT(dentry) && d_unhashed(dentry)) { | ||
1775 | buflen -= 10; | ||
1776 | end -= 10; | ||
1777 | if (buflen < 0) | ||
1778 | goto Elong; | 1785 | goto Elong; |
1779 | memcpy(end, " (deleted)", 10); | ||
1780 | } | ||
1781 | 1786 | ||
1782 | if (buflen < 1) | 1787 | if (buflen < 1) |
1783 | goto Elong; | 1788 | goto Elong; |
@@ -1804,13 +1809,10 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1804 | } | 1809 | } |
1805 | parent = dentry->d_parent; | 1810 | parent = dentry->d_parent; |
1806 | prefetch(parent); | 1811 | prefetch(parent); |
1807 | namelen = dentry->d_name.len; | 1812 | if ((prepend(&end, &buflen, dentry->d_name.name, |
1808 | buflen -= namelen + 1; | 1813 | dentry->d_name.len) != 0) || |
1809 | if (buflen < 0) | 1814 | (prepend(&end, &buflen, "/", 1) != 0)) |
1810 | goto Elong; | 1815 | goto Elong; |
1811 | end -= namelen; | ||
1812 | memcpy(end, dentry->d_name.name, namelen); | ||
1813 | *--end = '/'; | ||
1814 | retval = end; | 1816 | retval = end; |
1815 | dentry = parent; | 1817 | dentry = parent; |
1816 | } | 1818 | } |
@@ -1818,12 +1820,10 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1818 | return retval; | 1820 | return retval; |
1819 | 1821 | ||
1820 | global_root: | 1822 | global_root: |
1821 | namelen = dentry->d_name.len; | 1823 | retval += 1; /* hit the slash */ |
1822 | buflen -= namelen; | 1824 | if (prepend(&retval, &buflen, dentry->d_name.name, |
1823 | if (buflen < 0) | 1825 | dentry->d_name.len) != 0) |
1824 | goto Elong; | 1826 | goto Elong; |
1825 | retval -= namelen-1; /* hit the slash */ | ||
1826 | memcpy(retval, dentry->d_name.name, namelen); | ||
1827 | return retval; | 1827 | return retval; |
1828 | Elong: | 1828 | Elong: |
1829 | return ERR_PTR(-ENAMETOOLONG); | 1829 | return ERR_PTR(-ENAMETOOLONG); |
@@ -1859,7 +1859,7 @@ char *d_path(struct path *path, char *buf, int buflen) | |||
1859 | 1859 | ||
1860 | read_lock(¤t->fs->lock); | 1860 | read_lock(¤t->fs->lock); |
1861 | root = current->fs->root; | 1861 | root = current->fs->root; |
1862 | path_get(¤t->fs->root); | 1862 | path_get(&root); |
1863 | read_unlock(¤t->fs->lock); | 1863 | read_unlock(¤t->fs->lock); |
1864 | spin_lock(&dcache_lock); | 1864 | spin_lock(&dcache_lock); |
1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); | 1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); |
@@ -1890,6 +1890,48 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
1890 | } | 1890 | } |
1891 | 1891 | ||
1892 | /* | 1892 | /* |
1893 | * Write full pathname from the root of the filesystem into the buffer. | ||
1894 | */ | ||
1895 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | ||
1896 | { | ||
1897 | char *end = buf + buflen; | ||
1898 | char *retval; | ||
1899 | |||
1900 | spin_lock(&dcache_lock); | ||
1901 | prepend(&end, &buflen, "\0", 1); | ||
1902 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | ||
1903 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | ||
1904 | goto Elong; | ||
1905 | if (buflen < 1) | ||
1906 | goto Elong; | ||
1907 | /* Get '/' right */ | ||
1908 | retval = end-1; | ||
1909 | *retval = '/'; | ||
1910 | |||
1911 | for (;;) { | ||
1912 | struct dentry *parent; | ||
1913 | if (IS_ROOT(dentry)) | ||
1914 | break; | ||
1915 | |||
1916 | parent = dentry->d_parent; | ||
1917 | prefetch(parent); | ||
1918 | |||
1919 | if ((prepend(&end, &buflen, dentry->d_name.name, | ||
1920 | dentry->d_name.len) != 0) || | ||
1921 | (prepend(&end, &buflen, "/", 1) != 0)) | ||
1922 | goto Elong; | ||
1923 | |||
1924 | retval = end; | ||
1925 | dentry = parent; | ||
1926 | } | ||
1927 | spin_unlock(&dcache_lock); | ||
1928 | return retval; | ||
1929 | Elong: | ||
1930 | spin_unlock(&dcache_lock); | ||
1931 | return ERR_PTR(-ENAMETOOLONG); | ||
1932 | } | ||
1933 | |||
1934 | /* | ||
1893 | * NOTE! The user-level library version returns a | 1935 | * NOTE! The user-level library version returns a |
1894 | * character pointer. The kernel system call just | 1936 | * character pointer. The kernel system call just |
1895 | * returns the length of the buffer filled (which | 1937 | * returns the length of the buffer filled (which |
@@ -1918,9 +1960,9 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
1918 | 1960 | ||
1919 | read_lock(¤t->fs->lock); | 1961 | read_lock(¤t->fs->lock); |
1920 | pwd = current->fs->pwd; | 1962 | pwd = current->fs->pwd; |
1921 | path_get(¤t->fs->pwd); | 1963 | path_get(&pwd); |
1922 | root = current->fs->root; | 1964 | root = current->fs->root; |
1923 | path_get(¤t->fs->root); | 1965 | path_get(&root); |
1924 | read_unlock(¤t->fs->lock); | 1966 | read_unlock(¤t->fs->lock); |
1925 | 1967 | ||
1926 | error = -ENOENT; | 1968 | error = -ENOENT; |
diff --git a/fs/seq_file.c b/fs/seq_file.c index cdfd996ca6ef..ae59f5a6c5c1 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -350,28 +350,40 @@ int seq_printf(struct seq_file *m, const char *f, ...) | |||
350 | } | 350 | } |
351 | EXPORT_SYMBOL(seq_printf); | 351 | EXPORT_SYMBOL(seq_printf); |
352 | 352 | ||
353 | static char *mangle_path(char *s, char *p, char *esc) | ||
354 | { | ||
355 | while (s <= p) { | ||
356 | char c = *p++; | ||
357 | if (!c) { | ||
358 | return s; | ||
359 | } else if (!strchr(esc, c)) { | ||
360 | *s++ = c; | ||
361 | } else if (s + 4 > p) { | ||
362 | break; | ||
363 | } else { | ||
364 | *s++ = '\\'; | ||
365 | *s++ = '0' + ((c & 0300) >> 6); | ||
366 | *s++ = '0' + ((c & 070) >> 3); | ||
367 | *s++ = '0' + (c & 07); | ||
368 | } | ||
369 | } | ||
370 | return NULL; | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * return the absolute path of 'dentry' residing in mount 'mnt'. | ||
375 | */ | ||
353 | int seq_path(struct seq_file *m, struct path *path, char *esc) | 376 | int seq_path(struct seq_file *m, struct path *path, char *esc) |
354 | { | 377 | { |
355 | if (m->count < m->size) { | 378 | if (m->count < m->size) { |
356 | char *s = m->buf + m->count; | 379 | char *s = m->buf + m->count; |
357 | char *p = d_path(path, s, m->size - m->count); | 380 | char *p = d_path(path, s, m->size - m->count); |
358 | if (!IS_ERR(p)) { | 381 | if (!IS_ERR(p)) { |
359 | while (s <= p) { | 382 | s = mangle_path(s, p, esc); |
360 | char c = *p++; | 383 | if (s) { |
361 | if (!c) { | 384 | p = m->buf + m->count; |
362 | p = m->buf + m->count; | 385 | m->count = s - m->buf; |
363 | m->count = s - m->buf; | 386 | return s - p; |
364 | return s - p; | ||
365 | } else if (!strchr(esc, c)) { | ||
366 | *s++ = c; | ||
367 | } else if (s + 4 > p) { | ||
368 | break; | ||
369 | } else { | ||
370 | *s++ = '\\'; | ||
371 | *s++ = '0' + ((c & 0300) >> 6); | ||
372 | *s++ = '0' + ((c & 070) >> 3); | ||
373 | *s++ = '0' + (c & 07); | ||
374 | } | ||
375 | } | 387 | } |
376 | } | 388 | } |
377 | } | 389 | } |
@@ -380,6 +392,27 @@ int seq_path(struct seq_file *m, struct path *path, char *esc) | |||
380 | } | 392 | } |
381 | EXPORT_SYMBOL(seq_path); | 393 | EXPORT_SYMBOL(seq_path); |
382 | 394 | ||
395 | /* | ||
396 | * returns the path of the 'dentry' from the root of its filesystem. | ||
397 | */ | ||
398 | int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) | ||
399 | { | ||
400 | if (m->count < m->size) { | ||
401 | char *s = m->buf + m->count; | ||
402 | char *p = dentry_path(dentry, s, m->size - m->count); | ||
403 | if (!IS_ERR(p)) { | ||
404 | s = mangle_path(s, p, esc); | ||
405 | if (s) { | ||
406 | p = m->buf + m->count; | ||
407 | m->count = s - m->buf; | ||
408 | return s - p; | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | m->count = m->size; | ||
413 | return -1; | ||
414 | } | ||
415 | |||
383 | static void *single_start(struct seq_file *p, loff_t *pos) | 416 | static void *single_start(struct seq_file *p, loff_t *pos) |
384 | { | 417 | { |
385 | return NULL + (*pos == 0); | 418 | return NULL + (*pos == 0); |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index fabd16d03a27..63960033b6f5 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -302,6 +302,7 @@ extern int d_validate(struct dentry *, struct dentry *); | |||
302 | extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); | 302 | extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); |
303 | 303 | ||
304 | extern char *d_path(struct path *, char *, int); | 304 | extern char *d_path(struct path *, char *, int); |
305 | extern char *dentry_path(struct dentry *, char *, int); | ||
305 | 306 | ||
306 | /* Allocation counts.. */ | 307 | /* Allocation counts.. */ |
307 | 308 | ||
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index d65796dc26d9..11676ccef7b3 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h | |||
@@ -10,6 +10,7 @@ struct seq_operations; | |||
10 | struct file; | 10 | struct file; |
11 | struct path; | 11 | struct path; |
12 | struct inode; | 12 | struct inode; |
13 | struct dentry; | ||
13 | 14 | ||
14 | struct seq_file { | 15 | struct seq_file { |
15 | char *buf; | 16 | char *buf; |
@@ -44,6 +45,7 @@ int seq_printf(struct seq_file *, const char *, ...) | |||
44 | __attribute__ ((format (printf,2,3))); | 45 | __attribute__ ((format (printf,2,3))); |
45 | 46 | ||
46 | int seq_path(struct seq_file *, struct path *, char *); | 47 | int seq_path(struct seq_file *, struct path *, char *); |
48 | int seq_dentry(struct seq_file *, struct dentry *, char *); | ||
47 | 49 | ||
48 | int single_open(struct file *, int (*)(struct seq_file *, void *), void *); | 50 | int single_open(struct file *, int (*)(struct seq_file *, void *), void *); |
49 | int single_release(struct inode *, struct file *); | 51 | int single_release(struct inode *, struct file *); |