1/* $NetBSD: rump_cygwin_compat.c,v 1.3 2019/01/27 02:08:49 pgoyette Exp $ */ 2 3/* 4 * Copyright (c) 2013 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: rump_cygwin_compat.c,v 1.3 2019/01/27 02:08:49 pgoyette Exp $"); 30 31#include <sys/param.h> 32#include <sys/dirent.h> 33#include <sys/fcntl.h> 34#include <sys/file.h> 35#include <sys/filedesc.h> 36#include <sys/malloc.h> 37#include <sys/namei.h> 38#include <sys/stat.h> 39#include <sys/syscallargs.h> 40#include <sys/vnode.h> 41#include <sys/vfs_syscalls.h> 42 43#include <compat/sys/time_types.h> 44 45#include "rump_cygwin_syscallargs.h" 46 47struct cygwin_stat { 48 int st_dev; 49 int64_t st_ino; 50 int st_mode; 51 unsigned short st_nlink; 52 int st_uid; 53 int st_gid; 54 int st_rdev; 55 off_t st_size; 56 57 struct timespec50 st_atim; 58 struct timespec50 st_mtim; 59 struct timespec50 st_ctim; 60 61 long st_blksize; 62 uint64_t st_blocks; 63 64 struct timespec50 st_btim; 65}; 66 67#define PARCOPY(a) ssb->a = sb->a 68static void 69bsd_to_cygwin_stat(const struct stat *sb, struct cygwin_stat *ssb) 70{ 71 72 memset(ssb, 0, sizeof(*ssb)); 73 PARCOPY(st_dev); 74 PARCOPY(st_ino); 75 PARCOPY(st_mode); 76 PARCOPY(st_nlink); 77 PARCOPY(st_uid); 78 PARCOPY(st_gid); 79 PARCOPY(st_rdev); 80 PARCOPY(st_size); 81 PARCOPY(st_blksize); 82 PARCOPY(st_blocks); 83 84 timespec_to_timespec50(&sb->st_atimespec, &ssb->st_atim); 85 timespec_to_timespec50(&sb->st_mtimespec, &ssb->st_mtim); 86 timespec_to_timespec50(&sb->st_ctimespec, &ssb->st_ctim); 87 timespec_to_timespec50(&sb->st_birthtimespec, &ssb->st_btim); 88} 89 90int 91rump_cygwin_sys_stat(struct lwp *l, const struct rump_cygwin_sys_stat_args *uap, 92 register_t *retval) 93{ 94 struct cygwin_stat ssb; 95 struct stat sb; 96 int error; 97 98 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 99 if (error) 100 return error; 101 102 bsd_to_cygwin_stat(&sb, &ssb); 103 104 return copyout(&ssb, SCARG(uap, sp), sizeof(ssb)); 105} 106 107int 108rump_cygwin_sys_fstat(struct lwp *l, const struct rump_cygwin_sys_fstat_args *uap, 109 register_t *retval) 110{ 111 struct cygwin_stat ssb; 112 struct stat sb; 113 int error; 114 115 error = do_sys_fstat(SCARG(uap, fd), &sb); 116 if (error) 117 return error; 118 119 bsd_to_cygwin_stat(&sb, &ssb); 120 121 return copyout(&ssb, SCARG(uap, sp), sizeof(ssb)); 122} 123 124int 125rump_cygwin_sys_lstat(struct lwp *l, const struct rump_cygwin_sys_lstat_args *uap, 126 register_t *retval) 127{ 128 struct cygwin_stat ssb; 129 struct stat sb; 130 int error; 131 132 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 133 if (error) 134 return error; 135 136 bsd_to_cygwin_stat(&sb, &ssb); 137 138 return copyout(&ssb, SCARG(uap, sp), sizeof(ssb)); 139} 140 141int 142rump_cygwin_sys_open(struct lwp *l, const struct rump_cygwin_sys_open_args *uap, 143 register_t *retval) 144{ 145 /* { 146 syscallarg(const char *) path; 147 syscallarg(int) flags; 148 syscallarg(int) mode; 149 } */ 150 struct sys_open_args ua; 151 int sflags, flags; 152 153 sflags = SCARG(uap, flags); 154 flags = sflags & (3 | O_APPEND | O_ASYNC | O_CREAT | O_TRUNC | O_EXCL); 155 156 SCARG(&ua, path) = SCARG(uap, path); 157 SCARG(&ua, flags) = flags; 158 SCARG(&ua, mode) = SCARG(uap, mode); 159 160 return sys_open(l, &ua, retval); 161} 162 163#define CYGWIN_NAME_MAX 255 164struct cygwin_dirent { 165 long d_version; 166 int64_t d_ino; 167 unsigned char d_type; 168 unsigned char d_unused[3]; 169 uint32_t d_internal; 170 char d_name[CYGWIN_NAME_MAX + 1]; 171} __packed; 172 173#define CYGWIN_NAMEOFF(dp) offsetof(struct cygwin_dirent,d_name) 174#define CYGWIN_RECLEN(dp, namlen) ((CYGWIN_NAMEOFF(dp) + (namlen) + 1)) 175 176int 177rump_cygwin_sys_getdents(struct lwp *l, 178 const struct rump_cygwin_sys_getdents_args *uap, register_t *retval) 179{ 180 struct file *fp; 181 struct dirent *bdp; 182 struct cygwin_dirent idb; 183 char *buf, *inp, *outp; 184 size_t resid, buflen, nbytes; 185 size_t reclen, cygwin_reclen; 186 int error, done; 187 188 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 189 return (error); 190 191 /* 192 * Sneaky, but avoids having "rewind" f_offset due to the 193 * conversions not fitting from our intermediate kernel buffer 194 * into the user buffer 195 */ 196 nbytes = SCARG(uap, nbytes); 197 buflen = min(MAXBSIZE, (nbytes*8)/10); 198 buf = kmem_alloc(buflen, KM_SLEEP); 199 200 if ((fp->f_flag & FREAD) == 0) { 201 error = EBADF; 202 goto out; 203 } 204 205 resid = nbytes; 206 outp = SCARG(uap, buf); 207 208 again: 209 if ((error = vn_readdir(fp, buf, UIO_SYSSPACE, buflen, &done, 210 l, NULL, NULL)) != 0) 211 goto out; 212 if (done == 0) 213 goto eof; 214 215 for (inp = buf; done > 0; done -= reclen) { 216 bdp = (struct dirent *)inp; 217 reclen = bdp->d_reclen; 218 219 /* skip empty entries */ 220 if (bdp->d_fileno == 0) { 221 inp += reclen; 222 continue; 223 } 224 225 cygwin_reclen = CYGWIN_RECLEN(&idb, bdp->d_namlen); 226 if (resid < cygwin_reclen) { 227 panic("impossible shortage of resid"); 228 } 229 230 memset(&idb, 0, sizeof(idb)); 231 idb.d_ino = bdp->d_fileno; 232 idb.d_type = bdp->d_type; 233 strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name)); 234 if ((error = copyout(&idb, outp, cygwin_reclen)) != 0) 235 goto out; 236 237 inp += reclen; 238 outp += cygwin_reclen; 239 resid -= cygwin_reclen; 240 } 241 242 /* if we squished out the whole block, try again */ 243 if (outp == SCARG(uap, buf)) { 244 goto again; 245 } 246 247 eof: 248 *retval = nbytes - resid; 249 out: 250 kmem_free(buf, buflen); 251 fd_putfile(SCARG(uap, fd)); 252 253 return (error); 254} 255