No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / common / vfs_syscalls_30.c
blobc1876441d316b186572fdd388eeab45633e7850f
1 /* $NetBSD: vfs_syscalls_30.c,v 1.29 2009/01/11 02:45:47 christos Exp $ */
3 /*-
4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_30.c,v 1.29 2009/01/11 02:45:47 christos Exp $");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
37 #include <sys/filedesc.h>
38 #include <sys/kernel.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/socketvar.h>
42 #include <sys/vnode.h>
43 #include <sys/mount.h>
44 #include <sys/proc.h>
45 #include <sys/uio.h>
46 #include <sys/dirent.h>
47 #include <sys/malloc.h>
48 #include <sys/kauth.h>
49 #include <sys/vfs_syscalls.h>
51 #include <sys/syscallargs.h>
53 #include <compat/common/compat_util.h>
54 #include <compat/sys/stat.h>
55 #include <compat/sys/dirent.h>
56 #include <compat/sys/mount.h>
58 static void cvtstat(struct stat13 *, const struct stat *);
61 * Convert from a new to an old stat structure.
63 static void
64 cvtstat(struct stat13 *ost, const struct stat *st)
67 ost->st_dev = st->st_dev;
68 ost->st_ino = (uint32_t)st->st_ino;
69 ost->st_mode = st->st_mode;
70 ost->st_nlink = st->st_nlink;
71 ost->st_uid = st->st_uid;
72 ost->st_gid = st->st_gid;
73 ost->st_rdev = st->st_rdev;
74 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec);
75 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec);
76 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec);
77 timespec_to_timespec50(&st->st_birthtimespec, &ost->st_birthtimespec);
78 ost->st_size = st->st_size;
79 ost->st_blocks = st->st_blocks;
80 ost->st_blksize = st->st_blksize;
81 ost->st_flags = st->st_flags;
82 ost->st_gen = st->st_gen;
86 * Get file status; this version follows links.
88 /* ARGSUSED */
89 int
90 compat_30_sys___stat13(struct lwp *l, const struct compat_30_sys___stat13_args *uap, register_t *retval)
92 /* {
93 syscallarg(const char *) path;
94 syscallarg(struct stat13 *) ub;
95 } */
96 struct stat sb;
97 struct stat13 osb;
98 int error;
100 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
101 if (error)
102 return error;
103 cvtstat(&osb, &sb);
104 error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
105 return error;
110 * Get file status; this version does not follow links.
112 /* ARGSUSED */
114 compat_30_sys___lstat13(struct lwp *l, const struct compat_30_sys___lstat13_args *uap, register_t *retval)
116 /* {
117 syscallarg(const char *) path;
118 syscallarg(struct stat13 *) ub;
119 } */
120 struct stat sb;
121 struct stat13 osb;
122 int error;
124 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb);
125 if (error)
126 return error;
127 cvtstat(&osb, &sb);
128 error = copyout(&osb, SCARG(uap, ub), sizeof (osb));
129 return error;
132 /* ARGSUSED */
134 compat_30_sys_fhstat(struct lwp *l, const struct compat_30_sys_fhstat_args *uap, register_t *retval)
136 /* {
137 syscallarg(const struct compat_30_fhandle *) fhp;
138 syscallarg(struct stat13 *) sb;
139 } */
140 struct stat sb;
141 struct stat13 osb;
142 int error;
143 struct compat_30_fhandle fh;
144 struct mount *mp;
145 struct vnode *vp;
148 * Must be super user
150 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
151 0, NULL, NULL, NULL)))
152 return (error);
154 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fh))) != 0)
155 return (error);
157 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
158 return (ESTALE);
159 if (mp->mnt_op->vfs_fhtovp == NULL)
160 return EOPNOTSUPP;
161 if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp)))
162 return (error);
163 error = vn_stat(vp, &sb);
164 vput(vp);
165 if (error)
166 return (error);
167 cvtstat(&osb, &sb);
168 error = copyout(&osb, SCARG(uap, sb), sizeof(sb));
169 return (error);
173 * Return status information about a file descriptor.
175 /* ARGSUSED */
177 compat_30_sys___fstat13(struct lwp *l, const struct compat_30_sys___fstat13_args *uap, register_t *retval)
179 /* {
180 syscallarg(int) fd;
181 syscallarg(struct stat13 *) sb;
182 } */
183 struct stat sb;
184 struct stat13 osb;
185 int error;
187 error = do_sys_fstat(SCARG(uap, fd), &sb);
188 if (error)
189 return error;
190 cvtstat(&osb, &sb);
191 error = copyout(&osb, SCARG(uap, sb), sizeof (osb));
192 return error;
196 * Read a block of directory entries in a file system independent format.
199 compat_30_sys_getdents(struct lwp *l, const struct compat_30_sys_getdents_args *uap, register_t *retval)
201 /* {
202 syscallarg(int) fd;
203 syscallarg(char *) buf;
204 syscallarg(size_t) count;
205 } */
206 struct dirent *bdp;
207 struct vnode *vp;
208 char *inp, *tbuf; /* BSD-format */
209 int len, reclen; /* BSD-format */
210 char *outp; /* NetBSD-3.0-format */
211 int resid;
212 struct file *fp;
213 struct uio auio;
214 struct iovec aiov;
215 struct dirent12 idb;
216 off_t off; /* true file offset */
217 int buflen, error, eofflag;
218 off_t *cookiebuf = NULL, *cookie;
219 int ncookies;
221 /* fd_getvnode() will use the descriptor for us */
222 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
223 return error;
225 if ((fp->f_flag & FREAD) == 0) {
226 error = EBADF;
227 goto out1;
230 vp = fp->f_data;
231 if (vp->v_type != VDIR) {
232 error = EINVAL;
233 goto out1;
236 buflen = min(MAXBSIZE, SCARG(uap, count));
237 tbuf = malloc(buflen, M_TEMP, M_WAITOK);
238 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
239 off = fp->f_offset;
240 again:
241 aiov.iov_base = tbuf;
242 aiov.iov_len = buflen;
243 auio.uio_iov = &aiov;
244 auio.uio_iovcnt = 1;
245 auio.uio_rw = UIO_READ;
246 auio.uio_resid = buflen;
247 auio.uio_offset = off;
248 UIO_SETUP_SYSSPACE(&auio);
250 * First we read into the malloc'ed buffer, then
251 * we massage it into user space, one record at a time.
253 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
254 &ncookies);
255 if (error)
256 goto out;
258 inp = tbuf;
259 outp = SCARG(uap, buf);
260 resid = SCARG(uap, count);
261 if ((len = buflen - auio.uio_resid) == 0)
262 goto eof;
264 for (cookie = cookiebuf; len > 0; len -= reclen) {
265 bdp = (struct dirent *)inp;
266 reclen = bdp->d_reclen;
267 if (reclen & _DIRENT_ALIGN(bdp))
268 panic("netbsd30_getdents: bad reclen %d", reclen);
269 if (cookie)
270 off = *cookie++; /* each entry points to the next */
271 else
272 off += reclen;
273 if ((off >> 32) != 0) {
274 compat_offseterr(vp, "netbsd30_getdents");
275 error = EINVAL;
276 goto out;
278 if (bdp->d_namlen >= sizeof(idb.d_name))
279 idb.d_namlen = sizeof(idb.d_name) - 1;
280 else
281 idb.d_namlen = bdp->d_namlen;
282 idb.d_reclen = _DIRENT_SIZE(&idb);
283 if (reclen > len || resid < idb.d_reclen) {
284 /* entry too big for buffer, so just stop */
285 outp++;
286 break;
289 * Massage in place to make a NetBSD-3.0-shaped dirent
290 * (otherwise we have to worry about touching user memory
291 * outside of the copyout() call).
293 idb.d_fileno = (u_int32_t)bdp->d_fileno;
294 idb.d_type = bdp->d_type;
295 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen);
296 memset(idb.d_name + idb.d_namlen, 0,
297 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen);
298 if ((error = copyout(&idb, outp, idb.d_reclen)) != 0)
299 goto out;
300 /* advance past this real entry */
301 inp += reclen;
302 /* advance output past NetBSD-3.0-shaped entry */
303 outp += idb.d_reclen;
304 resid -= idb.d_reclen;
307 /* if we squished out the whole block, try again */
308 if (outp == SCARG(uap, buf))
309 goto again;
310 fp->f_offset = off; /* update the vnode offset */
312 eof:
313 *retval = SCARG(uap, count) - resid;
314 out:
315 VOP_UNLOCK(vp, 0);
316 if (cookiebuf)
317 free(cookiebuf, M_TEMP);
318 free(tbuf, M_TEMP);
319 out1:
320 fd_putfile(SCARG(uap, fd));
321 return error;
325 * Get file handle system call
328 compat_30_sys_getfh(struct lwp *l, const struct compat_30_sys_getfh_args *uap, register_t *retval)
330 /* {
331 syscallarg(char *) fname;
332 syscallarg(struct compat_30_fhandle *) fhp;
333 } */
334 struct vnode *vp;
335 struct compat_30_fhandle fh;
336 int error;
337 struct nameidata nd;
338 size_t sz;
341 * Must be super user
343 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
344 0, NULL, NULL, NULL);
345 if (error)
346 return (error);
347 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
348 SCARG(uap, fname));
349 error = namei(&nd);
350 if (error)
351 return (error);
352 vp = nd.ni_vp;
353 sz = sizeof(struct compat_30_fhandle);
354 error = vfs_composefh(vp, (void *)&fh, &sz);
355 vput(vp);
356 if (sz != FHANDLE_SIZE_COMPAT) {
357 error = EINVAL;
359 if (error)
360 return (error);
361 error = copyout(&fh, SCARG(uap, fhp), sizeof(struct compat_30_fhandle));
362 return (error);
366 * Open a file given a file handle.
368 * Check permissions, allocate an open file structure,
369 * and call the device open routine if any.
372 compat_30_sys_fhopen(struct lwp *l, const struct compat_30_sys_fhopen_args *uap, register_t *retval)
374 /* {
375 syscallarg(const fhandle_t *) fhp;
376 syscallarg(int) flags;
377 } */
379 return dofhopen(l, SCARG(uap, fhp), FHANDLE_SIZE_COMPAT,
380 SCARG(uap, flags), retval);
383 /* ARGSUSED */
385 compat_30_sys___fhstat30(struct lwp *l, const struct compat_30_sys___fhstat30_args *uap_30, register_t *retval)
387 /* {
388 syscallarg(const fhandle_t *) fhp;
389 syscallarg(struct stat30 *) sb;
390 } */
391 struct stat sb;
392 struct stat13 osb;
393 int error;
395 error = do_fhstat(l, SCARG(uap_30, fhp), FHANDLE_SIZE_COMPAT, &sb);
396 if (error)
397 return error;
398 cvtstat(&osb, &sb);
399 error = copyout(&osb, SCARG(uap_30, sb), sizeof (osb));
400 return error;
403 /* ARGSUSED */
405 compat_30_sys_fhstatvfs1(struct lwp *l, const struct compat_30_sys_fhstatvfs1_args *uap_30, register_t *retval)
407 /* {
408 syscallarg(const fhandle_t *) fhp;
409 syscallarg(struct statvfs *) buf;
410 syscallarg(int) flags;
411 } */
412 struct sys___fhstatvfs140_args uap;
414 SCARG(&uap, fhp) = SCARG(uap_30, fhp);
415 SCARG(&uap, fh_size) = FHANDLE_SIZE_COMPAT;
416 SCARG(&uap, buf) = SCARG(uap_30, buf);
417 SCARG(&uap, flags) = SCARG(uap_30, flags);
419 return sys___fhstatvfs140(l, &uap, retval);