1 /* 2 * linux/fs/9p/vfs_dir.c 3 * 4 * This file contains vfs directory ops for the 9P2000 protocol. 5 * 6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 11 * as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to: 20 * Free Software Foundation 21 * 51 Franklin Street, Fifth Floor 22 * Boston, MA 02111-1301 USA 23 * 24 */ 25 26 #include <linux/module.h> 27 #include <linux/errno.h> 28 #include <linux/fs.h> 29 #include <linux/file.h> 30 #include <linux/stat.h> 31 #include <linux/string.h> 32 #include <linux/sched.h> 33 #include <linux/inet.h> 34 #include <linux/idr.h> 35 36 #include "debug.h" 37 #include "v9fs.h" 38 #include "9p.h" 39 #include "conv.h" 40 #include "v9fs_vfs.h" 41 #include "fid.h" 42 43 /** 44 * dt_type - return file type 45 * @mistat: mistat structure 46 * 47 */ 48 49 static inline int dt_type(struct v9fs_stat *mistat) 50 { 51 unsigned long perm = mistat->mode; 52 int rettype = DT_REG; 53 54 if (perm & V9FS_DMDIR) 55 rettype = DT_DIR; 56 if (perm & V9FS_DMSYMLINK) 57 rettype = DT_LNK; 58 59 return rettype; 60 } 61 62 /** 63 * v9fs_dir_readdir - read a directory 64 * @filep: opened file structure 65 * @dirent: directory structure ??? 66 * @filldir: function to populate directory structure ??? 67 * 68 */ 69 70 static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) 71 { 72 struct v9fs_fcall *fcall = NULL; 73 struct inode *inode = filp->f_path.dentry->d_inode; 74 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 75 struct v9fs_fid *file = filp->private_data; 76 unsigned int i, n, s; 77 int fid = -1; 78 int ret = 0; 79 struct v9fs_stat stat; 80 int over = 0; 81 82 dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); 83 84 fid = file->fid; 85 86 if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) { 87 kfree(file->rdir_fcall); 88 file->rdir_fcall = NULL; 89 } 90 91 if (file->rdir_fcall) { 92 n = file->rdir_fcall->params.rread.count; 93 i = file->rdir_fpos; 94 while (i < n) { 95 s = v9fs_deserialize_stat( 96 file->rdir_fcall->params.rread.data + i, 97 n - i, &stat, v9ses->extended); 98 99 if (s == 0) { 100 dprintk(DEBUG_ERROR, 101 "error while deserializing stat\n"); 102 ret = -EIO; 103 goto FreeStructs; 104 } 105 106 over = filldir(dirent, stat.name.str, stat.name.len, 107 filp->f_pos, v9fs_qid2ino(&stat.qid), 108 dt_type(&stat)); 109 110 if (over) { 111 file->rdir_fpos = i; 112 file->rdir_pos = filp->f_pos; 113 break; 114 } 115 116 i += s; 117 filp->f_pos += s; 118 } 119 120 if (!over) { 121 kfree(file->rdir_fcall); 122 file->rdir_fcall = NULL; 123 } 124 } 125 126 while (!over) { 127 ret = v9fs_t_read(v9ses, fid, filp->f_pos, 128 v9ses->maxdata-V9FS_IOHDRSZ, &fcall); 129 if (ret < 0) { 130 dprintk(DEBUG_ERROR, "error while reading: %d: %p\n", 131 ret, fcall); 132 goto FreeStructs; 133 } else if (ret == 0) 134 break; 135 136 n = ret; 137 i = 0; 138 while (i < n) { 139 s = v9fs_deserialize_stat(fcall->params.rread.data + i, 140 n - i, &stat, v9ses->extended); 141 142 if (s == 0) { 143 dprintk(DEBUG_ERROR, 144 "error while deserializing stat\n"); 145 return -EIO; 146 } 147 148 over = filldir(dirent, stat.name.str, stat.name.len, 149 filp->f_pos, v9fs_qid2ino(&stat.qid), 150 dt_type(&stat)); 151 152 if (over) { 153 file->rdir_fcall = fcall; 154 file->rdir_fpos = i; 155 file->rdir_pos = filp->f_pos; 156 fcall = NULL; 157 break; 158 } 159 160 i += s; 161 filp->f_pos += s; 162 } 163 164 kfree(fcall); 165 } 166 167 FreeStructs: 168 kfree(fcall); 169 return ret; 170 } 171 172 /** 173 * v9fs_dir_release - close a directory 174 * @inode: inode of the directory 175 * @filp: file pointer to a directory 176 * 177 */ 178 179 int v9fs_dir_release(struct inode *inode, struct file *filp) 180 { 181 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 182 struct v9fs_fid *fid = filp->private_data; 183 int fidnum = -1; 184 185 dprintk(DEBUG_VFS, "inode: %p filp: %p fid: %d\n", inode, filp, 186 fid->fid); 187 fidnum = fid->fid; 188 189 filemap_write_and_wait(inode->i_mapping); 190 191 if (fidnum >= 0) { 192 dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, 193 fid->fid); 194 195 if (v9fs_t_clunk(v9ses, fidnum)) 196 dprintk(DEBUG_ERROR, "clunk failed\n"); 197 198 kfree(fid->rdir_fcall); 199 kfree(fid); 200 201 filp->private_data = NULL; 202 } 203 204 return 0; 205 } 206 207 const struct file_operations v9fs_dir_operations = { 208 .read = generic_read_dir, 209 .readdir = v9fs_dir_readdir, 210 .open = v9fs_file_open, 211 .release = v9fs_dir_release, 212 }; 213