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