1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2017, Joyent, Inc.
25 * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
26 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
27 */
28
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32 /*
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
35 * All Rights Reserved
36 *
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
39 * contributors.
40 */
41
42 /*
43 * Portions of code from both of:
44 * syscall/open.c
45 * fs/vnode.c
46 * heavily modified for this use.
47 */
48
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <sys/t_lock.h>
52 #include <sys/errno.h>
53 #include <sys/cred.h>
54 #include <sys/user.h>
55 #include <sys/uio.h>
56 #include <sys/file.h>
57 #include <sys/pathname.h>
58 #include <sys/vfs.h>
59 #include <sys/vfs_opreg.h>
60 #include <sys/vnode.h>
61 #include <sys/rwstlock.h>
62 #include <sys/fem.h>
63 #include <sys/stat.h>
64 #include <sys/mode.h>
65 #include <sys/conf.h>
66 #include <sys/sysmacros.h>
67 #include <sys/cmn_err.h>
68 #include <sys/systm.h>
69 #include <sys/kmem.h>
70 #include <sys/debug.h>
71 #include <sys/acl.h>
72 #include <sys/nbmlock.h>
73 #include <sys/fcntl.h>
74 #include <fs/fs_subr.h>
75 #include <sys/taskq.h>
76 #include <fs/fs_reparse.h>
77 #include <sys/time.h>
78
79 #include <libfksmbfs.h>
80
81 /* close and release */
82 int
vn_close_rele(vnode_t * vp,int flag)83 vn_close_rele(vnode_t *vp, int flag)
84 {
85 int error;
86
87 error = VOP_CLOSE(vp, flag, 0, 0, CRED(), NULL);
88 vn_rele(vp);
89
90 return (error);
91 }
92
93 /*
94 * Open/create a vnode.
95 * This may be callable by the kernel, the only known use
96 * of user context being that the current user credentials
97 * are used for permissions. crwhy is defined iff filemode & FCREAT.
98 */
99 int
vn_open(char * pnamep,enum uio_seg seg,int filemode,int createmode,struct vnode ** vpp,enum create crwhy,mode_t umask)100 vn_open(
101 char *pnamep,
102 enum uio_seg seg,
103 int filemode,
104 int createmode,
105 struct vnode **vpp,
106 enum create crwhy,
107 mode_t umask)
108 {
109 struct vnode *vp;
110 int mode;
111 int accessflags;
112 int error;
113 int open_done = 0;
114 struct vattr vattr;
115 int estale_retry = 0;
116
117 mode = 0;
118 accessflags = 0;
119 if (filemode & FREAD)
120 mode |= VREAD;
121 if (filemode & (FWRITE|FTRUNC))
122 mode |= VWRITE;
123 if (filemode & (FSEARCH|FEXEC|FXATTRDIROPEN))
124 mode |= VEXEC;
125
126 if (filemode & FAPPEND)
127 accessflags |= V_APPEND;
128
129 top:
130 if (filemode & FCREAT) {
131 enum vcexcl excl;
132
133 /*
134 * Wish to create a file.
135 */
136 vattr.va_type = VREG;
137 vattr.va_mode = createmode;
138 vattr.va_mask = AT_TYPE|AT_MODE;
139 if (filemode & FTRUNC) {
140 vattr.va_size = 0;
141 vattr.va_mask |= AT_SIZE;
142 }
143 if (filemode & FEXCL)
144 excl = EXCL;
145 else
146 excl = NONEXCL;
147
148 if ((error =
149 vn_create(pnamep, seg, &vattr, excl, mode, &vp, crwhy,
150 (filemode & ~(FTRUNC|FEXCL)), umask)) != 0)
151 return (error);
152 } else {
153 /*
154 * Wish to open a file. Just look it up.
155 * Was lookupnameat()
156 */
157 if ((error = fake_lookup(NULL, pnamep, &vp)) != 0) {
158 if ((error == ESTALE) &&
159 fs_need_estale_retry(estale_retry++))
160 goto top;
161 return (error);
162 }
163
164 /*
165 * Want the XATTRDIR under it?
166 */
167 if (filemode & FXATTRDIROPEN) {
168 vnode_t *xvp = NULL;
169 error = VOP_LOOKUP(vp, NULL, &xvp, NULL,
170 LOOKUP_XATTR, rootdir, CRED(), NULL,
171 NULL, NULL);
172 VN_RELE(vp);
173 vp = xvp;
174 /* continue with vp */
175 }
176
177 /*
178 * Can't write directories, active texts, or
179 * read-only filesystems. Can't truncate files
180 * on which mandatory locking is in effect.
181 */
182 if (filemode & (FWRITE|FTRUNC)) {
183 if (vp->v_type == VDIR) {
184 error = EISDIR;
185 goto out;
186 }
187 }
188 /*
189 * Check permissions.
190 */
191 if (error = VOP_ACCESS(vp, mode, accessflags, CRED(), NULL))
192 goto out;
193 /*
194 * Require FSEARCH to return a directory.
195 * Require FEXEC to return a regular file.
196 */
197 if ((filemode & FSEARCH) && vp->v_type != VDIR) {
198 error = ENOTDIR;
199 goto out;
200 }
201 if ((filemode & FEXEC) && vp->v_type != VREG) {
202 error = ENOEXEC;
203 goto out;
204 }
205 }
206
207 /*
208 * Do remaining checks for FNOFOLLOW and FNOLINKS.
209 */
210 if ((filemode & FNOFOLLOW) && vp->v_type == VLNK) {
211 error = ELOOP;
212 goto out;
213 }
214 if (filemode & FNOLINKS) {
215 vattr.va_mask = AT_NLINK;
216 if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))) {
217 goto out;
218 }
219 if (vattr.va_nlink != 1) {
220 error = EMLINK;
221 goto out;
222 }
223 }
224
225 /*
226 * Opening a socket corresponding to the AF_UNIX pathname
227 * in the filesystem name space is not supported...
228 */
229 if (vp->v_type == VSOCK) {
230 error = EOPNOTSUPP;
231 goto out;
232 }
233
234 /*
235 * Do opening protocol.
236 */
237 error = VOP_OPEN(&vp, filemode, CRED(), NULL);
238 if (error)
239 goto out;
240 open_done = 1;
241
242 /*
243 * Truncate if required.
244 */
245 if ((filemode & FTRUNC) && !(filemode & FCREAT)) {
246 vattr.va_size = 0;
247 vattr.va_mask = AT_SIZE;
248 if ((error = VOP_SETATTR(vp, &vattr, 0, CRED(), NULL)) != 0)
249 goto out;
250 }
251 out:
252 ASSERT(vp->v_count > 0);
253
254 if (error) {
255 if (open_done) {
256 (void) VOP_CLOSE(vp, filemode, 1, (offset_t)0, CRED(),
257 NULL);
258 open_done = 0;
259 }
260 VN_RELE(vp);
261 } else
262 *vpp = vp;
263 return (error);
264 }
265
266
267 /*
268 * Create a vnode (makenode).
269 */
270 int
vn_create(char * pnamep,enum uio_seg seg,struct vattr * vap,enum vcexcl excl,int mode,struct vnode ** vpp,enum create why,int flag,mode_t umask)271 vn_create(
272 char *pnamep,
273 enum uio_seg seg,
274 struct vattr *vap,
275 enum vcexcl excl,
276 int mode,
277 struct vnode **vpp,
278 enum create why,
279 int flag,
280 mode_t umask)
281 {
282 struct vnode *dvp = NULL; /* ptr to parent dir vnode */
283 char *lastcomp = NULL;
284 int error;
285
286 ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
287
288 flag &= ~(FNOFOLLOW|FNOLINKS);
289
290 *vpp = NULL;
291
292 /*
293 * Lookup directory and last component
294 */
295 error = fake_lookup_dir(pnamep, &dvp, &lastcomp);
296 if (error != 0) {
297 /* dir not found */
298 return (error);
299 }
300
301 /*
302 * If default ACLs are defined for the directory don't apply the
303 * umask if umask is passed.
304 */
305
306 if (umask) {
307 /*
308 * Apply the umask if no default ACLs...
309 */
310 vap->va_mode &= ~umask;
311 }
312
313 if (dvp->v_vfsp->vfs_flag & VFS_RDONLY) {
314 error = EROFS;
315 goto out;
316 }
317
318 /*
319 * Call mkdir() if specified, otherwise create().
320 */
321 if (why == CRMKDIR) {
322 /*
323 * N.B., if vn_createat() ever requests
324 * case-insensitive behavior then it will need
325 * to be passed to VOP_MKDIR(). VOP_CREATE()
326 * will already get it via "flag"
327 */
328 error = VOP_MKDIR(dvp, lastcomp, vap, vpp, CRED(),
329 NULL, 0, NULL);
330 } else {
331 error = VOP_CREATE(dvp, lastcomp, vap,
332 excl, mode, vpp, CRED(), flag, NULL, NULL);
333 }
334
335 out:
336 if (dvp != NULL)
337 VN_RELE(dvp);
338
339 return (error);
340 }
341