Print this page
cstyle sort of updates
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
+++ new/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
1 1 /*
2 2 * Copyright (c) 2000-2001 Boris Popov
3 3 * All rights reserved.
4 4 *
5 5 * Redistribution and use in source and binary forms, with or without
6 6 * modification, are permitted provided that the following conditions
7 7 * are met:
8 8 * 1. Redistributions of source code must retain the above copyright
9 9 * notice, this list of conditions and the following disclaimer.
10 10 * 2. Redistributions in binary form must reproduce the above copyright
11 11 * notice, this list of conditions and the following disclaimer in the
12 12 * documentation and/or other materials provided with the distribution.
13 13 * 3. All advertising materials mentioning features or use of this software
14 14 * must display the following acknowledgement:
15 15 * This product includes software developed by Boris Popov.
16 16 * 4. Neither the name of the author nor the names of any co-contributors
17 17 * may be used to endorse or promote products derived from this software
18 18 * without specific prior written permission.
19 19 *
20 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 30 * SUCH DAMAGE.
31 31 *
32 32 * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
33 33 */
34 34
35 35 /*
36 36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 37 */
38 38
39 39 #include <sys/systm.h>
40 40 #include <sys/cred.h>
41 41 #include <sys/vnode.h>
42 42 #include <sys/vfs.h>
43 43 #include <sys/filio.h>
44 44 #include <sys/uio.h>
45 45 #include <sys/dirent.h>
46 46 #include <sys/errno.h>
47 47 #include <sys/sunddi.h>
48 48 #include <sys/sysmacros.h>
49 49 #include <sys/kmem.h>
50 50 #include <sys/cmn_err.h>
51 51 #include <sys/vfs_opreg.h>
52 52 #include <sys/policy.h>
53 53
54 54 #include <netsmb/smb_osdep.h>
55 55 #include <netsmb/smb.h>
56 56 #include <netsmb/smb_conn.h>
57 57 #include <netsmb/smb_subr.h>
58 58
59 59 #include <smbfs/smbfs.h>
60 60 #include <smbfs/smbfs_node.h>
61 61 #include <smbfs/smbfs_subr.h>
62 62
63 63 #include <sys/fs/smbfs_ioctl.h>
64 64 #include <fs/fs_subr.h>
65 65
66 66 /*
67 67 * We assign directory offsets like the NFS client, where the
68 68 * offset increments by _one_ after each directory entry.
69 69 * Further, the entries "." and ".." are always at offsets
70 70 * zero and one (respectively) and the "real" entries from
71 71 * the server appear at offsets starting with two. This
72 72 * macro is used to initialize the n_dirofs field after
73 73 * setting n_dirseq with a _findopen call.
74 74 */
75 75 #define FIRST_DIROFS 2
76 76
77 77 /*
78 78 * These characters are illegal in NTFS file names.
79 79 * ref: http://support.microsoft.com/kb/147438
80 80 *
81 81 * Careful! The check in the XATTR case skips the
82 82 * first character to allow colon in XATTR names.
83 83 */
84 84 static const char illegal_chars[] = {
85 85 ':', /* colon - keep this first! */
86 86 '\\', /* back slash */
87 87 '/', /* slash */
88 88 '*', /* asterisk */
89 89 '?', /* question mark */
90 90 '"', /* double quote */
91 91 '<', /* less than sign */
92 92 '>', /* greater than sign */
93 93 '|', /* vertical bar */
94 94 0
95 95 };
96 96
97 97 /*
98 98 * Turning this on causes nodes to be created in the cache
99 99 * during directory listings, normally avoiding a second
100 100 * OtW attribute fetch just after a readdir.
101 101 */
102 102 int smbfs_fastlookup = 1;
103 103
104 104 /* local static function defines */
105 105
106 106 static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
107 107 cred_t *);
108 108 static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
109 109 int cache_ok, caller_context_t *);
110 110 static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
111 111 cred_t *cr, caller_context_t *);
112 112 static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
113 113 static int smbfs_accessx(void *, int, cred_t *);
114 114 static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
115 115 caller_context_t *);
116 116 static void smbfs_rele_fid(smbnode_t *, struct smb_cred *);
117 117
118 118 /*
119 119 * These are the vnode ops routines which implement the vnode interface to
120 120 * the networked file system. These routines just take their parameters,
121 121 * make them look networkish by putting the right info into interface structs,
122 122 * and then calling the appropriate remote routine(s) to do the work.
123 123 *
124 124 * Note on directory name lookup cacheing: If we detect a stale fhandle,
125 125 * we purge the directory cache relative to that vnode. This way, the
126 126 * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for
127 127 * more details on smbnode locking.
128 128 */
129 129
130 130 static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
131 131 static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
132 132 caller_context_t *);
133 133 static int smbfs_read(vnode_t *, struct uio *, int, cred_t *,
134 134 caller_context_t *);
135 135 static int smbfs_write(vnode_t *, struct uio *, int, cred_t *,
136 136 caller_context_t *);
137 137 static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
138 138 caller_context_t *);
139 139 static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
140 140 caller_context_t *);
141 141 static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
142 142 caller_context_t *);
143 143 static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
144 144 static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
145 145 static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
146 146 static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
147 147 int, vnode_t *, cred_t *, caller_context_t *,
148 148 int *, pathname_t *);
149 149 static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
150 150 int, vnode_t **, cred_t *, int, caller_context_t *,
151 151 vsecattr_t *);
152 152 static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
153 153 int);
154 154 static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
155 155 caller_context_t *, int);
156 156 static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
157 157 cred_t *, caller_context_t *, int, vsecattr_t *);
158 158 static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
159 159 caller_context_t *, int);
160 160 static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
161 161 caller_context_t *, int);
162 162 static int smbfs_rwlock(vnode_t *, int, caller_context_t *);
163 163 static void smbfs_rwunlock(vnode_t *, int, caller_context_t *);
164 164 static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
165 165 static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
166 166 struct flk_callback *, cred_t *, caller_context_t *);
167 167 static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
168 168 cred_t *, caller_context_t *);
169 169 static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
170 170 caller_context_t *);
171 171 static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
172 172 caller_context_t *);
173 173 static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
174 174 caller_context_t *);
175 175 static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
176 176 caller_context_t *);
177 177
178 178 /* Dummy function to use until correct function is ported in */
179 179 int noop_vnodeop() {
180 180 return (0);
181 181 }
182 182
183 183 struct vnodeops *smbfs_vnodeops = NULL;
184 184
185 185 /*
186 186 * Most unimplemented ops will return ENOSYS because of fs_nosys().
187 187 * The only ops where that won't work are ACCESS (due to open(2)
188 188 * failures) and ... (anything else left?)
189 189 */
190 190 const fs_operation_def_t smbfs_vnodeops_template[] = {
191 191 { VOPNAME_OPEN, { .vop_open = smbfs_open } },
192 192 { VOPNAME_CLOSE, { .vop_close = smbfs_close } },
193 193 { VOPNAME_READ, { .vop_read = smbfs_read } },
194 194 { VOPNAME_WRITE, { .vop_write = smbfs_write } },
195 195 { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } },
196 196 { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } },
197 197 { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } },
198 198 { VOPNAME_ACCESS, { .vop_access = smbfs_access } },
199 199 { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } },
200 200 { VOPNAME_CREATE, { .vop_create = smbfs_create } },
201 201 { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } },
202 202 { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */
203 203 { VOPNAME_RENAME, { .vop_rename = smbfs_rename } },
204 204 { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } },
205 205 { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } },
206 206 { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } },
207 207 { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */
208 208 { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */
209 209 { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } },
210 210 { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } },
211 211 { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */
212 212 { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } },
213 213 { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } },
214 214 { VOPNAME_SEEK, { .vop_seek = smbfs_seek } },
215 215 { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } },
216 216 { VOPNAME_SPACE, { .vop_space = smbfs_space } },
217 217 { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */
218 218 { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */
↓ open down ↓ |
218 lines elided |
↑ open up ↑ |
219 219 { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */
220 220 { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */
221 221 { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */
222 222 { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */
223 223 { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */
224 224 { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } },
225 225 { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */
226 226 { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } },
227 227 { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } },
228 228 { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } },
229 - { NULL, NULL }
229 + { NULL, { NULL } }
230 230 };
231 231
232 232 /*
233 233 * XXX
234 234 * When new and relevant functionality is enabled, we should be
235 235 * calling vfs_set_feature() to inform callers that pieces of
236 236 * functionality are available, per PSARC 2007/227.
237 237 */
238 238 /* ARGSUSED */
239 239 static int
240 240 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
241 241 {
242 242 smbnode_t *np;
243 243 vnode_t *vp;
244 244 smbfattr_t fa;
245 245 u_int32_t rights, rightsrcvd;
246 246 u_int16_t fid, oldfid;
247 247 int oldgenid;
248 248 struct smb_cred scred;
249 249 smbmntinfo_t *smi;
250 250 smb_share_t *ssp;
251 251 cred_t *oldcr;
252 252 int tmperror;
253 253 int error = 0;
254 254
255 255 vp = *vpp;
256 256 np = VTOSMB(vp);
257 257 smi = VTOSMI(vp);
258 258 ssp = smi->smi_share;
259 259
260 260 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
261 261 return (EIO);
262 262
263 263 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
264 264 return (EIO);
265 265
266 266 if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
267 267 SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
268 268 return (EACCES);
269 269 }
270 270
271 271 /*
272 272 * Get exclusive access to n_fid and related stuff.
273 273 * No returns after this until out.
274 274 */
275 275 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
276 276 return (EINTR);
277 277 smb_credinit(&scred, cr);
278 278
279 279 /*
280 280 * Keep track of the vnode type at first open.
281 281 * It may change later, and we need close to do
282 282 * cleanup for the type we opened. Also deny
283 283 * open of new types until old type is closed.
284 284 * XXX: Per-open instance nodes whould help.
285 285 */
286 286 if (np->n_ovtype == VNON) {
287 287 ASSERT(np->n_dirrefs == 0);
288 288 ASSERT(np->n_fidrefs == 0);
289 289 } else if (np->n_ovtype != vp->v_type) {
290 290 SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
291 291 np->n_ovtype, vp->v_type);
292 292 error = EACCES;
293 293 goto out;
294 294 }
295 295
296 296 /*
297 297 * Directory open. See smbfs_readvdir()
298 298 */
299 299 if (vp->v_type == VDIR) {
300 300 if (np->n_dirseq == NULL) {
301 301 /* first open */
302 302 error = smbfs_smb_findopen(np, "*", 1,
303 303 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
304 304 &scred, &np->n_dirseq);
305 305 if (error != 0)
306 306 goto out;
307 307 }
308 308 np->n_dirofs = FIRST_DIROFS;
309 309 np->n_dirrefs++;
310 310 goto have_fid;
311 311 }
312 312
313 313 /*
314 314 * If caller specified O_TRUNC/FTRUNC, then be sure to set
315 315 * FWRITE (to drive successful setattr(size=0) after open)
316 316 */
317 317 if (flag & FTRUNC)
318 318 flag |= FWRITE;
319 319
320 320 /*
321 321 * If we already have it open, and the FID is still valid,
322 322 * check whether the rights are sufficient for FID reuse.
323 323 */
324 324 if (np->n_fidrefs > 0 &&
325 325 np->n_vcgenid == ssp->ss_vcgenid) {
326 326 int upgrade = 0;
327 327
328 328 if ((flag & FWRITE) &&
329 329 !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
330 330 upgrade = 1;
331 331 if ((flag & FREAD) &&
332 332 !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
333 333 upgrade = 1;
334 334 if (!upgrade) {
335 335 /*
336 336 * the existing open is good enough
337 337 */
338 338 np->n_fidrefs++;
339 339 goto have_fid;
340 340 }
341 341 }
342 342 rights = np->n_fidrefs ? np->n_rights : 0;
343 343
344 344 /*
345 345 * we always ask for READ_CONTROL so we can always get the
346 346 * owner/group IDs to satisfy a stat. Ditto attributes.
347 347 */
348 348 rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
349 349 SA_RIGHT_FILE_READ_ATTRIBUTES);
350 350 if ((flag & FREAD))
351 351 rights |= SA_RIGHT_FILE_READ_DATA;
352 352 if ((flag & FWRITE))
353 353 rights |= SA_RIGHT_FILE_WRITE_DATA |
354 354 SA_RIGHT_FILE_APPEND_DATA |
355 355 SA_RIGHT_FILE_WRITE_ATTRIBUTES;
356 356
357 357 bzero(&fa, sizeof (fa));
358 358 error = smbfs_smb_open(np,
359 359 NULL, 0, 0, /* name nmlen xattr */
360 360 rights, &scred,
361 361 &fid, &rightsrcvd, &fa);
362 362 if (error)
363 363 goto out;
364 364 smbfs_attrcache_fa(vp, &fa);
365 365
366 366 /*
367 367 * We have a new FID and access rights.
368 368 */
369 369 oldfid = np->n_fid;
370 370 oldgenid = np->n_vcgenid;
371 371 np->n_fid = fid;
372 372 np->n_vcgenid = ssp->ss_vcgenid;
373 373 np->n_rights = rightsrcvd;
374 374 np->n_fidrefs++;
375 375 if (np->n_fidrefs > 1 &&
376 376 oldgenid == ssp->ss_vcgenid) {
377 377 /*
378 378 * We already had it open (presumably because
379 379 * it was open with insufficient rights.)
380 380 * Close old wire-open.
381 381 */
382 382 tmperror = smbfs_smb_close(ssp,
383 383 oldfid, NULL, &scred);
384 384 if (tmperror)
385 385 SMBVDEBUG("error %d closing %s\n",
386 386 tmperror, np->n_rpath);
387 387 }
388 388
389 389 /*
390 390 * This thread did the open.
391 391 * Save our credentials too.
392 392 */
393 393 mutex_enter(&np->r_statelock);
394 394 oldcr = np->r_cred;
395 395 np->r_cred = cr;
396 396 crhold(cr);
397 397 if (oldcr)
398 398 crfree(oldcr);
399 399 mutex_exit(&np->r_statelock);
400 400
401 401 have_fid:
402 402 /*
403 403 * Keep track of the vnode type at first open.
404 404 * (see comments above)
405 405 */
406 406 if (np->n_ovtype == VNON)
407 407 np->n_ovtype = vp->v_type;
408 408
409 409 out:
410 410 smb_credrele(&scred);
411 411 smbfs_rw_exit(&np->r_lkserlock);
412 412 return (error);
413 413 }
414 414
415 415 /*ARGSUSED*/
416 416 static int
417 417 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
418 418 caller_context_t *ct)
419 419 {
420 420 smbnode_t *np;
421 421 smbmntinfo_t *smi;
422 422 struct smb_cred scred;
423 423
424 424 np = VTOSMB(vp);
425 425 smi = VTOSMI(vp);
426 426
427 427 /*
428 428 * Don't "bail out" for VFS_UNMOUNTED here,
429 429 * as we want to do cleanup, etc.
430 430 */
431 431
432 432 /*
433 433 * zone_enter(2) prevents processes from changing zones with SMBFS files
434 434 * open; if we happen to get here from the wrong zone we can't do
435 435 * anything over the wire.
436 436 */
437 437 if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
438 438 /*
439 439 * We could attempt to clean up locks, except we're sure
440 440 * that the current process didn't acquire any locks on
441 441 * the file: any attempt to lock a file belong to another zone
442 442 * will fail, and one can't lock an SMBFS file and then change
443 443 * zones, as that fails too.
444 444 *
445 445 * Returning an error here is the sane thing to do. A
446 446 * subsequent call to VN_RELE() which translates to a
447 447 * smbfs_inactive() will clean up state: if the zone of the
448 448 * vnode's origin is still alive and kicking, an async worker
449 449 * thread will handle the request (from the correct zone), and
450 450 * everything (minus the final smbfs_getattr_otw() call) should
451 451 * be OK. If the zone is going away smbfs_async_inactive() will
452 452 * throw away cached pages inline.
453 453 */
454 454 return (EIO);
455 455 }
456 456
457 457 /*
458 458 * If we are using local locking for this filesystem, then
459 459 * release all of the SYSV style record locks. Otherwise,
460 460 * we are doing network locking and we need to release all
461 461 * of the network locks. All of the locks held by this
462 462 * process on this file are released no matter what the
463 463 * incoming reference count is.
464 464 */
465 465 if (smi->smi_flags & SMI_LLOCK) {
466 466 pid_t pid = ddi_get_pid();
467 467 cleanlocks(vp, pid, 0);
468 468 cleanshares(vp, pid);
469 469 }
470 470
471 471 /*
472 472 * This (passed in) count is the ref. count from the
473 473 * user's file_t before the closef call (fio.c).
474 474 * We only care when the reference goes away.
475 475 */
476 476 if (count > 1)
477 477 return (0);
478 478
479 479 /*
480 480 * Decrement the reference count for the FID
481 481 * and possibly do the OtW close.
482 482 *
483 483 * Exclusive lock for modifying n_fid stuff.
484 484 * Don't want this one ever interruptible.
485 485 */
486 486 (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
487 487 smb_credinit(&scred, cr);
488 488
489 489 smbfs_rele_fid(np, &scred);
490 490
491 491 smb_credrele(&scred);
492 492 smbfs_rw_exit(&np->r_lkserlock);
493 493
494 494 return (0);
495 495 }
496 496
497 497 /*
498 498 * Helper for smbfs_close. Decrement the reference count
499 499 * for an SMB-level file or directory ID, and when the last
500 500 * reference for the fid goes away, do the OtW close.
501 501 * Also called in smbfs_inactive (defensive cleanup).
502 502 */
503 503 static void
504 504 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
505 505 {
506 506 smb_share_t *ssp;
507 507 cred_t *oldcr;
508 508 struct smbfs_fctx *fctx;
509 509 int error;
510 510 uint16_t ofid;
511 511
512 512 ssp = np->n_mount->smi_share;
513 513 error = 0;
514 514
515 515 /* Make sure we serialize for n_dirseq use. */
516 516 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
517 517
518 518 /*
519 519 * Note that vp->v_type may change if a remote node
520 520 * is deleted and recreated as a different type, and
521 521 * our getattr may change v_type accordingly.
522 522 * Now use n_ovtype to keep track of the v_type
523 523 * we had during open (see comments above).
524 524 */
525 525 switch (np->n_ovtype) {
526 526 case VDIR:
527 527 ASSERT(np->n_dirrefs > 0);
528 528 if (--np->n_dirrefs)
529 529 return;
530 530 if ((fctx = np->n_dirseq) != NULL) {
531 531 np->n_dirseq = NULL;
532 532 np->n_dirofs = 0;
533 533 error = smbfs_smb_findclose(fctx, scred);
534 534 }
535 535 break;
536 536
537 537 case VREG:
538 538 ASSERT(np->n_fidrefs > 0);
539 539 if (--np->n_fidrefs)
540 540 return;
541 541 if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
542 542 np->n_fid = SMB_FID_UNUSED;
543 543 /* After reconnect, n_fid is invalid */
544 544 if (np->n_vcgenid == ssp->ss_vcgenid) {
545 545 error = smbfs_smb_close(
546 546 ssp, ofid, NULL, scred);
547 547 }
548 548 }
549 549 break;
550 550
551 551 default:
552 552 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
553 553 break;
554 554 }
555 555 if (error) {
556 556 SMBVDEBUG("error %d closing %s\n",
557 557 error, np->n_rpath);
558 558 }
559 559
560 560 /* Allow next open to use any v_type. */
561 561 np->n_ovtype = VNON;
562 562
563 563 /*
564 564 * Other "last close" stuff.
565 565 */
566 566 mutex_enter(&np->r_statelock);
567 567 if (np->n_flag & NATTRCHANGED)
568 568 smbfs_attrcache_rm_locked(np);
569 569 oldcr = np->r_cred;
570 570 np->r_cred = NULL;
571 571 mutex_exit(&np->r_statelock);
572 572 if (oldcr != NULL)
573 573 crfree(oldcr);
574 574 }
575 575
576 576 /* ARGSUSED */
577 577 static int
578 578 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
579 579 caller_context_t *ct)
580 580 {
581 581 struct smb_cred scred;
582 582 struct vattr va;
583 583 smbnode_t *np;
584 584 smbmntinfo_t *smi;
585 585 smb_share_t *ssp;
586 586 offset_t endoff;
587 587 ssize_t past_eof;
588 588 int error;
589 589
590 590 np = VTOSMB(vp);
591 591 smi = VTOSMI(vp);
592 592 ssp = smi->smi_share;
593 593
594 594 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
595 595 return (EIO);
596 596
597 597 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
598 598 return (EIO);
599 599
600 600 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
601 601
602 602 if (vp->v_type != VREG)
603 603 return (EISDIR);
604 604
605 605 if (uiop->uio_resid == 0)
606 606 return (0);
607 607
608 608 /*
609 609 * Like NFS3, just check for 63-bit overflow.
610 610 * Our SMB layer takes care to return EFBIG
611 611 * when it has to fallback to a 32-bit call.
612 612 */
613 613 endoff = uiop->uio_loffset + uiop->uio_resid;
614 614 if (uiop->uio_loffset < 0 || endoff < 0)
615 615 return (EINVAL);
616 616
617 617 /* get vnode attributes from server */
618 618 va.va_mask = AT_SIZE | AT_MTIME;
619 619 if (error = smbfsgetattr(vp, &va, cr))
620 620 return (error);
621 621
622 622 /* Update mtime with mtime from server here? */
623 623
624 624 /* if offset is beyond EOF, read nothing */
625 625 if (uiop->uio_loffset >= va.va_size)
626 626 return (0);
627 627
628 628 /*
629 629 * Limit the read to the remaining file size.
630 630 * Do this by temporarily reducing uio_resid
631 631 * by the amount the lies beyoned the EOF.
632 632 */
633 633 if (endoff > va.va_size) {
634 634 past_eof = (ssize_t)(endoff - va.va_size);
635 635 uiop->uio_resid -= past_eof;
636 636 } else
637 637 past_eof = 0;
638 638
639 639 /* Shared lock for n_fid use in smb_rwuio */
640 640 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
641 641 return (EINTR);
642 642 smb_credinit(&scred, cr);
643 643
644 644 /* After reconnect, n_fid is invalid */
645 645 if (np->n_vcgenid != ssp->ss_vcgenid)
646 646 error = ESTALE;
647 647 else
648 648 error = smb_rwuio(ssp, np->n_fid, UIO_READ,
649 649 uiop, &scred, smb_timo_read);
650 650
651 651 smb_credrele(&scred);
652 652 smbfs_rw_exit(&np->r_lkserlock);
653 653
654 654 /* undo adjustment of resid */
655 655 uiop->uio_resid += past_eof;
656 656
657 657 return (error);
658 658 }
659 659
660 660
661 661 /* ARGSUSED */
662 662 static int
663 663 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
664 664 caller_context_t *ct)
665 665 {
666 666 struct smb_cred scred;
667 667 struct vattr va;
668 668 smbnode_t *np;
669 669 smbmntinfo_t *smi;
670 670 smb_share_t *ssp;
671 671 offset_t endoff, limit;
672 672 ssize_t past_limit;
673 673 int error, timo;
674 674
675 675 np = VTOSMB(vp);
676 676 smi = VTOSMI(vp);
677 677 ssp = smi->smi_share;
678 678
679 679 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
680 680 return (EIO);
681 681
682 682 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
683 683 return (EIO);
684 684
685 685 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
686 686
687 687 if (vp->v_type != VREG)
688 688 return (EISDIR);
689 689
690 690 if (uiop->uio_resid == 0)
691 691 return (0);
692 692
693 693 /*
694 694 * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
695 695 */
696 696 if (ioflag & (FAPPEND | FSYNC)) {
697 697 if (np->n_flag & NMODIFIED) {
698 698 smbfs_attrcache_remove(np);
699 699 /* XXX: smbfs_vinvalbuf? */
700 700 }
701 701 }
702 702 if (ioflag & FAPPEND) {
703 703 /*
704 704 * File size can be changed by another client
705 705 */
706 706 va.va_mask = AT_SIZE;
707 707 if (error = smbfsgetattr(vp, &va, cr))
708 708 return (error);
709 709 uiop->uio_loffset = va.va_size;
710 710 }
711 711
712 712 /*
713 713 * Like NFS3, just check for 63-bit overflow.
714 714 */
715 715 endoff = uiop->uio_loffset + uiop->uio_resid;
716 716 if (uiop->uio_loffset < 0 || endoff < 0)
717 717 return (EINVAL);
718 718
719 719 /*
720 720 * Check to make sure that the process will not exceed
721 721 * its limit on file size. It is okay to write up to
722 722 * the limit, but not beyond. Thus, the write which
723 723 * reaches the limit will be short and the next write
724 724 * will return an error.
725 725 *
726 726 * So if we're starting at or beyond the limit, EFBIG.
727 727 * Otherwise, temporarily reduce resid to the amount
728 728 * the falls after the limit.
729 729 */
730 730 limit = uiop->uio_llimit;
731 731 if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
732 732 limit = MAXOFFSET_T;
733 733 if (uiop->uio_loffset >= limit)
734 734 return (EFBIG);
735 735 if (endoff > limit) {
736 736 past_limit = (ssize_t)(endoff - limit);
737 737 uiop->uio_resid -= past_limit;
738 738 } else
739 739 past_limit = 0;
740 740
741 741 /* Timeout: longer for append. */
742 742 timo = smb_timo_write;
743 743 if (endoff > np->r_size)
744 744 timo = smb_timo_append;
745 745
746 746 /* Shared lock for n_fid use in smb_rwuio */
747 747 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
748 748 return (EINTR);
749 749 smb_credinit(&scred, cr);
750 750
751 751 /* After reconnect, n_fid is invalid */
752 752 if (np->n_vcgenid != ssp->ss_vcgenid)
753 753 error = ESTALE;
754 754 else
755 755 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
756 756 uiop, &scred, timo);
757 757
758 758 if (error == 0) {
759 759 mutex_enter(&np->r_statelock);
760 760 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
761 761 if (uiop->uio_loffset > (offset_t)np->r_size)
762 762 np->r_size = (len_t)uiop->uio_loffset;
763 763 mutex_exit(&np->r_statelock);
764 764 if (ioflag & (FSYNC|FDSYNC)) {
765 765 /* Don't error the I/O if this fails. */
766 766 (void) smbfs_smb_flush(np, &scred);
767 767 }
768 768 }
769 769
770 770 smb_credrele(&scred);
771 771 smbfs_rw_exit(&np->r_lkserlock);
772 772
773 773 /* undo adjustment of resid */
774 774 uiop->uio_resid += past_limit;
775 775
776 776 return (error);
777 777 }
778 778
779 779
780 780 /* ARGSUSED */
781 781 static int
782 782 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
783 783 cred_t *cr, int *rvalp, caller_context_t *ct)
784 784 {
785 785 int error;
786 786 smbmntinfo_t *smi;
787 787
788 788 smi = VTOSMI(vp);
789 789
790 790 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
791 791 return (EIO);
792 792
793 793 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
794 794 return (EIO);
795 795
796 796 switch (cmd) {
797 797 /* First three from ZFS. XXX - need these? */
798 798
799 799 case _FIOFFS:
800 800 error = smbfs_fsync(vp, 0, cr, ct);
801 801 break;
802 802
803 803 /*
804 804 * The following two ioctls are used by bfu.
805 805 * Silently ignore to avoid bfu errors.
806 806 */
807 807 case _FIOGDIO:
808 808 case _FIOSDIO:
809 809 error = 0;
810 810 break;
811 811
812 812 #ifdef NOT_YET /* XXX - from the NFS code. */
813 813 case _FIODIRECTIO:
814 814 error = smbfs_directio(vp, (int)arg, cr);
815 815 #endif
816 816
817 817 /*
818 818 * Allow get/set with "raw" security descriptor (SD) data.
819 819 * Useful for testing, diagnosing idmap problems, etc.
820 820 */
821 821 case SMBFSIO_GETSD:
822 822 error = smbfs_acl_iocget(vp, arg, flag, cr);
823 823 break;
824 824
825 825 case SMBFSIO_SETSD:
826 826 error = smbfs_acl_iocset(vp, arg, flag, cr);
827 827 break;
828 828
829 829 default:
830 830 error = ENOTTY;
831 831 break;
832 832 }
833 833
834 834 return (error);
835 835 }
836 836
837 837
838 838 /*
839 839 * Return either cached or remote attributes. If get remote attr
840 840 * use them to check and invalidate caches, then cache the new attributes.
841 841 *
842 842 * XXX
843 843 * This op should eventually support PSARC 2007/315, Extensible Attribute
844 844 * Interfaces, for richer metadata.
845 845 */
846 846 /* ARGSUSED */
847 847 static int
848 848 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
849 849 caller_context_t *ct)
850 850 {
851 851 smbnode_t *np;
852 852 smbmntinfo_t *smi;
853 853
854 854 smi = VTOSMI(vp);
855 855
856 856 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
857 857 return (EIO);
858 858
859 859 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
860 860 return (EIO);
861 861
862 862 /*
863 863 * If it has been specified that the return value will
864 864 * just be used as a hint, and we are only being asked
865 865 * for size, fsid or rdevid, then return the client's
866 866 * notion of these values without checking to make sure
867 867 * that the attribute cache is up to date.
868 868 * The whole point is to avoid an over the wire GETATTR
869 869 * call.
870 870 */
871 871 np = VTOSMB(vp);
872 872 if (flags & ATTR_HINT) {
873 873 if (vap->va_mask ==
874 874 (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
875 875 mutex_enter(&np->r_statelock);
876 876 if (vap->va_mask | AT_SIZE)
877 877 vap->va_size = np->r_size;
878 878 if (vap->va_mask | AT_FSID)
879 879 vap->va_fsid = vp->v_vfsp->vfs_dev;
880 880 if (vap->va_mask | AT_RDEV)
881 881 vap->va_rdev = vp->v_rdev;
882 882 mutex_exit(&np->r_statelock);
883 883 return (0);
884 884 }
885 885 }
886 886
887 887 return (smbfsgetattr(vp, vap, cr));
888 888 }
889 889
890 890 /* smbfsgetattr() in smbfs_client.c */
891 891
892 892 /*
893 893 * XXX
894 894 * This op should eventually support PSARC 2007/315, Extensible Attribute
895 895 * Interfaces, for richer metadata.
896 896 */
897 897 /*ARGSUSED4*/
898 898 static int
899 899 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
900 900 caller_context_t *ct)
901 901 {
902 902 vfs_t *vfsp;
903 903 smbmntinfo_t *smi;
904 904 int error;
905 905 uint_t mask;
906 906 struct vattr oldva;
907 907
908 908 vfsp = vp->v_vfsp;
909 909 smi = VFTOSMI(vfsp);
910 910
911 911 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
912 912 return (EIO);
913 913
914 914 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
915 915 return (EIO);
916 916
917 917 mask = vap->va_mask;
918 918 if (mask & AT_NOSET)
919 919 return (EINVAL);
920 920
921 921 if (vfsp->vfs_flag & VFS_RDONLY)
922 922 return (EROFS);
923 923
924 924 /*
925 925 * This is a _local_ access check so that only the owner of
926 926 * this mount can set attributes. With ACLs enabled, the
927 927 * file owner can be different from the mount owner, and we
928 928 * need to check the _mount_ owner here. See _access_rwx
929 929 */
930 930 bzero(&oldva, sizeof (oldva));
931 931 oldva.va_mask = AT_TYPE | AT_MODE;
932 932 error = smbfsgetattr(vp, &oldva, cr);
933 933 if (error)
934 934 return (error);
935 935 oldva.va_mask |= AT_UID | AT_GID;
936 936 oldva.va_uid = smi->smi_uid;
937 937 oldva.va_gid = smi->smi_gid;
938 938
939 939 error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
940 940 smbfs_accessx, vp);
941 941 if (error)
942 942 return (error);
943 943
944 944 if (mask & (AT_UID | AT_GID)) {
945 945 if (smi->smi_flags & SMI_ACL)
946 946 error = smbfs_acl_setids(vp, vap, cr);
947 947 else
948 948 error = ENOSYS;
949 949 if (error != 0) {
950 950 SMBVDEBUG("error %d seting UID/GID on %s",
951 951 error, VTOSMB(vp)->n_rpath);
952 952 /*
953 953 * It might be more correct to return the
954 954 * error here, but that causes complaints
955 955 * when root extracts a cpio archive, etc.
956 956 * So ignore this error, and go ahead with
957 957 * the rest of the setattr work.
958 958 */
959 959 }
960 960 }
961 961
962 962 return (smbfssetattr(vp, vap, flags, cr));
963 963 }
964 964
965 965 /*
966 966 * Mostly from Darwin smbfs_setattr()
967 967 * but then modified a lot.
968 968 */
969 969 /* ARGSUSED */
970 970 static int
971 971 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
972 972 {
973 973 int error = 0;
974 974 smbnode_t *np = VTOSMB(vp);
975 975 uint_t mask = vap->va_mask;
976 976 struct timespec *mtime, *atime;
977 977 struct smb_cred scred;
978 978 int cerror, modified = 0;
979 979 unsigned short fid;
980 980 int have_fid = 0;
981 981 uint32_t rights = 0;
982 982
983 983 ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
984 984
985 985 /*
986 986 * There are no settable attributes on the XATTR dir,
987 987 * so just silently ignore these. On XATTR files,
988 988 * you can set the size but nothing else.
989 989 */
990 990 if (vp->v_flag & V_XATTRDIR)
991 991 return (0);
992 992 if (np->n_flag & N_XATTR) {
993 993 if (mask & AT_TIMES)
994 994 SMBVDEBUG("ignore set time on xattr\n");
995 995 mask &= AT_SIZE;
996 996 }
997 997
998 998 /*
999 999 * If our caller is trying to set multiple attributes, they
1000 1000 * can make no assumption about what order they are done in.
1001 1001 * Here we try to do them in order of decreasing likelihood
1002 1002 * of failure, just to minimize the chance we'll wind up
1003 1003 * with a partially complete request.
1004 1004 */
1005 1005
1006 1006 /* Shared lock for (possible) n_fid use. */
1007 1007 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1008 1008 return (EINTR);
1009 1009 smb_credinit(&scred, cr);
1010 1010
1011 1011 /*
1012 1012 * Will we need an open handle for this setattr?
1013 1013 * If so, what rights will we need?
1014 1014 */
1015 1015 if (mask & (AT_ATIME | AT_MTIME)) {
1016 1016 rights |=
1017 1017 SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1018 1018 }
1019 1019 if (mask & AT_SIZE) {
1020 1020 rights |=
1021 1021 SA_RIGHT_FILE_WRITE_DATA |
1022 1022 SA_RIGHT_FILE_APPEND_DATA;
1023 1023 }
1024 1024
1025 1025 /*
1026 1026 * Only SIZE really requires a handle, but it's
1027 1027 * simpler and more reliable to set via a handle.
1028 1028 * Some servers like NT4 won't set times by path.
1029 1029 * Also, we're usually setting everything anyway.
1030 1030 */
1031 1031 if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) {
1032 1032 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1033 1033 if (error) {
1034 1034 SMBVDEBUG("error %d opening %s\n",
1035 1035 error, np->n_rpath);
1036 1036 goto out;
1037 1037 }
1038 1038 have_fid = 1;
1039 1039 }
1040 1040
1041 1041 /*
1042 1042 * If the server supports the UNIX extensions, right here is where
1043 1043 * we'd support changes to uid, gid, mode, and possibly va_flags.
1044 1044 * For now we claim to have made any such changes.
1045 1045 */
1046 1046
1047 1047 if (mask & AT_SIZE) {
1048 1048 /*
1049 1049 * If the new file size is less than what the client sees as
1050 1050 * the file size, then just change the size and invalidate
1051 1051 * the pages.
1052 1052 * I am commenting this code at present because the function
1053 1053 * smbfs_putapage() is not yet implemented.
1054 1054 */
1055 1055
1056 1056 /*
1057 1057 * Set the file size to vap->va_size.
1058 1058 */
1059 1059 ASSERT(have_fid);
1060 1060 error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1061 1061 if (error) {
1062 1062 SMBVDEBUG("setsize error %d file %s\n",
1063 1063 error, np->n_rpath);
1064 1064 } else {
1065 1065 /*
1066 1066 * Darwin had code here to zero-extend.
1067 1067 * Tests indicate the server will zero-fill,
1068 1068 * so looks like we don't need to do this.
1069 1069 * Good thing, as this could take forever.
1070 1070 *
1071 1071 * XXX: Reportedly, writing one byte of zero
1072 1072 * at the end offset avoids problems here.
1073 1073 */
1074 1074 mutex_enter(&np->r_statelock);
1075 1075 np->r_size = vap->va_size;
1076 1076 mutex_exit(&np->r_statelock);
1077 1077 modified = 1;
1078 1078 }
1079 1079 }
1080 1080
1081 1081 /*
1082 1082 * XXX: When Solaris has create_time, set that too.
1083 1083 * Note: create_time is different from ctime.
1084 1084 */
1085 1085 mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1086 1086 atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1087 1087
1088 1088 if (mtime || atime) {
1089 1089 /*
1090 1090 * Always use the handle-based set attr call now.
1091 1091 * Not trying to set DOS attributes here so pass zero.
1092 1092 */
1093 1093 ASSERT(have_fid);
1094 1094 error = smbfs_smb_setfattr(np, fid,
1095 1095 0, mtime, atime, &scred);
1096 1096 if (error) {
1097 1097 SMBVDEBUG("set times error %d file %s\n",
1098 1098 error, np->n_rpath);
1099 1099 } else {
1100 1100 modified = 1;
1101 1101 }
1102 1102 }
1103 1103
1104 1104 out:
1105 1105 if (modified) {
1106 1106 /*
1107 1107 * Invalidate attribute cache in case the server
1108 1108 * doesn't set exactly the attributes we asked.
1109 1109 */
1110 1110 smbfs_attrcache_remove(np);
1111 1111 }
1112 1112
1113 1113 if (have_fid) {
1114 1114 cerror = smbfs_smb_tmpclose(np, fid, &scred);
1115 1115 if (cerror)
1116 1116 SMBVDEBUG("error %d closing %s\n",
1117 1117 cerror, np->n_rpath);
1118 1118 }
1119 1119
1120 1120 smb_credrele(&scred);
1121 1121 smbfs_rw_exit(&np->r_lkserlock);
1122 1122
1123 1123 return (error);
1124 1124 }
1125 1125
1126 1126 /*
1127 1127 * smbfs_access_rwx()
1128 1128 * Common function for smbfs_access, etc.
1129 1129 *
1130 1130 * The security model implemented by the FS is unusual
1131 1131 * due to the current "single user mounts" restriction:
1132 1132 * All access under a given mount point uses the CIFS
1133 1133 * credentials established by the owner of the mount.
1134 1134 *
1135 1135 * Most access checking is handled by the CIFS server,
1136 1136 * but we need sufficient Unix access checks here to
1137 1137 * prevent other local Unix users from having access
1138 1138 * to objects under this mount that the uid/gid/mode
1139 1139 * settings in the mount would not allow.
1140 1140 *
1141 1141 * With this model, there is a case where we need the
1142 1142 * ability to do an access check before we have the
1143 1143 * vnode for an object. This function takes advantage
1144 1144 * of the fact that the uid/gid/mode is per mount, and
1145 1145 * avoids the need for a vnode.
1146 1146 *
1147 1147 * We still (sort of) need a vnode when we call
1148 1148 * secpolicy_vnode_access, but that only uses
1149 1149 * the vtype field, so we can use a pair of fake
1150 1150 * vnodes that have only v_type filled in.
1151 1151 *
1152 1152 * XXX: Later, add a new secpolicy_vtype_access()
1153 1153 * that takes the vtype instead of a vnode, and
1154 1154 * get rid of the tmpl_vxxx fake vnodes below.
1155 1155 */
1156 1156 static int
1157 1157 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1158 1158 {
1159 1159 /* See the secpolicy call below. */
1160 1160 static const vnode_t tmpl_vdir = { .v_type = VDIR };
1161 1161 static const vnode_t tmpl_vreg = { .v_type = VREG };
1162 1162 vattr_t va;
1163 1163 vnode_t *tvp;
1164 1164 struct smbmntinfo *smi = VFTOSMI(vfsp);
1165 1165 int shift = 0;
1166 1166
1167 1167 /*
1168 1168 * Build our (fabricated) vnode attributes.
1169 1169 * XXX: Could make these templates in the
1170 1170 * per-mount struct and use them here.
1171 1171 */
1172 1172 bzero(&va, sizeof (va));
1173 1173 va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1174 1174 va.va_type = vtype;
1175 1175 va.va_mode = (vtype == VDIR) ?
1176 1176 smi->smi_dmode : smi->smi_fmode;
1177 1177 va.va_uid = smi->smi_uid;
1178 1178 va.va_gid = smi->smi_gid;
1179 1179
1180 1180 /*
1181 1181 * Disallow write attempts on read-only file systems,
1182 1182 * unless the file is a device or fifo node. Note:
1183 1183 * Inline vn_is_readonly and IS_DEVVP here because
1184 1184 * we may not have a vnode ptr. Original expr. was:
1185 1185 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1186 1186 */
1187 1187 if ((mode & VWRITE) &&
1188 1188 (vfsp->vfs_flag & VFS_RDONLY) &&
1189 1189 !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1190 1190 return (EROFS);
1191 1191
1192 1192 /*
1193 1193 * Disallow attempts to access mandatory lock files.
1194 1194 * Similarly, expand MANDLOCK here.
1195 1195 * XXX: not sure we need this.
1196 1196 */
1197 1197 if ((mode & (VWRITE | VREAD | VEXEC)) &&
1198 1198 va.va_type == VREG && MANDMODE(va.va_mode))
1199 1199 return (EACCES);
1200 1200
1201 1201 /*
1202 1202 * Access check is based on only
1203 1203 * one of owner, group, public.
1204 1204 * If not owner, then check group.
1205 1205 * If not a member of the group,
1206 1206 * then check public access.
1207 1207 */
1208 1208 if (crgetuid(cr) != va.va_uid) {
1209 1209 shift += 3;
1210 1210 if (!groupmember(va.va_gid, cr))
1211 1211 shift += 3;
1212 1212 }
1213 1213
1214 1214 /*
1215 1215 * We need a vnode for secpolicy_vnode_access,
1216 1216 * but the only thing it looks at is v_type,
1217 1217 * so pass one of the templates above.
1218 1218 */
1219 1219 tvp = (va.va_type == VDIR) ?
1220 1220 (vnode_t *)&tmpl_vdir :
1221 1221 (vnode_t *)&tmpl_vreg;
1222 1222
1223 1223 return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1224 1224 va.va_mode << shift, mode));
1225 1225 }
1226 1226
1227 1227 /*
1228 1228 * See smbfs_setattr
1229 1229 */
1230 1230 static int
1231 1231 smbfs_accessx(void *arg, int mode, cred_t *cr)
1232 1232 {
1233 1233 vnode_t *vp = arg;
1234 1234 /*
1235 1235 * Note: The caller has checked the current zone,
1236 1236 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1237 1237 */
1238 1238 return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1239 1239 }
1240 1240
1241 1241 /*
1242 1242 * XXX
1243 1243 * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1244 1244 */
1245 1245 /* ARGSUSED */
1246 1246 static int
1247 1247 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1248 1248 {
1249 1249 vfs_t *vfsp;
1250 1250 smbmntinfo_t *smi;
1251 1251
1252 1252 vfsp = vp->v_vfsp;
1253 1253 smi = VFTOSMI(vfsp);
1254 1254
1255 1255 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1256 1256 return (EIO);
1257 1257
1258 1258 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1259 1259 return (EIO);
1260 1260
1261 1261 return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1262 1262 }
1263 1263
1264 1264
1265 1265 /*
1266 1266 * Flush local dirty pages to stable storage on the server.
1267 1267 *
1268 1268 * If FNODSYNC is specified, then there is nothing to do because
1269 1269 * metadata changes are not cached on the client before being
1270 1270 * sent to the server.
1271 1271 */
1272 1272 /* ARGSUSED */
1273 1273 static int
1274 1274 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1275 1275 {
1276 1276 int error = 0;
1277 1277 smbmntinfo_t *smi;
1278 1278 smbnode_t *np;
1279 1279 struct smb_cred scred;
1280 1280
1281 1281 np = VTOSMB(vp);
1282 1282 smi = VTOSMI(vp);
1283 1283
1284 1284 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1285 1285 return (EIO);
1286 1286
1287 1287 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1288 1288 return (EIO);
1289 1289
1290 1290 if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1291 1291 return (0);
1292 1292
1293 1293 if ((syncflag & (FSYNC|FDSYNC)) == 0)
1294 1294 return (0);
1295 1295
1296 1296 /* Shared lock for n_fid use in _flush */
1297 1297 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1298 1298 return (EINTR);
1299 1299 smb_credinit(&scred, cr);
1300 1300
1301 1301 error = smbfs_smb_flush(np, &scred);
1302 1302
1303 1303 smb_credrele(&scred);
1304 1304 smbfs_rw_exit(&np->r_lkserlock);
1305 1305
1306 1306 return (error);
1307 1307 }
1308 1308
1309 1309 /*
1310 1310 * Last reference to vnode went away.
1311 1311 */
1312 1312 /* ARGSUSED */
1313 1313 static void
1314 1314 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1315 1315 {
1316 1316 smbnode_t *np;
1317 1317 struct smb_cred scred;
1318 1318
1319 1319 /*
1320 1320 * Don't "bail out" for VFS_UNMOUNTED here,
1321 1321 * as we want to do cleanup, etc.
1322 1322 * See also pcfs_inactive
1323 1323 */
1324 1324
1325 1325 np = VTOSMB(vp);
1326 1326
1327 1327 /*
1328 1328 * If this is coming from the wrong zone, we let someone in the right
1329 1329 * zone take care of it asynchronously. We can get here due to
1330 1330 * VN_RELE() being called from pageout() or fsflush(). This call may
1331 1331 * potentially turn into an expensive no-op if, for instance, v_count
1332 1332 * gets incremented in the meantime, but it's still correct.
1333 1333 */
1334 1334
1335 1335 /*
1336 1336 * Defend against the possibility that higher-level callers
1337 1337 * might not correctly balance open and close calls. If we
1338 1338 * get here with open references remaining, it means there
1339 1339 * was a missing VOP_CLOSE somewhere. If that happens, do
1340 1340 * the close here so we don't "leak" FIDs on the server.
1341 1341 *
1342 1342 * Exclusive lock for modifying n_fid stuff.
1343 1343 * Don't want this one ever interruptible.
1344 1344 */
1345 1345 (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1346 1346 smb_credinit(&scred, cr);
1347 1347
1348 1348 switch (np->n_ovtype) {
1349 1349 case VNON:
1350 1350 /* not open (OK) */
1351 1351 break;
1352 1352
1353 1353 case VDIR:
1354 1354 if (np->n_dirrefs == 0)
1355 1355 break;
1356 1356 SMBVDEBUG("open dir: refs %d path %s\n",
1357 1357 np->n_dirrefs, np->n_rpath);
1358 1358 /* Force last close. */
1359 1359 np->n_dirrefs = 1;
1360 1360 smbfs_rele_fid(np, &scred);
1361 1361 break;
1362 1362
1363 1363 case VREG:
1364 1364 if (np->n_fidrefs == 0)
1365 1365 break;
1366 1366 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1367 1367 np->n_fidrefs, np->n_fid, np->n_rpath);
1368 1368 /* Force last close. */
1369 1369 np->n_fidrefs = 1;
1370 1370 smbfs_rele_fid(np, &scred);
1371 1371 break;
1372 1372
1373 1373 default:
1374 1374 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1375 1375 np->n_ovtype = VNON;
1376 1376 break;
1377 1377 }
1378 1378
1379 1379 smb_credrele(&scred);
1380 1380 smbfs_rw_exit(&np->r_lkserlock);
1381 1381
1382 1382 smbfs_addfree(np);
1383 1383 }
1384 1384
1385 1385 /*
1386 1386 * Remote file system operations having to do with directory manipulation.
1387 1387 */
1388 1388 /* ARGSUSED */
1389 1389 static int
1390 1390 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1391 1391 int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1392 1392 int *direntflags, pathname_t *realpnp)
1393 1393 {
1394 1394 vfs_t *vfs;
1395 1395 smbmntinfo_t *smi;
1396 1396 smbnode_t *dnp;
1397 1397 int error;
1398 1398
1399 1399 vfs = dvp->v_vfsp;
1400 1400 smi = VFTOSMI(vfs);
1401 1401
1402 1402 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1403 1403 return (EPERM);
1404 1404
1405 1405 if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1406 1406 return (EIO);
1407 1407
1408 1408 dnp = VTOSMB(dvp);
1409 1409
1410 1410 /*
1411 1411 * Are we looking up extended attributes? If so, "dvp" is
1412 1412 * the file or directory for which we want attributes, and
1413 1413 * we need a lookup of the (faked up) attribute directory
1414 1414 * before we lookup the rest of the path.
1415 1415 */
1416 1416 if (flags & LOOKUP_XATTR) {
1417 1417 /*
1418 1418 * Require the xattr mount option.
1419 1419 */
1420 1420 if ((vfs->vfs_flag & VFS_XATTR) == 0)
1421 1421 return (EINVAL);
1422 1422
1423 1423 error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1424 1424 return (error);
1425 1425 }
1426 1426
1427 1427 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1428 1428 return (EINTR);
1429 1429
1430 1430 error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1431 1431
1432 1432 smbfs_rw_exit(&dnp->r_rwlock);
1433 1433
1434 1434 return (error);
1435 1435 }
1436 1436
1437 1437 /* ARGSUSED */
1438 1438 static int
1439 1439 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1440 1440 int cache_ok, caller_context_t *ct)
1441 1441 {
1442 1442 int error;
1443 1443 int supplen; /* supported length */
1444 1444 vnode_t *vp;
1445 1445 smbnode_t *np;
1446 1446 smbnode_t *dnp;
1447 1447 smbmntinfo_t *smi;
1448 1448 /* struct smb_vc *vcp; */
1449 1449 const char *ill;
1450 1450 const char *name = (const char *)nm;
1451 1451 int nmlen = strlen(nm);
1452 1452 int rplen;
1453 1453 struct smb_cred scred;
1454 1454 struct smbfattr fa;
1455 1455
1456 1456 smi = VTOSMI(dvp);
1457 1457 dnp = VTOSMB(dvp);
1458 1458
1459 1459 ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1460 1460
1461 1461 #ifdef NOT_YET
1462 1462 vcp = SSTOVC(smi->smi_share);
1463 1463
1464 1464 /* XXX: Should compute this once and store it in smbmntinfo_t */
1465 1465 supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1466 1466 #else
1467 1467 supplen = 255;
1468 1468 #endif
1469 1469
1470 1470 /*
1471 1471 * RWlock must be held, either reader or writer.
1472 1472 * XXX: Can we check without looking directly
1473 1473 * inside the struct smbfs_rwlock_t?
1474 1474 */
1475 1475 ASSERT(dnp->r_rwlock.count != 0);
1476 1476
1477 1477 /*
1478 1478 * If lookup is for "", just return dvp.
1479 1479 * No need to perform any access checks.
1480 1480 */
1481 1481 if (nmlen == 0) {
1482 1482 VN_HOLD(dvp);
1483 1483 *vpp = dvp;
1484 1484 return (0);
1485 1485 }
1486 1486
1487 1487 /*
1488 1488 * Can't do lookups in non-directories.
1489 1489 */
1490 1490 if (dvp->v_type != VDIR)
1491 1491 return (ENOTDIR);
1492 1492
1493 1493 /*
1494 1494 * Need search permission in the directory.
1495 1495 */
1496 1496 error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1497 1497 if (error)
1498 1498 return (error);
1499 1499
1500 1500 /*
1501 1501 * If lookup is for ".", just return dvp.
1502 1502 * Access check was done above.
1503 1503 */
1504 1504 if (nmlen == 1 && name[0] == '.') {
1505 1505 VN_HOLD(dvp);
1506 1506 *vpp = dvp;
1507 1507 return (0);
1508 1508 }
1509 1509
1510 1510 /*
1511 1511 * Now some sanity checks on the name.
1512 1512 * First check the length.
1513 1513 */
1514 1514 if (nmlen > supplen)
1515 1515 return (ENAMETOOLONG);
1516 1516
1517 1517 /*
1518 1518 * Avoid surprises with characters that are
1519 1519 * illegal in Windows file names.
1520 1520 * Todo: CATIA mappings XXX
1521 1521 */
1522 1522 ill = illegal_chars;
1523 1523 if (dnp->n_flag & N_XATTR)
1524 1524 ill++; /* allow colon */
1525 1525 if (strpbrk(nm, ill))
1526 1526 return (EINVAL);
1527 1527
1528 1528 /*
1529 1529 * Special handling for lookup of ".."
1530 1530 *
1531 1531 * We keep full pathnames (as seen on the server)
1532 1532 * so we can just trim off the last component to
1533 1533 * get the full pathname of the parent. Note:
1534 1534 * We don't actually copy and modify, but just
1535 1535 * compute the trimmed length and pass that with
1536 1536 * the current dir path (not null terminated).
1537 1537 *
1538 1538 * We don't go over-the-wire to get attributes
1539 1539 * for ".." because we know it's a directory,
1540 1540 * and we can just leave the rest "stale"
1541 1541 * until someone does a getattr.
1542 1542 */
1543 1543 if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1544 1544 if (dvp->v_flag & VROOT) {
1545 1545 /*
1546 1546 * Already at the root. This can happen
1547 1547 * with directory listings at the root,
1548 1548 * which lookup "." and ".." to get the
1549 1549 * inode numbers. Let ".." be the same
1550 1550 * as "." in the FS root.
1551 1551 */
1552 1552 VN_HOLD(dvp);
1553 1553 *vpp = dvp;
1554 1554 return (0);
1555 1555 }
1556 1556
1557 1557 /*
1558 1558 * Special case for XATTR directory
1559 1559 */
1560 1560 if (dvp->v_flag & V_XATTRDIR) {
1561 1561 error = smbfs_xa_parent(dvp, vpp);
1562 1562 return (error);
1563 1563 }
1564 1564
1565 1565 /*
1566 1566 * Find the parent path length.
1567 1567 */
1568 1568 rplen = dnp->n_rplen;
1569 1569 ASSERT(rplen > 0);
1570 1570 while (--rplen >= 0) {
1571 1571 if (dnp->n_rpath[rplen] == '\\')
1572 1572 break;
1573 1573 }
1574 1574 if (rplen <= 0) {
1575 1575 /* Found our way to the root. */
1576 1576 vp = SMBTOV(smi->smi_root);
1577 1577 VN_HOLD(vp);
1578 1578 *vpp = vp;
1579 1579 return (0);
1580 1580 }
1581 1581 np = smbfs_node_findcreate(smi,
1582 1582 dnp->n_rpath, rplen, NULL, 0, 0,
1583 1583 &smbfs_fattr0); /* force create */
1584 1584 ASSERT(np != NULL);
1585 1585 vp = SMBTOV(np);
1586 1586 vp->v_type = VDIR;
1587 1587
1588 1588 /* Success! */
1589 1589 *vpp = vp;
1590 1590 return (0);
1591 1591 }
1592 1592
1593 1593 /*
1594 1594 * Normal lookup of a name under this directory.
1595 1595 * Note we handled "", ".", ".." above.
1596 1596 */
1597 1597 if (cache_ok) {
1598 1598 /*
1599 1599 * The caller indicated that it's OK to use a
1600 1600 * cached result for this lookup, so try to
1601 1601 * reclaim a node from the smbfs node cache.
1602 1602 */
1603 1603 error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1604 1604 if (error)
1605 1605 return (error);
1606 1606 if (vp != NULL) {
1607 1607 /* hold taken in lookup_cache */
1608 1608 *vpp = vp;
1609 1609 return (0);
1610 1610 }
1611 1611 }
1612 1612
1613 1613 /*
1614 1614 * OK, go over-the-wire to get the attributes,
1615 1615 * then create the node.
1616 1616 */
1617 1617 smb_credinit(&scred, cr);
1618 1618 /* Note: this can allocate a new "name" */
1619 1619 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1620 1620 smb_credrele(&scred);
1621 1621 if (error == ENOTDIR) {
1622 1622 /*
1623 1623 * Lookup failed because this directory was
1624 1624 * removed or renamed by another client.
1625 1625 * Remove any cached attributes under it.
1626 1626 */
1627 1627 smbfs_attrcache_remove(dnp);
1628 1628 smbfs_attrcache_prune(dnp);
1629 1629 }
1630 1630 if (error)
1631 1631 goto out;
1632 1632
1633 1633 error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1634 1634 if (error)
1635 1635 goto out;
1636 1636
1637 1637 /* Success! */
1638 1638 *vpp = vp;
1639 1639
1640 1640 out:
1641 1641 /* smbfs_smb_lookup may have allocated name. */
1642 1642 if (name != nm)
1643 1643 smbfs_name_free(name, nmlen);
1644 1644
1645 1645 return (error);
1646 1646 }
1647 1647
1648 1648 /*
1649 1649 * smbfslookup_cache
1650 1650 *
1651 1651 * Try to reclaim a node from the smbfs node cache.
1652 1652 * Some statistics for DEBUG.
1653 1653 *
1654 1654 * This mechanism lets us avoid many of the five (or more)
1655 1655 * OtW lookup calls per file seen with "ls -l" if we search
1656 1656 * the smbfs node cache for recently inactive(ated) nodes.
1657 1657 */
1658 1658 #ifdef DEBUG
1659 1659 int smbfs_lookup_cache_calls = 0;
1660 1660 int smbfs_lookup_cache_error = 0;
1661 1661 int smbfs_lookup_cache_miss = 0;
1662 1662 int smbfs_lookup_cache_stale = 0;
1663 1663 int smbfs_lookup_cache_hits = 0;
1664 1664 #endif /* DEBUG */
1665 1665
1666 1666 /* ARGSUSED */
1667 1667 static int
1668 1668 smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1669 1669 vnode_t **vpp, cred_t *cr)
1670 1670 {
1671 1671 struct vattr va;
1672 1672 smbnode_t *dnp;
1673 1673 smbnode_t *np;
1674 1674 vnode_t *vp;
1675 1675 int error;
1676 1676 char sep;
1677 1677
1678 1678 dnp = VTOSMB(dvp);
1679 1679 *vpp = NULL;
1680 1680
1681 1681 #ifdef DEBUG
1682 1682 smbfs_lookup_cache_calls++;
1683 1683 #endif
1684 1684
1685 1685 /*
1686 1686 * First make sure we can get attributes for the
1687 1687 * directory. Cached attributes are OK here.
1688 1688 * If we removed or renamed the directory, this
1689 1689 * will return ENOENT. If someone else removed
1690 1690 * this directory or file, we'll find out when we
1691 1691 * try to open or get attributes.
1692 1692 */
1693 1693 va.va_mask = AT_TYPE | AT_MODE;
1694 1694 error = smbfsgetattr(dvp, &va, cr);
1695 1695 if (error) {
1696 1696 #ifdef DEBUG
1697 1697 smbfs_lookup_cache_error++;
1698 1698 #endif
1699 1699 return (error);
1700 1700 }
1701 1701
1702 1702 /*
1703 1703 * Passing NULL smbfattr here so we will
1704 1704 * just look, not create.
1705 1705 */
1706 1706 sep = SMBFS_DNP_SEP(dnp);
1707 1707 np = smbfs_node_findcreate(dnp->n_mount,
1708 1708 dnp->n_rpath, dnp->n_rplen,
1709 1709 nm, nmlen, sep, NULL);
1710 1710 if (np == NULL) {
1711 1711 #ifdef DEBUG
1712 1712 smbfs_lookup_cache_miss++;
1713 1713 #endif
1714 1714 return (0);
1715 1715 }
1716 1716
1717 1717 /*
1718 1718 * Found it. Attributes still valid?
1719 1719 */
1720 1720 vp = SMBTOV(np);
1721 1721 if (np->r_attrtime <= gethrtime()) {
1722 1722 /* stale */
1723 1723 #ifdef DEBUG
1724 1724 smbfs_lookup_cache_stale++;
1725 1725 #endif
1726 1726 VN_RELE(vp);
1727 1727 return (0);
1728 1728 }
1729 1729
1730 1730 /*
1731 1731 * Success!
1732 1732 * Caller gets hold from smbfs_node_findcreate
1733 1733 */
1734 1734 #ifdef DEBUG
1735 1735 smbfs_lookup_cache_hits++;
1736 1736 #endif
1737 1737 *vpp = vp;
1738 1738 return (0);
1739 1739 }
1740 1740
1741 1741 /*
1742 1742 * XXX
1743 1743 * vsecattr_t is new to build 77, and we need to eventually support
1744 1744 * it in order to create an ACL when an object is created.
1745 1745 *
1746 1746 * This op should support the new FIGNORECASE flag for case-insensitive
1747 1747 * lookups, per PSARC 2007/244.
1748 1748 */
1749 1749 /* ARGSUSED */
1750 1750 static int
1751 1751 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1752 1752 int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1753 1753 vsecattr_t *vsecp)
1754 1754 {
1755 1755 int error;
1756 1756 int cerror;
1757 1757 vfs_t *vfsp;
1758 1758 vnode_t *vp;
1759 1759 #ifdef NOT_YET
1760 1760 smbnode_t *np;
1761 1761 #endif
1762 1762 smbnode_t *dnp;
1763 1763 smbmntinfo_t *smi;
1764 1764 struct vattr vattr;
1765 1765 struct smbfattr fattr;
1766 1766 struct smb_cred scred;
1767 1767 const char *name = (const char *)nm;
1768 1768 int nmlen = strlen(nm);
1769 1769 uint32_t disp;
1770 1770 uint16_t fid;
1771 1771 int xattr;
1772 1772
1773 1773 vfsp = dvp->v_vfsp;
1774 1774 smi = VFTOSMI(vfsp);
1775 1775 dnp = VTOSMB(dvp);
1776 1776 vp = NULL;
1777 1777
1778 1778 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1779 1779 return (EPERM);
1780 1780
1781 1781 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1782 1782 return (EIO);
1783 1783
1784 1784 /*
1785 1785 * Note: this may break mknod(2) calls to create a directory,
1786 1786 * but that's obscure use. Some other filesystems do this.
1787 1787 * XXX: Later, redirect VDIR type here to _mkdir.
1788 1788 */
1789 1789 if (va->va_type != VREG)
1790 1790 return (EINVAL);
1791 1791
1792 1792 /*
1793 1793 * If the pathname is "", just use dvp, no checks.
1794 1794 * Do this outside of the rwlock (like zfs).
1795 1795 */
1796 1796 if (nmlen == 0) {
1797 1797 VN_HOLD(dvp);
1798 1798 *vpp = dvp;
1799 1799 return (0);
1800 1800 }
1801 1801
1802 1802 /* Don't allow "." or ".." through here. */
1803 1803 if ((nmlen == 1 && name[0] == '.') ||
1804 1804 (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1805 1805 return (EISDIR);
1806 1806
1807 1807 /*
1808 1808 * We make a copy of the attributes because the caller does not
1809 1809 * expect us to change what va points to.
1810 1810 */
1811 1811 vattr = *va;
1812 1812
1813 1813 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1814 1814 return (EINTR);
1815 1815 smb_credinit(&scred, cr);
1816 1816
1817 1817 /*
1818 1818 * XXX: Do we need r_lkserlock too?
1819 1819 * No use of any shared fid or fctx...
1820 1820 */
1821 1821
1822 1822 /*
1823 1823 * NFS needs to go over the wire, just to be sure whether the
1824 1824 * file exists or not. Using a cached result is dangerous in
1825 1825 * this case when making a decision regarding existence.
1826 1826 *
1827 1827 * The SMB protocol does NOT really need to go OTW here
1828 1828 * thanks to the expressive NTCREATE disposition values.
1829 1829 * Unfortunately, to do Unix access checks correctly,
1830 1830 * we need to know if the object already exists.
1831 1831 * When the object does not exist, we need VWRITE on
1832 1832 * the directory. Note: smbfslookup() checks VEXEC.
1833 1833 */
1834 1834 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1835 1835 if (error == 0) {
1836 1836 /*
1837 1837 * The file already exists. Error?
1838 1838 * NB: have a hold from smbfslookup
1839 1839 */
1840 1840 if (exclusive == EXCL) {
1841 1841 error = EEXIST;
1842 1842 VN_RELE(vp);
1843 1843 goto out;
1844 1844 }
1845 1845 /*
1846 1846 * Verify requested access.
1847 1847 */
1848 1848 error = smbfs_access(vp, mode, 0, cr, ct);
1849 1849 if (error) {
1850 1850 VN_RELE(vp);
1851 1851 goto out;
1852 1852 }
1853 1853
1854 1854 /*
1855 1855 * Truncate (if requested).
1856 1856 */
1857 1857 if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1858 1858 vattr.va_mask = AT_SIZE;
1859 1859 error = smbfssetattr(vp, &vattr, 0, cr);
1860 1860 if (error) {
1861 1861 VN_RELE(vp);
1862 1862 goto out;
1863 1863 }
1864 1864 }
1865 1865 /* Success! */
1866 1866 #ifdef NOT_YET
1867 1867 vnevent_create(vp, ct);
1868 1868 #endif
1869 1869 *vpp = vp;
1870 1870 goto out;
1871 1871 }
1872 1872
1873 1873 /*
1874 1874 * The file did not exist. Need VWRITE in the directory.
1875 1875 */
1876 1876 error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1877 1877 if (error)
1878 1878 goto out;
1879 1879
1880 1880 /*
1881 1881 * Now things get tricky. We also need to check the
1882 1882 * requested open mode against the file we may create.
1883 1883 * See comments at smbfs_access_rwx
1884 1884 */
1885 1885 error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1886 1886 if (error)
1887 1887 goto out;
1888 1888
1889 1889 /*
1890 1890 * Now the code derived from Darwin,
1891 1891 * but with greater use of NT_CREATE
1892 1892 * disposition options. Much changed.
1893 1893 *
1894 1894 * Create (or open) a new child node.
1895 1895 * Note we handled "." and ".." above.
1896 1896 */
1897 1897
1898 1898 if (exclusive == EXCL)
1899 1899 disp = NTCREATEX_DISP_CREATE;
1900 1900 else {
1901 1901 /* Truncate regular files if requested. */
1902 1902 if ((va->va_type == VREG) &&
1903 1903 (va->va_mask & AT_SIZE) &&
1904 1904 (va->va_size == 0))
1905 1905 disp = NTCREATEX_DISP_OVERWRITE_IF;
1906 1906 else
1907 1907 disp = NTCREATEX_DISP_OPEN_IF;
1908 1908 }
1909 1909 xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1910 1910 error = smbfs_smb_create(dnp,
1911 1911 name, nmlen, xattr,
1912 1912 disp, &scred, &fid);
1913 1913 if (error)
1914 1914 goto out;
1915 1915
1916 1916 /*
1917 1917 * XXX: Missing some code here to deal with
1918 1918 * the case where we opened an existing file,
1919 1919 * it's size is larger than 32-bits, and we're
1920 1920 * setting the size from a process that's not
1921 1921 * aware of large file offsets. i.e.
1922 1922 * from the NFS3 code:
1923 1923 */
1924 1924 #if NOT_YET /* XXX */
1925 1925 if ((vattr.va_mask & AT_SIZE) &&
1926 1926 vp->v_type == VREG) {
1927 1927 np = VTOSMB(vp);
1928 1928 /*
1929 1929 * Check here for large file handled
1930 1930 * by LF-unaware process (as
1931 1931 * ufs_create() does)
1932 1932 */
1933 1933 if (!(lfaware & FOFFMAX)) {
1934 1934 mutex_enter(&np->r_statelock);
1935 1935 if (np->r_size > MAXOFF32_T)
1936 1936 error = EOVERFLOW;
1937 1937 mutex_exit(&np->r_statelock);
1938 1938 }
1939 1939 if (!error) {
1940 1940 vattr.va_mask = AT_SIZE;
1941 1941 error = smbfssetattr(vp,
1942 1942 &vattr, 0, cr);
1943 1943 }
1944 1944 }
1945 1945 #endif /* XXX */
1946 1946 /*
1947 1947 * Should use the fid to get/set the size
1948 1948 * while we have it opened here. See above.
1949 1949 */
1950 1950
1951 1951 cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
1952 1952 if (cerror)
1953 1953 SMBVDEBUG("error %d closing %s\\%s\n",
1954 1954 cerror, dnp->n_rpath, name);
1955 1955
1956 1956 /*
1957 1957 * In the open case, the name may differ a little
1958 1958 * from what we passed to create (case, etc.)
1959 1959 * so call lookup to get the (opened) name.
1960 1960 *
1961 1961 * XXX: Could avoid this extra lookup if the
1962 1962 * "createact" result from NT_CREATE says we
1963 1963 * created the object.
1964 1964 */
1965 1965 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
1966 1966 if (error)
1967 1967 goto out;
1968 1968
1969 1969 /* update attr and directory cache */
1970 1970 smbfs_attr_touchdir(dnp);
1971 1971
1972 1972 error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
1973 1973 if (error)
1974 1974 goto out;
1975 1975
1976 1976 /* XXX invalidate pages if we truncated? */
1977 1977
1978 1978 /* Success! */
1979 1979 *vpp = vp;
1980 1980 error = 0;
1981 1981
1982 1982 out:
1983 1983 smb_credrele(&scred);
1984 1984 smbfs_rw_exit(&dnp->r_rwlock);
1985 1985 if (name != nm)
1986 1986 smbfs_name_free(name, nmlen);
1987 1987 return (error);
1988 1988 }
1989 1989
1990 1990 /*
1991 1991 * XXX
1992 1992 * This op should support the new FIGNORECASE flag for case-insensitive
1993 1993 * lookups, per PSARC 2007/244.
1994 1994 */
1995 1995 /* ARGSUSED */
1996 1996 static int
1997 1997 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
1998 1998 int flags)
1999 1999 {
2000 2000 int error;
2001 2001 vnode_t *vp;
2002 2002 smbnode_t *np;
2003 2003 smbnode_t *dnp;
2004 2004 struct smb_cred scred;
2005 2005 /* enum smbfsstat status; */
2006 2006 smbmntinfo_t *smi;
2007 2007
2008 2008 smi = VTOSMI(dvp);
2009 2009
2010 2010 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2011 2011 return (EPERM);
2012 2012
2013 2013 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2014 2014 return (EIO);
2015 2015
2016 2016 dnp = VTOSMB(dvp);
2017 2017 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2018 2018 return (EINTR);
2019 2019 smb_credinit(&scred, cr);
2020 2020
2021 2021 /*
2022 2022 * Verify access to the dirctory.
2023 2023 */
2024 2024 error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2025 2025 if (error)
2026 2026 goto out;
2027 2027
2028 2028 /*
2029 2029 * NOTE: the darwin code gets the "vp" passed in so it looks
2030 2030 * like the "vp" has probably been "lookup"ed by the VFS layer.
2031 2031 * It looks like we will need to lookup the vp to check the
2032 2032 * caches and check if the object being deleted is a directory.
2033 2033 */
2034 2034 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2035 2035 if (error)
2036 2036 goto out;
2037 2037
2038 2038 /* Never allow link/unlink directories on CIFS. */
2039 2039 if (vp->v_type == VDIR) {
2040 2040 VN_RELE(vp);
2041 2041 error = EPERM;
2042 2042 goto out;
2043 2043 }
2044 2044
2045 2045 /*
2046 2046 * Now we have the real reference count on the vnode
2047 2047 * Do we have the file open?
2048 2048 */
2049 2049 np = VTOSMB(vp);
2050 2050 mutex_enter(&np->r_statelock);
2051 2051 if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2052 2052 /*
2053 2053 * NFS does a rename on remove here.
2054 2054 * Probably not applicable for SMB.
2055 2055 * Like Darwin, just return EBUSY.
2056 2056 *
2057 2057 * XXX: Todo - Use Trans2rename, and
2058 2058 * if that fails, ask the server to
2059 2059 * set the delete-on-close flag.
2060 2060 */
2061 2061 mutex_exit(&np->r_statelock);
2062 2062 error = EBUSY;
2063 2063 } else {
2064 2064 smbfs_attrcache_rm_locked(np);
2065 2065 mutex_exit(&np->r_statelock);
2066 2066
2067 2067 error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
2068 2068
2069 2069 /*
2070 2070 * If the file should no longer exist, discard
2071 2071 * any cached attributes under this node.
2072 2072 */
2073 2073 switch (error) {
2074 2074 case 0:
2075 2075 case ENOENT:
2076 2076 case ENOTDIR:
2077 2077 smbfs_attrcache_prune(np);
2078 2078 break;
2079 2079 }
2080 2080 }
2081 2081
2082 2082 VN_RELE(vp);
2083 2083
2084 2084 out:
2085 2085 smb_credrele(&scred);
2086 2086 smbfs_rw_exit(&dnp->r_rwlock);
2087 2087
2088 2088 return (error);
2089 2089 }
2090 2090
2091 2091
2092 2092 /*
2093 2093 * XXX
2094 2094 * This op should support the new FIGNORECASE flag for case-insensitive
2095 2095 * lookups, per PSARC 2007/244.
2096 2096 */
2097 2097 /* ARGSUSED */
2098 2098 static int
2099 2099 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2100 2100 caller_context_t *ct, int flags)
2101 2101 {
2102 2102 /* vnode_t *realvp; */
2103 2103
2104 2104 if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2105 2105 curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2106 2106 return (EPERM);
2107 2107
2108 2108 if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2109 2109 VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2110 2110 odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2111 2111 ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2112 2112 return (EIO);
2113 2113
2114 2114 return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
2115 2115 }
2116 2116
2117 2117 /*
2118 2118 * smbfsrename does the real work of renaming in SMBFS
2119 2119 */
2120 2120 /* ARGSUSED */
2121 2121 static int
2122 2122 smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2123 2123 caller_context_t *ct)
2124 2124 {
2125 2125 int error;
2126 2126 int nvp_locked = 0;
2127 2127 vnode_t *nvp = NULL;
2128 2128 vnode_t *ovp = NULL;
2129 2129 smbnode_t *onp;
2130 2130 smbnode_t *nnp;
2131 2131 smbnode_t *odnp;
2132 2132 smbnode_t *ndnp;
2133 2133 struct smb_cred scred;
2134 2134 /* enum smbfsstat status; */
2135 2135
2136 2136 ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2137 2137
2138 2138 if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2139 2139 strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2140 2140 return (EINVAL);
2141 2141
2142 2142 /*
2143 2143 * Check that everything is on the same filesystem.
2144 2144 * vn_rename checks the fsid's, but in case we don't
2145 2145 * fill those in correctly, check here too.
2146 2146 */
2147 2147 if (odvp->v_vfsp != ndvp->v_vfsp)
2148 2148 return (EXDEV);
2149 2149
2150 2150 odnp = VTOSMB(odvp);
2151 2151 ndnp = VTOSMB(ndvp);
2152 2152
2153 2153 /*
2154 2154 * Avoid deadlock here on old vs new directory nodes
2155 2155 * by always taking the locks in order of address.
2156 2156 * The order is arbitrary, but must be consistent.
2157 2157 */
2158 2158 if (odnp < ndnp) {
2159 2159 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2160 2160 SMBINTR(odvp)))
2161 2161 return (EINTR);
2162 2162 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2163 2163 SMBINTR(ndvp))) {
2164 2164 smbfs_rw_exit(&odnp->r_rwlock);
2165 2165 return (EINTR);
2166 2166 }
2167 2167 } else {
2168 2168 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2169 2169 SMBINTR(ndvp)))
2170 2170 return (EINTR);
2171 2171 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2172 2172 SMBINTR(odvp))) {
2173 2173 smbfs_rw_exit(&ndnp->r_rwlock);
2174 2174 return (EINTR);
2175 2175 }
2176 2176 }
2177 2177 smb_credinit(&scred, cr);
2178 2178 /*
2179 2179 * No returns after this point (goto out)
2180 2180 */
2181 2181
2182 2182 /*
2183 2183 * Need write access on source and target.
2184 2184 * Server takes care of most checks.
2185 2185 */
2186 2186 error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2187 2187 if (error)
2188 2188 goto out;
2189 2189 if (odvp != ndvp) {
2190 2190 error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2191 2191 if (error)
2192 2192 goto out;
2193 2193 }
2194 2194
2195 2195 /*
2196 2196 * Lookup the source name. Must already exist.
2197 2197 */
2198 2198 error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2199 2199 if (error)
2200 2200 goto out;
2201 2201
2202 2202 /*
2203 2203 * Lookup the target file. If it exists, it needs to be
2204 2204 * checked to see whether it is a mount point and whether
2205 2205 * it is active (open).
2206 2206 */
2207 2207 error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
2208 2208 if (!error) {
2209 2209 /*
2210 2210 * Target (nvp) already exists. Check that it
2211 2211 * has the same type as the source. The server
2212 2212 * will check this also, (and more reliably) but
2213 2213 * this lets us return the correct error codes.
2214 2214 */
2215 2215 if (ovp->v_type == VDIR) {
2216 2216 if (nvp->v_type != VDIR) {
2217 2217 error = ENOTDIR;
2218 2218 goto out;
2219 2219 }
2220 2220 } else {
2221 2221 if (nvp->v_type == VDIR) {
2222 2222 error = EISDIR;
2223 2223 goto out;
2224 2224 }
2225 2225 }
2226 2226
2227 2227 /*
2228 2228 * POSIX dictates that when the source and target
2229 2229 * entries refer to the same file object, rename
2230 2230 * must do nothing and exit without error.
2231 2231 */
2232 2232 if (ovp == nvp) {
2233 2233 error = 0;
2234 2234 goto out;
2235 2235 }
2236 2236
2237 2237 /*
2238 2238 * Also must ensure the target is not a mount point,
2239 2239 * and keep mount/umount away until we're done.
2240 2240 */
2241 2241 if (vn_vfsrlock(nvp)) {
2242 2242 error = EBUSY;
2243 2243 goto out;
2244 2244 }
2245 2245 nvp_locked = 1;
2246 2246 if (vn_mountedvfs(nvp) != NULL) {
2247 2247 error = EBUSY;
2248 2248 goto out;
2249 2249 }
2250 2250
2251 2251 /*
2252 2252 * CIFS gives a SHARING_VIOLATION error when
2253 2253 * trying to rename onto an exising object,
2254 2254 * so try to remove the target first.
2255 2255 * (Only for files, not directories.)
2256 2256 */
2257 2257 if (nvp->v_type == VDIR) {
2258 2258 error = EEXIST;
2259 2259 goto out;
2260 2260 }
2261 2261
2262 2262 /*
2263 2263 * Nodes that are "not active" here have v_count=2
2264 2264 * because vn_renameat (our caller) did a lookup on
2265 2265 * both the source and target before this call.
2266 2266 * Otherwise this similar to smbfs_remove.
2267 2267 */
2268 2268 nnp = VTOSMB(nvp);
2269 2269 mutex_enter(&nnp->r_statelock);
2270 2270 if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) {
2271 2271 /*
2272 2272 * The target file exists, is not the same as
2273 2273 * the source file, and is active. Other FS
2274 2274 * implementations unlink the target here.
2275 2275 * For SMB, we don't assume we can remove an
2276 2276 * open file. Return an error instead.
2277 2277 */
2278 2278 mutex_exit(&nnp->r_statelock);
2279 2279 error = EBUSY;
2280 2280 goto out;
2281 2281 }
2282 2282
2283 2283 /*
2284 2284 * Target file is not active. Try to remove it.
2285 2285 */
2286 2286 smbfs_attrcache_rm_locked(nnp);
2287 2287 mutex_exit(&nnp->r_statelock);
2288 2288
2289 2289 error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
2290 2290
2291 2291 /*
2292 2292 * Similar to smbfs_remove
2293 2293 */
2294 2294 switch (error) {
2295 2295 case 0:
2296 2296 case ENOENT:
2297 2297 case ENOTDIR:
2298 2298 smbfs_attrcache_prune(nnp);
2299 2299 break;
2300 2300 }
2301 2301
2302 2302 if (error)
2303 2303 goto out;
2304 2304 /*
2305 2305 * OK, removed the target file. Continue as if
2306 2306 * lookup target had failed (nvp == NULL).
2307 2307 */
2308 2308 vn_vfsunlock(nvp);
2309 2309 nvp_locked = 0;
2310 2310 VN_RELE(nvp);
2311 2311 nvp = NULL;
2312 2312 } /* nvp */
2313 2313
2314 2314 onp = VTOSMB(ovp);
2315 2315 smbfs_attrcache_remove(onp);
2316 2316
2317 2317 error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
2318 2318
2319 2319 /*
2320 2320 * If the old name should no longer exist,
2321 2321 * discard any cached attributes under it.
2322 2322 */
2323 2323 if (error == 0)
2324 2324 smbfs_attrcache_prune(onp);
2325 2325
2326 2326 out:
2327 2327 if (nvp) {
2328 2328 if (nvp_locked)
2329 2329 vn_vfsunlock(nvp);
2330 2330 VN_RELE(nvp);
2331 2331 }
2332 2332 if (ovp)
2333 2333 VN_RELE(ovp);
2334 2334
2335 2335 smb_credrele(&scred);
2336 2336 smbfs_rw_exit(&odnp->r_rwlock);
2337 2337 smbfs_rw_exit(&ndnp->r_rwlock);
2338 2338
2339 2339 return (error);
2340 2340 }
2341 2341
2342 2342 /*
2343 2343 * XXX
2344 2344 * vsecattr_t is new to build 77, and we need to eventually support
2345 2345 * it in order to create an ACL when an object is created.
2346 2346 *
2347 2347 * This op should support the new FIGNORECASE flag for case-insensitive
2348 2348 * lookups, per PSARC 2007/244.
2349 2349 */
2350 2350 /* ARGSUSED */
2351 2351 static int
2352 2352 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2353 2353 cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2354 2354 {
2355 2355 vnode_t *vp;
2356 2356 struct smbnode *dnp = VTOSMB(dvp);
2357 2357 struct smbmntinfo *smi = VTOSMI(dvp);
2358 2358 struct smb_cred scred;
2359 2359 struct smbfattr fattr;
2360 2360 const char *name = (const char *) nm;
2361 2361 int nmlen = strlen(name);
2362 2362 int error, hiderr;
2363 2363
2364 2364 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2365 2365 return (EPERM);
2366 2366
2367 2367 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2368 2368 return (EIO);
2369 2369
2370 2370 if ((nmlen == 1 && name[0] == '.') ||
2371 2371 (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2372 2372 return (EEXIST);
2373 2373
2374 2374 /* Only plain files are allowed in V_XATTRDIR. */
2375 2375 if (dvp->v_flag & V_XATTRDIR)
2376 2376 return (EINVAL);
2377 2377
2378 2378 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2379 2379 return (EINTR);
2380 2380 smb_credinit(&scred, cr);
2381 2381
2382 2382 /*
2383 2383 * XXX: Do we need r_lkserlock too?
2384 2384 * No use of any shared fid or fctx...
2385 2385 */
2386 2386
2387 2387 /*
2388 2388 * Require write access in the containing directory.
2389 2389 */
2390 2390 error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2391 2391 if (error)
2392 2392 goto out;
2393 2393
2394 2394 error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2395 2395 if (error)
2396 2396 goto out;
2397 2397
2398 2398 error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2399 2399 if (error)
2400 2400 goto out;
2401 2401
2402 2402 smbfs_attr_touchdir(dnp);
2403 2403
2404 2404 error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2405 2405 if (error)
2406 2406 goto out;
2407 2407
2408 2408 if (name[0] == '.')
2409 2409 if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2410 2410 SMBVDEBUG("hide failure %d\n", hiderr);
2411 2411
2412 2412 /* Success! */
2413 2413 *vpp = vp;
2414 2414 error = 0;
2415 2415 out:
2416 2416 smb_credrele(&scred);
2417 2417 smbfs_rw_exit(&dnp->r_rwlock);
2418 2418
2419 2419 if (name != nm)
2420 2420 smbfs_name_free(name, nmlen);
2421 2421
2422 2422 return (error);
2423 2423 }
2424 2424
2425 2425 /*
2426 2426 * XXX
2427 2427 * This op should support the new FIGNORECASE flag for case-insensitive
2428 2428 * lookups, per PSARC 2007/244.
2429 2429 */
2430 2430 /* ARGSUSED */
2431 2431 static int
2432 2432 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2433 2433 caller_context_t *ct, int flags)
2434 2434 {
2435 2435 vnode_t *vp = NULL;
2436 2436 int vp_locked = 0;
2437 2437 struct smbmntinfo *smi = VTOSMI(dvp);
2438 2438 struct smbnode *dnp = VTOSMB(dvp);
2439 2439 struct smbnode *np;
2440 2440 struct smb_cred scred;
2441 2441 int error;
2442 2442
2443 2443 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2444 2444 return (EPERM);
2445 2445
2446 2446 if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2447 2447 return (EIO);
2448 2448
2449 2449 if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2450 2450 return (EINTR);
2451 2451 smb_credinit(&scred, cr);
2452 2452
2453 2453 /*
2454 2454 * Require w/x access in the containing directory.
2455 2455 * Server handles all other access checks.
2456 2456 */
2457 2457 error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2458 2458 if (error)
2459 2459 goto out;
2460 2460
2461 2461 /*
2462 2462 * First lookup the entry to be removed.
2463 2463 */
2464 2464 error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2465 2465 if (error)
2466 2466 goto out;
2467 2467 np = VTOSMB(vp);
2468 2468
2469 2469 /*
2470 2470 * Disallow rmdir of "." or current dir, or the FS root.
2471 2471 * Also make sure it's a directory, not a mount point,
2472 2472 * and lock to keep mount/umount away until we're done.
2473 2473 */
2474 2474 if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2475 2475 error = EINVAL;
2476 2476 goto out;
2477 2477 }
2478 2478 if (vp->v_type != VDIR) {
2479 2479 error = ENOTDIR;
2480 2480 goto out;
2481 2481 }
2482 2482 if (vn_vfsrlock(vp)) {
2483 2483 error = EBUSY;
2484 2484 goto out;
2485 2485 }
2486 2486 vp_locked = 1;
2487 2487 if (vn_mountedvfs(vp) != NULL) {
2488 2488 error = EBUSY;
2489 2489 goto out;
2490 2490 }
2491 2491
2492 2492 smbfs_attrcache_remove(np);
2493 2493 error = smbfs_smb_rmdir(np, &scred);
2494 2494
2495 2495 /*
2496 2496 * Similar to smbfs_remove
2497 2497 */
2498 2498 switch (error) {
2499 2499 case 0:
2500 2500 case ENOENT:
2501 2501 case ENOTDIR:
2502 2502 smbfs_attrcache_prune(np);
2503 2503 break;
2504 2504 }
2505 2505
2506 2506 if (error)
2507 2507 goto out;
2508 2508
2509 2509 mutex_enter(&np->r_statelock);
2510 2510 dnp->n_flag |= NMODIFIED;
2511 2511 mutex_exit(&np->r_statelock);
2512 2512 smbfs_attr_touchdir(dnp);
2513 2513 smbfs_rmhash(np);
2514 2514
2515 2515 out:
2516 2516 if (vp) {
2517 2517 if (vp_locked)
2518 2518 vn_vfsunlock(vp);
2519 2519 VN_RELE(vp);
2520 2520 }
2521 2521 smb_credrele(&scred);
2522 2522 smbfs_rw_exit(&dnp->r_rwlock);
2523 2523
2524 2524 return (error);
2525 2525 }
2526 2526
2527 2527
2528 2528 /* ARGSUSED */
2529 2529 static int
2530 2530 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2531 2531 caller_context_t *ct, int flags)
2532 2532 {
2533 2533 struct smbnode *np = VTOSMB(vp);
2534 2534 int error = 0;
2535 2535 smbmntinfo_t *smi;
2536 2536
2537 2537 smi = VTOSMI(vp);
2538 2538
2539 2539 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2540 2540 return (EIO);
2541 2541
2542 2542 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2543 2543 return (EIO);
2544 2544
2545 2545 /*
2546 2546 * Require read access in the directory.
2547 2547 */
2548 2548 error = smbfs_access(vp, VREAD, 0, cr, ct);
2549 2549 if (error)
2550 2550 return (error);
2551 2551
2552 2552 ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2553 2553
2554 2554 /*
2555 2555 * XXX: Todo readdir cache here
2556 2556 * Note: NFS code is just below this.
2557 2557 *
2558 2558 * I am serializing the entire readdir opreation
2559 2559 * now since we have not yet implemented readdir
2560 2560 * cache. This fix needs to be revisited once
2561 2561 * we implement readdir cache.
2562 2562 */
2563 2563 if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2564 2564 return (EINTR);
2565 2565
2566 2566 error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2567 2567
2568 2568 smbfs_rw_exit(&np->r_lkserlock);
2569 2569
2570 2570 return (error);
2571 2571 }
2572 2572
2573 2573 /* ARGSUSED */
2574 2574 static int
2575 2575 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2576 2576 caller_context_t *ct)
2577 2577 {
2578 2578 /*
2579 2579 * Note: "limit" tells the SMB-level FindFirst/FindNext
2580 2580 * functions how many directory entries to request in
2581 2581 * each OtW call. It needs to be large enough so that
2582 2582 * we don't make lots of tiny OtW requests, but there's
2583 2583 * no point making it larger than the maximum number of
2584 2584 * OtW entries that would fit in a maximum sized trans2
2585 2585 * response (64k / 48). Beyond that, it's just tuning.
2586 2586 * WinNT used 512, Win2k used 1366. We use 1000.
2587 2587 */
2588 2588 static const int limit = 1000;
2589 2589 /* Largest possible dirent size. */
2590 2590 static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2591 2591 struct smb_cred scred;
2592 2592 vnode_t *newvp;
2593 2593 struct smbnode *np = VTOSMB(vp);
2594 2594 struct smbfs_fctx *ctx;
2595 2595 struct dirent64 *dp;
2596 2596 ssize_t save_resid;
2597 2597 offset_t save_offset; /* 64 bits */
2598 2598 int offset; /* yes, 32 bits */
2599 2599 int nmlen, error;
2600 2600 ushort_t reclen;
2601 2601
2602 2602 ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2603 2603
2604 2604 /* Make sure we serialize for n_dirseq use. */
2605 2605 ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2606 2606
2607 2607 /*
2608 2608 * Make sure smbfs_open filled in n_dirseq
2609 2609 */
2610 2610 if (np->n_dirseq == NULL)
2611 2611 return (EBADF);
2612 2612
2613 2613 /* Check for overflow of (32-bit) directory offset. */
2614 2614 if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2615 2615 (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2616 2616 return (EINVAL);
2617 2617
2618 2618 /* Require space for at least one dirent. */
2619 2619 if (uio->uio_resid < dbufsiz)
2620 2620 return (EINVAL);
2621 2621
2622 2622 SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2623 2623 smb_credinit(&scred, cr);
2624 2624 dp = kmem_alloc(dbufsiz, KM_SLEEP);
2625 2625
2626 2626 save_resid = uio->uio_resid;
2627 2627 save_offset = uio->uio_loffset;
2628 2628 offset = uio->uio_offset;
2629 2629 SMBVDEBUG("in: offset=%d, resid=%d\n",
2630 2630 (int)uio->uio_offset, (int)uio->uio_resid);
2631 2631 error = 0;
2632 2632
2633 2633 /*
2634 2634 * Generate the "." and ".." entries here so we can
2635 2635 * (1) make sure they appear (but only once), and
2636 2636 * (2) deal with getting their I numbers which the
2637 2637 * findnext below does only for normal names.
2638 2638 */
2639 2639 while (offset < FIRST_DIROFS) {
2640 2640 /*
2641 2641 * Tricky bit filling in the first two:
2642 2642 * offset 0 is ".", offset 1 is ".."
2643 2643 * so strlen of these is offset+1.
2644 2644 */
2645 2645 reclen = DIRENT64_RECLEN(offset + 1);
2646 2646 if (uio->uio_resid < reclen)
2647 2647 goto out;
2648 2648 bzero(dp, reclen);
2649 2649 dp->d_reclen = reclen;
2650 2650 dp->d_name[0] = '.';
2651 2651 dp->d_name[1] = '.';
2652 2652 dp->d_name[offset + 1] = '\0';
2653 2653 /*
2654 2654 * Want the real I-numbers for the "." and ".."
2655 2655 * entries. For these two names, we know that
2656 2656 * smbfslookup can get the nodes efficiently.
2657 2657 */
2658 2658 error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2659 2659 if (error) {
2660 2660 dp->d_ino = np->n_ino + offset; /* fiction */
2661 2661 } else {
2662 2662 dp->d_ino = VTOSMB(newvp)->n_ino;
2663 2663 VN_RELE(newvp);
2664 2664 }
2665 2665 /*
2666 2666 * Note: d_off is the offset that a user-level program
2667 2667 * should seek to for reading the NEXT directory entry.
2668 2668 * See libc: readdir, telldir, seekdir
2669 2669 */
2670 2670 dp->d_off = offset + 1;
2671 2671 error = uiomove(dp, reclen, UIO_READ, uio);
2672 2672 if (error)
2673 2673 goto out;
2674 2674 /*
2675 2675 * Note: uiomove updates uio->uio_offset,
2676 2676 * but we want it to be our "cookie" value,
2677 2677 * which just counts dirents ignoring size.
2678 2678 */
2679 2679 uio->uio_offset = ++offset;
2680 2680 }
2681 2681
2682 2682 /*
2683 2683 * If there was a backward seek, we have to reopen.
2684 2684 */
2685 2685 if (offset < np->n_dirofs) {
2686 2686 SMBVDEBUG("Reopening search %d:%d\n",
2687 2687 offset, np->n_dirofs);
2688 2688 error = smbfs_smb_findopen(np, "*", 1,
2689 2689 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2690 2690 &scred, &ctx);
2691 2691 if (error) {
2692 2692 SMBVDEBUG("can not open search, error = %d", error);
2693 2693 goto out;
2694 2694 }
2695 2695 /* free the old one */
2696 2696 (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2697 2697 /* save the new one */
2698 2698 np->n_dirseq = ctx;
2699 2699 np->n_dirofs = FIRST_DIROFS;
2700 2700 } else {
2701 2701 ctx = np->n_dirseq;
2702 2702 }
2703 2703
2704 2704 /*
2705 2705 * Skip entries before the requested offset.
2706 2706 */
2707 2707 while (np->n_dirofs < offset) {
2708 2708 error = smbfs_smb_findnext(ctx, limit, &scred);
2709 2709 if (error != 0)
2710 2710 goto out;
2711 2711 np->n_dirofs++;
2712 2712 }
2713 2713
2714 2714 /*
2715 2715 * While there's room in the caller's buffer:
2716 2716 * get a directory entry from SMB,
2717 2717 * convert to a dirent, copyout.
2718 2718 * We stop when there is no longer room for a
2719 2719 * maximum sized dirent because we must decide
2720 2720 * before we know anything about the next entry.
2721 2721 */
2722 2722 while (uio->uio_resid >= dbufsiz) {
2723 2723 error = smbfs_smb_findnext(ctx, limit, &scred);
2724 2724 if (error != 0)
2725 2725 goto out;
2726 2726 np->n_dirofs++;
2727 2727
2728 2728 /* Sanity check the name length. */
2729 2729 nmlen = ctx->f_nmlen;
2730 2730 if (nmlen > SMB_MAXFNAMELEN) {
2731 2731 nmlen = SMB_MAXFNAMELEN;
2732 2732 SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2733 2733 }
2734 2734 if (smbfs_fastlookup) {
2735 2735 /* See comment at smbfs_fastlookup above. */
2736 2736 if (smbfs_nget(vp, ctx->f_name, nmlen,
2737 2737 &ctx->f_attr, &newvp) == 0)
2738 2738 VN_RELE(newvp);
2739 2739 }
2740 2740
2741 2741 reclen = DIRENT64_RECLEN(nmlen);
2742 2742 bzero(dp, reclen);
2743 2743 dp->d_reclen = reclen;
2744 2744 bcopy(ctx->f_name, dp->d_name, nmlen);
2745 2745 dp->d_name[nmlen] = '\0';
2746 2746 dp->d_ino = ctx->f_inum;
2747 2747 dp->d_off = offset + 1; /* See d_off comment above */
2748 2748 error = uiomove(dp, reclen, UIO_READ, uio);
2749 2749 if (error)
2750 2750 goto out;
2751 2751 /* See comment re. uio_offset above. */
2752 2752 uio->uio_offset = ++offset;
2753 2753 }
2754 2754
2755 2755 out:
2756 2756 /*
2757 2757 * When we come to the end of a directory, the
2758 2758 * SMB-level functions return ENOENT, but the
2759 2759 * caller is not expecting an error return.
2760 2760 *
2761 2761 * Also note that we must delay the call to
2762 2762 * smbfs_smb_findclose(np->n_dirseq, ...)
2763 2763 * until smbfs_close so that all reads at the
2764 2764 * end of the directory will return no data.
2765 2765 */
2766 2766 if (error == ENOENT) {
2767 2767 error = 0;
2768 2768 if (eofp)
2769 2769 *eofp = 1;
2770 2770 }
2771 2771 /*
2772 2772 * If we encountered an error (i.e. "access denied")
2773 2773 * from the FindFirst call, we will have copied out
2774 2774 * the "." and ".." entries leaving offset == 2.
2775 2775 * In that case, restore the original offset/resid
2776 2776 * so the caller gets no data with the error.
2777 2777 */
2778 2778 if (error != 0 && offset == FIRST_DIROFS) {
2779 2779 uio->uio_loffset = save_offset;
2780 2780 uio->uio_resid = save_resid;
2781 2781 }
2782 2782 SMBVDEBUG("out: offset=%d, resid=%d\n",
2783 2783 (int)uio->uio_offset, (int)uio->uio_resid);
2784 2784
2785 2785 kmem_free(dp, dbufsiz);
2786 2786 smb_credrele(&scred);
2787 2787 return (error);
2788 2788 }
2789 2789
2790 2790
2791 2791 /*
2792 2792 * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2793 2793 * are optional functions that are called by:
2794 2794 * getdents, before/after VOP_READDIR
2795 2795 * pread, before/after ... VOP_READ
2796 2796 * pwrite, before/after ... VOP_WRITE
2797 2797 * (other places)
2798 2798 *
2799 2799 * Careful here: None of the above check for any
2800 2800 * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2801 2801 * In fact, the return value from _rwlock is NOT
2802 2802 * an error code, but V_WRITELOCK_TRUE / _FALSE.
2803 2803 *
2804 2804 * Therefore, it's up to _this_ code to make sure
2805 2805 * the lock state remains balanced, which means
2806 2806 * we can't "bail out" on interrupts, etc.
2807 2807 */
2808 2808
2809 2809 /* ARGSUSED2 */
2810 2810 static int
2811 2811 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2812 2812 {
2813 2813 smbnode_t *np = VTOSMB(vp);
2814 2814
2815 2815 if (!write_lock) {
2816 2816 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2817 2817 return (V_WRITELOCK_FALSE);
2818 2818 }
2819 2819
2820 2820
2821 2821 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2822 2822 return (V_WRITELOCK_TRUE);
2823 2823 }
2824 2824
2825 2825 /* ARGSUSED */
2826 2826 static void
2827 2827 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2828 2828 {
2829 2829 smbnode_t *np = VTOSMB(vp);
2830 2830
2831 2831 smbfs_rw_exit(&np->r_rwlock);
2832 2832 }
2833 2833
2834 2834
2835 2835 /* ARGSUSED */
2836 2836 static int
2837 2837 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2838 2838 {
2839 2839 smbmntinfo_t *smi;
2840 2840
2841 2841 smi = VTOSMI(vp);
2842 2842
2843 2843 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2844 2844 return (EPERM);
2845 2845
2846 2846 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2847 2847 return (EIO);
2848 2848
2849 2849 /*
2850 2850 * Because we stuff the readdir cookie into the offset field
2851 2851 * someone may attempt to do an lseek with the cookie which
2852 2852 * we want to succeed.
2853 2853 */
2854 2854 if (vp->v_type == VDIR)
2855 2855 return (0);
2856 2856
2857 2857 /* Like NFS3, just check for 63-bit overflow. */
2858 2858 if (*noffp < 0)
2859 2859 return (EINVAL);
2860 2860
2861 2861 return (0);
2862 2862 }
2863 2863
2864 2864
2865 2865 /*
2866 2866 * XXX
2867 2867 * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2868 2868 */
2869 2869 static int
2870 2870 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2871 2871 offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2872 2872 caller_context_t *ct)
2873 2873 {
2874 2874 if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2875 2875 return (EIO);
2876 2876
2877 2877 if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2878 2878 return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2879 2879 else
2880 2880 return (ENOSYS);
2881 2881 }
2882 2882
2883 2883 /*
2884 2884 * Free storage space associated with the specified vnode. The portion
2885 2885 * to be freed is specified by bfp->l_start and bfp->l_len (already
2886 2886 * normalized to a "whence" of 0).
2887 2887 *
2888 2888 * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2889 2889 */
2890 2890 /* ARGSUSED */
2891 2891 static int
2892 2892 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2893 2893 offset_t offset, cred_t *cr, caller_context_t *ct)
2894 2894 {
2895 2895 int error;
2896 2896 smbmntinfo_t *smi;
2897 2897
2898 2898 smi = VTOSMI(vp);
2899 2899
2900 2900 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2901 2901 return (EIO);
2902 2902
2903 2903 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2904 2904 return (EIO);
2905 2905
2906 2906 /* Caller (fcntl) has checked v_type */
2907 2907 ASSERT(vp->v_type == VREG);
2908 2908 if (cmd != F_FREESP)
2909 2909 return (EINVAL);
2910 2910
2911 2911 /*
2912 2912 * Like NFS3, no 32-bit offset checks here.
2913 2913 * Our SMB layer takes care to return EFBIG
2914 2914 * when it has to fallback to a 32-bit call.
2915 2915 */
2916 2916
2917 2917 error = convoff(vp, bfp, 0, offset);
2918 2918 if (!error) {
2919 2919 ASSERT(bfp->l_start >= 0);
2920 2920 if (bfp->l_len == 0) {
2921 2921 struct vattr va;
2922 2922
2923 2923 /*
2924 2924 * ftruncate should not change the ctime and
2925 2925 * mtime if we truncate the file to its
2926 2926 * previous size.
2927 2927 */
2928 2928 va.va_mask = AT_SIZE;
2929 2929 error = smbfsgetattr(vp, &va, cr);
2930 2930 if (error || va.va_size == bfp->l_start)
2931 2931 return (error);
2932 2932 va.va_mask = AT_SIZE;
2933 2933 va.va_size = bfp->l_start;
2934 2934 error = smbfssetattr(vp, &va, 0, cr);
2935 2935 } else
2936 2936 error = EINVAL;
2937 2937 }
2938 2938
2939 2939 return (error);
2940 2940 }
2941 2941
2942 2942 /* ARGSUSED */
2943 2943 static int
2944 2944 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
2945 2945 caller_context_t *ct)
2946 2946 {
2947 2947 vfs_t *vfs;
2948 2948 smbmntinfo_t *smi;
2949 2949 struct smb_share *ssp;
2950 2950
2951 2951 vfs = vp->v_vfsp;
2952 2952 smi = VFTOSMI(vfs);
2953 2953
2954 2954 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2955 2955 return (EIO);
2956 2956
2957 2957 if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2958 2958 return (EIO);
2959 2959
2960 2960 switch (cmd) {
2961 2961 case _PC_FILESIZEBITS:
2962 2962 ssp = smi->smi_share;
2963 2963 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
2964 2964 *valp = 64;
2965 2965 else
2966 2966 *valp = 32;
2967 2967 break;
2968 2968
2969 2969 case _PC_LINK_MAX:
2970 2970 /* We only ever report one link to an object */
2971 2971 *valp = 1;
2972 2972 break;
2973 2973
2974 2974 case _PC_ACL_ENABLED:
2975 2975 /*
2976 2976 * Always indicate that ACLs are enabled and
2977 2977 * that we support ACE_T format, otherwise
2978 2978 * libsec will ask for ACLENT_T format data
2979 2979 * which we don't support.
2980 2980 */
2981 2981 *valp = _ACL_ACE_ENABLED;
2982 2982 break;
2983 2983
2984 2984 case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */
2985 2985 *valp = 0;
2986 2986 break;
2987 2987
2988 2988 case _PC_XATTR_EXISTS:
2989 2989 if (vfs->vfs_flag & VFS_XATTR) {
2990 2990 *valp = smbfs_xa_exists(vp, cr);
2991 2991 break;
2992 2992 }
2993 2993 return (EINVAL);
2994 2994
2995 2995 case _PC_TIMESTAMP_RESOLUTION:
2996 2996 /*
2997 2997 * Windows times are tenths of microseconds
2998 2998 * (multiples of 100 nanoseconds).
2999 2999 */
3000 3000 *valp = 100L;
3001 3001 break;
3002 3002
3003 3003 default:
3004 3004 return (fs_pathconf(vp, cmd, valp, cr, ct));
3005 3005 }
3006 3006 return (0);
3007 3007 }
3008 3008
3009 3009 /* ARGSUSED */
3010 3010 static int
3011 3011 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3012 3012 caller_context_t *ct)
3013 3013 {
3014 3014 vfs_t *vfsp;
3015 3015 smbmntinfo_t *smi;
3016 3016 int error;
3017 3017 uint_t mask;
3018 3018
3019 3019 vfsp = vp->v_vfsp;
3020 3020 smi = VFTOSMI(vfsp);
3021 3021
3022 3022 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3023 3023 return (EIO);
3024 3024
3025 3025 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3026 3026 return (EIO);
3027 3027
3028 3028 /*
3029 3029 * Our _pathconf indicates _ACL_ACE_ENABLED,
3030 3030 * so we should only see VSA_ACE, etc here.
3031 3031 * Note: vn_create asks for VSA_DFACLCNT,
3032 3032 * and it expects ENOSYS and empty data.
3033 3033 */
3034 3034 mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3035 3035 VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3036 3036 if (mask == 0)
3037 3037 return (ENOSYS);
3038 3038
3039 3039 if (smi->smi_flags & SMI_ACL)
3040 3040 error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3041 3041 else
3042 3042 error = ENOSYS;
3043 3043
3044 3044 if (error == ENOSYS)
3045 3045 error = fs_fab_acl(vp, vsa, flag, cr, ct);
3046 3046
3047 3047 return (error);
3048 3048 }
3049 3049
3050 3050 /* ARGSUSED */
3051 3051 static int
3052 3052 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3053 3053 caller_context_t *ct)
3054 3054 {
3055 3055 vfs_t *vfsp;
3056 3056 smbmntinfo_t *smi;
3057 3057 int error;
3058 3058 uint_t mask;
3059 3059
3060 3060 vfsp = vp->v_vfsp;
3061 3061 smi = VFTOSMI(vfsp);
3062 3062
3063 3063 if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3064 3064 return (EIO);
3065 3065
3066 3066 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3067 3067 return (EIO);
3068 3068
3069 3069 /*
3070 3070 * Our _pathconf indicates _ACL_ACE_ENABLED,
3071 3071 * so we should only see VSA_ACE, etc here.
3072 3072 */
3073 3073 mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3074 3074 if (mask == 0)
3075 3075 return (ENOSYS);
3076 3076
3077 3077 if (vfsp->vfs_flag & VFS_RDONLY)
3078 3078 return (EROFS);
3079 3079
3080 3080 /*
3081 3081 * Allow only the mount owner to do this.
3082 3082 * See comments at smbfs_access_rwx.
3083 3083 */
3084 3084 error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3085 3085 if (error != 0)
3086 3086 return (error);
3087 3087
3088 3088 if (smi->smi_flags & SMI_ACL)
3089 3089 error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3090 3090 else
3091 3091 error = ENOSYS;
3092 3092
3093 3093 return (error);
3094 3094 }
3095 3095
3096 3096
3097 3097 /*
3098 3098 * XXX
3099 3099 * This op should eventually support PSARC 2007/268.
3100 3100 */
3101 3101 static int
3102 3102 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3103 3103 caller_context_t *ct)
3104 3104 {
3105 3105 if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3106 3106 return (EIO);
3107 3107
3108 3108 if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3109 3109 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3110 3110 else
3111 3111 return (ENOSYS);
3112 3112 }
↓ open down ↓ |
2873 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX