2 * TUX - Integrated Application Protocols Layer and Object Cache
4 * Copyright (C) 2000, 2001, Ingo Molnar <mingo@redhat.com>
6 * directory.c: directory listing support
9 #define __KERNEL_SYSCALLS__
12 /****************************************************************
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 ****************************************************************/
29 char * tux_print_path (tux_req_t *req, struct dentry *dentry, struct vfsmount *mnt, char *buf, unsigned int max_len)
32 struct dentry *cwd, *root;
33 struct vfsmount *cwd_mnt, *rootmnt;
36 cwd_mnt = mntget(mnt);
37 root = dget(req->docroot_dentry);
38 rootmnt = mntget(req->docroot_mnt);
40 spin_lock(&dcache_lock);
41 res = __d_path(cwd, cwd_mnt, root, rootmnt, buf, max_len);
42 spin_unlock(&dcache_lock);
53 * There are filesystems that do not fill in ->d_type correctly.
54 * Determine file-type.
56 static int get_d_type (struct dentry *dentry)
58 unsigned int mode = dentry->d_inode->i_mode;
77 static void do_dir_line (tux_req_t *req, int cachemiss)
79 struct linux_dirent64 *dirp, *dirp0;
80 char string0[MAX_OBJECTNAME_LEN+200], *tmp;
81 int len, curroff, total, str_len = 0;
82 int err, flag = cachemiss ? 0 : LOOKUP_ATOMIC;
83 struct nameidata base = { };
84 struct dentry *dentry = NULL;
85 struct inode *inode = NULL;
86 struct vfsmount *mnt = NULL;
88 if (req->proto->check_req_err(req, cachemiss))
93 curroff = req->curroff;
96 dirp = (struct linux_dirent64 *)((char *)dirp0 + curroff);
97 if (!dirp->d_name || !dirp->d_name[0])
102 if (dirp->d_name[0] == '.')
104 Dprintk("<%s T:%d (off:%Ld) (len:%d)>\n", dirp->d_name, dirp->d_type, dirp->d_off, dirp->d_reclen);
105 if (tux_hide_unreadable) {
106 switch (dirp->d_type) {
113 /* valid entries - fall through. */
117 len = strlen(dirp->d_name);
118 if (len >= MAX_OBJECTNAME_LEN) {
119 dirp->d_name[MAX_OBJECTNAME_LEN] = 0;
120 len = MAX_OBJECTNAME_LEN-1;
127 base.last_type = LAST_ROOT;
128 base.dentry = dget(req->dentry);
129 base.mnt = mntget(req->cwd_mnt);
132 err = path_walk(dirp->d_name, &base);
134 Dprintk("path_walk() returned %d.\n", err);
137 if (err == -EWOULDBLOCKIO) {
138 add_tux_atom(req, do_dir_line);
139 queue_cachemiss(req);
145 dentry = base.dentry;
151 inode = dentry->d_inode;
155 dirp->d_type = get_d_type(dentry);
156 if (tux_hide_unreadable) {
159 mode = inode->i_mode;
160 if (mode & tux_mode_forbidden)
162 if (!(mode & tux_mode_allowed))
165 err = permission(inode, MAY_READ, NULL);
168 if (dirp->d_type == DT_DIR) {
169 err = permission(inode, MAY_EXEC, NULL);
175 tmp = req->proto->print_dir_line(req, string0, dirp->d_name, len, dirp->d_type, dentry, inode);
177 str_len = tmp-string0;
182 curroff += dirp->d_reclen;
184 if (tmp && (tmp != string0))
185 Dprintk("writing line (len: %d): <%s>\n", strlen(string0), string0);
187 if (curroff < total) {
189 req->curroff = curroff;
190 add_tux_atom(req, do_dir_line);
195 // falls back to the list_directory atom
197 if (tmp && (tmp != string0))
198 __send_async_message(req, string0, 200, str_len, 0);
200 add_req_to_workqueue(req);
203 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
204 #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
205 #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
207 static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
208 ino_t ino, unsigned int d_type)
210 struct linux_dirent64 * dirent, d;
211 struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
212 int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
215 buf->error = -EINVAL; /* only used if we fail.. */
216 if (reclen > buf->count)
218 dirent = buf->previous;
221 err = copy_to_user(&dirent->d_off, &d.d_off, sizeof(d.d_off));
224 dirent = buf->current_dir;
225 buf->previous = dirent;
226 memset(&d, 0, NAME_OFFSET(&d));
230 err = copy_to_user(dirent, &d, NAME_OFFSET(&d));
232 err = copy_to_user(dirent->d_name, name, namlen);
234 err = put_user(0, dirent->d_name + namlen);
236 dirent = (void *)dirent + reclen;
237 buf->current_dir = dirent;
238 buf->count -= reclen;
241 #define DIRENT_SIZE 3000
243 void list_directory (tux_req_t *req, int cachemiss)
245 struct getdents_callback64 buf;
246 struct linux_dirent64 *dirp0;
250 Dprintk("list_directory(%p, %d), dentry: %p.\n", req, cachemiss, req->dentry);
251 if (!req->cwd_dentry)
255 add_tux_atom(req, list_directory);
256 queue_cachemiss(req);
260 dirp0 = tux_kmalloc(DIRENT_SIZE);
262 buf.current_dir = dirp0;
264 buf.count = DIRENT_SIZE;
267 oldmm = get_fs(); set_fs(KERNEL_DS);
269 total = vfs_readdir(req->in_file, filldir64, &buf);
273 total = DIRENT_SIZE - buf.count;
275 Dprintk("total: %d (buf.error: %d, buf.previous %p)\n",
276 total, buf.error, buf.previous);
281 add_req_to_workqueue(req);
286 req->in_file->f_pos = 0;
287 add_req_to_workqueue(req);
291 if (!req->cwd_dentry)
293 add_tux_atom(req, list_directory);
298 add_tux_atom(req, do_dir_line);
300 add_req_to_workqueue(req);