xref: /netbsd-src/sys/rump/kern/lib/libsys_cygwin/rump_cygwin_compat.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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