aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c90
-rw-r--r--fs/seq_file.c65
-rw-r--r--include/linux/dcache.h1
-rw-r--r--include/linux/seq_file.h2
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
1749static 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
1820global_root: 1822global_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;
1828Elong: 1828Elong:
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(&current->fs->lock); 1860 read_lock(&current->fs->lock);
1861 root = current->fs->root; 1861 root = current->fs->root;
1862 path_get(&current->fs->root); 1862 path_get(&root);
1863 read_unlock(&current->fs->lock); 1863 read_unlock(&current->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 */
1895char *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;
1929Elong:
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(&current->fs->lock); 1961 read_lock(&current->fs->lock);
1920 pwd = current->fs->pwd; 1962 pwd = current->fs->pwd;
1921 path_get(&current->fs->pwd); 1963 path_get(&pwd);
1922 root = current->fs->root; 1964 root = current->fs->root;
1923 path_get(&current->fs->root); 1965 path_get(&root);
1924 read_unlock(&current->fs->lock); 1966 read_unlock(&current->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}
351EXPORT_SYMBOL(seq_printf); 351EXPORT_SYMBOL(seq_printf);
352 352
353static 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 */
353int seq_path(struct seq_file *m, struct path *path, char *esc) 376int 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}
381EXPORT_SYMBOL(seq_path); 393EXPORT_SYMBOL(seq_path);
382 394
395/*
396 * returns the path of the 'dentry' from the root of its filesystem.
397 */
398int 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
383static void *single_start(struct seq_file *p, loff_t *pos) 416static 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 *);
302extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); 302extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
303 303
304extern char *d_path(struct path *, char *, int); 304extern char *d_path(struct path *, char *, int);
305extern 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;
10struct file; 10struct file;
11struct path; 11struct path;
12struct inode; 12struct inode;
13struct dentry;
13 14
14struct seq_file { 15struct 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
46int seq_path(struct seq_file *, struct path *, char *); 47int seq_path(struct seq_file *, struct path *, char *);
48int seq_dentry(struct seq_file *, struct dentry *, char *);
47 49
48int single_open(struct file *, int (*)(struct seq_file *, void *), void *); 50int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
49int single_release(struct inode *, struct file *); 51int single_release(struct inode *, struct file *);