Annotation of src/sys/compat/linux/common/linux_file64.c, Revision 1.28.2.4
1.28.2.4! yamt 1: /* $NetBSD: linux_file64.c,v 1.28.2.3 2007/02/26 09:09:19 yamt Exp $ */
1.1 jdolecek 2:
3: /*-
4: * Copyright (c) 1995, 1998, 2000 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Frank van der Linden and Eric Haszlakiewicz.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*
40: * Linux 64bit filesystem calls. Used on 32bit archs, not used on 64bit ones.
41: */
1.6 lukem 42:
43: #include <sys/cdefs.h>
1.28.2.4! yamt 44: __KERNEL_RCSID(0, "$NetBSD: linux_file64.c,v 1.28.2.3 2007/02/26 09:09:19 yamt Exp $");
1.1 jdolecek 45:
46: #include <sys/param.h>
47: #include <sys/systm.h>
48: #include <sys/namei.h>
49: #include <sys/proc.h>
1.11 tron 50: #include <sys/dirent.h>
1.1 jdolecek 51: #include <sys/file.h>
52: #include <sys/stat.h>
53: #include <sys/filedesc.h>
54: #include <sys/ioctl.h>
55: #include <sys/kernel.h>
56: #include <sys/mount.h>
57: #include <sys/malloc.h>
1.28.2.4! yamt 58: #include <sys/namei.h>
! 59: #include <sys/vfs_syscalls.h>
1.1 jdolecek 60: #include <sys/vnode.h>
61: #include <sys/tty.h>
62: #include <sys/conf.h>
63:
64: #include <sys/syscallargs.h>
65:
66: #include <compat/linux/common/linux_types.h>
67: #include <compat/linux/common/linux_signal.h>
68: #include <compat/linux/common/linux_fcntl.h>
69: #include <compat/linux/common/linux_util.h>
70: #include <compat/linux/common/linux_machdep.h>
1.11 tron 71: #include <compat/linux/common/linux_dirent.h>
1.1 jdolecek 72:
73: #include <compat/linux/linux_syscallargs.h>
74:
1.15 matt 75: #ifndef alpha
76:
1.28.2.1 yamt 77: # ifndef COMPAT_LINUX32
78:
1.1 jdolecek 79: static void bsd_to_linux_stat __P((struct stat *, struct linux_stat64 *));
1.19 thorpej 80: static int linux_do_stat64 __P((struct lwp *, void *, register_t *, int));
1.1 jdolecek 81:
82: /*
83: * Convert a NetBSD stat structure to a Linux stat structure.
84: * Only the order of the fields and the padding in the structure
85: * is different. linux_fakedev is a machine-dependent function
86: * which optionally converts device driver major/minor numbers
87: * (XXX horrible, but what can you do against code that compares
88: * things against constant major device numbers? sigh)
89: */
90: static void
91: bsd_to_linux_stat(bsp, lsp)
92: struct stat *bsp;
93: struct linux_stat64 *lsp;
94: {
1.7 christos 95: lsp->lst_dev = linux_fakedev(bsp->st_dev, 0);
1.1 jdolecek 96: lsp->lst_ino = bsp->st_ino;
97: lsp->lst_mode = (linux_mode_t)bsp->st_mode;
98: if (bsp->st_nlink >= (1 << 15))
99: lsp->lst_nlink = (1 << 15) - 1;
100: else
101: lsp->lst_nlink = (linux_nlink_t)bsp->st_nlink;
102: lsp->lst_uid = bsp->st_uid;
103: lsp->lst_gid = bsp->st_gid;
1.7 christos 104: lsp->lst_rdev = linux_fakedev(bsp->st_rdev, 1);
1.1 jdolecek 105: lsp->lst_size = bsp->st_size;
106: lsp->lst_blksize = bsp->st_blksize;
107: lsp->lst_blocks = bsp->st_blocks;
108: lsp->lst_atime = bsp->st_atime;
109: lsp->lst_mtime = bsp->st_mtime;
110: lsp->lst_ctime = bsp->st_ctime;
1.28.2.1 yamt 111: # ifdef LINUX_STAT64_HAS_NSEC
1.25 christos 112: lsp->lst_atime_nsec = bsp->st_atimensec;
113: lsp->lst_mtime_nsec = bsp->st_mtimensec;
114: lsp->lst_ctime_nsec = bsp->st_ctimensec;
1.28.2.1 yamt 115: # endif
116: # if LINUX_STAT64_HAS_BROKEN_ST_INO
1.16 jdolecek 117: lsp->__lst_ino = (linux_ino_t) bsp->st_ino;
1.28.2.1 yamt 118: # endif
1.1 jdolecek 119: }
120:
121: /*
122: * The stat functions below are plain sailing. stat and lstat are handled
123: * by one function to avoid code duplication.
124: */
125: int
1.19 thorpej 126: linux_sys_fstat64(l, v, retval)
127: struct lwp *l;
1.1 jdolecek 128: void *v;
129: register_t *retval;
130: {
131: struct linux_sys_fstat64_args /* {
132: syscallarg(int) fd;
1.5 manu 133: syscallarg(struct linux_stat64 *) sp;
1.1 jdolecek 134: } */ *uap = v;
135: struct linux_stat64 tmplst;
1.28.2.4! yamt 136: struct stat tmpst;
1.1 jdolecek 137: int error;
138:
1.28.2.4! yamt 139: error = do_sys_fstat(l, SCARG(uap, fd), &tmpst);
! 140: if (error != 0)
1.1 jdolecek 141: return error;
142:
143: bsd_to_linux_stat(&tmpst, &tmplst);
144:
1.28.2.4! yamt 145: return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst);
1.1 jdolecek 146: }
147:
148: static int
1.28.2.4! yamt 149: linux_do_stat64(l, v, retval, flags)
1.19 thorpej 150: struct lwp *l;
1.1 jdolecek 151: void *v;
152: register_t *retval;
1.28.2.4! yamt 153: int flags;
1.1 jdolecek 154: {
155: struct linux_stat64 tmplst;
1.28.2.4! yamt 156: struct stat tmpst;
1.1 jdolecek 157: int error;
158: struct linux_sys_stat64_args *uap = v;
159:
1.28.2.4! yamt 160: error = do_sys_stat(l, SCARG(uap, path), flags, &tmpst);
! 161: if (error != 0)
1.1 jdolecek 162: return error;
163:
164: bsd_to_linux_stat(&tmpst, &tmplst);
165:
1.28.2.4! yamt 166: return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst);
1.1 jdolecek 167: }
168:
169: int
1.19 thorpej 170: linux_sys_stat64(l, v, retval)
171: struct lwp *l;
1.1 jdolecek 172: void *v;
173: register_t *retval;
174: {
175: struct linux_sys_stat64_args /* {
176: syscallarg(const char *) path;
177: syscallarg(struct linux_stat64 *) sp;
178: } */ *uap = v;
179:
1.28.2.4! yamt 180: return linux_do_stat64(l, uap, retval, FOLLOW);
1.1 jdolecek 181: }
182:
183: int
1.19 thorpej 184: linux_sys_lstat64(l, v, retval)
185: struct lwp *l;
1.1 jdolecek 186: void *v;
187: register_t *retval;
188: {
189: struct linux_sys_lstat64_args /* {
190: syscallarg(const char *) path;
191: syscallarg(struct linux_stat64 *) sp;
192: } */ *uap = v;
193:
1.28.2.4! yamt 194: return linux_do_stat64(l, uap, retval, NOFOLLOW);
1.2 jdolecek 195: }
196:
197: int
1.19 thorpej 198: linux_sys_truncate64(l, v, retval)
199: struct lwp *l;
1.2 jdolecek 200: void *v;
201: register_t *retval;
202: {
203: struct linux_sys_truncate64_args /* {
204: syscallarg(const char *) path;
205: syscallarg(off_t) length;
206: } */ *uap = v;
1.22 jdolecek 207: struct sys_truncate_args ta;
1.2 jdolecek 208:
1.22 jdolecek 209: /* Linux doesn't have the 'pad' pseudo-parameter */
210: SCARG(&ta, path) = SCARG(uap, path);
211: SCARG(&ta, pad) = 0;
212: SCARG(&ta, length) = SCARG(uap, length);
213:
214: return sys_truncate(l, &ta, retval);
215: }
216:
217: int
218: linux_sys_ftruncate64(l, v, retval)
219: struct lwp *l;
220: void *v;
221: register_t *retval;
222: {
223: struct linux_sys_ftruncate64_args /* {
224: syscallarg(unsigned int) fd;
225: syscallarg(off_t) length;
226: } */ *uap = v;
227: struct sys_ftruncate_args ta;
228:
229: /* Linux doesn't have the 'pad' pseudo-parameter */
230: SCARG(&ta, fd) = SCARG(uap, fd);
231: SCARG(&ta, pad) = 0;
232: SCARG(&ta, length) = SCARG(uap, length);
233:
234: return sys_ftruncate(l, &ta, retval);
1.1 jdolecek 235: }
1.28.2.1 yamt 236: # endif /* !COMPAT_LINUX32 */
1.3 manu 237:
1.28.2.1 yamt 238: # if !defined(__m68k__) && (!defined(__amd64__) || defined(COMPAT_LINUX32))
1.9 christos 239: static void bsd_to_linux_flock64 __P((struct linux_flock64 *,
240: const struct flock *));
1.24 perry 241: static void linux_to_bsd_flock64 __P((struct flock *,
1.9 christos 242: const struct linux_flock64 *));
243:
244: static void
245: bsd_to_linux_flock64(lfp, bfp)
246: struct linux_flock64 *lfp;
247: const struct flock *bfp;
248: {
249:
250: lfp->l_start = bfp->l_start;
251: lfp->l_len = bfp->l_len;
252: lfp->l_pid = bfp->l_pid;
253: lfp->l_whence = bfp->l_whence;
254: switch (bfp->l_type) {
255: case F_RDLCK:
256: lfp->l_type = LINUX_F_RDLCK;
257: break;
258: case F_UNLCK:
259: lfp->l_type = LINUX_F_UNLCK;
260: break;
261: case F_WRLCK:
262: lfp->l_type = LINUX_F_WRLCK;
263: break;
264: }
265: }
266:
267: static void
268: linux_to_bsd_flock64(bfp, lfp)
269: struct flock *bfp;
270: const struct linux_flock64 *lfp;
271: {
272:
273: bfp->l_start = lfp->l_start;
274: bfp->l_len = lfp->l_len;
275: bfp->l_pid = lfp->l_pid;
276: bfp->l_whence = lfp->l_whence;
277: switch (lfp->l_type) {
278: case LINUX_F_RDLCK:
279: bfp->l_type = F_RDLCK;
280: break;
281: case LINUX_F_UNLCK:
282: bfp->l_type = F_UNLCK;
283: break;
284: case LINUX_F_WRLCK:
285: bfp->l_type = F_WRLCK;
286: break;
287: }
288: }
1.13 jdolecek 289:
1.3 manu 290: int
1.19 thorpej 291: linux_sys_fcntl64(l, v, retval)
292: struct lwp *l;
1.3 manu 293: void *v;
294: register_t *retval;
295: {
296: struct linux_sys_fcntl64_args /* {
1.9 christos 297: syscallarg(int) fd;
298: syscallarg(int) cmd;
299: syscallarg(void *) arg;
1.3 manu 300: } */ *uap = v;
1.9 christos 301: struct linux_flock64 lfl;
1.28.2.4! yamt 302: struct flock bfl;
1.3 manu 303: int error;
1.9 christos 304: void *arg = SCARG(uap, arg);
305: int cmd = SCARG(uap, cmd);
306: int fd = SCARG(uap, fd);
1.3 manu 307:
308: switch (cmd) {
1.9 christos 309: case LINUX_F_GETLK64:
310: if ((error = copyin(arg, &lfl, sizeof lfl)) != 0)
311: return error;
312: linux_to_bsd_flock64(&bfl, &lfl);
1.28.2.4! yamt 313: error = do_fcntl_lock(l, fd, F_GETLK, &bfl);
! 314: if (error != 0)
1.9 christos 315: return error;
316: bsd_to_linux_flock64(&lfl, &bfl);
317: return copyout(&lfl, arg, sizeof lfl);
318: case LINUX_F_SETLK64:
319: case LINUX_F_SETLKW64:
320: cmd = (cmd == LINUX_F_SETLK64 ? F_SETLK : F_SETLKW);
321: if ((error = copyin(arg, &lfl, sizeof lfl)) != 0)
322: return error;
323: linux_to_bsd_flock64(&bfl, &lfl);
1.28.2.4! yamt 324: return do_fcntl_lock(l, fd, cmd, &bfl);
1.9 christos 325: default:
1.19 thorpej 326: return linux_sys_fcntl(l, v, retval);
1.3 manu 327: }
1.11 tron 328: }
1.28.2.1 yamt 329: # endif /* !m69k && !amd64 && !COMPAT_LINUX32 */
1.15 matt 330:
331: #endif /* !alpha */
1.11 tron 332:
333: /*
334: * Linux 'readdir' call. This code is mostly taken from the
335: * SunOS getdents call (see compat/sunos/sunos_misc.c), though
1.18 jdolecek 336: * an attempt has been made to keep it a little cleaner.
1.11 tron 337: *
1.18 jdolecek 338: * The d_off field contains the offset of the next valid entry,
339: * unless the older Linux getdents(2), which used to have it set
340: * to the offset of the entry itself. This function also doesn't
341: * need to deal with the old count == 1 glibc problem.
1.11 tron 342: *
343: * Read in BSD-style entries, convert them, and copy them out.
344: *
345: * Note that this doesn't handle union-mounted filesystems.
346: */
1.28.2.1 yamt 347: #ifndef COMPAT_LINUX32
1.11 tron 348: int
1.19 thorpej 349: linux_sys_getdents64(l, v, retval)
350: struct lwp *l;
1.11 tron 351: void *v;
352: register_t *retval;
353: {
354: struct linux_sys_getdents_args /* {
355: syscallarg(int) fd;
356: syscallarg(struct linux_dirent64 *) dent;
357: syscallarg(unsigned int) count;
358: } */ *uap = v;
359: struct dirent *bdp;
360: struct vnode *vp;
1.28.2.4! yamt 361: char *inp, *tbuf; /* BSD-format */
1.11 tron 362: int len, reclen; /* BSD-format */
1.28.2.4! yamt 363: char *outp; /* Linux-format */
1.11 tron 364: int resid, linux_reclen = 0; /* Linux-format */
365: struct file *fp;
366: struct uio auio;
367: struct iovec aiov;
368: struct linux_dirent64 idb;
369: off_t off; /* true file offset */
1.18 jdolecek 370: int buflen, error, eofflag, nbytes;
1.11 tron 371: struct vattr va;
372: off_t *cookiebuf = NULL, *cookie;
373: int ncookies;
374:
375: /* getvnode() will use the descriptor for us */
1.28.2.2 yamt 376: if ((error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
1.11 tron 377: return (error);
378:
379: if ((fp->f_flag & FREAD) == 0) {
380: error = EBADF;
381: goto out1;
382: }
383:
384: vp = (struct vnode *)fp->f_data;
385: if (vp->v_type != VDIR) {
386: error = EINVAL;
387: goto out1;
388: }
389:
1.28.2.2 yamt 390: if ((error = VOP_GETATTR(vp, &va, l->l_cred, l)))
1.11 tron 391: goto out1;
392:
393: nbytes = SCARG(uap, count);
1.18 jdolecek 394: buflen = min(MAXBSIZE, nbytes);
395: if (buflen < va.va_blocksize)
396: buflen = va.va_blocksize;
1.28 christos 397: tbuf = malloc(buflen, M_TEMP, M_WAITOK);
1.11 tron 398:
399: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
400: off = fp->f_offset;
401: again:
1.28 christos 402: aiov.iov_base = tbuf;
1.11 tron 403: aiov.iov_len = buflen;
404: auio.uio_iov = &aiov;
405: auio.uio_iovcnt = 1;
406: auio.uio_rw = UIO_READ;
407: auio.uio_resid = buflen;
408: auio.uio_offset = off;
1.28.2.1 yamt 409: UIO_SETUP_SYSSPACE(&auio);
1.11 tron 410: /*
411: * First we read into the malloc'ed buffer, then
412: * we massage it into user space, one record at a time.
413: */
414: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
415: &ncookies);
416: if (error)
417: goto out;
418:
1.28 christos 419: inp = tbuf;
1.28.2.4! yamt 420: outp = (void *)SCARG(uap, dent);
1.11 tron 421: resid = nbytes;
422: if ((len = buflen - auio.uio_resid) == 0)
423: goto eof;
424:
425: for (cookie = cookiebuf; len > 0; len -= reclen) {
426: bdp = (struct dirent *)inp;
427: reclen = bdp->d_reclen;
428: if (reclen & 3)
429: panic("linux_readdir");
430: if (bdp->d_fileno == 0) {
431: inp += reclen; /* it is a hole; squish it out */
1.26 christos 432: if (cookie)
433: off = *cookie++;
434: else
435: off += reclen;
1.11 tron 436: continue;
437: }
438: linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
439: if (reclen > len || resid < linux_reclen) {
440: /* entry too big for buffer, so just stop */
441: outp++;
442: break;
443: }
1.26 christos 444: if (cookie)
445: off = *cookie++; /* each entry points to next */
446: else
447: off += reclen;
1.11 tron 448: /*
449: * Massage in place to make a Linux-shaped dirent (otherwise
450: * we have to worry about touching user memory outside of
451: * the copyout() call).
452: */
453: idb.d_ino = bdp->d_fileno;
454: idb.d_type = bdp->d_type;
1.18 jdolecek 455: idb.d_off = off;
456: idb.d_reclen = (u_short)linux_reclen;
1.11 tron 457: strcpy(idb.d_name, bdp->d_name);
1.28.2.4! yamt 458: if ((error = copyout((void *)&idb, outp, linux_reclen)))
1.11 tron 459: goto out;
460: /* advance past this real entry */
461: inp += reclen;
462: /* advance output past Linux-shaped entry */
463: outp += linux_reclen;
464: resid -= linux_reclen;
465: }
466:
467: /* if we squished out the whole block, try again */
1.28.2.4! yamt 468: if (outp == (void *)SCARG(uap, dent))
1.11 tron 469: goto again;
470: fp->f_offset = off; /* update the vnode offset */
471:
472: eof:
473: *retval = nbytes - resid;
474: out:
475: VOP_UNLOCK(vp, 0);
476: if (cookiebuf)
477: free(cookiebuf, M_TEMP);
1.28 christos 478: free(tbuf, M_TEMP);
1.11 tron 479: out1:
1.28.2.1 yamt 480: FILE_UNUSE(fp, l);
1.3 manu 481: return error;
482: }
1.28.2.1 yamt 483: #endif /* !COMPAT_LINUX32 */
CVSweb <webmaster@jp.NetBSD.org>