1 /* $NetBSD: rump_cygwin_compat.c,v 1.1 2013/04/10 16:44:54 pooka 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/param.h> 29 #include <sys/dirent.h> 30 #include <sys/fcntl.h> 31 #include <sys/file.h> 32 #include <sys/filedesc.h> 33 #include <sys/malloc.h> 34 #include <sys/namei.h> 35 #include <sys/stat.h> 36 #include <sys/syscallargs.h> 37 #include <sys/vnode.h> 38 #include <sys/vfs_syscalls.h> 39 40 #include <compat/sys/time_types.h> 41 42 #include "rump_cygwin_syscallargs.h" 43 44 struct cygwin_stat { 45 int st_dev; 46 int64_t st_ino; 47 int st_mode; 48 unsigned short st_nlink; 49 int st_uid; 50 int st_gid; 51 int st_rdev; 52 off_t st_size; 53 54 struct timespec50 st_atim; 55 struct timespec50 st_mtim; 56 struct timespec50 st_ctim; 57 58 long st_blksize; 59 uint64_t st_blocks; 60 61 struct timespec50 st_btim; 62 }; 63 64 #define PARCOPY(a) ssb->a = sb->a 65 static void 66 bsd_to_cygwin_stat(const struct stat *sb, struct cygwin_stat *ssb) 67 { 68 69 memset(ssb, 0, sizeof(*ssb)); 70 PARCOPY(st_dev); 71 PARCOPY(st_ino); 72 PARCOPY(st_mode); 73 PARCOPY(st_nlink); 74 PARCOPY(st_uid); 75 PARCOPY(st_gid); 76 PARCOPY(st_rdev); 77 PARCOPY(st_size); 78 PARCOPY(st_blksize); 79 PARCOPY(st_blocks); 80 81 timespec_to_timespec50(&sb->st_atimespec, &ssb->st_atim); 82 timespec_to_timespec50(&sb->st_mtimespec, &ssb->st_mtim); 83 timespec_to_timespec50(&sb->st_ctimespec, &ssb->st_ctim); 84 timespec_to_timespec50(&sb->st_birthtimespec, &ssb->st_btim); 85 } 86 87 int 88 rump_cygwin_sys_stat(struct lwp *l, const struct rump_cygwin_sys_stat_args *uap, 89 register_t *retval) 90 { 91 struct cygwin_stat ssb; 92 struct stat sb; 93 int error; 94 95 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 96 if (error) 97 return error; 98 99 bsd_to_cygwin_stat(&sb, &ssb); 100 101 return copyout(&ssb, SCARG(uap, sp), sizeof(ssb)); 102 } 103 104 int 105 rump_cygwin_sys_fstat(struct lwp *l, const struct rump_cygwin_sys_fstat_args *uap, 106 register_t *retval) 107 { 108 struct cygwin_stat ssb; 109 struct stat sb; 110 int error; 111 112 error = do_sys_fstat(SCARG(uap, fd), &sb); 113 if (error) 114 return error; 115 116 bsd_to_cygwin_stat(&sb, &ssb); 117 118 return copyout(&ssb, SCARG(uap, sp), sizeof(ssb)); 119 } 120 121 int 122 rump_cygwin_sys_lstat(struct lwp *l, const struct rump_cygwin_sys_lstat_args *uap, 123 register_t *retval) 124 { 125 struct cygwin_stat ssb; 126 struct stat sb; 127 int error; 128 129 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 130 if (error) 131 return error; 132 133 bsd_to_cygwin_stat(&sb, &ssb); 134 135 return copyout(&ssb, SCARG(uap, sp), sizeof(ssb)); 136 } 137 138 int 139 rump_cygwin_sys_open(struct lwp *l, const struct rump_cygwin_sys_open_args *uap, 140 register_t *retval) 141 { 142 /* { 143 syscallarg(const char *) path; 144 syscallarg(int) flags; 145 syscallarg(int) mode; 146 } */ 147 struct sys_open_args ua; 148 int sflags, flags; 149 150 sflags = SCARG(uap, flags); 151 flags = sflags & (3 | O_APPEND | O_ASYNC | O_CREAT | O_TRUNC | O_EXCL); 152 153 SCARG(&ua, path) = SCARG(uap, path); 154 SCARG(&ua, flags) = flags; 155 SCARG(&ua, mode) = SCARG(uap, mode); 156 157 return sys_open(l, &ua, retval); 158 } 159 160 #define CYGWIN_NAME_MAX 255 161 struct cygwin_dirent { 162 long d_version; 163 int64_t d_ino; 164 unsigned char d_type; 165 unsigned char d_unused[3]; 166 uint32_t d_internal; 167 char d_name[CYGWIN_NAME_MAX + 1]; 168 } __packed; 169 170 #define CYGWIN_NAMEOFF(dp) offsetof(struct cygwin_dirent,d_name) 171 #define CYGWIN_RECLEN(dp, namlen) ((CYGWIN_NAMEOFF(dp) + (namlen) + 1)) 172 173 int 174 rump_cygwin_sys_getdents(struct lwp *l, 175 const struct rump_cygwin_sys_getdents_args *uap, register_t *retval) 176 { 177 struct file *fp; 178 struct dirent *bdp; 179 struct cygwin_dirent idb; 180 char *buf, *inp, *outp; 181 size_t resid, buflen, nbytes; 182 size_t reclen, cygwin_reclen; 183 int error, done; 184 185 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 186 return (error); 187 188 /* 189 * Sneaky, but avoids having "rewind" f_offset due to the 190 * conversions not fitting from our intermediate kernel buffer 191 * into the user buffer 192 */ 193 nbytes = SCARG(uap, nbytes); 194 buflen = min(MAXBSIZE, (nbytes*8)/10); 195 buf = kmem_alloc(buflen, KM_SLEEP); 196 197 if ((fp->f_flag & FREAD) == 0) { 198 error = EBADF; 199 goto out; 200 } 201 202 resid = nbytes; 203 outp = SCARG(uap, buf); 204 205 again: 206 if ((error = vn_readdir(fp, buf, UIO_SYSSPACE, buflen, &done, 207 l, NULL, NULL)) != 0) 208 goto out; 209 if (done == 0) 210 goto eof; 211 212 for (inp = buf; done > 0; done -= reclen) { 213 bdp = (struct dirent *)inp; 214 reclen = bdp->d_reclen; 215 216 /* skip empty entries */ 217 if (bdp->d_fileno == 0) { 218 inp += reclen; 219 continue; 220 } 221 222 cygwin_reclen = CYGWIN_RECLEN(&idb, bdp->d_namlen); 223 if (resid < cygwin_reclen) { 224 panic("impossible shortage of resid"); 225 } 226 227 memset(&idb, 0, sizeof(idb)); 228 idb.d_ino = bdp->d_fileno; 229 idb.d_type = bdp->d_type; 230 strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name)); 231 if ((error = copyout(&idb, outp, cygwin_reclen)) != 0) 232 goto out; 233 234 inp += reclen; 235 outp += cygwin_reclen; 236 resid -= cygwin_reclen; 237 } 238 239 /* if we squished out the whole block, try again */ 240 if (outp == SCARG(uap, buf)) { 241 goto again; 242 } 243 244 eof: 245 *retval = nbytes - resid; 246 out: 247 kmem_free(buf, buflen); 248 fd_putfile(SCARG(uap, fd)); 249 250 return (error); 251 } 252