Print this page
NEX-19152 MacOS HighSierra Finder crashes...
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-19025 CIFS gets confused with filenames containing enhanced Unicode
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
and: (fix build, check-rtime)
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-4820 intended nbmand locking functionality is confused
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-17289 Minimal SMB 3.0.2 support
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16157 Removal of "Read Attributes" prevents reading directory over SMB
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16157 Removal of "Read Attributes" prevents reading directory over SMB
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6116 Failures in smbtorture raw.open (2)
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6276 SMB sparse file support
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-6096 Enable compile warnings re. parentheses in smbsrv
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
SMB-65 SMB server in non-global zones (use zone_kcred())
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).
re #7815 SMB server delivers old modification time...
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_vops.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_vops.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <sys/stat.h>
28 28 #include <sys/uio.h>
29 29 #include <sys/statvfs.h>
30 30 #include <sys/vnode.h>
31 31 #include <sys/thread.h>
32 32 #include <sys/pathname.h>
33 33 #include <sys/cred.h>
34 34 #include <sys/extdirent.h>
35 35 #include <sys/nbmlock.h>
36 36 #include <sys/share.h>
37 37 #include <sys/fcntl.h>
38 38 #include <nfs/lm.h>
39 39
40 40 #include <smbsrv/smb_kproto.h>
41 41 #include <smbsrv/string.h>
42 42 #include <smbsrv/smb_vops.h>
43 43 #include <smbsrv/smb_fsops.h>
44 44
45 45 /*
46 46 * CATIA support
47 47 *
48 48 * CATIA V4 is a UNIX product and uses characters in filenames that
49 49 * are considered invalid by Windows. CATIA V5 is available on both
50 50 * UNIX and Windows. Thus, as CATIA customers migrate from V4 to V5,
51 51 * some V4 files could become inaccessible to windows clients if the
52 52 * filename contains the characters that are considered illegal in
53 53 * Windows. In order to address this issue an optional character
54 54 * translation is applied to filenames at the smb_vop interface.
55 55 *
56 56 * Character Translation Table
57 57 * ----------------------------------
58 58 * Unix-char (v4) | Windows-char (v5)
59 59 * ----------------------------------
60 60 * * | 0x00a4 Currency Sign
61 61 * | | 0x00a6 Broken Bar
62 62 * " | 0x00a8 Diaeresis
63 63 * < | 0x00ab Left-Pointing Double Angle Quotation Mark
64 64 * > | 0x00bb Right-Pointing Double Angle Quotation Mark
65 65 * ? | 0x00bf Inverted Question mark
66 66 * : | 0x00f7 Division Sign
67 67 * / | 0x00f8 Latin Small Letter o with stroke
68 68 * \ | 0x00ff Latin Small Letter Y with Diaeresis
69 69 *
70 70 *
71 71 * Two lookup tables are used to perform the character translation:
72 72 *
73 73 * smb_catia_v5_lookup - provides the mapping between UNIX ASCII (v4)
74 74 * characters and equivalent or translated wide characters.
75 75 * It is indexed by the decimal value of the ASCII character (0-127).
76 76 *
77 77 * smb_catia_v4_lookup - provides the mapping between wide characters
78 78 * in the range from 0x00A4 to 0x00FF and their UNIX (v4) equivalent
79 79 * (in wide character format). It is indexed by the decimal value of
80 80 * the wide character (164-255) with an offset of -164.
81 81 * If this translation produces a filename containing a '/' create, mkdir
82 82 * or rename (to the '/' name) operations will not be permitted. It is
83 83 * not valid to create a filename with a '/' in it. However, if such a
84 84 * file already exists other operations (e.g, lookup, delete, rename)
85 85 * are permitted on it.
86 86 */
87 87
88 88 /* number of characters mapped */
89 89 #define SMB_CATIA_NUM_MAPS 9
90 90
91 91 /* Windows Characters used in special character mapping */
92 92 #define SMB_CATIA_WIN_CURRENCY 0x00a4
93 93 #define SMB_CATIA_WIN_BROKEN_BAR 0x00a6
94 94 #define SMB_CATIA_WIN_DIAERESIS 0x00a8
95 95 #define SMB_CATIA_WIN_LEFT_ANGLE 0x00ab
96 96 #define SMB_CATIA_WIN_RIGHT_ANGLE 0x00bb
97 97 #define SMB_CATIA_WIN_INVERTED_QUESTION 0x00bf
98 98 #define SMB_CATIA_WIN_DIVISION 0x00f7
99 99 #define SMB_CATIA_WIN_LATIN_O 0x00f8
100 100 #define SMB_CATIA_WIN_LATIN_Y 0x00ff
101 101
102 102 #define SMB_CATIA_V4_LOOKUP_LOW SMB_CATIA_WIN_CURRENCY
103 103 #define SMB_CATIA_V4_LOOKUP_UPPER SMB_CATIA_WIN_LATIN_Y
104 104 #define SMB_CATIA_V4_LOOKUP_MAX \
105 105 (SMB_CATIA_V4_LOOKUP_UPPER - SMB_CATIA_V4_LOOKUP_LOW + 1)
106 106 #define SMB_CATIA_V5_LOOKUP_MAX 0x0080
107 107
108 108 typedef struct smb_catia_map
109 109 {
110 110 unsigned char unixchar; /* v4 */
111 111 smb_wchar_t winchar; /* v5 */
112 112 } smb_catia_map_t;
113 113
114 114 smb_catia_map_t const catia_maps[SMB_CATIA_NUM_MAPS] =
115 115 {
116 116 {'"', SMB_CATIA_WIN_DIAERESIS},
117 117 {'*', SMB_CATIA_WIN_CURRENCY},
118 118 {':', SMB_CATIA_WIN_DIVISION},
119 119 {'<', SMB_CATIA_WIN_LEFT_ANGLE},
120 120 {'>', SMB_CATIA_WIN_RIGHT_ANGLE},
121 121 {'?', SMB_CATIA_WIN_INVERTED_QUESTION},
122 122 {'\\', SMB_CATIA_WIN_LATIN_Y},
123 123 {'/', SMB_CATIA_WIN_LATIN_O},
124 124 {'|', SMB_CATIA_WIN_BROKEN_BAR}
125 125 };
126 126
127 127 static smb_wchar_t smb_catia_v5_lookup[SMB_CATIA_V5_LOOKUP_MAX];
128 128 static smb_wchar_t smb_catia_v4_lookup[SMB_CATIA_V4_LOOKUP_MAX];
129 129
130 130 static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr);
131 131 static void smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
132 132 static callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *);
133 133 static void smb_vop_catia_init();
134 134
135 135 extern sysid_t lm_alloc_sysidt();
136 136
137 137 #define SMB_AT_MAX 16
138 138 static const uint_t smb_attrmap[SMB_AT_MAX] = {
139 139 0,
140 140 AT_TYPE,
141 141 AT_MODE,
142 142 AT_UID,
143 143 AT_GID,
144 144 AT_FSID,
145 145 AT_NODEID,
146 146 AT_NLINK,
147 147 AT_SIZE,
148 148 AT_ATIME,
149 149 AT_MTIME,
150 150 AT_CTIME,
151 151 AT_RDEV,
152 152 AT_BLKSIZE,
153 153 AT_NBLOCKS,
154 154 AT_SEQ
155 155 };
156 156
157 157 static boolean_t smb_vop_initialized = B_FALSE;
158 158 caller_context_t smb_ct;
159 159
160 160 /*
161 161 * smb_vop_init
162 162 *
163 163 * This function is not multi-thread safe. The caller must make sure only one
164 164 * thread makes the call.
165 165 */
166 166 int
167 167 smb_vop_init(void)
168 168 {
169 169 if (smb_vop_initialized)
170 170 return (0);
171 171 /*
172 172 * The caller_context will be used primarily for range locking.
173 173 * Since the CIFS server is mapping its locks to POSIX locks,
174 174 * only one pid is used for operations originating from the
175 175 * CIFS server (to represent CIFS in the VOP_FRLOCK routines).
176 176 *
177 177 * XXX: Should smb_ct be per-zone?
178 178 */
179 179 smb_ct.cc_sysid = lm_alloc_sysidt();
180 180 if (smb_ct.cc_sysid == LM_NOSYSID)
181 181 return (ENOMEM);
182 182
183 183 smb_ct.cc_caller_id = fs_new_caller_id();
184 184 smb_ct.cc_pid = IGN_PID;
185 185 smb_ct.cc_flags = 0;
186 186 smb_vop_catia_init();
187 187
188 188 smb_vop_initialized = B_TRUE;
189 189 return (0);
190 190 }
191 191
192 192 /*
193 193 * smb_vop_fini
194 194 *
195 195 * This function is not multi-thread safe. The caller must make sure only one
196 196 * thread makes the call.
197 197 */
198 198 void
199 199 smb_vop_fini(void)
200 200 {
201 201 if (!smb_vop_initialized)
202 202 return;
203 203
204 204 lm_free_sysidt(smb_ct.cc_sysid);
205 205 smb_ct.cc_pid = IGN_PID;
206 206 smb_ct.cc_sysid = LM_NOSYSID;
207 207 smb_vop_initialized = B_FALSE;
208 208 }
209 209
210 210 /*
211 211 * The smb_ct will be used primarily for range locking.
212 212 * Since the CIFS server is mapping its locks to POSIX locks,
213 213 * only one pid is used for operations originating from the
214 214 * CIFS server (to represent CIFS in the VOP_FRLOCK routines).
215 215 */
216 216 int
217 217 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred)
218 218 {
219 219 return (VOP_OPEN(vpp, mode, cred, &smb_ct));
220 220 }
221 221
222 222 void
223 223 smb_vop_close(vnode_t *vp, int mode, cred_t *cred)
224 224 {
225 225 (void) VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct);
226 226 }
227 227
228 228 int
229 229 smb_vop_other_opens(vnode_t *vp, int mode)
230 230 {
231 231 return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) ||
232 232 (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) ||
233 233 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) ||
234 234 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) ||
235 235 vn_is_mapped(vp, V_RDORWR));
236 236 }
237 237
238 238 /*
239 239 * The smb_vop_* functions have minimal knowledge of CIFS semantics and
240 240 * serve as an interface to the VFS layer.
241 241 *
242 242 * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
|
↓ open down ↓ |
209 lines elided |
↑ open up ↑ |
243 243 * (Higher-level CIFS service code should never skip the smb_fsop_* layer
244 244 * to call smb_vop_* layer functions directly.)
245 245 */
246 246
247 247 /*
248 248 * XXX - Extended attributes support in the file system assumed.
249 249 * This is needed for full NT Streams functionality.
250 250 */
251 251
252 252 int
253 -smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr)
253 +smb_vop_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr)
254 254 {
255 255 int error;
256 256
257 257 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
258 - error = VOP_READ(vp, uiop, 0, cr, &smb_ct);
258 + error = VOP_READ(vp, uiop, ioflag, cr, &smb_ct);
259 259 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
260 260 return (error);
261 261 }
262 262
263 263 int
264 264 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount,
265 265 cred_t *cr)
266 266 {
267 267 int error;
268 268
269 269 *lcount = uiop->uio_resid;
270 270
271 271 uiop->uio_llimit = MAXOFFSET_T;
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
272 272
273 273 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
274 274 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct);
275 275 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
276 276
277 277 *lcount -= uiop->uio_resid;
278 278
279 279 return (error);
280 280 }
281 281
282 +int
283 +smb_vop_ioctl(vnode_t *vp, int cmd, void *arg, cred_t *cr)
284 +{
285 + int error, rval = 0;
286 + uint_t flags = 0;
287 +
288 +#ifdef FKIOCTL
289 + flags |= FKIOCTL;
290 +#endif
291 + error = VOP_IOCTL(vp, cmd, (intptr_t)arg, (int)flags, cr,
292 + &rval, &smb_ct);
293 + if (error != 0)
294 + rval = error;
295 +
296 + return (rval);
297 +}
298 +
282 299 /*
283 300 * smb_vop_getattr()
284 301 *
285 302 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
286 303 * service (instead of calling VOP_GETATTR directly) to retrieve attributes
287 304 * due to special processing needed for streams files.
288 305 *
289 306 * All attributes are retrieved.
290 307 *
291 308 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
292 309 * the corresponding unnamed stream).
293 310 * A named stream's attributes (as far as CIFS is concerned) are those of the
294 311 * unnamed stream (minus the size attribute, and the type), plus the size of
295 312 * the named stream, and a type value of VREG.
296 313 * Although the file system may store other attributes with the named stream,
297 314 * these should not be used by CIFS for any purpose.
298 315 *
299 316 * File systems without VFSFT_XVATTR do not support DOS attributes or create
300 317 * time (crtime). In this case the mtime is used as the crtime.
301 318 * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr
302 319 * is 0 and the mtime is used as the crtime.
303 320 */
304 321 int
305 322 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
306 323 int flags, cred_t *cr)
307 324 {
308 325 int error;
309 326 vnode_t *use_vp;
310 327 smb_attr_t tmp_attr;
311 328 xvattr_t tmp_xvattr;
312 329 xoptattr_t *xoap = NULL;
313 330
314 331 if (unnamed_vp)
315 332 use_vp = unnamed_vp;
316 333 else
317 334 use_vp = vp;
318 335
319 336 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
320 337 xva_init(&tmp_xvattr);
321 338 xoap = xva_getxoptattr(&tmp_xvattr);
322 339 ASSERT(xoap);
323 340
324 341 smb_sa_to_va_mask(ret_attr->sa_mask,
325 342 &tmp_xvattr.xva_vattr.va_mask);
326 343
327 344 XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
328 345 XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
329 346 XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
330 347 XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
331 348 XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
332 349 XVA_SET_REQ(&tmp_xvattr, XAT_REPARSE);
333 350 XVA_SET_REQ(&tmp_xvattr, XAT_OFFLINE);
334 351 XVA_SET_REQ(&tmp_xvattr, XAT_SPARSE);
335 352
336 353 error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags,
337 354 cr, &smb_ct);
338 355 if (error != 0)
339 356 return (error);
340 357
341 358 ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
342 359 ret_attr->sa_dosattr = 0;
343 360
344 361 if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) {
345 362 xoap = xva_getxoptattr(&tmp_xvattr);
346 363 ASSERT(xoap);
347 364
348 365 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) &&
349 366 (xoap->xoa_readonly)) {
350 367 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
351 368 }
352 369
353 370 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) &&
354 371 (xoap->xoa_hidden)) {
355 372 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
356 373 }
357 374
358 375 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) &&
359 376 (xoap->xoa_system)) {
360 377 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
361 378 }
362 379
363 380 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) &&
364 381 (xoap->xoa_archive)) {
365 382 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
366 383 }
367 384
368 385 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_REPARSE)) &&
369 386 (xoap->xoa_reparse)) {
370 387 ret_attr->sa_dosattr |=
371 388 FILE_ATTRIBUTE_REPARSE_POINT;
372 389 }
373 390
374 391 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_OFFLINE)) &&
375 392 (xoap->xoa_offline)) {
376 393 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_OFFLINE;
377 394 }
378 395
379 396 if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SPARSE)) &&
380 397 (xoap->xoa_sparse)) {
381 398 ret_attr->sa_dosattr |=
382 399 FILE_ATTRIBUTE_SPARSE_FILE;
383 400 }
384 401
385 402 ret_attr->sa_crtime = xoap->xoa_createtime;
386 403 } else {
387 404 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
388 405 }
389 406 } else {
390 407 /*
391 408 * Support for file systems without VFSFT_XVATTR
392 409 */
393 410 smb_sa_to_va_mask(ret_attr->sa_mask,
394 411 &ret_attr->sa_vattr.va_mask);
395 412
396 413 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr,
397 414 flags, cr, &smb_ct);
398 415 if (error != 0)
399 416 return (error);
400 417
401 418 ret_attr->sa_dosattr = 0;
402 419 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
403 420 }
404 421
405 422 if (unnamed_vp) {
406 423 ret_attr->sa_vattr.va_type = VREG;
407 424
408 425 if (ret_attr->sa_mask & (SMB_AT_SIZE | SMB_AT_NBLOCKS)) {
409 426 tmp_attr.sa_vattr.va_mask = AT_SIZE | AT_NBLOCKS;
410 427
411 428 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr,
412 429 flags, cr, &smb_ct);
413 430 if (error != 0)
414 431 return (error);
415 432
416 433 ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
417 434 ret_attr->sa_vattr.va_nblocks =
418 435 tmp_attr.sa_vattr.va_nblocks;
419 436 }
420 437 }
421 438
422 439 if (ret_attr->sa_vattr.va_type == VDIR)
423 440 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
424 441
425 442 return (error);
426 443 }
427 444
428 445 /*
429 446 * smb_vop_setattr()
430 447 *
431 448 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of
432 449 * VOP_SETATTR() when calling from the CIFS service, due to special processing
433 450 * for streams files.
434 451 *
435 452 * Streams have a size but otherwise do not have separate attributes from
436 453 * the (unnamed stream) file, i.e., the security and ownership of the file
437 454 * applies to the stream. In contrast, extended attribute files, which are
438 455 * used to implement streams, are independent objects with their own
439 456 * attributes.
440 457 *
441 458 * For compatibility with streams, we set the size on the extended attribute
442 459 * file and apply other attributes to the (unnamed stream) file. The one
443 460 * exception is that the UID and GID can be set on the stream by passing a
444 461 * NULL unnamed_vp, which allows callers to synchronize stream ownership
445 462 * with the (unnamed stream) file.
446 463 */
447 464 int
448 465 smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *attr,
449 466 int flags, cred_t *cr)
450 467 {
451 468 int error = 0;
452 469 int at_size = 0;
453 470 vnode_t *use_vp;
454 471 xvattr_t xvattr;
455 472 vattr_t *vap;
456 473
457 474 if (attr->sa_mask & SMB_AT_DOSATTR) {
458 475 attr->sa_dosattr &=
459 476 (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY |
460 477 FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
461 478 FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_SPARSE_FILE);
462 479 }
463 480
464 481 if (unnamed_vp) {
465 482 use_vp = unnamed_vp;
466 483 if (attr->sa_mask & SMB_AT_SIZE) {
467 484 at_size = 1;
468 485 attr->sa_mask &= ~SMB_AT_SIZE;
469 486 }
470 487 } else {
471 488 use_vp = vp;
472 489 }
473 490
474 491 /*
475 492 * The caller should not be setting sa_vattr.va_mask,
476 493 * but rather sa_mask.
477 494 */
478 495
479 496 attr->sa_vattr.va_mask = 0;
480 497
481 498 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
482 499 smb_vop_setup_xvattr(attr, &xvattr);
483 500 vap = &xvattr.xva_vattr;
484 501 } else {
485 502 smb_sa_to_va_mask(attr->sa_mask,
486 503 &attr->sa_vattr.va_mask);
487 504 vap = &attr->sa_vattr;
488 505 }
489 506
490 507 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0)
491 508 return (error);
492 509
493 510 if (at_size) {
|
↓ open down ↓ |
202 lines elided |
↑ open up ↑ |
494 511 attr->sa_vattr.va_mask = AT_SIZE;
495 512 error = VOP_SETATTR(vp, &attr->sa_vattr, flags,
496 513 zone_kcred(), &smb_ct);
497 514 }
498 515
499 516 return (error);
500 517 }
501 518
502 519 int
503 520 smb_vop_space(vnode_t *vp, int cmd, flock64_t *bfp, int flags,
504 - offset_t offset, cred_t *cr)
521 + offset_t offset, cred_t *cr)
505 522 {
506 523 int error;
507 524
508 525 error = VOP_SPACE(vp, cmd, bfp, flags, offset, cr, &smb_ct);
509 526
510 527 return (error);
511 528 }
512 529
513 530 /*
514 531 * smb_vop_access
515 532 *
516 533 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
517 534 * against file's ACL or Unix permissions. CIFS on the other hand needs to
518 535 * know if the requested operation can succeed for the given object, this
519 536 * requires more checks in case of DELETE bit since permissions on the parent
520 537 * directory are important as well. Based on Windows rules if parent's ACL
521 538 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
522 539 * permissions.
523 540 */
524 541 int
525 542 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
526 543 {
527 544 int error = 0;
528 545
529 546 if (mode == 0)
530 547 return (0);
531 548
532 - if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
533 - if (dir_vp) {
534 - error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
535 - cr, NULL);
549 + error = VOP_ACCESS(vp, mode, flags, cr, NULL);
536 550
537 - if (error == 0)
538 - mode &= ~ACE_DELETE;
539 - }
551 + if (error == 0)
552 + return (0);
553 +
554 + if ((mode & (ACE_DELETE|ACE_READ_ATTRIBUTES)) == 0 ||
555 + flags != V_ACE_MASK || dir_vp == NULL)
556 + return (error);
557 +
558 + smb_audit_save();
559 + if ((mode & ACE_DELETE) != 0) {
560 + error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
561 + cr, NULL);
562 +
563 + if (error == 0)
564 + mode &= ~ACE_DELETE;
540 565 }
566 + if ((mode & ACE_READ_ATTRIBUTES) != 0) {
567 + error = VOP_ACCESS(dir_vp, ACE_LIST_DIRECTORY, flags,
568 + cr, NULL);
541 569
542 - if (mode) {
543 - error = VOP_ACCESS(vp, mode, flags, cr, NULL);
570 + if (error == 0)
571 + mode &= ~ACE_READ_ATTRIBUTES;
544 572 }
545 573
574 + if (mode != 0)
575 + error = VOP_ACCESS(vp, mode, flags, cr, NULL);
576 +
577 + smb_audit_load();
546 578 return (error);
547 579 }
548 580
549 581 /*
550 582 * smb_vop_lookup
551 583 *
552 584 * dvp: directory vnode (in)
553 585 * name: name of file to be looked up (in)
554 586 * vpp: looked-up vnode (out)
555 587 * od_name: on-disk name of file (out).
556 588 * This parameter is optional. If a pointer is passed in, it
557 - * must be allocated with MAXNAMELEN bytes
589 + * must be allocated with MAXNAMELEN bytes
558 590 * rootvp: vnode of the tree root (in)
559 591 * This parameter is always passed in non-NULL except at the time
560 592 * of share set up.
561 593 * direntflags: dirent flags returned from VOP_LOOKUP
562 594 */
563 595 int
564 596 smb_vop_lookup(
565 597 vnode_t *dvp,
566 598 char *name,
567 599 vnode_t **vpp,
568 600 char *od_name,
569 601 int flags,
570 602 int *direntflags,
571 603 vnode_t *rootvp,
572 604 smb_attr_t *attr,
573 605 cred_t *cr)
574 606 {
575 607 int error = 0;
576 608 int option_flags = 0;
577 609 pathname_t rpn;
578 610 char *np = name;
579 611 char namebuf[MAXNAMELEN];
580 612
581 613 if (*name == '\0')
582 614 return (EINVAL);
583 615
584 616 ASSERT(vpp);
585 617 *vpp = NULL;
586 618 *direntflags = 0;
587 619
588 620 if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) {
589 621 if (rootvp && (dvp == rootvp)) {
590 622 VN_HOLD(dvp);
591 623 *vpp = dvp;
592 624 return (0);
593 625 }
594 626
595 627 if (dvp->v_flag & VROOT) {
596 628 vfs_t *vfsp;
597 629 vnode_t *cvp = dvp;
598 630
599 631 /*
600 632 * Set dvp and check for races with forced unmount
601 633 * (see lookuppnvp())
602 634 */
603 635
604 636 vfsp = cvp->v_vfsp;
605 637 vfs_rlock_wait(vfsp);
606 638 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
607 639 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
608 640 vfs_unlock(vfsp);
609 641 return (EIO);
610 642 }
611 643 vfs_unlock(vfsp);
612 644 }
|
↓ open down ↓ |
45 lines elided |
↑ open up ↑ |
613 645 }
614 646
615 647 if (flags & SMB_IGNORE_CASE)
616 648 option_flags = FIGNORECASE;
617 649
618 650 if (flags & SMB_CATIA)
619 651 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
620 652
621 653 pn_alloc(&rpn);
622 654
655 + /*
656 + * Easier to not have junk in rpn, as not every FS type
657 + * will necessarily fill that in for us.
658 + */
659 + bzero(rpn.pn_buf, rpn.pn_bufsize);
660 +
623 661 error = VOP_LOOKUP(dvp, np, vpp, NULL, option_flags, NULL, cr,
624 662 &smb_ct, direntflags, &rpn);
625 663
626 664 if (error == 0) {
627 665 if (od_name) {
628 666 bzero(od_name, MAXNAMELEN);
629 - np = (option_flags == FIGNORECASE) ? rpn.pn_buf : name;
630 -
667 + if ((option_flags & FIGNORECASE) != 0 &&
668 + rpn.pn_buf[0] != '\0')
669 + np = rpn.pn_buf;
670 + else
671 + np = name;
631 672 if (flags & SMB_CATIA)
632 673 smb_vop_catia_v4tov5(np, od_name, MAXNAMELEN);
633 674 else
634 675 (void) strlcpy(od_name, np, MAXNAMELEN);
635 676 }
636 677
637 678 if (attr != NULL) {
638 679 attr->sa_mask = SMB_AT_ALL;
639 680 (void) smb_vop_getattr(*vpp, NULL, attr, 0,
640 681 zone_kcred());
641 682 }
642 683 }
643 684
644 685 pn_free(&rpn);
645 686 return (error);
646 687 }
647 688
648 689 int
649 690 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
650 691 int flags, cred_t *cr, vsecattr_t *vsap)
651 692 {
652 693 int error;
653 694 int option_flags = 0;
654 695 xvattr_t xvattr;
655 696 vattr_t *vap;
656 697 char *np = name;
657 698 char namebuf[MAXNAMELEN];
658 699
659 700 if (flags & SMB_IGNORE_CASE)
660 701 option_flags = FIGNORECASE;
661 702
662 703 attr->sa_vattr.va_mask = 0;
663 704
664 705 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
665 706 smb_vop_setup_xvattr(attr, &xvattr);
666 707 vap = &xvattr.xva_vattr;
667 708 } else {
668 709 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
669 710 vap = &attr->sa_vattr;
670 711 }
|
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
671 712
672 713 if (flags & SMB_CATIA) {
673 714 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
674 715 if (strchr(np, '/') != NULL)
675 716 return (EILSEQ);
676 717 }
677 718
678 719 error = VOP_CREATE(dvp, np, vap, EXCL, attr->sa_vattr.va_mode,
679 720 vpp, cr, option_flags, &smb_ct, vsap);
680 721
722 + /*
723 + * One could argue that filesystems should obey the size
724 + * if specified in the create attributes. Unfortunately,
725 + * they only appear to let you truncate the size to zero.
726 + * SMB needs to set a non-zero size, so work-around.
727 + */
728 + if (error == 0 && *vpp != NULL &&
729 + (vap->va_mask & AT_SIZE) != 0 &&
730 + vap->va_size > 0) {
731 + vattr_t ta = *vap;
732 + ta.va_mask = AT_SIZE;
733 + (void) VOP_SETATTR(*vpp, &ta, 0, cr, &smb_ct);
734 + }
735 +
681 736 return (error);
682 737 }
683 738
684 739 int
685 740 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr)
686 741 {
687 742 int error;
688 743 int option_flags = 0;
689 744 char *np = name;
690 745 char namebuf[MAXNAMELEN];
691 746
692 747 if (flags & SMB_IGNORE_CASE)
693 748 option_flags = FIGNORECASE;
694 749
695 750 if (flags & SMB_CATIA)
696 751 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
697 752
698 753 error = VOP_REMOVE(dvp, np, cr, &smb_ct, option_flags);
699 754
700 755 return (error);
701 756 }
702 757
703 758 /*
704 759 * smb_vop_link(target-dir-vp, source-file-vp, target-name)
705 760 *
706 761 * Create a link - same tree (identical TID) only.
707 762 */
708 763 int
709 764 smb_vop_link(vnode_t *to_dvp, vnode_t *from_vp, char *to_name,
710 765 int flags, cred_t *cr)
711 766 {
712 767 int option_flags = 0;
713 768 char *np, *buf;
714 769 int rc;
715 770
716 771 if (flags & SMB_IGNORE_CASE)
717 772 option_flags = FIGNORECASE;
718 773
719 774 if (flags & SMB_CATIA) {
720 775 buf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
721 776 np = smb_vop_catia_v5tov4(to_name, buf, MAXNAMELEN);
722 777 if (strchr(np, '/') != NULL) {
723 778 kmem_free(buf, MAXNAMELEN);
724 779 return (EILSEQ);
725 780 }
726 781
727 782 rc = VOP_LINK(to_dvp, from_vp, np, cr, &smb_ct, option_flags);
728 783 kmem_free(buf, MAXNAMELEN);
729 784 return (rc);
730 785 }
731 786
732 787 rc = VOP_LINK(to_dvp, from_vp, to_name, cr, &smb_ct, option_flags);
733 788 return (rc);
734 789 }
735 790
736 791 /*
737 792 * smb_vop_rename()
738 793 *
739 794 * The rename is for files in the same tree (identical TID) only.
740 795 */
741 796 int
742 797 smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp,
743 798 char *to_name, int flags, cred_t *cr)
744 799 {
745 800 int error;
746 801 int option_flags = 0;
747 802 char *from, *to, *fbuf, *tbuf;
748 803
749 804 if (flags & SMB_IGNORE_CASE)
750 805 option_flags = FIGNORECASE;
751 806
752 807 if (flags & SMB_CATIA) {
753 808 tbuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
754 809 to = smb_vop_catia_v5tov4(to_name, tbuf, MAXNAMELEN);
755 810 if (strchr(to, '/') != NULL) {
756 811 kmem_free(tbuf, MAXNAMELEN);
757 812 return (EILSEQ);
758 813 }
759 814
760 815 fbuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
761 816 from = smb_vop_catia_v5tov4(from_name, fbuf, MAXNAMELEN);
762 817
763 818 error = VOP_RENAME(from_dvp, from, to_dvp, to, cr,
764 819 &smb_ct, option_flags);
765 820
766 821 kmem_free(tbuf, MAXNAMELEN);
767 822 kmem_free(fbuf, MAXNAMELEN);
768 823 return (error);
769 824 }
770 825
771 826 error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr,
772 827 &smb_ct, option_flags);
773 828
774 829 return (error);
775 830 }
776 831
777 832 int
778 833 smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
779 834 int flags, cred_t *cr, vsecattr_t *vsap)
780 835 {
781 836 int error;
782 837 int option_flags = 0;
783 838 xvattr_t xvattr;
784 839 vattr_t *vap;
785 840 char *np = name;
786 841 char namebuf[MAXNAMELEN];
787 842
788 843 if (flags & SMB_IGNORE_CASE)
789 844 option_flags = FIGNORECASE;
790 845
791 846 attr->sa_vattr.va_mask = 0;
792 847
793 848 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
794 849 smb_vop_setup_xvattr(attr, &xvattr);
795 850 vap = &xvattr.xva_vattr;
796 851 } else {
797 852 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
798 853 vap = &attr->sa_vattr;
799 854 }
800 855
801 856 if (flags & SMB_CATIA) {
802 857 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
803 858 if (strchr(np, '/') != NULL)
804 859 return (EILSEQ);
805 860 }
806 861
807 862 error = VOP_MKDIR(dvp, np, vap, vpp, cr, &smb_ct, option_flags, vsap);
808 863
809 864 return (error);
810 865 }
811 866
812 867 /*
813 868 * smb_vop_rmdir()
814 869 *
815 870 * Only simple rmdir supported, consistent with NT semantics
816 871 * (can only remove an empty directory).
817 872 *
818 873 * The third argument to VOP_RMDIR is the current directory of
819 874 * the process. It allows rmdir wants to EINVAL if one tries to
820 875 * remove ".". Since SMB servers do not know what their clients'
821 876 * current directories are, we fake it by supplying a vnode known
822 877 * to exist and illegal to remove (rootdir).
823 878 */
824 879 int
825 880 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr)
826 881 {
827 882 int error;
828 883 int option_flags = 0;
829 884 char *np = name;
830 885 char namebuf[MAXNAMELEN];
831 886
832 887 if (flags & SMB_IGNORE_CASE)
833 888 option_flags = FIGNORECASE;
834 889
835 890 if (flags & SMB_CATIA)
836 891 np = smb_vop_catia_v5tov4(name, namebuf, sizeof (namebuf));
837 892
838 893 error = VOP_RMDIR(dvp, np, rootdir, cr, &smb_ct, option_flags);
839 894 return (error);
840 895 }
841 896
842 897 int
843 898 smb_vop_commit(vnode_t *vp, cred_t *cr)
844 899 {
845 900 return (VOP_FSYNC(vp, 1, cr, &smb_ct));
846 901 }
847 902
848 903 /*
849 904 * Some code in smb_node.c needs to know which DOS attributes
850 905 * we can actually store. Let's define a mask here of all the
851 906 * DOS attribute flags supported by the following function.
852 907 */
853 908 const uint32_t
854 909 smb_vop_dosattr_settable =
855 910 FILE_ATTRIBUTE_ARCHIVE |
856 911 FILE_ATTRIBUTE_SYSTEM |
857 912 FILE_ATTRIBUTE_HIDDEN |
858 913 FILE_ATTRIBUTE_READONLY |
859 914 FILE_ATTRIBUTE_OFFLINE |
860 915 FILE_ATTRIBUTE_SPARSE_FILE;
861 916
862 917 static void
863 918 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr)
864 919 {
865 920 xoptattr_t *xoap = NULL;
866 921 uint_t xva_mask;
867 922
868 923 /*
869 924 * Initialize xvattr, including bzero
870 925 */
871 926 xva_init(xvattr);
872 927 xoap = xva_getxoptattr(xvattr);
873 928
874 929 ASSERT(xoap);
875 930
876 931 /*
877 932 * Copy caller-specified classic attributes to xvattr.
878 933 * First save xvattr's mask (set in xva_init()), which
879 934 * contains AT_XVATTR. This is |'d in later if needed.
880 935 */
881 936
882 937 xva_mask = xvattr->xva_vattr.va_mask;
883 938 xvattr->xva_vattr = smb_attr->sa_vattr;
884 939
885 940 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask);
886 941
887 942 /*
888 943 * Do not set ctime (only the file system can do it)
889 944 */
890 945
891 946 xvattr->xva_vattr.va_mask &= ~AT_CTIME;
892 947
893 948 if (smb_attr->sa_mask & SMB_AT_DOSATTR) {
894 949
895 950 /*
896 951 * "|" in the original xva_mask, which contains
897 952 * AT_XVATTR
898 953 */
899 954
900 955 xvattr->xva_vattr.va_mask |= xva_mask;
901 956
902 957 XVA_SET_REQ(xvattr, XAT_ARCHIVE);
903 958 XVA_SET_REQ(xvattr, XAT_SYSTEM);
904 959 XVA_SET_REQ(xvattr, XAT_READONLY);
905 960 XVA_SET_REQ(xvattr, XAT_HIDDEN);
906 961 XVA_SET_REQ(xvattr, XAT_OFFLINE);
907 962 XVA_SET_REQ(xvattr, XAT_SPARSE);
908 963
909 964 /*
910 965 * smb_attr->sa_dosattr: If a given bit is not set,
911 966 * that indicates that the corresponding field needs
912 967 * to be updated with a "0" value. This is done
913 968 * implicitly as the xoap->xoa_* fields were bzero'd.
914 969 */
915 970
916 971 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE)
917 972 xoap->xoa_archive = 1;
918 973
919 974 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM)
920 975 xoap->xoa_system = 1;
921 976
922 977 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY)
923 978 xoap->xoa_readonly = 1;
924 979
925 980 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN)
926 981 xoap->xoa_hidden = 1;
927 982
928 983 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_OFFLINE)
929 984 xoap->xoa_offline = 1;
930 985
931 986 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE)
932 987 xoap->xoa_sparse = 1;
933 988 }
934 989
935 990 if (smb_attr->sa_mask & SMB_AT_CRTIME) {
936 991 /*
937 992 * "|" in the original xva_mask, which contains
938 993 * AT_XVATTR
939 994 */
940 995
941 996 xvattr->xva_vattr.va_mask |= xva_mask;
942 997 XVA_SET_REQ(xvattr, XAT_CREATETIME);
943 998 xoap->xoa_createtime = smb_attr->sa_crtime;
944 999 }
945 1000 }
946 1001
947 1002 /*
948 1003 * smb_vop_readdir()
949 1004 *
950 1005 * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries.
951 1006 * The directory entries are returned in an fs-independent format by the
952 1007 * underlying file system. That is, the "page" of information returned is
953 1008 * not literally stored on-disk in the format returned.
954 1009 * If the file system supports extended directory entries (has features
955 1010 * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
956 1011 * filled with edirent_t structures, instead of dirent64_t structures.
957 1012 * If the file system supports access based enumeration (abe), set
958 1013 * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
959 1014 */
960 1015 int
961 1016 smb_vop_readdir(vnode_t *vp, uint32_t offset,
962 1017 void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
|
↓ open down ↓ |
272 lines elided |
↑ open up ↑ |
963 1018 {
964 1019 int error = 0;
965 1020 int flags = 0;
966 1021 int rdirent_size;
967 1022 struct uio auio;
968 1023 struct iovec aiov;
969 1024
970 1025 if (vp->v_type != VDIR)
971 1026 return (ENOTDIR);
972 1027
973 - if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
1028 + if ((rddir_flag & SMB_EDIRENT) != 0 &&
1029 + vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
974 1030 flags |= V_RDDIR_ENTFLAGS;
975 1031 rdirent_size = sizeof (edirent_t);
976 1032 } else {
977 1033 rdirent_size = sizeof (dirent64_t);
978 1034 }
979 1035
980 1036 if (*count < rdirent_size)
981 1037 return (EINVAL);
982 1038
983 1039 if (rddir_flag & SMB_ABE)
984 1040 flags |= V_RDDIR_ACCFILTER;
985 1041
986 1042 aiov.iov_base = buf;
987 1043 aiov.iov_len = *count;
988 1044 auio.uio_iov = &aiov;
989 1045 auio.uio_iovcnt = 1;
990 1046 auio.uio_loffset = (uint64_t)offset;
991 1047 auio.uio_segflg = UIO_SYSSPACE;
992 1048 auio.uio_extflg = UIO_COPY_DEFAULT;
993 1049 auio.uio_resid = *count;
994 1050 auio.uio_fmode = 0;
995 1051
996 1052 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
997 1053 error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, flags);
998 1054 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
999 1055
1000 1056 if (error == 0)
1001 1057 *count = *count - auio.uio_resid;
1002 1058
1003 1059 return (error);
1004 1060 }
1005 1061
1006 1062 /*
1007 1063 * smb_sa_to_va_mask
1008 1064 *
1009 1065 * Set va_mask by running through the SMB_AT_* #define's and
1010 1066 * setting those bits that correspond to the SMB_AT_* bits
1011 1067 * set in sa_mask.
1012 1068 */
1013 1069 void
1014 1070 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp)
1015 1071 {
1016 1072 int i;
1017 1073 uint_t smask;
1018 1074
1019 1075 smask = (sa_mask);
1020 1076 for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) {
1021 1077 if (smask & 1)
1022 1078 *(va_maskp) |= smb_attrmap[i];
1023 1079
1024 1080 smask >>= 1;
1025 1081 }
1026 1082 }
1027 1083
1028 1084 /*
1029 1085 * smb_vop_stream_lookup()
1030 1086 *
1031 1087 * The name returned in od_name is the on-disk name of the stream with the
1032 1088 * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN
1033 1089 * by the caller.
1034 1090 */
1035 1091 int
1036 1092 smb_vop_stream_lookup(
1037 1093 vnode_t *fvp,
1038 1094 char *stream_name,
1039 1095 vnode_t **vpp,
1040 1096 char *od_name,
1041 1097 vnode_t **xattrdirvpp,
1042 1098 int flags,
1043 1099 vnode_t *rootvp,
1044 1100 cred_t *cr)
1045 1101 {
1046 1102 char *solaris_stream_name;
1047 1103 char *name;
1048 1104 int error, tmpflgs;
1049 1105
1050 1106 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
1051 1107 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0)
1052 1108 return (error);
1053 1109
1054 1110 /*
1055 1111 * Prepend SMB_STREAM_PREFIX to stream name
1056 1112 */
1057 1113
1058 1114 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1059 1115 (void) snprintf(solaris_stream_name, MAXNAMELEN,
1060 1116 "%s%s", SMB_STREAM_PREFIX, stream_name);
1061 1117
1062 1118 /*
1063 1119 * "name" will hold the on-disk name returned from smb_vop_lookup
1064 1120 * for the stream, including the SMB_STREAM_PREFIX.
1065 1121 */
1066 1122
1067 1123 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
1068 1124
1069 1125 if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp,
1070 1126 name, flags, &tmpflgs, rootvp, NULL, cr)) != 0) {
1071 1127 VN_RELE(*xattrdirvpp);
1072 1128 } else {
1073 1129 (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]),
1074 1130 MAXNAMELEN);
1075 1131 }
1076 1132
1077 1133 kmem_free(solaris_stream_name, MAXNAMELEN);
1078 1134 kmem_free(name, MAXNAMELEN);
1079 1135
1080 1136 return (error);
1081 1137 }
1082 1138
1083 1139 int
1084 1140 smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr,
1085 1141 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr)
1086 1142 {
1087 1143 char *solaris_stream_name;
1088 1144 int error;
1089 1145
1090 1146 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
1091 1147 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0)
1092 1148 return (error);
1093 1149
1094 1150 /*
1095 1151 * Prepend SMB_STREAM_PREFIX to stream name
1096 1152 */
1097 1153
1098 1154 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1099 1155 (void) snprintf(solaris_stream_name, MAXNAMELEN,
1100 1156 "%s%s", SMB_STREAM_PREFIX, stream_name);
1101 1157
1102 1158 if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr,
1103 1159 vpp, flags, cr, NULL)) != 0)
1104 1160 VN_RELE(*xattrdirvpp);
1105 1161
1106 1162 kmem_free(solaris_stream_name, MAXNAMELEN);
1107 1163
1108 1164 return (error);
1109 1165 }
1110 1166
1111 1167 int
1112 1168 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr)
1113 1169 {
1114 1170 char *solaris_stream_name;
1115 1171 vnode_t *xattrdirvp;
1116 1172 int error;
1117 1173
1118 1174 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr);
1119 1175 if (error != 0)
1120 1176 return (error);
1121 1177
1122 1178 /*
1123 1179 * Prepend SMB_STREAM_PREFIX to stream name
1124 1180 */
1125 1181
1126 1182 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1127 1183 (void) snprintf(solaris_stream_name, MAXNAMELEN,
1128 1184 "%s%s", SMB_STREAM_PREFIX, stream_name);
1129 1185
1130 1186 /* XXX might have to use kcred */
1131 1187 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr);
1132 1188
1133 1189 kmem_free(solaris_stream_name, MAXNAMELEN);
1134 1190 VN_RELE(xattrdirvp);
1135 1191
1136 1192 return (error);
1137 1193 }
1138 1194
1139 1195 int
1140 1196 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags,
1141 1197 cred_t *cr)
1142 1198 {
1143 1199 int error;
1144 1200
1145 1201 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr,
1146 1202 &smb_ct, NULL, NULL);
1147 1203 return (error);
1148 1204 }
1149 1205
1150 1206 /*
1151 1207 * smb_vop_traverse_check()
1152 1208 *
1153 1209 * This function checks to see if the passed-in vnode has a file system
1154 1210 * mounted on it. If it does, the mount point is "traversed" and the
1155 1211 * vnode for the root of the file system is returned.
1156 1212 */
1157 1213 int
1158 1214 smb_vop_traverse_check(vnode_t **vpp)
1159 1215 {
1160 1216 int error;
1161 1217
1162 1218 if (vn_mountedvfs(*vpp) == 0)
1163 1219 return (0);
1164 1220
1165 1221 /*
1166 1222 * traverse() may return a different held vnode, even in the error case.
1167 1223 * If it returns a different vnode, it will have released the original.
1168 1224 */
1169 1225
1170 1226 error = traverse(vpp);
1171 1227
1172 1228 return (error);
1173 1229 }
1174 1230
1175 1231 int /*ARGSUSED*/
1176 1232 smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr)
1177 1233 {
1178 1234 int error;
1179 1235
1180 1236 error = VFS_STATVFS(vp->v_vfsp, statp);
1181 1237
1182 1238 return (error);
1183 1239 }
1184 1240
1185 1241 /*
1186 1242 * smb_vop_acl_read
1187 1243 *
1188 1244 * Reads the ACL of the specified file into 'aclp'.
1189 1245 * acl_type is the type of ACL which the filesystem supports.
1190 1246 *
1191 1247 * Caller has to free the allocated memory for aclp by calling
1192 1248 * acl_free().
1193 1249 */
1194 1250 int
1195 1251 smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
1196 1252 cred_t *cr)
1197 1253 {
1198 1254 int error;
1199 1255 vsecattr_t vsecattr;
1200 1256
1201 1257 ASSERT(vp);
1202 1258 ASSERT(aclp);
1203 1259
1204 1260 *aclp = NULL;
1205 1261 bzero(&vsecattr, sizeof (vsecattr_t));
1206 1262
1207 1263 switch (acl_type) {
1208 1264 case ACLENT_T:
1209 1265 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
1210 1266 VSA_DFACLCNT;
|
↓ open down ↓ |
227 lines elided |
↑ open up ↑ |
1211 1267 break;
1212 1268
1213 1269 case ACE_T:
1214 1270 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
1215 1271 break;
1216 1272
1217 1273 default:
1218 1274 return (EINVAL);
1219 1275 }
1220 1276
1221 - if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct))
1277 + if ((error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) != 0)
1222 1278 return (error);
1223 1279
1224 1280 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
1225 1281 if (vp->v_type == VDIR)
1226 1282 (*aclp)->acl_flags |= ACL_IS_DIR;
1227 1283
1228 1284 return (0);
1229 1285 }
1230 1286
1231 1287 /*
1232 1288 * smb_vop_acl_write
1233 1289 *
1234 1290 * Writes the given ACL in aclp for the specified file.
1235 1291 */
1236 1292 int
1237 1293 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
1238 1294 {
1239 1295 int error;
1240 1296 vsecattr_t vsecattr;
1241 1297 int aclbsize;
1242 1298
1243 1299 ASSERT(vp);
1244 1300 ASSERT(aclp);
1245 1301
1246 1302 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize);
1247 1303
1248 1304 if (error == 0) {
1249 1305 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
1250 1306 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct);
1251 1307 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct);
1252 1308 }
1253 1309
1254 1310 if (aclbsize && vsecattr.vsa_aclentp)
1255 1311 kmem_free(vsecattr.vsa_aclentp, aclbsize);
1256 1312
1257 1313 return (error);
1258 1314 }
1259 1315
1260 1316 /*
1261 1317 * smb_vop_acl_type
1262 1318 *
1263 1319 * Determines the ACL type for the given vnode.
1264 1320 * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL.
1265 1321 */
1266 1322 acl_type_t
1267 1323 smb_vop_acl_type(vnode_t *vp)
1268 1324 {
1269 1325 int error;
1270 1326 ulong_t whichacl;
1271 1327
1272 1328 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
1273 1329 zone_kcred(), NULL);
1274 1330 if (error != 0) {
1275 1331 /*
1276 1332 * If we got an error, then the filesystem
1277 1333 * likely does not understand the _PC_ACL_ENABLED
1278 1334 * pathconf. In this case, we fall back to trying
1279 1335 * POSIX-draft (aka UFS-style) ACLs.
1280 1336 */
1281 1337 whichacl = _ACL_ACLENT_ENABLED;
1282 1338 }
1283 1339
1284 1340 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
1285 1341 /*
1286 1342 * If the file system supports neither ACE nor
1287 1343 * ACLENT ACLs we will fall back to UFS-style ACLs
1288 1344 * like we did above if there was an error upon
1289 1345 * calling VOP_PATHCONF.
1290 1346 *
1291 1347 * ACE and ACLENT type ACLs are the only interfaces
1292 1348 * supported thus far. If any other bits are set on
1293 1349 * 'whichacl' upon return from VOP_PATHCONF, we will
1294 1350 * ignore them.
1295 1351 */
1296 1352 whichacl = _ACL_ACLENT_ENABLED;
1297 1353 }
1298 1354
1299 1355 if (whichacl == _ACL_ACLENT_ENABLED)
1300 1356 return (ACLENT_T);
1301 1357
1302 1358 return (ACE_T);
1303 1359 }
1304 1360
1305 1361 static const int zfs_perms[] = {
1306 1362 ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS,
1307 1363 ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD,
1308 1364 ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL,
1309 1365 ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE
1310 1366 };
1311 1367
1312 1368 static const int unix_perms[] = { VREAD, VWRITE, VEXEC };
1313 1369 /*
1314 1370 * smb_vop_eaccess
1315 1371 *
1316 1372 * Returns the effective permission of the given credential for the
1317 1373 * specified object.
1318 1374 *
1319 1375 * This is just a workaround. We need VFS/FS support for this.
1320 1376 */
1321 1377 void
1322 1378 smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr)
1323 1379 {
1324 1380 int error, i;
1325 1381 int pnum;
1326 1382
1327 1383 *mode = 0;
1328 1384
1329 1385 if (flags == V_ACE_MASK) {
1330 1386 pnum = sizeof (zfs_perms) / sizeof (int);
1331 1387
1332 1388 for (i = 0; i < pnum; i++) {
1333 1389 error = smb_vop_access(vp, zfs_perms[i], flags,
1334 1390 dir_vp, cr);
1335 1391 if (error == 0)
1336 1392 *mode |= zfs_perms[i];
1337 1393 }
1338 1394 } else {
1339 1395 pnum = sizeof (unix_perms) / sizeof (int);
1340 1396
1341 1397 for (i = 0; i < pnum; i++) {
1342 1398 error = smb_vop_access(vp, unix_perms[i], flags,
1343 1399 dir_vp, cr);
1344 1400 if (error == 0)
1345 1401 *mode |= unix_perms[i];
1346 1402 }
1347 1403 }
1348 1404 }
1349 1405
1350 1406 /*
1351 1407 * See comments for smb_fsop_shrlock()
1352 1408 */
1353 1409 int
1354 1410 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access,
1355 1411 uint32_t share_access, cred_t *cr)
1356 1412 {
1357 1413 struct shrlock shr;
1358 1414 struct shr_locowner shr_own;
1359 1415 short new_access = 0;
1360 1416 short deny = 0;
1361 1417 int flag = 0;
1362 1418 int cmd;
1363 1419
1364 1420 /*
1365 1421 * share locking is not supported for non-regular
1366 1422 * objects in NBMAND mode.
1367 1423 */
1368 1424 if (nbl_need_check(vp)) {
1369 1425 if (vp->v_type != VREG)
1370 1426 return (0);
1371 1427
1372 1428 cmd = F_SHARE_NBMAND;
1373 1429 } else {
1374 1430 cmd = F_SHARE;
1375 1431 }
1376 1432
1377 1433 if ((desired_access & FILE_DATA_ALL) == 0) {
1378 1434 /* metadata access only */
1379 1435 new_access |= F_MDACC;
1380 1436 } else {
1381 1437 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) {
1382 1438 new_access |= F_RDACC;
1383 1439 flag |= FREAD;
1384 1440 }
1385 1441
1386 1442 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA |
1387 1443 ACE_ADD_FILE)) {
1388 1444 new_access |= F_WRACC;
1389 1445 flag |= FWRITE;
1390 1446 }
1391 1447
1392 1448 if (SMB_DENY_READ(share_access)) {
1393 1449 deny |= F_RDDNY;
1394 1450 }
1395 1451
1396 1452 if (SMB_DENY_WRITE(share_access)) {
1397 1453 deny |= F_WRDNY;
1398 1454 }
1399 1455
1400 1456 if (cmd == F_SHARE_NBMAND) {
1401 1457 if (desired_access & ACE_DELETE)
1402 1458 new_access |= F_RMACC;
1403 1459
1404 1460 if (SMB_DENY_DELETE(share_access)) {
1405 1461 deny |= F_RMDNY;
1406 1462 }
1407 1463 }
1408 1464 }
1409 1465
1410 1466 shr.s_access = new_access;
1411 1467 shr.s_deny = deny;
1412 1468 shr.s_sysid = smb_ct.cc_sysid;
1413 1469 shr.s_pid = uniq_fid;
1414 1470 shr.s_own_len = sizeof (shr_own);
1415 1471 shr.s_owner = (caddr_t)&shr_own;
1416 1472 shr_own.sl_id = shr.s_sysid;
1417 1473 shr_own.sl_pid = shr.s_pid;
1418 1474
1419 1475 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL));
1420 1476 }
1421 1477
1422 1478 int
1423 1479 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr)
1424 1480 {
1425 1481 struct shrlock shr;
1426 1482 struct shr_locowner shr_own;
1427 1483
1428 1484 /*
1429 1485 * share locking is not supported for non-regular
1430 1486 * objects in NBMAND mode.
1431 1487 */
1432 1488 if (nbl_need_check(vp) && (vp->v_type != VREG))
1433 1489 return (0);
1434 1490
1435 1491 /*
1436 1492 * For s_access and s_deny, we do not need to pass in the original
1437 1493 * values.
1438 1494 */
1439 1495 shr.s_access = 0;
1440 1496 shr.s_deny = 0;
|
↓ open down ↓ |
209 lines elided |
↑ open up ↑ |
1441 1497 shr.s_sysid = smb_ct.cc_sysid;
1442 1498 shr.s_pid = uniq_fid;
1443 1499 shr.s_own_len = sizeof (shr_own);
1444 1500 shr.s_owner = (caddr_t)&shr_own;
1445 1501 shr_own.sl_id = shr.s_sysid;
1446 1502 shr_own.sl_pid = shr.s_pid;
1447 1503
1448 1504 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL));
1449 1505 }
1450 1506
1507 +/*
1508 + * Note about mandatory vs advisory locks:
1509 + *
1510 + * The SMB server really should always request mandatory locks, and
1511 + * if the file system does not support them, the SMB server should
1512 + * just tell the client it could not get the lock. If we were to
1513 + * tell the SMB client "you got the lock" when what they really
1514 + * got was only an advisory lock, we would be lying to the client
1515 + * about their having exclusive access to the locked range, which
1516 + * could easily lead to data corruption. If someone really wants
1517 + * the (dangerous) behavior they can set: smb_allow_advisory_locks
1518 + */
1451 1519 int
1452 1520 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf)
1453 1521 {
1454 - int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
1455 1522 flk_callback_t flk_cb;
1523 + int cmd = F_SETLK_NBMAND;
1456 1524
1525 + if (smb_allow_advisory_locks != 0 && !nbl_need_check(vp)) {
1526 + /*
1527 + * The file system does not support nbmand, and
1528 + * smb_allow_advisory_locks is enabled. (danger!)
1529 + */
1530 + cmd = F_SETLK;
1531 + }
1532 +
1457 1533 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL);
1458 1534
1459 1535 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct));
1460 1536 }
1461 1537
1462 1538 static callb_cpr_t *
1463 1539 /* ARGSUSED */
1464 1540 smb_lock_frlock_callback(flk_cb_when_t when, void *error)
1465 1541 {
1466 1542 return (0);
1467 1543 }
1468 1544
1469 1545 /*
1470 1546 * smb_vop_catia_init_v4_lookup
1471 1547 * Initialize mapping between wide characters in the range from
1472 1548 * 0x00A4 to 0x00FF and their UNIX (v4) equivalent (wide character).
1473 1549 * Indexed by the decimal value of the wide character (164-255)
1474 1550 * with an offset of -164.
1475 1551 */
1476 1552 static void
1477 1553 smb_vop_catia_init_v4_lookup()
1478 1554 {
1479 1555 int i, idx, offset = SMB_CATIA_V4_LOOKUP_LOW;
1480 1556
1481 1557 for (i = 0; i < SMB_CATIA_V4_LOOKUP_MAX; i++)
1482 1558 smb_catia_v4_lookup[i] = (smb_wchar_t)(i + offset);
1483 1559
1484 1560 for (i = 0; i < SMB_CATIA_NUM_MAPS; i++) {
1485 1561 idx = (int)catia_maps[i].winchar - offset;
1486 1562 smb_catia_v4_lookup[idx] = (smb_wchar_t)catia_maps[i].unixchar;
1487 1563 }
1488 1564 }
1489 1565
1490 1566 /*
1491 1567 * smb_vop_catia_init_v5_lookup
1492 1568 * Initialize mapping between UNIX ASCII (v4) characters and equivalent
1493 1569 * or translated wide characters.
1494 1570 * Indexed by the decimal value of the ASCII character (0-127).
1495 1571 */
1496 1572 static void
1497 1573 smb_vop_catia_init_v5_lookup()
1498 1574 {
1499 1575 int i, idx;
1500 1576
1501 1577 for (i = 0; i < SMB_CATIA_V5_LOOKUP_MAX; i++)
1502 1578 smb_catia_v5_lookup[i] = (smb_wchar_t)i;
1503 1579
1504 1580 for (i = 0; i < SMB_CATIA_NUM_MAPS; i++) {
1505 1581 idx = (int)catia_maps[i].unixchar;
1506 1582 smb_catia_v5_lookup[idx] = catia_maps[i].winchar;
1507 1583 }
1508 1584 }
1509 1585
1510 1586 static void
1511 1587 smb_vop_catia_init()
1512 1588 {
1513 1589 smb_vop_catia_init_v4_lookup();
1514 1590 smb_vop_catia_init_v5_lookup();
1515 1591 }
1516 1592
1517 1593 /*
1518 1594 * smb_vop_catia_v5tov4
1519 1595 * (windows (v5) to unix (v4))
1520 1596 *
1521 1597 * Traverse each character in the given source filename and convert the
1522 1598 * multibyte that is equivalent to any special Windows character listed
1523 1599 * in the catia_maps table to the Unix ASCII character if any is
|
↓ open down ↓ |
57 lines elided |
↑ open up ↑ |
1524 1600 * encountered in the filename. The translated name is returned in buf.
1525 1601 *
1526 1602 * If an error occurs the conversion terminates and name is returned,
1527 1603 * otherwise buf is returned.
1528 1604 */
1529 1605 char *
1530 1606 smb_vop_catia_v5tov4(char *name, char *buf, int buflen)
1531 1607 {
1532 1608 int v4_idx, numbytes, inc;
1533 1609 int space_left = buflen - 1; /* one byte reserved for null */
1534 - smb_wchar_t wc;
1610 + uint32_t wc;
1535 1611 char mbstring[MTS_MB_CHAR_MAX];
1536 1612 char *p, *src = name, *dst = buf;
1537 1613
1538 1614 ASSERT(name);
1539 1615 ASSERT(buf);
1540 1616
1541 1617 if (!buf || !name)
1542 1618 return (name);
1543 1619
1544 1620 bzero(buf, buflen);
1545 1621
1546 1622 while (*src) {
1547 1623 if ((numbytes = smb_mbtowc(&wc, src, MTS_MB_CHAR_MAX)) < 0)
1548 1624 return (name);
1549 1625
1550 1626 if (wc < SMB_CATIA_V4_LOOKUP_LOW ||
1551 1627 wc > SMB_CATIA_V4_LOOKUP_UPPER) {
1552 1628 inc = numbytes;
1553 1629 p = src;
1554 1630 } else {
1555 1631 /* Lookup required. */
1556 1632 v4_idx = (int)wc - SMB_CATIA_V4_LOOKUP_LOW;
1557 1633 inc = smb_wctomb(mbstring, smb_catia_v4_lookup[v4_idx]);
1558 1634 p = mbstring;
1559 1635 }
1560 1636
1561 1637 if (space_left < inc)
1562 1638 return (name);
1563 1639
1564 1640 (void) strncpy(dst, p, inc);
1565 1641 dst += inc;
1566 1642 space_left -= inc;
1567 1643 src += numbytes;
1568 1644 }
1569 1645
1570 1646 return (buf);
1571 1647 }
1572 1648
1573 1649 /*
1574 1650 * smb_vop_catia_v4tov5
1575 1651 * (unix (v4) to windows (v5))
1576 1652 *
1577 1653 * Traverse each character in the given filename 'srcbuf' and convert
1578 1654 * the special Unix character that is listed in the catia_maps table to
1579 1655 * the UTF-8 encoding of the corresponding Windows character if any is
1580 1656 * encountered in the filename.
|
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
1581 1657 *
1582 1658 * The translated name is returned in buf.
1583 1659 * If an error occurs the conversion terminates and the original name
1584 1660 * is returned in buf.
1585 1661 */
1586 1662 void
1587 1663 smb_vop_catia_v4tov5(char *name, char *buf, int buflen)
1588 1664 {
1589 1665 int v5_idx, numbytes;
1590 1666 int space_left = buflen - 1; /* one byte reserved for null */
1591 - smb_wchar_t wc;
1667 + uint32_t wc;
1592 1668 char mbstring[MTS_MB_CHAR_MAX];
1593 1669 char *src = name, *dst = buf;
1594 1670
1595 1671 ASSERT(name);
1596 1672 ASSERT(buf);
1597 1673
1598 1674 if (!buf || !name)
1599 1675 return;
1600 1676
1601 1677 (void) bzero(buf, buflen);
1602 1678 while (*src) {
1603 1679 if (smb_isascii(*src)) {
1604 1680 /* Lookup required */
1605 1681 v5_idx = (int)*src++;
1606 1682 numbytes = smb_wctomb(mbstring,
1607 1683 smb_catia_v5_lookup[v5_idx]);
1608 1684 if (space_left < numbytes)
1609 1685 break;
1610 1686 (void) strncpy(dst, mbstring, numbytes);
1611 1687 } else {
1612 1688 if ((numbytes = smb_mbtowc(&wc, src,
1613 1689 MTS_MB_CHAR_MAX)) < 0)
1614 1690 break;
1615 1691 if (space_left < numbytes)
1616 1692 break;
1617 1693 (void) strncpy(dst, src, numbytes);
1618 1694 src += numbytes;
1619 1695 }
1620 1696
1621 1697 dst += numbytes;
1622 1698 space_left -= numbytes;
1623 1699 }
1624 1700
1625 1701 if (*src)
1626 1702 (void) strlcpy(buf, name, buflen);
1627 1703 }
|
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX