1 /*	$OpenBSD: linux_file64.c,v 1.6 2003/08/03 18:08:03 deraadt Exp $	*/
2 /*	$NetBSD: linux_file64.c,v 1.2 2000/12/12 22:24:56 jdolecek Exp $	*/
3 
4 /*-
5  * Copyright (c) 1995, 1998, 2000 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Frank van der Linden and Eric Haszlakiewicz.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * Linux 64bit filesystem calls. Used on 32bit archs, not used on 64bit ones.
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/namei.h>
47 #include <sys/proc.h>
48 #include <sys/file.h>
49 #include <sys/stat.h>
50 #include <sys/filedesc.h>
51 #include <sys/ioctl.h>
52 #include <sys/kernel.h>
53 #include <sys/mount.h>
54 #include <sys/malloc.h>
55 #include <sys/vnode.h>
56 #include <sys/tty.h>
57 #include <sys/conf.h>
58 
59 #include <sys/syscallargs.h>
60 
61 #include <compat/linux/linux_types.h>
62 #include <compat/linux/linux_signal.h>
63 #include <compat/linux/linux_syscallargs.h>
64 #include <compat/linux/linux_fcntl.h>
65 #include <compat/linux/linux_util.h>
66 
67 #include <machine/linux_machdep.h>
68 
69 
70 void bsd_to_linux_flock64(struct flock *, struct linux_flock64 *);
71 void linux_to_bsd_flock64(struct linux_flock64 *, struct flock *);
72 static void bsd_to_linux_stat(struct stat *, struct linux_stat64 *);
73 static int linux_do_stat64(struct proc *, void *, register_t *, int);
74 
75 /*
76  * Convert a OpenBSD stat structure to a Linux stat structure.
77  * Only the order of the fields and the padding in the structure
78  * is different. linux_fakedev is a machine-dependent function
79  * which optionally converts device driver major/minor numbers
80  * (XXX horrible, but what can you do against code that compares
81  * things against constant major device numbers? sigh)
82  */
83 static void
bsd_to_linux_stat(bsp,lsp)84 bsd_to_linux_stat(bsp, lsp)
85 	struct stat *bsp;
86 	struct linux_stat64 *lsp;
87 {
88 	lsp->lst_dev     = bsp->st_dev;
89 	lsp->lst_ino     = bsp->st_ino;
90 	lsp->lst_mode    = (linux_mode_t)bsp->st_mode;
91 	if (bsp->st_nlink >= (1 << 15))
92 		lsp->lst_nlink = (1 << 15) - 1;
93 	else
94 		lsp->lst_nlink = (linux_nlink_t)bsp->st_nlink;
95 	lsp->lst_uid     = bsp->st_uid;
96 	lsp->lst_gid     = bsp->st_gid;
97 	lsp->lst_rdev    = linux_fakedev(bsp->st_rdev);
98 	lsp->lst_size    = bsp->st_size;
99 	lsp->lst_blksize = bsp->st_blksize;
100 	lsp->lst_blocks  = bsp->st_blocks;
101 	lsp->lst_atime   = bsp->st_atime;
102 	lsp->lst_mtime   = bsp->st_mtime;
103 	lsp->lst_ctime   = bsp->st_ctime;
104 #if LINUX_STAT64_HAS_BROKEN_ST_INO
105 	lsp->__lst_ino   = (linux_ino_t)bsp->st_ino;
106 #endif
107 }
108 
109 /*
110  * The stat functions below are plain sailing. stat and lstat are handled
111  * by one function to avoid code duplication.
112  */
113 int
linux_sys_fstat64(p,v,retval)114 linux_sys_fstat64(p, v, retval)
115 	struct proc *p;
116 	void *v;
117 	register_t *retval;
118 {
119 	struct linux_sys_fstat64_args /* {
120 		syscallarg(int) fd;
121 		syscallarg(linux_stat64 *) sp;
122 	} */ *uap = v;
123 	struct sys_fstat_args fsa;
124 	struct linux_stat64 tmplst;
125 	struct stat *st,tmpst;
126 	caddr_t sg;
127 	int error;
128 
129 	sg = stackgap_init(p->p_emul);
130 
131 	st = stackgap_alloc(&sg, sizeof (struct stat));
132 
133 	SCARG(&fsa, fd) = SCARG(uap, fd);
134 	SCARG(&fsa, sb) = st;
135 
136 	if ((error = sys_fstat(p, &fsa, retval)))
137 		return error;
138 
139 	if ((error = copyin(st, &tmpst, sizeof tmpst)))
140 		return error;
141 
142 	bsd_to_linux_stat(&tmpst, &tmplst);
143 
144 	if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
145 		return error;
146 
147 	return 0;
148 }
149 
150 static int
linux_do_stat64(p,v,retval,dolstat)151 linux_do_stat64(p, v, retval, dolstat)
152 	struct proc *p;
153 	void *v;
154 	register_t *retval;
155 	int dolstat;
156 {
157 	struct sys_stat_args sa;
158 	struct linux_stat64 tmplst;
159 	struct stat *st, tmpst;
160 	caddr_t sg;
161 	int error;
162 	struct linux_sys_stat64_args *uap = v;
163 
164 	sg = stackgap_init(p->p_emul);
165 	st = stackgap_alloc(&sg, sizeof (struct stat));
166 	LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
167 
168 	SCARG(&sa, ub) = st;
169 	SCARG(&sa, path) = SCARG(uap, path);
170 
171 	if ((error = (dolstat ? sys_lstat(p, &sa, retval) :
172 				sys_stat(p, &sa, retval))))
173 		return error;
174 
175 	if ((error = copyin(st, &tmpst, sizeof tmpst)))
176 		return error;
177 
178 	bsd_to_linux_stat(&tmpst, &tmplst);
179 
180 	if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
181 		return error;
182 
183 	return 0;
184 }
185 
186 int
linux_sys_stat64(p,v,retval)187 linux_sys_stat64(p, v, retval)
188 	struct proc *p;
189 	void *v;
190 	register_t *retval;
191 {
192 	struct linux_sys_stat64_args /* {
193 		syscallarg(const char *) path;
194 		syscallarg(struct linux_stat64 *) sp;
195 	} */ *uap = v;
196 
197 	return linux_do_stat64(p, uap, retval, 0);
198 }
199 
200 int
linux_sys_lstat64(p,v,retval)201 linux_sys_lstat64(p, v, retval)
202 	struct proc *p;
203 	void *v;
204 	register_t *retval;
205 {
206 	struct linux_sys_lstat64_args /* {
207 		syscallarg(char *) path;
208 		syscallarg(struct linux_stat64 *) sp;
209 	} */ *uap = v;
210 
211 	return linux_do_stat64(p, uap, retval, 1);
212 }
213 
214 int
linux_sys_truncate64(p,v,retval)215 linux_sys_truncate64(p, v, retval)
216 	struct proc *p;
217 	void *v;
218 	register_t *retval;
219 {
220 	struct linux_sys_truncate64_args /* {
221 		syscallarg(char *) path;
222 		syscallarg(off_t) length;
223 	} */ *uap = v;
224 	struct sys_truncate_args ta;
225 	caddr_t sg = stackgap_init(p->p_emul);
226 
227 	LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
228 
229 	SCARG(&ta, path) = SCARG(uap, path);
230 	SCARG(&ta, length) = SCARG(uap, length);
231 
232 	return sys_truncate(p, &ta, retval);
233 }
234 
235 /*
236  * This is needed due to padding in OpenBSD's sys_ftruncate_args
237  */
238 int
linux_sys_ftruncate64(p,v,retval)239 linux_sys_ftruncate64(p, v, retval)
240 	struct proc *p;
241 	void *v;
242 	register_t *retval;
243 {
244 	struct linux_sys_ftruncate64_args /* {
245 		syscallarg(int) fd;
246 		syscallarg(off_t) length;
247         } */ *uap = v;
248 	struct sys_ftruncate_args fta;
249 
250 	SCARG(&fta, fd) = SCARG(uap, fd);
251 	SCARG(&fta, length) = SCARG(uap, length);
252 
253 	return sys_ftruncate(p, &fta, retval);
254 }
255 
256 /*
257  * The next two functions take care of converting the flock
258  * structure back and forth between Linux and OpenBSD format.
259  * The only difference in the structures is the order of
260  * the fields, and the 'whence' value.
261  */
262 void
bsd_to_linux_flock64(struct flock * bfp,struct linux_flock64 * lfp)263 bsd_to_linux_flock64(struct flock *bfp, struct linux_flock64 *lfp)
264 {
265 	lfp->l_start = bfp->l_start;
266 	lfp->l_len = bfp->l_len;
267 	lfp->l_pid = bfp->l_pid;
268 	lfp->l_whence = bfp->l_whence;
269 	switch (bfp->l_type) {
270 	case F_RDLCK:
271 		lfp->l_type = LINUX_F_RDLCK;
272 		break;
273 	case F_UNLCK:
274 		lfp->l_type = LINUX_F_UNLCK;
275 		break;
276 	case F_WRLCK:
277 		lfp->l_type = LINUX_F_WRLCK;
278 		break;
279 	}
280 }
281 
282 void
linux_to_bsd_flock64(struct linux_flock64 * lfp,struct flock * bfp)283 linux_to_bsd_flock64(struct linux_flock64 *lfp, struct flock *bfp)
284 {
285 	bfp->l_start = lfp->l_start;
286 	bfp->l_len = lfp->l_len;
287 	bfp->l_pid = lfp->l_pid;
288 	bfp->l_whence = lfp->l_whence;
289 	switch (lfp->l_type) {
290 	case LINUX_F_RDLCK:
291 		bfp->l_type = F_RDLCK;
292 		break;
293 	case LINUX_F_UNLCK:
294 		bfp->l_type = F_UNLCK;
295 		break;
296 	case LINUX_F_WRLCK:
297 		bfp->l_type = F_WRLCK;
298 		break;
299 	}
300 }
301 
302 int
linux_sys_fcntl64(p,v,retval)303 linux_sys_fcntl64(p, v, retval)
304 	struct proc *p;
305 	void *v;
306 	register_t *retval;
307 {
308 	struct linux_sys_fcntl64_args /* {
309 		syscallarg(u_int) fd;
310 		syscallarg(u_int) cmd;
311 		syscallarg(void *) arg;
312 	} */ *uap = v;
313 	int fd, cmd, error;
314 	caddr_t arg, sg;
315 	struct linux_flock64 lfl;
316 	struct flock *bfp, bfl;
317 	struct sys_fcntl_args fca;
318 
319 	fd = SCARG(uap, fd);
320 	cmd = SCARG(uap, cmd);
321 	arg = (caddr_t) SCARG(uap, arg);
322 
323 	switch (cmd) {
324 	case LINUX_F_GETLK64:
325 		sg = stackgap_init(p->p_emul);
326 		if ((error = copyin(arg, &lfl, sizeof lfl)))
327 			return error;
328 		linux_to_bsd_flock64(&lfl, &bfl);
329 		bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
330 		SCARG(&fca, fd) = fd;
331 		SCARG(&fca, cmd) = F_GETLK;
332 		SCARG(&fca, arg) = bfp;
333 		if ((error = copyout(&bfl, bfp, sizeof bfl)))
334 			return error;
335 		if ((error = sys_fcntl(p, &fca, retval)))
336 			return error;
337 		if ((error = copyin(bfp, &bfl, sizeof bfl)))
338 			return error;
339 		bsd_to_linux_flock64(&bfl, &lfl);
340 		error = copyout(&lfl, arg, sizeof lfl);
341 		return (error);
342 	case LINUX_F_SETLK64:
343 	case LINUX_F_SETLKW64:
344 		cmd = (cmd == LINUX_F_SETLK64 ? F_SETLK : F_SETLKW);
345 		if ((error = copyin(arg, &lfl, sizeof lfl)))
346 			return error;
347 		linux_to_bsd_flock64(&lfl, &bfl);
348 		sg = stackgap_init(p->p_emul);
349 		bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
350 		if ((error = copyout(&bfl, bfp, sizeof bfl)))
351 			return error;
352 		SCARG(&fca, fd) = fd;
353 		SCARG(&fca, cmd) = cmd;
354 		SCARG(&fca, arg) = bfp;
355 		return (sys_fcntl(p, &fca, retval));
356 	default:
357 		return (linux_sys_fcntl(p, v, retval));
358 	}
359 	/* NOTREACHED */
360 }
361