Print this page
5111 smb_common_rename uses uninitialized variable
Reviewed by: Gordon Ross <gwr@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_rename.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_rename.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 *
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 23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <sys/synch.h>
27 27 #include <smbsrv/smb_kproto.h>
28 28 #include <smbsrv/smb_fsops.h>
29 29 #include <sys/nbmlock.h>
30 30
31 31 /*
32 32 * NT_RENAME InformationLevels:
33 33 *
34 34 * SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter.
35 35 * SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file.
36 36 * SMB_NT_RENAME_RENAME_FILE In-place rename of a file.
37 37 * SMB_NT_RENAME_MOVE_FILE Move (rename) a file.
38 38 */
39 39 #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102
40 40 #define SMB_NT_RENAME_SET_LINK_INFO 0x0103
41 41 #define SMB_NT_RENAME_RENAME_FILE 0x0104
42 42 #define SMB_NT_RENAME_MOVE_FILE 0x0105
43 43
44 44 /*
45 45 * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
46 46 */
47 47 #define SMB_RENAME_FLAG_OVERWRITE 0x001
48 48
49 49 static int smb_common_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
50 50 static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
51 51 static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
52 52 static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
53 53 static void smb_rename_set_error(smb_request_t *, int);
54 54
55 55 static int smb_rename_lookup_src(smb_request_t *);
56 56 static void smb_rename_release_src(smb_request_t *);
57 57
58 58 /*
59 59 * smb_com_rename
60 60 *
61 61 * Rename a file. Files OldFileName must exist and NewFileName must not.
62 62 * Both pathnames must be relative to the Tid specified in the request.
63 63 * Open files may be renamed.
64 64 *
65 65 * Multiple files may be renamed in response to a single request as Rename
66 66 * File supports wildcards in the file name (last component of the path).
67 67 * NOTE: we don't support rename with wildcards.
68 68 *
69 69 * SearchAttributes indicates the attributes that the target file(s) must
70 70 * have. If SearchAttributes is zero then only normal files are renamed.
71 71 * If the system file or hidden attributes are specified then the rename
72 72 * is inclusive - both the specified type(s) of files and normal files are
73 73 * renamed.
74 74 */
75 75 smb_sdrc_t
76 76 smb_pre_rename(smb_request_t *sr)
77 77 {
78 78 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
79 79 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
80 80 int rc;
81 81
82 82 if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) {
83 83 rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path,
84 84 &dst_fqi->fq_path.pn_path);
85 85
86 86 dst_fqi->fq_sattr = 0;
87 87 }
88 88
89 89 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr,
90 90 struct dirop *, &sr->arg.dirop);
91 91
92 92 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
93 93 }
94 94
95 95 void
96 96 smb_post_rename(smb_request_t *sr)
97 97 {
98 98 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr);
99 99 }
100 100
101 101 smb_sdrc_t
102 102 smb_com_rename(smb_request_t *sr)
103 103 {
104 104 int rc;
105 105 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
106 106 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
107 107 smb_pathname_t *src_pn = &src_fqi->fq_path;
108 108 smb_pathname_t *dst_pn = &dst_fqi->fq_path;
109 109
110 110 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
111 111 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
112 112 ERRDOS, ERROR_ACCESS_DENIED);
113 113 return (SDRC_ERROR);
114 114 }
115 115
116 116 smb_pathname_init(sr, src_pn, src_pn->pn_path);
117 117 smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
118 118 if (!smb_pathname_validate(sr, src_pn) ||
119 119 !smb_pathname_validate(sr, dst_pn)) {
120 120 return (SDRC_ERROR);
121 121 }
122 122
123 123 rc = smb_common_rename(sr, src_fqi, dst_fqi);
124 124
125 125 if (rc != 0) {
126 126 smb_rename_set_error(sr, rc);
127 127 return (SDRC_ERROR);
128 128 }
129 129
130 130 rc = smbsr_encode_empty_result(sr);
131 131 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
132 132 }
133 133
134 134 /*
135 135 * smb_com_nt_rename
136 136 *
137 137 * Rename a file. Files OldFileName must exist and NewFileName must not.
138 138 * Both pathnames must be relative to the Tid specified in the request.
139 139 * Open files may be renamed.
140 140 *
141 141 * SearchAttributes indicates the attributes that the target file(s) must
142 142 * have. If SearchAttributes is zero then only normal files are renamed.
143 143 * If the system file or hidden attributes are specified then the rename
144 144 * is inclusive - both the specified type(s) of files and normal files are
145 145 * renamed.
146 146 */
147 147 smb_sdrc_t
148 148 smb_pre_nt_rename(smb_request_t *sr)
149 149 {
150 150 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
151 151 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
152 152 uint32_t clusters;
153 153 int rc;
154 154
155 155 rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr,
156 156 &sr->arg.dirop.info_level, &clusters);
157 157 if (rc == 0) {
158 158 rc = smbsr_decode_data(sr, "%SS", sr,
159 159 &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path);
160 160
161 161 dst_fqi->fq_sattr = 0;
162 162 }
163 163
164 164 DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr,
165 165 struct dirop *, &sr->arg.dirop);
166 166
167 167 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
168 168 }
169 169
170 170 void
171 171 smb_post_nt_rename(smb_request_t *sr)
172 172 {
173 173 DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr);
174 174 }
175 175
176 176 smb_sdrc_t
177 177 smb_com_nt_rename(smb_request_t *sr)
178 178 {
179 179 int rc;
180 180 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
181 181 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
182 182 smb_pathname_t *src_pn = &src_fqi->fq_path;
183 183 smb_pathname_t *dst_pn = &dst_fqi->fq_path;
184 184
185 185 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
186 186 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
187 187 ERRDOS, ERROR_ACCESS_DENIED);
188 188 return (SDRC_ERROR);
189 189 }
190 190
191 191 smb_pathname_init(sr, src_pn, src_pn->pn_path);
192 192 smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
193 193 if (!smb_pathname_validate(sr, src_pn) ||
194 194 !smb_pathname_validate(sr, dst_pn)) {
195 195 return (SDRC_ERROR);
196 196 }
197 197
198 198 if (smb_contains_wildcards(src_pn->pn_path)) {
199 199 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
200 200 ERRDOS, ERROR_BAD_PATHNAME);
201 201 return (SDRC_ERROR);
202 202 }
203 203
204 204 switch (sr->arg.dirop.info_level) {
205 205 case SMB_NT_RENAME_SET_LINK_INFO:
206 206 rc = smb_make_link(sr, src_fqi, dst_fqi);
207 207 break;
208 208 case SMB_NT_RENAME_RENAME_FILE:
209 209 case SMB_NT_RENAME_MOVE_FILE:
210 210 rc = smb_common_rename(sr, src_fqi, dst_fqi);
211 211 break;
212 212 case SMB_NT_RENAME_MOVE_CLUSTER_INFO:
213 213 rc = EINVAL;
214 214 break;
215 215 default:
216 216 rc = EACCES;
217 217 break;
218 218 }
219 219
220 220 if (rc != 0) {
221 221 smb_rename_set_error(sr, rc);
222 222 return (SDRC_ERROR);
223 223 }
224 224
225 225 rc = smbsr_encode_empty_result(sr);
226 226 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
227 227 }
228 228
229 229 /*
230 230 * smb_nt_transact_rename
231 231 *
232 232 * Windows servers return SUCCESS without renaming file.
233 233 * The only check required is to check that the handle (fid) is valid.
234 234 */
235 235 smb_sdrc_t
236 236 smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa)
237 237 {
238 238 if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0)
239 239 return (SDRC_ERROR);
240 240
241 241 smbsr_lookup_file(sr);
242 242 if (sr->fid_ofile == NULL) {
243 243 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
244 244 return (SDRC_ERROR);
245 245 }
246 246 smbsr_release_file(sr);
247 247
248 248 return (SDRC_SUCCESS);
249 249 }
250 250
251 251 /*
252 252 * smb_trans2_rename
253 253 *
254 254 * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
255 255 * and Trans2_Set_PathInfo.
256 256 * If the new filename (dst_fqi) already exists it may be overwritten
257 257 * if flags == 1.
258 258 */
259 259 int
260 260 smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags)
261 261 {
262 262 int rc = 0;
263 263 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
264 264 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
265 265 smb_pathname_t *dst_pn = &dst_fqi->fq_path;
266 266 char *path;
267 267 int len;
268 268
269 269 sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0;
270 270 sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE;
271 271
272 272 src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES;
273 273 src_fqi->fq_fnode = node;
274 274 src_fqi->fq_dnode = node->n_dnode;
275 275
276 276 /* costruct and validate the dst pathname */
277 277 path = smb_srm_zalloc(sr, MAXPATHLEN);
278 278 if (src_fqi->fq_path.pn_pname) {
279 279 (void) snprintf(path, MAXPATHLEN, "%s\\%s",
280 280 src_fqi->fq_path.pn_pname, fname);
281 281 } else {
282 282 rc = smb_node_getshrpath(node->n_dnode, sr->tid_tree,
283 283 path, MAXPATHLEN);
284 284 if (rc != 0) {
285 285 smb_rename_set_error(sr, rc);
286 286 return (-1);
287 287 }
288 288 len = strlen(path);
289 289 (void) snprintf(path + len, MAXPATHLEN - len, "\\%s", fname);
290 290 }
291 291
292 292 smb_pathname_init(sr, dst_pn, path);
293 293 if (!smb_pathname_validate(sr, dst_pn))
294 294 return (-1);
295 295
296 296 dst_fqi->fq_dnode = node->n_dnode;
297 297 (void) strlcpy(dst_fqi->fq_last_comp, dst_pn->pn_fname, MAXNAMELEN);
298 298
299 299 rc = smb_common_rename(sr, src_fqi, dst_fqi);
300 300 if (rc != 0) {
301 301 smb_rename_set_error(sr, rc);
302 302 return (-1);
303 303 }
304 304
305 305 return (0);
306 306 }
307 307
308 308 /*
309 309 * smb_common_rename
310 310 *
311 311 * Common code for renaming a file.
312 312 *
313 313 * If the source and destination are identical, we go through all
314 314 * the checks but we don't actually do the rename. If the source
315 315 * and destination files differ only in case, we do a case-sensitive
316 316 * rename. Otherwise, we do a full case-insensitive rename.
317 317 *
318 318 * Returns errno values.
319 319 */
320 320 static int
321 321 smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
322 322 {
323 323 smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode;
324 324 smb_node_t *tnode;
325 325 int rc, count;
326 326 DWORD status;
327 327 char *new_name, *path;
328 328
329 329 path = dst_fqi->fq_path.pn_path;
330 330
331 331 /* Check if attempting to rename a stream - not yet supported */
332 332 rc = smb_rename_check_stream(src_fqi, dst_fqi);
333 333 if (rc != 0)
334 334 return (rc);
335 335
336 336 /* The source node may already have been provided */
337 337 if (src_fqi->fq_fnode) {
338 338 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
339 339 smb_node_ref(src_fqi->fq_fnode);
|
↓ open down ↓ |
339 lines elided |
↑ open up ↑ |
340 340 smb_node_ref(src_fqi->fq_dnode);
341 341 } else {
342 342 /* lookup and validate src node */
343 343 rc = smb_rename_lookup_src(sr);
344 344 if (rc != 0)
345 345 return (rc);
346 346 }
347 347
348 348 src_fnode = src_fqi->fq_fnode;
349 349 src_dnode = src_fqi->fq_dnode;
350 + tnode = sr->tid_tree->t_snode;
350 351
351 352 /* Find destination dnode and last_comp */
352 353 if (dst_fqi->fq_dnode) {
353 354 smb_node_ref(dst_fqi->fq_dnode);
354 355 } else {
355 - tnode = sr->tid_tree->t_snode;
356 356 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
357 357 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
358 358 if (rc != 0) {
359 359 smb_rename_release_src(sr);
360 360 return (rc);
361 361 }
362 362 }
363 363
364 364 dst_dnode = dst_fqi->fq_dnode;
365 365 new_name = dst_fqi->fq_last_comp;
366 366
367 367 /* If exact name match in same directory, we're done */
368 368 if ((src_dnode == dst_dnode) &&
369 369 (strcmp(src_fnode->od_name, new_name) == 0)) {
370 370 smb_rename_release_src(sr);
371 371 smb_node_release(dst_dnode);
372 372 return (0);
373 373 }
374 374
375 375 /* Lookup destination node */
376 376 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
377 377 dst_dnode, new_name, &dst_fqi->fq_fnode);
378 378
379 379 /* If the destination node doesn't already exist, validate new_name. */
380 380 if (rc == ENOENT) {
381 381 if (smb_is_invalid_filename(new_name)) {
382 382 smb_rename_release_src(sr);
383 383 smb_node_release(dst_dnode);
384 384 return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
385 385 }
386 386 }
387 387
388 388 /*
389 389 * Handle case where changing case of the same directory entry.
390 390 *
391 391 * If we found the dst node in the same directory as the src node,
392 392 * and their names differ only in case:
393 393 *
394 394 * If the tree is case sensitive (or mixed):
395 395 * Do case sensitive lookup to see if exact match exists.
396 396 * If the exact match is the same node as src_node we're done.
397 397 *
398 398 * If the tree is case insensitive:
399 399 * There is currently no way to tell if the case is different
400 400 * or not, so do the rename (unless the specified new name was
401 401 * mangled).
402 402 */
403 403 if ((rc == 0) &&
404 404 (src_dnode == dst_dnode) &&
405 405 (smb_strcasecmp(src_fnode->od_name,
406 406 dst_fqi->fq_fnode->od_name, 0) == 0)) {
407 407 smb_node_release(dst_fqi->fq_fnode);
408 408 dst_fqi->fq_fnode = NULL;
409 409
410 410 if (smb_tree_has_feature(sr->tid_tree,
411 411 SMB_TREE_NO_CASESENSITIVE)) {
412 412 if (smb_strcasecmp(src_fnode->od_name,
413 413 dst_fqi->fq_last_comp, 0) != 0) {
414 414 smb_rename_release_src(sr);
415 415 smb_node_release(dst_dnode);
416 416 return (0);
417 417 }
418 418 } else {
419 419 rc = smb_fsop_lookup(sr, sr->user_cr,
420 420 SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name,
421 421 &dst_fqi->fq_fnode);
422 422
423 423 if ((rc == 0) &&
424 424 (dst_fqi->fq_fnode == src_fnode)) {
425 425 smb_rename_release_src(sr);
426 426 smb_node_release(dst_fqi->fq_fnode);
427 427 smb_node_release(dst_dnode);
428 428 return (0);
429 429 }
430 430 }
431 431 }
432 432
433 433 if ((rc != 0) && (rc != ENOENT)) {
434 434 smb_rename_release_src(sr);
435 435 smb_node_release(dst_fqi->fq_dnode);
436 436 return (rc);
437 437 }
438 438
439 439 if (dst_fqi->fq_fnode) {
440 440 dst_fnode = dst_fqi->fq_fnode;
441 441
442 442 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
443 443 smb_rename_release_src(sr);
444 444 smb_node_release(dst_fnode);
445 445 smb_node_release(dst_dnode);
446 446 return (EEXIST);
447 447 }
448 448
449 449 (void) smb_oplock_break(sr, dst_fnode,
450 450 SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH);
451 451
452 452 for (count = 0; count <= 3; count++) {
453 453 if (count) {
454 454 smb_node_end_crit(dst_fnode);
455 455 delay(MSEC_TO_TICK(400));
456 456 }
457 457
458 458 smb_node_start_crit(dst_fnode, RW_READER);
459 459 status = smb_node_delete_check(dst_fnode);
460 460
461 461 if (status != NT_STATUS_SHARING_VIOLATION)
462 462 break;
463 463 }
464 464
465 465 if (status != NT_STATUS_SHARING_VIOLATION)
466 466 status = smb_range_check(sr, dst_fnode,
467 467 0, UINT64_MAX, B_TRUE);
468 468
469 469 if (status != NT_STATUS_SUCCESS) {
470 470 smb_rename_release_src(sr);
471 471 smb_node_end_crit(dst_fnode);
472 472 smb_node_release(dst_fnode);
473 473 smb_node_release(dst_dnode);
474 474 return (EACCES);
475 475 }
476 476
477 477 new_name = dst_fnode->od_name;
478 478 }
479 479
480 480 rc = smb_fsop_rename(sr, sr->user_cr,
481 481 src_dnode, src_fnode->od_name,
482 482 dst_dnode, new_name);
483 483
484 484 if (rc == 0) {
485 485 /*
486 486 * Note that renames in the same directory are normally
487 487 * delivered in {old,new} pairs, and clients expect them
488 488 * in that order, if both events are delivered.
489 489 */
490 490 int a_src, a_dst; /* action codes */
491 491 if (src_dnode == dst_dnode) {
492 492 a_src = FILE_ACTION_RENAMED_OLD_NAME;
493 493 a_dst = FILE_ACTION_RENAMED_NEW_NAME;
494 494 } else {
495 495 a_src = FILE_ACTION_REMOVED;
496 496 a_dst = FILE_ACTION_ADDED;
497 497 }
498 498 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
499 499 smb_node_notify_change(dst_dnode, a_dst, new_name);
500 500 }
501 501
502 502 smb_rename_release_src(sr);
503 503
504 504 if (dst_fqi->fq_fnode) {
505 505 smb_node_end_crit(dst_fnode);
506 506 smb_node_release(dst_fnode);
507 507 }
508 508 smb_node_release(dst_dnode);
509 509
510 510 return (rc);
511 511 }
512 512
513 513 /*
514 514 * smb_rename_check_stream
515 515 *
516 516 * For a stream rename the dst path must begin with ':', or "\\:".
517 517 * We don't yet support stream rename, Return EACCES.
518 518 *
519 519 * If not a stream rename, in accordance with the above rule,
520 520 * it is not valid for either the src or dst to be a stream.
521 521 * Return EINVAL.
522 522 */
523 523 static int
524 524 smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
525 525 {
526 526 smb_node_t *src_fnode = src_fqi->fq_fnode;
527 527 char *src_path = src_fqi->fq_path.pn_path;
528 528 char *dst_path = dst_fqi->fq_path.pn_path;
529 529
530 530 /* We do not yet support named stream rename - ACCESS DENIED */
531 531 if ((dst_path[0] == ':') ||
532 532 ((dst_path[0] == '\\') && (dst_path[1] == ':'))) {
533 533 return (EACCES);
534 534 }
535 535
536 536 /*
537 537 * If not stream rename (above) neither src or dst can be
538 538 * a named stream.
539 539 */
540 540
541 541 if (smb_is_stream_name(dst_path))
542 542 return (EINVAL);
543 543
544 544 if (src_fqi->fq_fnode) {
545 545 if (SMB_IS_STREAM(src_fnode))
546 546 return (EINVAL);
547 547 } else {
548 548 if (smb_is_stream_name(src_path))
549 549 return (EINVAL);
550 550 }
551 551
552 552 return (0);
553 553 }
554 554
555 555
556 556 /*
557 557 * smb_make_link
558 558 *
559 559 * Creating a hard link (adding an additional name) for a file.
560 560 *
561 561 * If the source and destination are identical, we go through all
562 562 * the checks but we don't create a link.
563 563 *
564 564 * If the file is a symlink we create the hardlink on the target
565 565 * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
566 566 * If the target of the symlink does not exist we fail with ENOENT.
567 567 *
568 568 * Returns errno values.
569 569 */
570 570 static int
571 571 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
572 572 {
573 573 smb_node_t *tnode;
574 574 char *path;
575 575 int rc;
576 576
577 577 /* Cannnot create link on named stream */
578 578 if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
579 579 smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
580 580 return (EINVAL);
581 581 }
582 582
583 583 /* lookup and validate src node */
584 584 rc = smb_rename_lookup_src(sr);
585 585 if (rc != 0)
586 586 return (rc);
587 587
588 588 /* if src and dest paths match we're done */
589 589 if (smb_strcasecmp(src_fqi->fq_path.pn_path,
590 590 dst_fqi->fq_path.pn_path, 0) == 0) {
591 591 smb_rename_release_src(sr);
592 592 return (0);
593 593 }
594 594
595 595 /* find the destination dnode and last_comp */
596 596 tnode = sr->tid_tree->t_snode;
597 597 path = dst_fqi->fq_path.pn_path;
598 598 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
599 599 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
600 600 if (rc != 0) {
601 601 smb_rename_release_src(sr);
602 602 return (rc);
603 603 }
604 604
605 605 /* If name match in same directory, we're done */
606 606 if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
607 607 (smb_strcasecmp(src_fqi->fq_fnode->od_name,
608 608 dst_fqi->fq_last_comp, 0) == 0)) {
609 609 smb_rename_release_src(sr);
610 610 smb_node_release(dst_fqi->fq_dnode);
611 611 return (0);
612 612 }
613 613
614 614 if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) {
615 615 smb_rename_release_src(sr);
616 616 smb_node_release(dst_fqi->fq_dnode);
617 617 return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */
618 618 }
619 619
620 620 /* Lookup the destination node. It MUST NOT exist. */
621 621 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
622 622 dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
623 623 if (rc == 0) {
624 624 smb_node_release(dst_fqi->fq_fnode);
625 625 rc = EEXIST;
626 626 }
627 627 if (rc != ENOENT) {
628 628 smb_rename_release_src(sr);
629 629 smb_node_release(dst_fqi->fq_dnode);
630 630 return (rc);
631 631 }
632 632
633 633 rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
634 634 dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
635 635
636 636 if (rc == 0) {
637 637 smb_node_notify_change(dst_fqi->fq_dnode,
638 638 FILE_ACTION_ADDED, dst_fqi->fq_last_comp);
639 639 }
640 640
641 641 smb_rename_release_src(sr);
642 642 smb_node_release(dst_fqi->fq_dnode);
643 643 return (rc);
644 644 }
645 645
646 646 /*
647 647 * smb_rename_lookup_src
648 648 *
649 649 * Lookup the src node, checking for sharing violations and
650 650 * breaking any existing BATCH oplock.
651 651 * Populate sr->arg.dirop.fqi
652 652 *
653 653 * Upon success, the dnode and fnode will have holds and the
654 654 * fnode will be in a critical section. These should be
655 655 * released using smb_rename_release_src().
656 656 *
657 657 * Returns errno values.
658 658 */
659 659 static int
660 660 smb_rename_lookup_src(smb_request_t *sr)
661 661 {
662 662 smb_node_t *src_node, *tnode;
663 663 DWORD status;
664 664 int rc;
665 665 int count;
666 666 char *path;
667 667
668 668 struct dirop *dirop = &sr->arg.dirop;
669 669 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
670 670
671 671 if (smb_is_stream_name(src_fqi->fq_path.pn_path))
672 672 return (EINVAL);
673 673
674 674 /* Lookup the source node */
675 675 tnode = sr->tid_tree->t_snode;
676 676 path = src_fqi->fq_path.pn_path;
677 677 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
678 678 &src_fqi->fq_dnode, src_fqi->fq_last_comp);
679 679 if (rc != 0)
680 680 return (rc);
681 681
682 682 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
683 683 src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
684 684 if (rc != 0) {
685 685 smb_node_release(src_fqi->fq_dnode);
686 686 return (rc);
687 687 }
688 688
689 689 /* Not valid to create hardlink for directory */
690 690 if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) &&
691 691 (smb_node_is_dir(src_fqi->fq_fnode))) {
692 692 smb_node_release(src_fqi->fq_fnode);
693 693 smb_node_release(src_fqi->fq_dnode);
694 694 return (EISDIR);
695 695 }
696 696
697 697 src_node = src_fqi->fq_fnode;
698 698
699 699 rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
700 700 if (rc != 0) {
701 701 smb_node_release(src_fqi->fq_fnode);
702 702 smb_node_release(src_fqi->fq_dnode);
703 703 return (rc);
704 704 }
705 705
706 706 /*
707 707 * Break BATCH oplock before access checks. If a client
708 708 * has a file open, this will force a flush or close,
709 709 * which may affect the outcome of any share checking.
710 710 */
711 711 (void) smb_oplock_break(sr, src_node,
712 712 SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
713 713
714 714 for (count = 0; count <= 3; count++) {
715 715 if (count) {
716 716 smb_node_end_crit(src_node);
717 717 delay(MSEC_TO_TICK(400));
718 718 }
719 719
720 720 smb_node_start_crit(src_node, RW_READER);
721 721
722 722 status = smb_node_rename_check(src_node);
723 723 if (status != NT_STATUS_SHARING_VIOLATION)
724 724 break;
725 725 }
726 726
727 727 if (status == NT_STATUS_SHARING_VIOLATION) {
728 728 smb_node_end_crit(src_node);
729 729 smb_node_release(src_fqi->fq_fnode);
730 730 smb_node_release(src_fqi->fq_dnode);
731 731 return (EPIPE); /* = ERRbadshare */
732 732 }
733 733
734 734 status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
735 735 if (status != NT_STATUS_SUCCESS) {
736 736 smb_node_end_crit(src_node);
737 737 smb_node_release(src_fqi->fq_fnode);
738 738 smb_node_release(src_fqi->fq_dnode);
739 739 return (EACCES);
740 740 }
741 741
742 742 return (0);
743 743 }
744 744
745 745 /*
746 746 * smb_rename_release_src
747 747 */
748 748 static void
749 749 smb_rename_release_src(smb_request_t *sr)
750 750 {
751 751 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
752 752
753 753 smb_node_end_crit(src_fqi->fq_fnode);
754 754 smb_node_release(src_fqi->fq_fnode);
755 755 smb_node_release(src_fqi->fq_dnode);
756 756 }
757 757
758 758
759 759 static int
760 760 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
761 761 {
762 762 smb_attr_t attr;
763 763
764 764 if (smb_node_getattr(sr, node, &attr) != 0)
765 765 return (EIO);
766 766
767 767 if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
768 768 !(SMB_SEARCH_HIDDEN(sattr)))
769 769 return (ESRCH);
770 770
771 771 if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
772 772 !(SMB_SEARCH_SYSTEM(sattr)))
773 773 return (ESRCH);
774 774
775 775 return (0);
776 776 }
777 777
778 778 /*
779 779 * The following values are based on observed WFWG, Windows 9x, Windows NT
780 780 * and Windows 2000 behaviour.
781 781 *
782 782 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
783 783 *
784 784 * Windows 95 clients don't see the problem because the target is deleted
785 785 * before the rename request.
786 786 */
787 787 static void
788 788 smb_rename_set_error(smb_request_t *sr, int errnum)
789 789 {
790 790 static struct {
791 791 int errnum;
792 792 uint16_t errcode;
793 793 uint32_t status32;
794 794 } rc_map[] = {
795 795 { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION },
796 796 { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION },
797 797 { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND },
798 798 { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE },
799 799 { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER },
800 800 { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED },
801 801 { EISDIR, ERROR_ACCESS_DENIED, NT_STATUS_FILE_IS_A_DIRECTORY },
802 802 { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR }
803 803 };
804 804
805 805 int i;
806 806
807 807 if (errnum == 0)
808 808 return;
809 809
810 810 for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) {
811 811 if (rc_map[i].errnum == errnum) {
812 812 smbsr_error(sr, rc_map[i].status32,
813 813 ERRDOS, rc_map[i].errcode);
814 814 return;
815 815 }
816 816 }
817 817
818 818 smbsr_errno(sr, errnum);
819 819 }
|
↓ open down ↓ |
454 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX