1 /* 2 * linux/fs/readdir.c 3 * 4 * Copyright (C) 1995 Linus Torvalds 5 */ 6 7 #include <linux/stddef.h> 8 #include <linux/kernel.h> 9 #include <linux/export.h> 10 #include <linux/time.h> 11 #include <linux/mm.h> 12 #include <linux/errno.h> 13 #include <linux/stat.h> 14 #include <linux/file.h> 15 #include <linux/fs.h> 16 #include <linux/fsnotify.h> 17 #include <linux/dirent.h> 18 #include <linux/security.h> 19 #include <linux/syscalls.h> 20 #include <linux/unistd.h> 21 22 #include <asm/uaccess.h> 23 24 int iterate_dir(struct file *file, struct dir_context *ctx) 25 { 26 struct inode *inode = file_inode(file); 27 int res = -ENOTDIR; 28 if (!file->f_op->iterate) 29 goto out; 30 31 res = security_file_permission(file, MAY_READ); 32 if (res) 33 goto out; 34 35 inode_lock(inode); 36 // res = mutex_lock_killable(&inode->i_mutex); 37 // if (res) 38 // goto out; 39 40 res = -ENOENT; 41 if (!IS_DEADDIR(inode)) { 42 ctx->pos = file->f_pos; 43 res = file->f_op->iterate(file, ctx); 44 file->f_pos = ctx->pos; 45 fsnotify_access(file); 46 file_accessed(file); 47 } 48 inode_unlock(inode); 49 out: 50 return res; 51 } 52 EXPORT_SYMBOL(iterate_dir); 53 54 /* 55 * Traditional linux readdir() handling.. 56 * 57 * "count=1" is a special case, meaning that the buffer is one 58 * dirent-structure in size and that the code can't handle more 59 * anyway. Thus the special "fillonedir()" function for that 60 * case (the low-level handlers don't need to care about this). 61 */ 62 63 #ifdef __ARCH_WANT_OLD_READDIR 64 65 struct old_linux_dirent { 66 unsigned long d_ino; 67 unsigned long d_offset; 68 unsigned short d_namlen; 69 char d_name[1]; 70 }; 71 72 struct readdir_callback { 73 struct dir_context ctx; 74 struct old_linux_dirent __user * dirent; 75 int result; 76 }; 77 78 static int fillonedir(struct dir_context *ctx, const char *name, int namlen, 79 loff_t offset, u64 ino, unsigned int d_type) 80 { 81 struct readdir_callback *buf = 82 container_of(ctx, struct readdir_callback, ctx); 83 struct old_linux_dirent __user * dirent; 84 unsigned long d_ino; 85 86 if (buf->result) 87 return -EINVAL; 88 d_ino = ino; 89 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 90 buf->result = -EOVERFLOW; 91 return -EOVERFLOW; 92 } 93 buf->result++; 94 dirent = buf->dirent; 95 if (!access_ok(VERIFY_WRITE, dirent, 96 (unsigned long)(dirent->d_name + namlen + 1) - 97 (unsigned long)dirent)) 98 goto efault; 99 if ( __put_user(d_ino, &dirent->d_ino) || 100 __put_user(offset, &dirent->d_offset) || 101 __put_user(namlen, &dirent->d_namlen) || 102 __copy_to_user(dirent->d_name, name, namlen) || 103 __put_user(0, dirent->d_name + namlen)) 104 goto efault; 105 return 0; 106 efault: 107 buf->result = -EFAULT; 108 return -EFAULT; 109 } 110 111 SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 112 struct old_linux_dirent __user *, dirent, unsigned int, count) 113 { 114 int error; 115 struct fd f = fdget(fd); 116 struct readdir_callback buf = { 117 .ctx.actor = fillonedir, 118 .dirent = dirent 119 }; 120 121 if (!f.file) 122 return -EBADF; 123 124 error = iterate_dir(f.file, &buf.ctx); 125 if (buf.result) 126 error = buf.result; 127 128 fdput(f); 129 return error; 130 } 131 132 #endif /* __ARCH_WANT_OLD_READDIR */ 133 134 /* 135 * New, all-improved, singing, dancing, iBCS2-compliant getdents() 136 * interface. 137 */ 138 struct linux_dirent { 139 unsigned long d_ino; 140 unsigned long d_off; 141 unsigned short d_reclen; 142 char d_name[1]; 143 }; 144 145 struct getdents_callback { 146 struct dir_context ctx; 147 struct linux_dirent __user * current_dir; 148 struct linux_dirent __user * previous; 149 int count; 150 int error; 151 }; 152 153 static int filldir(struct dir_context *ctx, const char *name, int namlen, 154 loff_t offset, u64 ino, unsigned int d_type) 155 { 156 struct linux_dirent __user * dirent; 157 struct getdents_callback *buf = 158 container_of(ctx, struct getdents_callback, ctx); 159 unsigned long d_ino; 160 int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, 161 sizeof(long)); 162 163 buf->error = -EINVAL; /* only used if we fail.. */ 164 if (reclen > buf->count) 165 return -EINVAL; 166 d_ino = ino; 167 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 168 buf->error = -EOVERFLOW; 169 return -EOVERFLOW; 170 } 171 dirent = buf->previous; 172 if (dirent) { 173 if (__put_user(offset, &dirent->d_off)) 174 goto efault; 175 } 176 dirent = buf->current_dir; 177 if (__put_user(d_ino, &dirent->d_ino)) 178 goto efault; 179 if (__put_user(reclen, &dirent->d_reclen)) 180 goto efault; 181 if (copy_to_user(dirent->d_name, name, namlen)) 182 goto efault; 183 if (__put_user(0, dirent->d_name + namlen)) 184 goto efault; 185 if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 186 goto efault; 187 buf->previous = dirent; 188 dirent = (void __user *)dirent + reclen; 189 buf->current_dir = dirent; 190 buf->count -= reclen; 191 return 0; 192 efault: 193 buf->error = -EFAULT; 194 return -EFAULT; 195 } 196 197 SYSCALL_DEFINE3(getdents, unsigned int, fd, 198 struct linux_dirent __user *, dirent, unsigned int, count) 199 { 200 struct fd f; 201 struct linux_dirent __user * lastdirent; 202 struct getdents_callback buf = { 203 .ctx.actor = filldir, 204 .count = count, 205 .current_dir = dirent 206 }; 207 int error; 208 209 if (!access_ok(VERIFY_WRITE, dirent, count)) 210 return -EFAULT; 211 212 f = fdget(fd); 213 if (!f.file) 214 return -EBADF; 215 216 error = iterate_dir(f.file, &buf.ctx); 217 if (error >= 0) 218 error = buf.error; 219 lastdirent = buf.previous; 220 if (lastdirent) { 221 if (put_user(buf.ctx.pos, &lastdirent->d_off)) 222 error = -EFAULT; 223 else 224 error = count - buf.count; 225 } 226 fdput(f); 227 return error; 228 } 229 230 struct getdents_callback64 { 231 struct dir_context ctx; 232 struct linux_dirent64 __user * current_dir; 233 struct linux_dirent64 __user * previous; 234 int count; 235 int error; 236 }; 237 238 static int filldir64(struct dir_context *ctx, const char *name, int namlen, 239 loff_t offset, u64 ino, unsigned int d_type) 240 { 241 struct linux_dirent64 __user *dirent; 242 struct getdents_callback64 *buf = 243 container_of(ctx, struct getdents_callback64, ctx); 244 int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, 245 sizeof(u64)); 246 247 buf->error = -EINVAL; /* only used if we fail.. */ 248 if (reclen > buf->count) 249 return -EINVAL; 250 dirent = buf->previous; 251 if (dirent) { 252 if (__put_user(offset, &dirent->d_off)) 253 goto efault; 254 } 255 dirent = buf->current_dir; 256 if (__put_user(ino, &dirent->d_ino)) 257 goto efault; 258 if (__put_user(0, &dirent->d_off)) 259 goto efault; 260 if (__put_user(reclen, &dirent->d_reclen)) 261 goto efault; 262 if (__put_user(d_type, &dirent->d_type)) 263 goto efault; 264 if (copy_to_user(dirent->d_name, name, namlen)) 265 goto efault; 266 if (__put_user(0, dirent->d_name + namlen)) 267 goto efault; 268 buf->previous = dirent; 269 dirent = (void __user *)dirent + reclen; 270 buf->current_dir = dirent; 271 buf->count -= reclen; 272 return 0; 273 efault: 274 buf->error = -EFAULT; 275 return -EFAULT; 276 } 277 278 SYSCALL_DEFINE3(getdents64, unsigned int, fd, 279 struct linux_dirent64 __user *, dirent, unsigned int, count) 280 { 281 struct fd f; 282 struct linux_dirent64 __user * lastdirent; 283 struct getdents_callback64 buf = { 284 .ctx.actor = filldir64, 285 .count = count, 286 .current_dir = dirent 287 }; 288 int error; 289 290 if (!access_ok(VERIFY_WRITE, dirent, count)) 291 return -EFAULT; 292 293 f = fdget(fd); 294 if (!f.file) 295 return -EBADF; 296 297 error = iterate_dir(f.file, &buf.ctx); 298 if (error >= 0) 299 error = buf.error; 300 lastdirent = buf.previous; 301 if (lastdirent) { 302 typeof(lastdirent->d_off) d_off = buf.ctx.pos; 303 if (__put_user(d_off, &lastdirent->d_off)) 304 error = -EFAULT; 305 else 306 error = count - buf.count; 307 } 308 fdput(f); 309 return error; 310 } 311