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 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 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 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