diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/dcache.c | 19 | ||||
| -rw-r--r-- | fs/namespace.c | 11 | ||||
| -rw-r--r-- | fs/seq_file.c | 31 |
3 files changed, 44 insertions, 17 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 33e861853287..4bbd819d97cf 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1275,7 +1275,7 @@ void d_move(struct dentry * dentry, struct dentry * target) * the string " (deleted)" is appended. Note that this is ambiguous. Returns * the buffer. * - * "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock. + * "buflen" should be positive. Caller holds the dcache_lock. */ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt, @@ -1290,9 +1290,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, if (!IS_ROOT(dentry) && d_unhashed(dentry)) { buflen -= 10; end -= 10; + if (buflen < 0) + goto Elong; memcpy(end, " (deleted)", 10); } + if (buflen < 1) + goto Elong; /* Get '/' right */ retval = end-1; *retval = '/'; @@ -1315,7 +1319,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, namelen = dentry->d_name.len; buflen -= namelen + 1; if (buflen < 0) - return ERR_PTR(-ENAMETOOLONG); + goto Elong; end -= namelen; memcpy(end, dentry->d_name.name, namelen); *--end = '/'; @@ -1328,12 +1332,13 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, global_root: namelen = dentry->d_name.len; buflen -= namelen; - if (buflen >= 0) { - retval -= namelen-1; /* hit the slash */ - memcpy(retval, dentry->d_name.name, namelen); - } else - retval = ERR_PTR(-ENAMETOOLONG); + if (buflen < 0) + goto Elong; + retval -= namelen-1; /* hit the slash */ + memcpy(retval, dentry->d_name.name, namelen); return retval; +Elong: + return ERR_PTR(-ENAMETOOLONG); } /* write full pathname into buffer and return start of pathname */ diff --git a/fs/namespace.c b/fs/namespace.c index 6c46fbda724d..09238867b43b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -211,19 +211,10 @@ static int show_vfsmnt(struct seq_file *m, void *v) { 0, NULL } }; struct proc_fs_info *fs_infop; - char *path_buf, *path; - - path_buf = (char *) __get_free_page(GFP_KERNEL); - if (!path_buf) - return -ENOMEM; - path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE); - if (IS_ERR(path)) - path = " (too long)"; mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); seq_putc(m, ' '); - mangle(m, path); - free_page((unsigned long) path_buf); + seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); seq_putc(m, ' '); mangle(m, mnt->mnt_sb->s_type->name); seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); diff --git a/fs/seq_file.c b/fs/seq_file.c index 98d7a01c14a4..7a9bcab37d49 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -297,6 +297,37 @@ int seq_printf(struct seq_file *m, const char *f, ...) return -1; } +int seq_path(struct seq_file *m, + struct vfsmount *mnt, struct dentry *dentry, + char *esc) +{ + if (m->count < m->size) { + char *s = m->buf + m->count; + char *p = d_path(dentry, mnt, s, m->size - m->count); + if (!IS_ERR(p)) { + while (s <= p) { + char c = *p++; + if (!c) { + p = m->buf + m->count; + m->count = s - m->buf; + return s - p; + } else if (!strchr(esc, c)) { + *s++ = c; + } else if (s + 4 > p) { + break; + } else { + *s++ = '\\'; + *s++ = '0' + ((c & 0300) >> 6); + *s++ = '0' + ((c & 070) >> 3); + *s++ = '0' + (c & 07); + } + } + } + } + m->count = m->size; + return -1; +} + static void *single_start(struct seq_file *p, loff_t *pos) { return NULL + (*pos == 0); |
