1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <smbsrv/smb_kproto.h> 27 28 /* 29 * smb_com_search 30 * smb_com_find, smb_com_find_close 31 * smb_find_unique 32 * 33 * These commands are used for directory searching. They share the same 34 * message formats, defined below: 35 * 36 * Client Request Description 37 * ---------------------------------- --------------------------------- 38 * 39 * UCHAR WordCount; Count of parameter words = 2 40 * USHORT MaxCount; Number of dir. entries to return 41 * USHORT SearchAttributes; 42 * USHORT ByteCount; Count of data bytes; min = 5 43 * UCHAR BufferFormat1; 0x04 -- ASCII 44 * UCHAR FileName[]; File name, may be null 45 * UCHAR BufferFormat2; 0x05 -- Variable block 46 * USHORT ResumeKeyLength; Length of resume key, may be 0 47 * UCHAR ResumeKey[]; Resume key 48 * 49 * FileName specifies the file to be sought. SearchAttributes indicates 50 * the attributes that the file must have. If SearchAttributes is 51 * zero then only normal files are returned. If the system file, hidden or 52 * directory attributes are specified then the search is inclusive - both the 53 * specified type(s) of files and normal files are returned. If the volume 54 * label attribute is specified then the search is exclusive, and only the 55 * volume label entry is returned. 56 * 57 * MaxCount specifies the number of directory entries to be returned. 58 * 59 * Server Response Description 60 * ---------------------------------- --------------------------------- 61 * 62 * UCHAR WordCount; Count of parameter words = 1 63 * USHORT Count; Number of entries returned 64 * USHORT ByteCount; Count of data bytes; min = 3 65 * UCHAR BufferFormat; 0x05 -- Variable block 66 * USHORT DataLength; Length of data 67 * UCHAR DirectoryInformationData[]; Data 68 * 69 * The response will contain one or more directory entries as determined by 70 * the Count field. No more than MaxCount entries will be returned. Only 71 * entries that match the sought FileName and SearchAttributes combination 72 * will be returned. 73 * 74 * ResumeKey must be null (length = 0) on the initial search request. 75 * Subsequent search requests intended to continue a search must contain 76 * the ResumeKey field extracted from the last directory entry of the 77 * previous response. ResumeKey is self-contained, for calls containing 78 * a non-zero ResumeKey neither the SearchAttributes or FileName fields 79 * will be valid in the request. ResumeKey has the following format: 80 * 81 * Resume Key Field Description 82 * ---------------------------------- --------------------------------- 83 * 84 * UCHAR Reserved; bit 7 - consumer use 85 * bits 5,6 - system use (must preserve) 86 * bits 0-4 - server use (must preserve) 87 * UCHAR FileName[11]; Name of the returned file 88 * UCHAR ReservedForServer[5]; Client must not modify 89 * byte 0 - uniquely identifies find 90 * through find_close 91 * bytes 1-4 - available for server use 92 * (must be non-zero) 93 * UCHAR ReservedForConsumer[4]; Server must not modify 94 * 95 * FileName is 8.3 format, with the three character extension left 96 * justified into FileName[9-11]. 97 * 98 * There may be multiple matching entries in response to a single request 99 * as wildcards are supported in the last component of FileName of the 100 * initial request. 101 * 102 * Returned directory entries in the DirectoryInformationData field of the 103 * response each have the following format: 104 * 105 * Directory Information Field Description 106 * ---------------------------------- --------------------------------- 107 * 108 * SMB_RESUME_KEY ResumeKey; Described above 109 * UCHAR FileAttributes; Attributes of the found file 110 * SMB_TIME LastWriteTime; Time file was last written 111 * SMB_DATE LastWriteDate; Date file was last written 112 * ULONG FileSize; Size of the file 113 * UCHAR FileName[13]; ASCII, space-filled null terminated 114 * 115 * FileName must conform to 8.3 rules, and is padded after the extension 116 * with 0x20 characters if necessary. 117 * 118 * As can be seen from the above structure, these commands cannot return 119 * long filenames, and cannot return UNICODE filenames. 120 * 121 * Files which have a size greater than 2^32 bytes should have the least 122 * significant 32 bits of their size returned in FileSize. 123 * 124 * smb_com_search 125 * -------------- 126 * 127 * If the client is prior to the LANMAN1.0 dialect, the returned FileName 128 * should be uppercased. 129 * If the client has negotiated a dialect prior to the LANMAN1.0 dialect, 130 * or if bit0 of the Flags2 SMB header field of the request is clear, 131 * the returned FileName should be uppercased. 132 * 133 * SMB_COM_SEARCH terminates when either the requested maximum number of 134 * entries that match the named file are found, or the end of directory is 135 * reached without the maximum number of matches being found. A response 136 * containing no entries indicates that no matching entries were found 137 * between the starting point of the search and the end of directory. 138 * 139 * 140 * The find, find_close and find_unique protocols may be used in place of 141 * the core "search" protocol when LANMAN 1.0 dialect has been negotiated. 142 * 143 * smb_com_find 144 * ------------ 145 * 146 * The find protocol is used to match the find OS/2 system call. 147 * 148 * The format of the find protocol is the same as the core "search" protocol. 149 * The difference is that the directory is logically Opened with a find protocol 150 * and logically closed with the find close protocol. 151 * As is true of a failing open, if a find request (find "first" request where 152 * resume_key is null) fails (no entries are found), no find close protocol is 153 * expected. 154 * 155 * If no global characters are present, a "find unique" protocol should be used 156 * (only one entry is expected and find close need not be sent). 157 * 158 * A find request will terminate when either the requested maximum number of 159 * entries that match the named file are found, or the end of directory is 160 * reached without the maximum number of matches being found. A response 161 * containing no entries indicates that no matching entries were found between 162 * the starting point of the search and the end of directory. 163 * 164 * If a find requests more data than can be placed in a message of the 165 * max-xmit-size for the TID specified, the server will return only the number 166 * of entries which will fit. 167 * 168 * 169 * smb_com_find_close 170 * ------------------ 171 * 172 * The find close protocol is used to match the find close OS/2 system call. 173 * 174 * Whereas the first find protocol logically opens the directory, subsequent 175 * find protocols presenting a resume_key further "read" the directory, the 176 * find close protocol "closes" the directory allowing the server to free any 177 * resources held in support of the directory search. 178 * 179 * In our implementation this translates to closing the odir. 180 * 181 * 182 * smb_com_find_unique 183 * ------------------- 184 * 185 * The format of the find unique protocol is the same as the core "search" 186 * protocol. The difference is that the directory is logically opened, any 187 * matching entries returned, and then the directory is logically closed. 188 * 189 * The resume search key key will be returned as in the find protocol and 190 * search protocol however it may NOT be returned to continue the search. 191 * Only one buffer of entries is expected and find close need not be sent. 192 * 193 * If a find unique requests more data than can be placed in a message of the 194 * max-xmit-size for the TID specified, the server will abort the virtual 195 * circuit to the consumer. 196 */ 197 198 #define SMB_NAME83_BUFLEN 12 199 static void smb_name83(const char *, char *, size_t); 200 201 /* *** smb_com_search *** */ 202 203 smb_sdrc_t 204 smb_pre_search(smb_request_t *sr) 205 { 206 DTRACE_SMB_1(op__Search__start, smb_request_t *, sr); 207 return (SDRC_SUCCESS); 208 } 209 210 void 211 smb_post_search(smb_request_t *sr) 212 { 213 DTRACE_SMB_1(op__Search__done, smb_request_t *, sr); 214 } 215 216 smb_sdrc_t 217 smb_com_search(smb_request_t *sr) 218 { 219 int rc; 220 uint16_t count, maxcount, index; 221 uint16_t sattr, odid; 222 uint16_t key_len; 223 uint32_t client_key; 224 char name[SMB_SHORTNAMELEN]; 225 char name83[SMB_SHORTNAMELEN]; 226 smb_pathname_t *pn; 227 unsigned char resume_char; 228 unsigned char type; 229 boolean_t find_first, to_upper; 230 smb_tree_t *tree; 231 smb_odir_t *od; 232 smb_fileinfo_t fileinfo; 233 smb_odir_resume_t odir_resume; 234 uint32_t status; 235 uint16_t eos; 236 237 to_upper = B_FALSE; 238 if ((sr->session->dialect <= LANMAN1_0) || 239 ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) { 240 to_upper = B_TRUE; 241 } 242 243 /* We only handle 8.3 name here */ 244 sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES; 245 sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE; 246 247 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 248 return (SDRC_ERROR); 249 250 pn = &sr->arg.dirop.fqi.fq_path; 251 rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len); 252 if ((rc != 0) || (type != 0x05)) 253 return (SDRC_ERROR); 254 255 smb_pathname_init(sr, pn, pn->pn_path); 256 if (!smb_pathname_validate(sr, pn) || 257 smb_is_stream_name(pn->pn_path)) { 258 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 259 ERRDOS, ERROR_NO_MORE_FILES); 260 return (SDRC_ERROR); 261 } 262 263 tree = sr->tid_tree; 264 265 /* Volume information only */ 266 if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) { 267 (void) memset(name, ' ', sizeof (name)); 268 (void) strncpy(name, tree->t_volume, sizeof (name)); 269 270 if (key_len >= 21) { 271 (void) smb_mbc_decodef(&sr->smb_data, "17.l", 272 &client_key); 273 } else { 274 client_key = 0; 275 } 276 277 (void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c", 278 1, 0, VAR_BCC, 5, 0, 0, pn->pn_path+1, 279 client_key, sattr, name); 280 281 rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; 282 (void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 283 1, 1, rc+3, 5, rc); 284 285 return (SDRC_SUCCESS); 286 } 287 288 if ((key_len != 0) && (key_len != 21)) 289 return (SDRC_ERROR); 290 291 find_first = (key_len == 0); 292 resume_char = 0; 293 client_key = 0; 294 295 if (find_first) { 296 status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od); 297 if (status != 0) { 298 if (status == NT_STATUS_ACCESS_DENIED) 299 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 300 ERRDOS, ERROR_NO_MORE_FILES); 301 return (SDRC_ERROR); 302 } 303 } else { 304 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 305 &resume_char, &index, &odid, &client_key) != 0) { 306 return (SDRC_ERROR); 307 } 308 od = smb_tree_lookup_odir(sr, odid); 309 } 310 311 if (od == NULL) { 312 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 313 ERRDOS, ERROR_INVALID_HANDLE); 314 return (SDRC_ERROR); 315 } 316 317 if (!find_first) { 318 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) { 319 od->d_eof = B_TRUE; 320 } else { 321 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 322 odir_resume.or_idx = index; 323 smb_odir_resume_at(od, &odir_resume); 324 } 325 } 326 327 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 328 329 rc = 0; 330 index = 0; 331 count = 0; 332 if (maxcount > SMB_MAX_SEARCH) 333 maxcount = SMB_MAX_SEARCH; 334 335 while (count < maxcount) { 336 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 337 if (rc != 0 || eos != 0) 338 break; 339 340 if (*fileinfo.fi_shortname == '\0') { 341 if (smb_needs_mangled(fileinfo.fi_name)) 342 continue; 343 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 344 SMB_SHORTNAMELEN - 1); 345 if (to_upper) 346 (void) smb_strupr(fileinfo.fi_shortname); 347 } 348 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 349 350 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 351 resume_char, name83, index, odid, client_key, 352 fileinfo.fi_dosattr & 0xff, 353 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 354 (int32_t)fileinfo.fi_size, 355 fileinfo.fi_shortname); 356 357 smb_odir_save_cookie(od, index, fileinfo.fi_cookie); 358 359 count++; 360 index++; 361 } 362 if (eos && rc == ENOENT) 363 rc = 0; 364 365 if (rc != 0) { 366 smb_odir_close(od); 367 smb_odir_release(od); 368 return (SDRC_ERROR); 369 } 370 371 if (count == 0 && find_first) { 372 smb_odir_close(od); 373 smb_odir_release(od); 374 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 375 ERRDOS, ERROR_NO_MORE_FILES); 376 return (SDRC_ERROR); 377 } 378 379 rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; 380 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 381 1, count, rc+3, 5, rc) < 0) { 382 smb_odir_close(od); 383 smb_odir_release(od); 384 return (SDRC_ERROR); 385 } 386 387 smb_odir_release(od); 388 return (SDRC_SUCCESS); 389 } 390 391 392 /* *** smb_com_find *** */ 393 394 smb_sdrc_t 395 smb_pre_find(smb_request_t *sr) 396 { 397 DTRACE_SMB_1(op__Find__start, smb_request_t *, sr); 398 return (SDRC_SUCCESS); 399 } 400 401 void 402 smb_post_find(smb_request_t *sr) 403 { 404 DTRACE_SMB_1(op__Find__done, smb_request_t *, sr); 405 } 406 407 smb_sdrc_t 408 smb_com_find(smb_request_t *sr) 409 { 410 int rc; 411 uint16_t count, maxcount, index; 412 uint16_t sattr, odid; 413 uint16_t key_len; 414 uint32_t client_key; 415 char name83[SMB_SHORTNAMELEN]; 416 smb_odir_t *od; 417 smb_fileinfo_t fileinfo; 418 uint32_t status; 419 uint16_t eos; 420 421 smb_pathname_t *pn; 422 unsigned char resume_char; 423 unsigned char type; 424 boolean_t find_first = B_TRUE; 425 smb_odir_resume_t odir_resume; 426 427 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 428 return (SDRC_ERROR); 429 430 pn = &sr->arg.dirop.fqi.fq_path; 431 rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len); 432 if ((rc != 0) || (type != 0x05)) 433 return (SDRC_ERROR); 434 435 if ((key_len != 0) && (key_len != 21)) 436 return (SDRC_ERROR); 437 438 smb_pathname_init(sr, pn, pn->pn_path); 439 if (!smb_pathname_validate(sr, pn)) 440 return (SDRC_ERROR); 441 442 if (smb_is_stream_name(pn->pn_path)) { 443 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 444 ERRDOS, ERROR_INVALID_NAME); 445 return (SDRC_ERROR); 446 } 447 448 find_first = (key_len == 0); 449 resume_char = 0; 450 client_key = 0; 451 452 if (find_first) { 453 status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od); 454 if (status != 0) { 455 smbsr_error(sr, status, 0, 0); 456 return (SDRC_ERROR); 457 } 458 } else { 459 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 460 &resume_char, &index, &odid, &client_key) != 0) { 461 return (SDRC_ERROR); 462 } 463 od = smb_tree_lookup_odir(sr, odid); 464 } 465 466 if (od == NULL) { 467 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 468 ERRDOS, ERROR_INVALID_HANDLE); 469 return (SDRC_ERROR); 470 } 471 472 if (!find_first) { 473 if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) { 474 od->d_eof = B_TRUE; 475 } else { 476 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 477 odir_resume.or_idx = index; 478 smb_odir_resume_at(od, &odir_resume); 479 } 480 } 481 482 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 483 484 rc = 0; 485 index = 0; 486 count = 0; 487 if (maxcount > SMB_MAX_SEARCH) 488 maxcount = SMB_MAX_SEARCH; 489 490 while (count < maxcount) { 491 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 492 if (rc != 0 || eos != 0) 493 break; 494 495 if (*fileinfo.fi_shortname == '\0') { 496 if (smb_needs_mangled(fileinfo.fi_name)) 497 continue; 498 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 499 SMB_SHORTNAMELEN - 1); 500 } 501 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 502 503 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 504 resume_char, name83, index, odid, client_key, 505 fileinfo.fi_dosattr & 0xff, 506 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 507 (int32_t)fileinfo.fi_size, 508 fileinfo.fi_shortname); 509 510 smb_odir_save_cookie(od, index, fileinfo.fi_cookie); 511 512 count++; 513 index++; 514 } 515 if (eos && rc == ENOENT) 516 rc = 0; 517 518 if (rc != 0) { 519 smb_odir_close(od); 520 smb_odir_release(od); 521 return (SDRC_ERROR); 522 } 523 524 if (count == 0 && find_first) { 525 smb_odir_close(od); 526 smb_odir_release(od); 527 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 528 ERRDOS, ERROR_NO_MORE_FILES); 529 return (SDRC_ERROR); 530 } 531 532 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 533 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 534 1, count, rc+3, 5, rc) < 0) { 535 smb_odir_close(od); 536 smb_odir_release(od); 537 return (SDRC_ERROR); 538 } 539 540 smb_odir_release(od); 541 return (SDRC_SUCCESS); 542 } 543 544 545 /* *** smb_com_find_close *** */ 546 547 smb_sdrc_t 548 smb_pre_find_close(smb_request_t *sr) 549 { 550 DTRACE_SMB_1(op__FindClose__start, smb_request_t *, sr); 551 return (SDRC_SUCCESS); 552 } 553 554 void 555 smb_post_find_close(smb_request_t *sr) 556 { 557 DTRACE_SMB_1(op__FindClose__done, smb_request_t *, sr); 558 } 559 560 smb_sdrc_t 561 smb_com_find_close(smb_request_t *sr) 562 { 563 int rc; 564 uint16_t maxcount, index; 565 uint16_t sattr, odid; 566 uint16_t key_len; 567 uint32_t client_key; 568 char *path; 569 unsigned char resume_char; 570 unsigned char type; 571 smb_odir_t *od; 572 573 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 574 return (SDRC_ERROR); 575 576 rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); 577 if ((rc != 0) || (type != 0x05)) 578 return (SDRC_ERROR); 579 580 if (key_len == 0) { 581 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 582 ERRDOS, ERROR_INVALID_HANDLE); 583 return (SDRC_ERROR); 584 } else if (key_len != 21) { 585 return (SDRC_ERROR); 586 } 587 588 odid = 0; 589 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 590 &resume_char, &index, &odid, &client_key) != 0) { 591 return (SDRC_ERROR); 592 } 593 594 od = smb_tree_lookup_odir(sr, odid); 595 if (od == NULL) { 596 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 597 ERRDOS, ERROR_INVALID_HANDLE); 598 return (SDRC_ERROR); 599 } 600 601 smb_odir_close(od); 602 smb_odir_release(od); 603 604 if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0)) 605 return (SDRC_ERROR); 606 607 return (SDRC_SUCCESS); 608 } 609 610 611 /* *** smb_com_find_unique *** */ 612 613 smb_sdrc_t 614 smb_pre_find_unique(smb_request_t *sr) 615 { 616 DTRACE_SMB_1(op__FindUnique__start, smb_request_t *, sr); 617 return (SDRC_SUCCESS); 618 } 619 620 void 621 smb_post_find_unique(smb_request_t *sr) 622 { 623 DTRACE_SMB_1(op__FindUnique__done, smb_request_t *, sr); 624 } 625 626 smb_sdrc_t 627 smb_com_find_unique(struct smb_request *sr) 628 { 629 int rc; 630 uint16_t count, maxcount, index; 631 uint16_t sattr; 632 smb_pathname_t *pn; 633 unsigned char resume_char = '\0'; 634 uint32_t client_key = 0; 635 char name83[SMB_SHORTNAMELEN]; 636 smb_odir_t *od; 637 smb_fileinfo_t fileinfo; 638 uint32_t status; 639 uint16_t eos; 640 smb_vdb_t *vdb; 641 642 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 643 return (SDRC_ERROR); 644 645 pn = &sr->arg.dirop.fqi.fq_path; 646 vdb = kmem_alloc(sizeof (smb_vdb_t), KM_SLEEP); 647 if ((smbsr_decode_data(sr, "%AV", sr, &pn->pn_path, vdb) != 0) || 648 (vdb->vdb_len != 0)) { 649 kmem_free(vdb, sizeof (smb_vdb_t)); 650 return (SDRC_ERROR); 651 } 652 kmem_free(vdb, sizeof (smb_vdb_t)); 653 654 smb_pathname_init(sr, pn, pn->pn_path); 655 if (!smb_pathname_validate(sr, pn)) 656 return (SDRC_ERROR); 657 658 if (smb_is_stream_name(pn->pn_path)) { 659 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 660 ERRDOS, ERROR_INVALID_NAME); 661 return (SDRC_ERROR); 662 } 663 664 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 665 666 status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od); 667 if (status != 0) { 668 smbsr_error(sr, status, 0, 0); 669 return (SDRC_ERROR); 670 } 671 if (od == NULL) 672 return (SDRC_ERROR); 673 674 rc = 0; 675 count = 0; 676 index = 0; 677 if (maxcount > SMB_MAX_SEARCH) 678 maxcount = SMB_MAX_SEARCH; 679 680 while (count < maxcount) { 681 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 682 if (rc != 0 || eos != 0) 683 break; 684 685 if (*fileinfo.fi_shortname == '\0') { 686 if (smb_needs_mangled(fileinfo.fi_name)) 687 continue; 688 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 689 SMB_SHORTNAMELEN - 1); 690 } 691 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 692 693 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 694 resume_char, name83, index, od->d_odid, 695 client_key, fileinfo.fi_dosattr & 0xff, 696 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 697 (int32_t)fileinfo.fi_size, 698 fileinfo.fi_shortname); 699 700 count++; 701 index++; 702 } 703 if (eos && rc == ENOENT) 704 rc = 0; 705 706 smb_odir_close(od); 707 smb_odir_release(od); 708 709 if (rc != 0) 710 return (SDRC_ERROR); 711 712 if (count == 0) { 713 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 714 ERRDOS, ERROR_NO_MORE_FILES); 715 return (SDRC_ERROR); 716 } 717 718 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 719 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, 720 "bwwbw", 1, count, rc+3, 5, rc) < 0) { 721 return (SDRC_ERROR); 722 } 723 724 return (SDRC_SUCCESS); 725 } 726 727 /* 728 * smb_name83 729 * 730 * Format the filename for inclusion in the resume key. The filename 731 * returned in the resume key is 11 bytes: 732 * - up to 8 bytes of filename, space padded to 8 bytes 733 * - up to 3 bytes of ext, space padded to 3 bytes 734 * 735 * The name passed to smb_name83 should be a shortname or a name that 736 * doesn't require mangling. 737 * 738 * Examples: 739 * "fname.txt" -> "FNAME TXT" 740 * "fname.tx" -> "FNAME TX " 741 * "filename" -> "FILENAME " 742 * "filename.txt" -> "FILENAMETXT" 743 * "FILE~1.TXT" -> "FILE~1 TXT" 744 */ 745 static void 746 smb_name83(const char *name, char *buf, size_t buflen) 747 { 748 const char *p; 749 char *pbuf; 750 int i; 751 752 ASSERT(name && buf && (buflen >= SMB_NAME83_BUFLEN)); 753 754 (void) strlcpy(buf, " ", SMB_NAME83_BUFLEN); 755 756 /* Process "." and ".." up front */ 757 if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { 758 (void) strncpy(buf, name, strlen(name)); 759 return; 760 } 761 762 ASSERT(smb_needs_mangled(name) == B_FALSE); 763 764 /* Process basename */ 765 for (i = 0, p = name, pbuf = buf; 766 (i < SMB_NAME83_BASELEN) && (*p != '\0') && (*p != '.'); ++i) 767 *pbuf++ = *p++; 768 769 /* Process the extension from the last dot in name */ 770 if ((p = strchr(name, '.')) != NULL) { 771 ++p; 772 pbuf = &buf[SMB_NAME83_BASELEN]; 773 for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i) 774 *pbuf++ = *p++; 775 } 776 777 (void) smb_strupr(buf); 778 } 779