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 2012 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 uint16_t eos; 235 236 to_upper = B_FALSE; 237 if ((sr->session->dialect <= LANMAN1_0) || 238 ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) { 239 to_upper = B_TRUE; 240 } 241 242 /* We only handle 8.3 name here */ 243 sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES; 244 sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE; 245 246 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 247 return (SDRC_ERROR); 248 249 pn = &sr->arg.dirop.fqi.fq_path; 250 rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len); 251 if ((rc != 0) || (type != 0x05)) 252 return (SDRC_ERROR); 253 254 smb_pathname_init(sr, pn, pn->pn_path); 255 if (!smb_pathname_validate(sr, pn) || 256 smb_is_stream_name(pn->pn_path)) { 257 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 258 ERRDOS, ERROR_NO_MORE_FILES); 259 return (SDRC_ERROR); 260 } 261 262 tree = sr->tid_tree; 263 264 /* Volume information only */ 265 if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) { 266 (void) memset(name, ' ', sizeof (name)); 267 (void) strncpy(name, tree->t_volume, sizeof (name)); 268 269 if (key_len >= 21) { 270 (void) smb_mbc_decodef(&sr->smb_data, "17.l", 271 &client_key); 272 } else { 273 client_key = 0; 274 } 275 276 (void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c", 277 1, 0, VAR_BCC, 5, 0, 0, pn->pn_path+1, 278 client_key, sattr, name); 279 280 rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; 281 (void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 282 1, 1, rc+3, 5, rc); 283 284 return (SDRC_SUCCESS); 285 } 286 287 if ((key_len != 0) && (key_len != 21)) 288 return (SDRC_ERROR); 289 290 find_first = (key_len == 0); 291 resume_char = 0; 292 client_key = 0; 293 294 if (find_first) { 295 odid = smb_odir_open(sr, pn->pn_path, sattr, 0); 296 if (odid == 0) { 297 if (sr->smb_error.status == NT_STATUS_ACCESS_DENIED) 298 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 299 ERRDOS, ERROR_NO_MORE_FILES); 300 return (SDRC_ERROR); 301 } 302 } else { 303 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 304 &resume_char, &index, &odid, &client_key) != 0) { 305 return (SDRC_ERROR); 306 } 307 } 308 309 od = smb_tree_lookup_odir(sr, odid); 310 if (od == NULL) { 311 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 312 ERRDOS, ERROR_INVALID_HANDLE); 313 return (SDRC_ERROR); 314 } 315 316 if (!find_first) { 317 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 318 odir_resume.or_idx = index; 319 smb_odir_resume_at(od, &odir_resume); 320 } 321 322 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 323 324 rc = 0; 325 index = 0; 326 count = 0; 327 if (maxcount > SMB_MAX_SEARCH) 328 maxcount = SMB_MAX_SEARCH; 329 330 while (count < maxcount) { 331 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 332 if (rc != 0 || eos != 0) 333 break; 334 335 if (*fileinfo.fi_shortname == '\0') { 336 if (smb_needs_mangled(fileinfo.fi_name)) 337 continue; 338 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 339 SMB_SHORTNAMELEN - 1); 340 if (to_upper) 341 (void) smb_strupr(fileinfo.fi_shortname); 342 } 343 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 344 345 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 346 resume_char, name83, index, odid, client_key, 347 fileinfo.fi_dosattr & 0xff, 348 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 349 (int32_t)fileinfo.fi_size, 350 fileinfo.fi_shortname); 351 352 smb_odir_save_cookie(od, index, fileinfo.fi_cookie); 353 354 count++; 355 index++; 356 } 357 358 if (rc != 0) { 359 smb_odir_close(od); 360 smb_odir_release(od); 361 return (SDRC_ERROR); 362 } 363 364 if (count == 0 && find_first) { 365 smb_odir_close(od); 366 smb_odir_release(od); 367 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 368 ERRDOS, ERROR_NO_MORE_FILES); 369 return (SDRC_ERROR); 370 } 371 372 rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; 373 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 374 1, count, rc+3, 5, rc) < 0) { 375 smb_odir_close(od); 376 smb_odir_release(od); 377 return (SDRC_ERROR); 378 } 379 380 smb_odir_release(od); 381 return (SDRC_SUCCESS); 382 } 383 384 385 /* *** smb_com_find *** */ 386 387 smb_sdrc_t 388 smb_pre_find(smb_request_t *sr) 389 { 390 DTRACE_SMB_1(op__Find__start, smb_request_t *, sr); 391 return (SDRC_SUCCESS); 392 } 393 394 void 395 smb_post_find(smb_request_t *sr) 396 { 397 DTRACE_SMB_1(op__Find__done, smb_request_t *, sr); 398 } 399 400 smb_sdrc_t 401 smb_com_find(smb_request_t *sr) 402 { 403 int rc; 404 uint16_t count, maxcount, index; 405 uint16_t sattr, odid; 406 uint16_t key_len; 407 uint32_t client_key; 408 char name83[SMB_SHORTNAMELEN]; 409 smb_odir_t *od; 410 smb_fileinfo_t fileinfo; 411 uint16_t eos; 412 413 smb_pathname_t *pn; 414 unsigned char resume_char; 415 unsigned char type; 416 boolean_t find_first = B_TRUE; 417 smb_odir_resume_t odir_resume; 418 419 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 420 return (SDRC_ERROR); 421 422 pn = &sr->arg.dirop.fqi.fq_path; 423 rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len); 424 if ((rc != 0) || (type != 0x05)) 425 return (SDRC_ERROR); 426 427 if ((key_len != 0) && (key_len != 21)) 428 return (SDRC_ERROR); 429 430 smb_pathname_init(sr, pn, pn->pn_path); 431 if (!smb_pathname_validate(sr, pn)) 432 return (SDRC_ERROR); 433 434 if (smb_is_stream_name(pn->pn_path)) { 435 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 436 ERRDOS, ERROR_INVALID_NAME); 437 return (SDRC_ERROR); 438 } 439 440 find_first = (key_len == 0); 441 resume_char = 0; 442 client_key = 0; 443 444 if (find_first) { 445 odid = smb_odir_open(sr, pn->pn_path, sattr, 0); 446 if (odid == 0) 447 return (SDRC_ERROR); 448 } else { 449 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 450 &resume_char, &index, &odid, &client_key) != 0) { 451 return (SDRC_ERROR); 452 } 453 } 454 455 od = smb_tree_lookup_odir(sr, odid); 456 if (od == NULL) { 457 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 458 ERRDOS, ERROR_INVALID_HANDLE); 459 return (SDRC_ERROR); 460 } 461 462 if (!find_first) { 463 odir_resume.or_type = SMB_ODIR_RESUME_IDX; 464 odir_resume.or_idx = index; 465 smb_odir_resume_at(od, &odir_resume); 466 } 467 468 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 469 470 rc = 0; 471 index = 0; 472 count = 0; 473 if (maxcount > SMB_MAX_SEARCH) 474 maxcount = SMB_MAX_SEARCH; 475 476 while (count < maxcount) { 477 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 478 if (rc != 0 || eos != 0) 479 break; 480 481 if (*fileinfo.fi_shortname == '\0') { 482 if (smb_needs_mangled(fileinfo.fi_name)) 483 continue; 484 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 485 SMB_SHORTNAMELEN - 1); 486 } 487 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 488 489 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 490 resume_char, name83, index, odid, client_key, 491 fileinfo.fi_dosattr & 0xff, 492 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 493 (int32_t)fileinfo.fi_size, 494 fileinfo.fi_shortname); 495 496 smb_odir_save_cookie(od, index, fileinfo.fi_cookie); 497 498 count++; 499 index++; 500 } 501 502 if (rc != 0) { 503 smb_odir_close(od); 504 smb_odir_release(od); 505 return (SDRC_ERROR); 506 } 507 508 if (count == 0 && find_first) { 509 smb_odir_close(od); 510 smb_odir_release(od); 511 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 512 ERRDOS, ERROR_NO_MORE_FILES); 513 return (SDRC_ERROR); 514 } 515 516 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 517 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 518 1, count, rc+3, 5, rc) < 0) { 519 smb_odir_close(od); 520 smb_odir_release(od); 521 return (SDRC_ERROR); 522 } 523 524 smb_odir_release(od); 525 return (SDRC_SUCCESS); 526 } 527 528 529 /* *** smb_com_find_close *** */ 530 531 smb_sdrc_t 532 smb_pre_find_close(smb_request_t *sr) 533 { 534 DTRACE_SMB_1(op__FindClose__start, smb_request_t *, sr); 535 return (SDRC_SUCCESS); 536 } 537 538 void 539 smb_post_find_close(smb_request_t *sr) 540 { 541 DTRACE_SMB_1(op__FindClose__done, smb_request_t *, sr); 542 } 543 544 smb_sdrc_t 545 smb_com_find_close(smb_request_t *sr) 546 { 547 int rc; 548 uint16_t maxcount, index; 549 uint16_t sattr, odid; 550 uint16_t key_len; 551 uint32_t client_key; 552 char *path; 553 unsigned char resume_char; 554 unsigned char type; 555 smb_odir_t *od; 556 557 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 558 return (SDRC_ERROR); 559 560 rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); 561 if ((rc != 0) || (type != 0x05)) 562 return (SDRC_ERROR); 563 564 if (key_len == 0) { 565 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 566 ERRDOS, ERROR_INVALID_HANDLE); 567 return (SDRC_ERROR); 568 } else if (key_len != 21) { 569 return (SDRC_ERROR); 570 } 571 572 odid = 0; 573 if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", 574 &resume_char, &index, &odid, &client_key) != 0) { 575 return (SDRC_ERROR); 576 } 577 578 od = smb_tree_lookup_odir(sr, odid); 579 if (od == NULL) { 580 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, 581 ERRDOS, ERROR_INVALID_HANDLE); 582 return (SDRC_ERROR); 583 } 584 585 smb_odir_close(od); 586 smb_odir_release(od); 587 588 if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0)) 589 return (SDRC_ERROR); 590 591 return (SDRC_SUCCESS); 592 } 593 594 595 /* *** smb_com_find_unique *** */ 596 597 smb_sdrc_t 598 smb_pre_find_unique(smb_request_t *sr) 599 { 600 DTRACE_SMB_1(op__FindUnique__start, smb_request_t *, sr); 601 return (SDRC_SUCCESS); 602 } 603 604 void 605 smb_post_find_unique(smb_request_t *sr) 606 { 607 DTRACE_SMB_1(op__FindUnique__done, smb_request_t *, sr); 608 } 609 610 smb_sdrc_t 611 smb_com_find_unique(struct smb_request *sr) 612 { 613 int rc; 614 uint16_t count, maxcount, index; 615 uint16_t sattr, odid; 616 smb_pathname_t *pn; 617 unsigned char resume_char = '\0'; 618 uint32_t client_key = 0; 619 char name83[SMB_SHORTNAMELEN]; 620 smb_odir_t *od; 621 smb_fileinfo_t fileinfo; 622 uint16_t eos; 623 smb_vdb_t *vdb; 624 625 if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) 626 return (SDRC_ERROR); 627 628 pn = &sr->arg.dirop.fqi.fq_path; 629 vdb = kmem_alloc(sizeof (smb_vdb_t), KM_SLEEP); 630 if ((smbsr_decode_data(sr, "%AV", sr, &pn->pn_path, vdb) != 0) || 631 (vdb->vdb_len != 0)) { 632 kmem_free(vdb, sizeof (smb_vdb_t)); 633 return (SDRC_ERROR); 634 } 635 kmem_free(vdb, sizeof (smb_vdb_t)); 636 637 smb_pathname_init(sr, pn, pn->pn_path); 638 if (!smb_pathname_validate(sr, pn)) 639 return (SDRC_ERROR); 640 641 if (smb_is_stream_name(pn->pn_path)) { 642 smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, 643 ERRDOS, ERROR_INVALID_NAME); 644 return (SDRC_ERROR); 645 } 646 647 (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); 648 649 odid = smb_odir_open(sr, pn->pn_path, sattr, 0); 650 if (odid == 0) 651 return (SDRC_ERROR); 652 od = smb_tree_lookup_odir(sr, odid); 653 if (od == NULL) 654 return (SDRC_ERROR); 655 656 rc = 0; 657 count = 0; 658 index = 0; 659 if (maxcount > SMB_MAX_SEARCH) 660 maxcount = SMB_MAX_SEARCH; 661 662 while (count < maxcount) { 663 rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); 664 if (rc != 0 || eos != 0) 665 break; 666 667 if (*fileinfo.fi_shortname == '\0') { 668 if (smb_needs_mangled(fileinfo.fi_name)) 669 continue; 670 (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, 671 SMB_SHORTNAMELEN - 1); 672 } 673 smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN); 674 675 (void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c", 676 resume_char, name83, index, odid, client_key, 677 fileinfo.fi_dosattr & 0xff, 678 smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec), 679 (int32_t)fileinfo.fi_size, 680 fileinfo.fi_shortname); 681 682 count++; 683 index++; 684 } 685 686 smb_odir_close(od); 687 smb_odir_release(od); 688 689 if (rc != 0) 690 return (SDRC_ERROR); 691 692 if (count == 0) { 693 smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, 694 ERRDOS, ERROR_NO_MORE_FILES); 695 return (SDRC_ERROR); 696 } 697 698 rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; 699 if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, 700 "bwwbw", 1, count, rc+3, 5, rc) < 0) { 701 return (SDRC_ERROR); 702 } 703 704 return (SDRC_SUCCESS); 705 } 706 707 /* 708 * smb_name83 709 * 710 * Format the filename for inclusion in the resume key. The filename 711 * returned in the resume key is 11 bytes: 712 * - up to 8 bytes of filename, space padded to 8 bytes 713 * - up to 3 bytes of ext, space padded to 3 bytes 714 * 715 * The name passed to smb_name83 should be a shortname or a name that 716 * doesn't require mangling. 717 * 718 * Examples: 719 * "fname.txt" -> "FNAME TXT" 720 * "fname.tx" -> "FNAME TX " 721 * "filename" -> "FILENAME " 722 * "filename.txt" -> "FILENAMETXT" 723 * "FILE~1.TXT" -> "FILE~1 TXT" 724 */ 725 static void 726 smb_name83(const char *name, char *buf, size_t buflen) 727 { 728 const char *p; 729 char *pbuf; 730 int i; 731 732 ASSERT(name && buf && (buflen >= SMB_NAME83_BUFLEN)); 733 734 (void) strlcpy(buf, " ", SMB_NAME83_BUFLEN); 735 736 /* Process "." and ".." up front */ 737 if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) { 738 (void) strncpy(buf, name, strlen(name)); 739 return; 740 } 741 742 ASSERT(smb_needs_mangled(name) == B_FALSE); 743 744 /* Process basename */ 745 for (i = 0, p = name, pbuf = buf; 746 (i < SMB_NAME83_BASELEN) && (*p != '\0') && (*p != '.'); ++i) 747 *pbuf++ = *p++; 748 749 /* Process the extension from the last dot in name */ 750 if ((p = strchr(name, '.')) != NULL) { 751 ++p; 752 pbuf = &buf[SMB_NAME83_BASELEN]; 753 for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i) 754 *pbuf++ = *p++; 755 } 756 757 (void) smb_strupr(buf); 758 } 759