]> git.karo-electronics.de Git - karo-tx-linux.git/blob - fs/compat.c
4f22a56c6fcaa06cb0b1629c61576ebcdbb2ef59
[karo-tx-linux.git] / fs / compat.c
1 /*
2  *  linux/fs/compat.c
3  *
4  *  Kernel compatibililty routines for e.g. 32 bit syscall support
5  *  on 64 bit kernels.
6  *
7  *  Copyright (C) 2002       Stephen Rothwell, IBM Corporation
8  *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
9  *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
10  *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
11  *  Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
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 version 2 as
15  *  published by the Free Software Foundation.
16  */
17
18 #include <linux/stddef.h>
19 #include <linux/kernel.h>
20 #include <linux/linkage.h>
21 #include <linux/compat.h>
22 #include <linux/errno.h>
23 #include <linux/time.h>
24 #include <linux/cred.h>
25 #include <linux/fs.h>
26 #include <linux/fcntl.h>
27 #include <linux/namei.h>
28 #include <linux/file.h>
29 #include <linux/fdtable.h>
30 #include <linux/vfs.h>
31 #include <linux/ioctl.h>
32 #include <linux/init.h>
33 #include <linux/ncp_mount.h>
34 #include <linux/nfs4_mount.h>
35 #include <linux/syscalls.h>
36 #include <linux/ctype.h>
37 #include <linux/dirent.h>
38 #include <linux/fsnotify.h>
39 #include <linux/highuid.h>
40 #include <linux/personality.h>
41 #include <linux/rwsem.h>
42 #include <linux/tsacct_kern.h>
43 #include <linux/security.h>
44 #include <linux/highmem.h>
45 #include <linux/signal.h>
46 #include <linux/mm.h>
47 #include <linux/fs_struct.h>
48 #include <linux/slab.h>
49 #include <linux/pagemap.h>
50 #include <linux/aio.h>
51
52 #include <linux/uaccess.h>
53 #include <asm/mmu_context.h>
54 #include <asm/ioctls.h>
55 #include "internal.h"
56
57 static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
58 {
59         struct compat_stat tmp;
60
61         if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
62                 return -EOVERFLOW;
63
64         memset(&tmp, 0, sizeof(tmp));
65         tmp.st_dev = old_encode_dev(stat->dev);
66         tmp.st_ino = stat->ino;
67         if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
68                 return -EOVERFLOW;
69         tmp.st_mode = stat->mode;
70         tmp.st_nlink = stat->nlink;
71         if (tmp.st_nlink != stat->nlink)
72                 return -EOVERFLOW;
73         SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
74         SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
75         tmp.st_rdev = old_encode_dev(stat->rdev);
76         if ((u64) stat->size > MAX_NON_LFS)
77                 return -EOVERFLOW;
78         tmp.st_size = stat->size;
79         tmp.st_atime = stat->atime.tv_sec;
80         tmp.st_atime_nsec = stat->atime.tv_nsec;
81         tmp.st_mtime = stat->mtime.tv_sec;
82         tmp.st_mtime_nsec = stat->mtime.tv_nsec;
83         tmp.st_ctime = stat->ctime.tv_sec;
84         tmp.st_ctime_nsec = stat->ctime.tv_nsec;
85         tmp.st_blocks = stat->blocks;
86         tmp.st_blksize = stat->blksize;
87         return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
88 }
89
90 COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename,
91                        struct compat_stat __user *, statbuf)
92 {
93         struct kstat stat;
94         int error;
95
96         error = vfs_stat(filename, &stat);
97         if (error)
98                 return error;
99         return cp_compat_stat(&stat, statbuf);
100 }
101
102 COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename,
103                        struct compat_stat __user *, statbuf)
104 {
105         struct kstat stat;
106         int error;
107
108         error = vfs_lstat(filename, &stat);
109         if (error)
110                 return error;
111         return cp_compat_stat(&stat, statbuf);
112 }
113
114 #ifndef __ARCH_WANT_STAT64
115 COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd,
116                        const char __user *, filename,
117                        struct compat_stat __user *, statbuf, int, flag)
118 {
119         struct kstat stat;
120         int error;
121
122         error = vfs_fstatat(dfd, filename, &stat, flag);
123         if (error)
124                 return error;
125         return cp_compat_stat(&stat, statbuf);
126 }
127 #endif
128
129 COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
130                        struct compat_stat __user *, statbuf)
131 {
132         struct kstat stat;
133         int error = vfs_fstat(fd, &stat);
134
135         if (!error)
136                 error = cp_compat_stat(&stat, statbuf);
137         return error;
138 }
139
140 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
141 {
142         if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
143             __get_user(kfl->l_type, &ufl->l_type) ||
144             __get_user(kfl->l_whence, &ufl->l_whence) ||
145             __get_user(kfl->l_start, &ufl->l_start) ||
146             __get_user(kfl->l_len, &ufl->l_len) ||
147             __get_user(kfl->l_pid, &ufl->l_pid))
148                 return -EFAULT;
149         return 0;
150 }
151
152 static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
153 {
154         if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
155             __put_user(kfl->l_type, &ufl->l_type) ||
156             __put_user(kfl->l_whence, &ufl->l_whence) ||
157             __put_user(kfl->l_start, &ufl->l_start) ||
158             __put_user(kfl->l_len, &ufl->l_len) ||
159             __put_user(kfl->l_pid, &ufl->l_pid))
160                 return -EFAULT;
161         return 0;
162 }
163
164 #ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
165 static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
166 {
167         if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
168             __get_user(kfl->l_type, &ufl->l_type) ||
169             __get_user(kfl->l_whence, &ufl->l_whence) ||
170             __get_user(kfl->l_start, &ufl->l_start) ||
171             __get_user(kfl->l_len, &ufl->l_len) ||
172             __get_user(kfl->l_pid, &ufl->l_pid))
173                 return -EFAULT;
174         return 0;
175 }
176 #endif
177
178 #ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
179 static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
180 {
181         if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
182             __put_user(kfl->l_type, &ufl->l_type) ||
183             __put_user(kfl->l_whence, &ufl->l_whence) ||
184             __put_user(kfl->l_start, &ufl->l_start) ||
185             __put_user(kfl->l_len, &ufl->l_len) ||
186             __put_user(kfl->l_pid, &ufl->l_pid))
187                 return -EFAULT;
188         return 0;
189 }
190 #endif
191
192 static unsigned int
193 convert_fcntl_cmd(unsigned int cmd)
194 {
195         switch (cmd) {
196         case F_GETLK64:
197                 return F_GETLK;
198         case F_SETLK64:
199                 return F_SETLK;
200         case F_SETLKW64:
201                 return F_SETLKW;
202         }
203
204         return cmd;
205 }
206
207 COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
208                        compat_ulong_t, arg)
209 {
210         mm_segment_t old_fs;
211         struct flock f;
212         long ret;
213         unsigned int conv_cmd;
214
215         switch (cmd) {
216         case F_GETLK:
217         case F_SETLK:
218         case F_SETLKW:
219                 ret = get_compat_flock(&f, compat_ptr(arg));
220                 if (ret != 0)
221                         break;
222                 old_fs = get_fs();
223                 set_fs(KERNEL_DS);
224                 ret = sys_fcntl(fd, cmd, (unsigned long)&f);
225                 set_fs(old_fs);
226                 if (cmd == F_GETLK && ret == 0) {
227                         /* GETLK was successful and we need to return the data...
228                          * but it needs to fit in the compat structure.
229                          * l_start shouldn't be too big, unless the original
230                          * start + end is greater than COMPAT_OFF_T_MAX, in which
231                          * case the app was asking for trouble, so we return
232                          * -EOVERFLOW in that case.
233                          * l_len could be too big, in which case we just truncate it,
234                          * and only allow the app to see that part of the conflicting
235                          * lock that might make sense to it anyway
236                          */
237
238                         if (f.l_start > COMPAT_OFF_T_MAX)
239                                 ret = -EOVERFLOW;
240                         if (f.l_len > COMPAT_OFF_T_MAX)
241                                 f.l_len = COMPAT_OFF_T_MAX;
242                         if (ret == 0)
243                                 ret = put_compat_flock(&f, compat_ptr(arg));
244                 }
245                 break;
246
247         case F_GETLK64:
248         case F_SETLK64:
249         case F_SETLKW64:
250         case F_OFD_GETLK:
251         case F_OFD_SETLK:
252         case F_OFD_SETLKW:
253                 ret = get_compat_flock64(&f, compat_ptr(arg));
254                 if (ret != 0)
255                         break;
256                 old_fs = get_fs();
257                 set_fs(KERNEL_DS);
258                 conv_cmd = convert_fcntl_cmd(cmd);
259                 ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f);
260                 set_fs(old_fs);
261                 if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) {
262                         /* need to return lock information - see above for commentary */
263                         if (f.l_start > COMPAT_LOFF_T_MAX)
264                                 ret = -EOVERFLOW;
265                         if (f.l_len > COMPAT_LOFF_T_MAX)
266                                 f.l_len = COMPAT_LOFF_T_MAX;
267                         if (ret == 0)
268                                 ret = put_compat_flock64(&f, compat_ptr(arg));
269                 }
270                 break;
271
272         default:
273                 ret = sys_fcntl(fd, cmd, arg);
274                 break;
275         }
276         return ret;
277 }
278
279 COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
280                        compat_ulong_t, arg)
281 {
282         switch (cmd) {
283         case F_GETLK64:
284         case F_SETLK64:
285         case F_SETLKW64:
286         case F_OFD_GETLK:
287         case F_OFD_SETLK:
288         case F_OFD_SETLKW:
289                 return -EINVAL;
290         }
291         return compat_sys_fcntl64(fd, cmd, arg);
292 }
293
294 /* A write operation does a read from user space and vice versa */
295 #define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
296
297 ssize_t compat_rw_copy_check_uvector(int type,
298                 const struct compat_iovec __user *uvector, unsigned long nr_segs,
299                 unsigned long fast_segs, struct iovec *fast_pointer,
300                 struct iovec **ret_pointer)
301 {
302         compat_ssize_t tot_len;
303         struct iovec *iov = *ret_pointer = fast_pointer;
304         ssize_t ret = 0;
305         int seg;
306
307         /*
308          * SuS says "The readv() function *may* fail if the iovcnt argument
309          * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
310          * traditionally returned zero for zero segments, so...
311          */
312         if (nr_segs == 0)
313                 goto out;
314
315         ret = -EINVAL;
316         if (nr_segs > UIO_MAXIOV)
317                 goto out;
318         if (nr_segs > fast_segs) {
319                 ret = -ENOMEM;
320                 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
321                 if (iov == NULL)
322                         goto out;
323         }
324         *ret_pointer = iov;
325
326         ret = -EFAULT;
327         if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
328                 goto out;
329
330         /*
331          * Single unix specification:
332          * We should -EINVAL if an element length is not >= 0 and fitting an
333          * ssize_t.
334          *
335          * In Linux, the total length is limited to MAX_RW_COUNT, there is
336          * no overflow possibility.
337          */
338         tot_len = 0;
339         ret = -EINVAL;
340         for (seg = 0; seg < nr_segs; seg++) {
341                 compat_uptr_t buf;
342                 compat_ssize_t len;
343
344                 if (__get_user(len, &uvector->iov_len) ||
345                    __get_user(buf, &uvector->iov_base)) {
346                         ret = -EFAULT;
347                         goto out;
348                 }
349                 if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
350                         goto out;
351                 if (type >= 0 &&
352                     !access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
353                         ret = -EFAULT;
354                         goto out;
355                 }
356                 if (len > MAX_RW_COUNT - tot_len)
357                         len = MAX_RW_COUNT - tot_len;
358                 tot_len += len;
359                 iov->iov_base = compat_ptr(buf);
360                 iov->iov_len = (compat_size_t) len;
361                 uvector++;
362                 iov++;
363         }
364         ret = tot_len;
365
366 out:
367         return ret;
368 }
369
370 struct compat_ncp_mount_data {
371         compat_int_t version;
372         compat_uint_t ncp_fd;
373         __compat_uid_t mounted_uid;
374         compat_pid_t wdog_pid;
375         unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
376         compat_uint_t time_out;
377         compat_uint_t retry_count;
378         compat_uint_t flags;
379         __compat_uid_t uid;
380         __compat_gid_t gid;
381         compat_mode_t file_mode;
382         compat_mode_t dir_mode;
383 };
384
385 struct compat_ncp_mount_data_v4 {
386         compat_int_t version;
387         compat_ulong_t flags;
388         compat_ulong_t mounted_uid;
389         compat_long_t wdog_pid;
390         compat_uint_t ncp_fd;
391         compat_uint_t time_out;
392         compat_uint_t retry_count;
393         compat_ulong_t uid;
394         compat_ulong_t gid;
395         compat_ulong_t file_mode;
396         compat_ulong_t dir_mode;
397 };
398
399 static void *do_ncp_super_data_conv(void *raw_data)
400 {
401         int version = *(unsigned int *)raw_data;
402
403         if (version == 3) {
404                 struct compat_ncp_mount_data *c_n = raw_data;
405                 struct ncp_mount_data *n = raw_data;
406
407                 n->dir_mode = c_n->dir_mode;
408                 n->file_mode = c_n->file_mode;
409                 n->gid = c_n->gid;
410                 n->uid = c_n->uid;
411                 memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
412                 n->wdog_pid = c_n->wdog_pid;
413                 n->mounted_uid = c_n->mounted_uid;
414         } else if (version == 4) {
415                 struct compat_ncp_mount_data_v4 *c_n = raw_data;
416                 struct ncp_mount_data_v4 *n = raw_data;
417
418                 n->dir_mode = c_n->dir_mode;
419                 n->file_mode = c_n->file_mode;
420                 n->gid = c_n->gid;
421                 n->uid = c_n->uid;
422                 n->retry_count = c_n->retry_count;
423                 n->time_out = c_n->time_out;
424                 n->ncp_fd = c_n->ncp_fd;
425                 n->wdog_pid = c_n->wdog_pid;
426                 n->mounted_uid = c_n->mounted_uid;
427                 n->flags = c_n->flags;
428         } else if (version != 5) {
429                 return NULL;
430         }
431
432         return raw_data;
433 }
434
435
436 struct compat_nfs_string {
437         compat_uint_t len;
438         compat_uptr_t data;
439 };
440
441 static inline void compat_nfs_string(struct nfs_string *dst,
442                                      struct compat_nfs_string *src)
443 {
444         dst->data = compat_ptr(src->data);
445         dst->len = src->len;
446 }
447
448 struct compat_nfs4_mount_data_v1 {
449         compat_int_t version;
450         compat_int_t flags;
451         compat_int_t rsize;
452         compat_int_t wsize;
453         compat_int_t timeo;
454         compat_int_t retrans;
455         compat_int_t acregmin;
456         compat_int_t acregmax;
457         compat_int_t acdirmin;
458         compat_int_t acdirmax;
459         struct compat_nfs_string client_addr;
460         struct compat_nfs_string mnt_path;
461         struct compat_nfs_string hostname;
462         compat_uint_t host_addrlen;
463         compat_uptr_t host_addr;
464         compat_int_t proto;
465         compat_int_t auth_flavourlen;
466         compat_uptr_t auth_flavours;
467 };
468
469 static int do_nfs4_super_data_conv(void *raw_data)
470 {
471         int version = *(compat_uint_t *) raw_data;
472
473         if (version == 1) {
474                 struct compat_nfs4_mount_data_v1 *raw = raw_data;
475                 struct nfs4_mount_data *real = raw_data;
476
477                 /* copy the fields backwards */
478                 real->auth_flavours = compat_ptr(raw->auth_flavours);
479                 real->auth_flavourlen = raw->auth_flavourlen;
480                 real->proto = raw->proto;
481                 real->host_addr = compat_ptr(raw->host_addr);
482                 real->host_addrlen = raw->host_addrlen;
483                 compat_nfs_string(&real->hostname, &raw->hostname);
484                 compat_nfs_string(&real->mnt_path, &raw->mnt_path);
485                 compat_nfs_string(&real->client_addr, &raw->client_addr);
486                 real->acdirmax = raw->acdirmax;
487                 real->acdirmin = raw->acdirmin;
488                 real->acregmax = raw->acregmax;
489                 real->acregmin = raw->acregmin;
490                 real->retrans = raw->retrans;
491                 real->timeo = raw->timeo;
492                 real->wsize = raw->wsize;
493                 real->rsize = raw->rsize;
494                 real->flags = raw->flags;
495                 real->version = raw->version;
496         }
497
498         return 0;
499 }
500
501 #define NCPFS_NAME      "ncpfs"
502 #define NFS4_NAME       "nfs4"
503
504 COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
505                        const char __user *, dir_name,
506                        const char __user *, type, compat_ulong_t, flags,
507                        const void __user *, data)
508 {
509         char *kernel_type;
510         void *options;
511         char *kernel_dev;
512         int retval;
513
514         kernel_type = copy_mount_string(type);
515         retval = PTR_ERR(kernel_type);
516         if (IS_ERR(kernel_type))
517                 goto out;
518
519         kernel_dev = copy_mount_string(dev_name);
520         retval = PTR_ERR(kernel_dev);
521         if (IS_ERR(kernel_dev))
522                 goto out1;
523
524         options = copy_mount_options(data);
525         retval = PTR_ERR(options);
526         if (IS_ERR(options))
527                 goto out2;
528
529         if (kernel_type && options) {
530                 if (!strcmp(kernel_type, NCPFS_NAME)) {
531                         do_ncp_super_data_conv(options);
532                 } else if (!strcmp(kernel_type, NFS4_NAME)) {
533                         retval = -EINVAL;
534                         if (do_nfs4_super_data_conv(options))
535                                 goto out3;
536                 }
537         }
538
539         retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
540
541  out3:
542         kfree(options);
543  out2:
544         kfree(kernel_dev);
545  out1:
546         kfree(kernel_type);
547  out:
548         return retval;
549 }
550
551 struct compat_old_linux_dirent {
552         compat_ulong_t  d_ino;
553         compat_ulong_t  d_offset;
554         unsigned short  d_namlen;
555         char            d_name[1];
556 };
557
558 struct compat_readdir_callback {
559         struct dir_context ctx;
560         struct compat_old_linux_dirent __user *dirent;
561         int result;
562 };
563
564 static int compat_fillonedir(struct dir_context *ctx, const char *name,
565                              int namlen, loff_t offset, u64 ino,
566                              unsigned int d_type)
567 {
568         struct compat_readdir_callback *buf =
569                 container_of(ctx, struct compat_readdir_callback, ctx);
570         struct compat_old_linux_dirent __user *dirent;
571         compat_ulong_t d_ino;
572
573         if (buf->result)
574                 return -EINVAL;
575         d_ino = ino;
576         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
577                 buf->result = -EOVERFLOW;
578                 return -EOVERFLOW;
579         }
580         buf->result++;
581         dirent = buf->dirent;
582         if (!access_ok(VERIFY_WRITE, dirent,
583                         (unsigned long)(dirent->d_name + namlen + 1) -
584                                 (unsigned long)dirent))
585                 goto efault;
586         if (    __put_user(d_ino, &dirent->d_ino) ||
587                 __put_user(offset, &dirent->d_offset) ||
588                 __put_user(namlen, &dirent->d_namlen) ||
589                 __copy_to_user(dirent->d_name, name, namlen) ||
590                 __put_user(0, dirent->d_name + namlen))
591                 goto efault;
592         return 0;
593 efault:
594         buf->result = -EFAULT;
595         return -EFAULT;
596 }
597
598 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
599                 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
600 {
601         int error;
602         struct fd f = fdget_pos(fd);
603         struct compat_readdir_callback buf = {
604                 .ctx.actor = compat_fillonedir,
605                 .dirent = dirent
606         };
607
608         if (!f.file)
609                 return -EBADF;
610
611         error = iterate_dir(f.file, &buf.ctx);
612         if (buf.result)
613                 error = buf.result;
614
615         fdput_pos(f);
616         return error;
617 }
618
619 struct compat_linux_dirent {
620         compat_ulong_t  d_ino;
621         compat_ulong_t  d_off;
622         unsigned short  d_reclen;
623         char            d_name[1];
624 };
625
626 struct compat_getdents_callback {
627         struct dir_context ctx;
628         struct compat_linux_dirent __user *current_dir;
629         struct compat_linux_dirent __user *previous;
630         int count;
631         int error;
632 };
633
634 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
635                 loff_t offset, u64 ino, unsigned int d_type)
636 {
637         struct compat_linux_dirent __user * dirent;
638         struct compat_getdents_callback *buf =
639                 container_of(ctx, struct compat_getdents_callback, ctx);
640         compat_ulong_t d_ino;
641         int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
642                 namlen + 2, sizeof(compat_long_t));
643
644         buf->error = -EINVAL;   /* only used if we fail.. */
645         if (reclen > buf->count)
646                 return -EINVAL;
647         d_ino = ino;
648         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
649                 buf->error = -EOVERFLOW;
650                 return -EOVERFLOW;
651         }
652         dirent = buf->previous;
653         if (dirent) {
654                 if (signal_pending(current))
655                         return -EINTR;
656                 if (__put_user(offset, &dirent->d_off))
657                         goto efault;
658         }
659         dirent = buf->current_dir;
660         if (__put_user(d_ino, &dirent->d_ino))
661                 goto efault;
662         if (__put_user(reclen, &dirent->d_reclen))
663                 goto efault;
664         if (copy_to_user(dirent->d_name, name, namlen))
665                 goto efault;
666         if (__put_user(0, dirent->d_name + namlen))
667                 goto efault;
668         if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
669                 goto efault;
670         buf->previous = dirent;
671         dirent = (void __user *)dirent + reclen;
672         buf->current_dir = dirent;
673         buf->count -= reclen;
674         return 0;
675 efault:
676         buf->error = -EFAULT;
677         return -EFAULT;
678 }
679
680 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
681                 struct compat_linux_dirent __user *, dirent, unsigned int, count)
682 {
683         struct fd f;
684         struct compat_linux_dirent __user * lastdirent;
685         struct compat_getdents_callback buf = {
686                 .ctx.actor = compat_filldir,
687                 .current_dir = dirent,
688                 .count = count
689         };
690         int error;
691
692         if (!access_ok(VERIFY_WRITE, dirent, count))
693                 return -EFAULT;
694
695         f = fdget_pos(fd);
696         if (!f.file)
697                 return -EBADF;
698
699         error = iterate_dir(f.file, &buf.ctx);
700         if (error >= 0)
701                 error = buf.error;
702         lastdirent = buf.previous;
703         if (lastdirent) {
704                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
705                         error = -EFAULT;
706                 else
707                         error = count - buf.count;
708         }
709         fdput_pos(f);
710         return error;
711 }
712
713 /*
714  * Exactly like fs/open.c:sys_open(), except that it doesn't set the
715  * O_LARGEFILE flag.
716  */
717 COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
718 {
719         return do_sys_open(AT_FDCWD, filename, flags, mode);
720 }
721
722 /*
723  * Exactly like fs/open.c:sys_openat(), except that it doesn't set the
724  * O_LARGEFILE flag.
725  */
726 COMPAT_SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, umode_t, mode)
727 {
728         return do_sys_open(dfd, filename, flags, mode);
729 }
730
731 #ifdef CONFIG_FHANDLE
732 /*
733  * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
734  * doesn't set the O_LARGEFILE flag.
735  */
736 COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
737                              struct file_handle __user *, handle, int, flags)
738 {
739         return do_handle_open(mountdirfd, handle, flags);
740 }
741 #endif