1/* 2 Unix SMB/CIFS implementation. 3 4 POSIX NTVFS backend - filename resolution 5 6 Copyright (C) Andrew Tridgell 2004 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22/* 23 this is the core code for converting a filename from the format as 24 given by a client to a posix filename, including any case-matching 25 required, and checks for legal characters 26*/ 27 28 29#include "includes.h" 30#include "vfs_posix.h" 31#include "system/dir.h" 32#include "param/param.h" 33 34/** 35 compare two filename components. This is where the name mangling hook will go 36*/ 37static int component_compare(struct pvfs_state *pvfs, const char *comp, const char *name) 38{ 39 int ret; 40 41 ret = strcasecmp_m(comp, name); 42 43 if (ret != 0) { 44 char *shortname = pvfs_short_name_component(pvfs, name); 45 if (shortname) { 46 ret = strcasecmp_m(comp, shortname); 47 talloc_free(shortname); 48 } 49 } 50 51 return ret; 52} 53 54/* 55 search for a filename in a case insensitive fashion 56 57 TODO: add a cache for previously resolved case-insensitive names 58 TODO: add mangled name support 59*/ 60static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, 61 struct pvfs_filename *name, 62 uint_t flags) 63{ 64 /* break into a series of components */ 65 int num_components; 66 char **components; 67 char *p, *partial_name; 68 int i; 69 70 /* break up the full name info pathname components */ 71 num_components=2; 72 p = name->full_name + strlen(pvfs->base_directory) + 1; 73 74 for (;*p;p++) { 75 if (*p == '/') { 76 num_components++; 77 } 78 } 79 80 components = talloc_array(name, char *, num_components); 81 p = name->full_name + strlen(pvfs->base_directory); 82 *p++ = 0; 83 84 components[0] = name->full_name; 85 86 for (i=1;i<num_components;i++) { 87 components[i] = p; 88 p = strchr(p, '/'); 89 if (p) *p++ = 0; 90 if (pvfs_is_reserved_name(pvfs, components[i])) { 91 return NT_STATUS_ACCESS_DENIED; 92 } 93 } 94 95 partial_name = talloc_strdup(name, components[0]); 96 if (!partial_name) { 97 return NT_STATUS_NO_MEMORY; 98 } 99 100 /* for each component, check if it exists as-is, and if not then 101 do a directory scan */ 102 for (i=1;i<num_components;i++) { 103 char *test_name; 104 DIR *dir; 105 struct dirent *de; 106 char *long_component; 107 108 /* possibly remap from the short name cache */ 109 long_component = pvfs_mangled_lookup(pvfs, name, components[i]); 110 if (long_component) { 111 components[i] = long_component; 112 } 113 114 test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]); 115 if (!test_name) { 116 return NT_STATUS_NO_MEMORY; 117 } 118 119 /* check if this component exists as-is */ 120 if (stat(test_name, &name->st) == 0) { 121 if (i<num_components-1 && !S_ISDIR(name->st.st_mode)) { 122 return NT_STATUS_OBJECT_PATH_NOT_FOUND; 123 } 124 talloc_free(partial_name); 125 partial_name = test_name; 126 if (i == num_components - 1) { 127 name->exists = true; 128 } 129 continue; 130 } 131 132 /* the filesystem might be case insensitive, in which 133 case a search is pointless unless the name is 134 mangled */ 135 if ((pvfs->flags & PVFS_FLAG_CI_FILESYSTEM) && 136 !pvfs_is_mangled_component(pvfs, components[i])) { 137 if (i < num_components-1) { 138 return NT_STATUS_OBJECT_PATH_NOT_FOUND; 139 } 140 partial_name = test_name; 141 continue; 142 } 143 144 dir = opendir(partial_name); 145 if (!dir) { 146 return pvfs_map_errno(pvfs, errno); 147 } 148 149 while ((de = readdir(dir))) { 150 if (component_compare(pvfs, components[i], de->d_name) == 0) { 151 break; 152 } 153 } 154 155 if (!de) { 156 if (i < num_components-1) { 157 closedir(dir); 158 return NT_STATUS_OBJECT_PATH_NOT_FOUND; 159 } 160 } else { 161 components[i] = talloc_strdup(name, de->d_name); 162 } 163 test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]); 164 talloc_free(partial_name); 165 partial_name = test_name; 166 167 closedir(dir); 168 } 169 170 if (!name->exists) { 171 if (stat(partial_name, &name->st) == 0) { 172 name->exists = true; 173 } 174 } 175 176 talloc_free(name->full_name); 177 name->full_name = partial_name; 178 179 if (name->exists) { 180 return pvfs_fill_dos_info(pvfs, name, flags, -1); 181 } 182 183 return NT_STATUS_OK; 184} 185 186/* 187 parse a alternate data stream name 188*/ 189static NTSTATUS parse_stream_name(struct smb_iconv_convenience *ic, 190 struct pvfs_filename *name, 191 const char *s) 192{ 193 char *p, *stream_name; 194 if (s[1] == '\0') { 195 return NT_STATUS_OBJECT_NAME_INVALID; 196 } 197 name->stream_name = stream_name = talloc_strdup(name, s+1); 198 if (name->stream_name == NULL) { 199 return NT_STATUS_NO_MEMORY; 200 } 201 202 p = stream_name; 203 204 while (*p) { 205 size_t c_size; 206 codepoint_t c = next_codepoint_convenience(ic, p, &c_size); 207 208 switch (c) { 209 case '/': 210 case '\\': 211 return NT_STATUS_OBJECT_NAME_INVALID; 212 case ':': 213 *p= 0; 214 p++; 215 if (*p == '\0') { 216 return NT_STATUS_OBJECT_NAME_INVALID; 217 } 218 if (strcasecmp_m(p, "$DATA") != 0) { 219 if (strchr_m(p, ':')) { 220 return NT_STATUS_OBJECT_NAME_INVALID; 221 } 222 return NT_STATUS_INVALID_PARAMETER; 223 } 224 c_size = 0; 225 p--; 226 break; 227 } 228 229 p += c_size; 230 } 231 232 if (strcmp(name->stream_name, "") == 0) { 233 /* 234 * we don't set stream_name to NULL, here 235 * as this would be wrong for directories 236 * 237 * pvfs_fill_dos_info() will set it to NULL 238 * if it's not a directory. 239 */ 240 name->stream_id = 0; 241 } else { 242 name->stream_id = pvfs_name_hash(name->stream_name, 243 strlen(name->stream_name)); 244 } 245 246 return NT_STATUS_OK; 247} 248 249 250/* 251 convert a CIFS pathname to a unix pathname. Note that this does NOT 252 take into account case insensitivity, and in fact does not access 253 the filesystem at all. It is merely a reformatting and charset 254 checking routine. 255 256 errors are returned if the filename is illegal given the flags 257*/ 258static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name, 259 uint_t flags, struct pvfs_filename *name) 260{ 261 char *ret, *p, *p_start; 262 struct smb_iconv_convenience *ic = NULL; 263 NTSTATUS status; 264 265 name->original_name = talloc_strdup(name, cifs_name); 266 name->stream_name = NULL; 267 name->stream_id = 0; 268 name->has_wildcard = false; 269 270 while (*cifs_name == '\\') { 271 cifs_name++; 272 } 273 274 if (*cifs_name == 0) { 275 name->full_name = talloc_asprintf(name, "%s/.", pvfs->base_directory); 276 if (name->full_name == NULL) { 277 return NT_STATUS_NO_MEMORY; 278 } 279 return NT_STATUS_OK; 280 } 281 282 ret = talloc_asprintf(name, "%s/%s", pvfs->base_directory, cifs_name); 283 if (ret == NULL) { 284 return NT_STATUS_NO_MEMORY; 285 } 286 287 p = ret + strlen(pvfs->base_directory) + 1; 288 289 /* now do an in-place conversion of '\' to '/', checking 290 for legal characters */ 291 p_start = p; 292 293 ic = lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx); 294 while (*p) { 295 size_t c_size; 296 codepoint_t c = next_codepoint_convenience(ic, p, &c_size); 297 298 if (c <= 0x1F) { 299 return NT_STATUS_OBJECT_NAME_INVALID; 300 } 301 302 switch (c) { 303 case '\\': 304 if (name->has_wildcard) { 305 /* wildcards are only allowed in the last part 306 of a name */ 307 return NT_STATUS_OBJECT_NAME_INVALID; 308 } 309 if (p > p_start && (p[1] == '\\' || p[1] == '\0')) { 310 /* see if it is definately a "\\" or 311 * a trailing "\". If it is then fail here, 312 * and let the next layer up try again after 313 * pvfs_reduce_name() if it wants to. This is 314 * much more efficient on average than always 315 * scanning for these separately 316 */ 317 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; 318 } else { 319 *p = '/'; 320 } 321 break; 322 case ':': 323 if (!(flags & PVFS_RESOLVE_STREAMS)) { 324 return NT_STATUS_OBJECT_NAME_INVALID; 325 } 326 if (name->has_wildcard) { 327 return NT_STATUS_OBJECT_NAME_INVALID; 328 } 329 status = parse_stream_name(ic, name, p); 330 if (!NT_STATUS_IS_OK(status)) { 331 return status; 332 } 333 *p-- = 0; 334 break; 335 case '*': 336 case '>': 337 case '<': 338 case '?': 339 case '"': 340 if (!(flags & PVFS_RESOLVE_WILDCARD)) { 341 return NT_STATUS_OBJECT_NAME_INVALID; 342 } 343 name->has_wildcard = true; 344 break; 345 case '/': 346 case '|': 347 return NT_STATUS_OBJECT_NAME_INVALID; 348 case '.': 349 /* see if it is definately a .. or 350 . component. If it is then fail here, and 351 let the next layer up try again after 352 pvfs_reduce_name() if it wants to. This is 353 much more efficient on average than always 354 scanning for these separately */ 355 if (p[1] == '.' && 356 (p[2] == 0 || p[2] == '\\') && 357 (p == p_start || p[-1] == '/')) { 358 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; 359 } 360 if ((p[1] == 0 || p[1] == '\\') && 361 (p == p_start || p[-1] == '/')) { 362 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; 363 } 364 break; 365 } 366 367 p += c_size; 368 } 369 370 name->full_name = ret; 371 372 return NT_STATUS_OK; 373} 374 375 376/* 377 reduce a name that contains .. components or repeated \ separators 378 return NULL if it can't be reduced 379*/ 380static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, 381 struct smb_iconv_convenience *iconv_convenience, 382 const char **fname, uint_t flags) 383{ 384 codepoint_t c; 385 size_t c_size, len; 386 int i, num_components, err_count; 387 char **components; 388 char *p, *s, *ret; 389 390 s = talloc_strdup(mem_ctx, *fname); 391 if (s == NULL) return NT_STATUS_NO_MEMORY; 392 393 for (num_components=1, p=s; *p; p += c_size) { 394 c = next_codepoint_convenience(iconv_convenience, p, &c_size); 395 if (c == '\\') num_components++; 396 } 397 398 components = talloc_array(s, char *, num_components+1); 399 if (components == NULL) { 400 talloc_free(s); 401 return NT_STATUS_NO_MEMORY; 402 } 403 404 components[0] = s; 405 for (i=0, p=s; *p; p += c_size) { 406 c = next_codepoint_convenience(iconv_convenience, p, &c_size); 407 if (c == '\\') { 408 *p = 0; 409 components[++i] = p+1; 410 } 411 } 412 components[i+1] = NULL; 413 414 /* 415 rather bizarre! 416 417 '.' components are not allowed, but the rules for what error 418 code to give don't seem to make sense. This is a close 419 approximation. 420 */ 421 for (err_count=i=0;components[i];i++) { 422 if (strcmp(components[i], "") == 0) { 423 continue; 424 } 425 if (ISDOT(components[i]) || err_count) { 426 err_count++; 427 } 428 } 429 if (err_count) { 430 if (flags & PVFS_RESOLVE_WILDCARD) err_count--; 431 432 if (err_count==1) { 433 return NT_STATUS_OBJECT_NAME_INVALID; 434 } else { 435 return NT_STATUS_OBJECT_PATH_NOT_FOUND; 436 } 437 } 438 439 /* remove any null components */ 440 for (i=0;components[i];i++) { 441 if (strcmp(components[i], "") == 0) { 442 memmove(&components[i], &components[i+1], 443 sizeof(char *)*(num_components-i)); 444 i--; 445 continue; 446 } 447 if (ISDOTDOT(components[i])) { 448 if (i < 1) return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; 449 memmove(&components[i-1], &components[i+1], 450 sizeof(char *)*(num_components-i)); 451 i -= 2; 452 continue; 453 } 454 } 455 456 if (components[0] == NULL) { 457 talloc_free(s); 458 *fname = talloc_strdup(mem_ctx, "\\"); 459 return NT_STATUS_OK; 460 } 461 462 for (len=i=0;components[i];i++) { 463 len += strlen(components[i]) + 1; 464 } 465 466 /* rebuild the name */ 467 ret = talloc_array(mem_ctx, char, len+1); 468 if (ret == NULL) { 469 talloc_free(s); 470 return NT_STATUS_NO_MEMORY; 471 } 472 473 for (len=0,i=0;components[i];i++) { 474 size_t len1 = strlen(components[i]); 475 ret[len] = '\\'; 476 memcpy(ret+len+1, components[i], len1); 477 len += len1 + 1; 478 } 479 ret[len] = 0; 480 481 talloc_set_name_const(ret, ret); 482 483 talloc_free(s); 484 485 *fname = ret; 486 487 return NT_STATUS_OK; 488} 489 490 491/* 492 resolve a name from relative client format to a struct pvfs_filename 493 the memory for the filename is made as a talloc child of 'name' 494 495 flags include: 496 PVFS_RESOLVE_NO_WILDCARD = wildcards are considered illegal characters 497 PVFS_RESOLVE_STREAMS = stream names are allowed 498 499 TODO: ../ collapsing, and outside share checking 500*/ 501NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, 502 const char *cifs_name, 503 uint_t flags, struct pvfs_filename **name) 504{ 505 NTSTATUS status; 506 507 *name = talloc(mem_ctx, struct pvfs_filename); 508 if (*name == NULL) { 509 return NT_STATUS_NO_MEMORY; 510 } 511 512 (*name)->exists = false; 513 (*name)->stream_exists = false; 514 515 if (!(pvfs->fs_attribs & FS_ATTR_NAMED_STREAMS)) { 516 flags &= ~PVFS_RESOLVE_STREAMS; 517 } 518 519 /* do the basic conversion to a unix formatted path, 520 also checking for allowable characters */ 521 status = pvfs_unix_path(pvfs, cifs_name, flags, *name); 522 523 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) { 524 /* it might contain .. components which need to be reduced */ 525 status = pvfs_reduce_name(*name, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), &cifs_name, flags); 526 if (!NT_STATUS_IS_OK(status)) { 527 return status; 528 } 529 status = pvfs_unix_path(pvfs, cifs_name, flags, *name); 530 } 531 532 if (!NT_STATUS_IS_OK(status)) { 533 return status; 534 } 535 536 /* if it has a wildcard then no point doing a stat() of the 537 full name. Instead We need check if the directory exists 538 */ 539 if ((*name)->has_wildcard) { 540 const char *p; 541 char *dir_name, *saved_name; 542 p = strrchr((*name)->full_name, '/'); 543 if (p == NULL) { 544 /* root directory wildcard is OK */ 545 return NT_STATUS_OK; 546 } 547 dir_name = talloc_strndup(*name, (*name)->full_name, (p-(*name)->full_name)); 548 if (stat(dir_name, &(*name)->st) == 0) { 549 talloc_free(dir_name); 550 return NT_STATUS_OK; 551 } 552 /* we need to search for a matching name */ 553 saved_name = (*name)->full_name; 554 (*name)->full_name = dir_name; 555 status = pvfs_case_search(pvfs, *name, flags); 556 if (!NT_STATUS_IS_OK(status)) { 557 /* the directory doesn't exist */ 558 (*name)->full_name = saved_name; 559 return status; 560 } 561 /* it does exist, but might need a case change */ 562 if (dir_name != (*name)->full_name) { 563 (*name)->full_name = talloc_asprintf(*name, "%s%s", 564 (*name)->full_name, p); 565 NT_STATUS_HAVE_NO_MEMORY((*name)->full_name); 566 } else { 567 (*name)->full_name = saved_name; 568 talloc_free(dir_name); 569 } 570 return NT_STATUS_OK; 571 } 572 573 /* if we can stat() the full name now then we are done */ 574 if (stat((*name)->full_name, &(*name)->st) == 0) { 575 (*name)->exists = true; 576 return pvfs_fill_dos_info(pvfs, *name, flags, -1); 577 } 578 579 /* search for a matching filename */ 580 status = pvfs_case_search(pvfs, *name, flags); 581 582 return status; 583} 584 585 586/* 587 do a partial resolve, returning a pvfs_filename structure given a 588 base path and a relative component. It is an error if the file does 589 not exist. No case-insensitive matching is done. 590 591 this is used in places like directory searching where we need a pvfs_filename 592 to pass to a function, but already know the unix base directory and component 593*/ 594NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, 595 const char *unix_dir, const char *fname, 596 uint_t flags, struct pvfs_filename **name) 597{ 598 NTSTATUS status; 599 600 *name = talloc(mem_ctx, struct pvfs_filename); 601 if (*name == NULL) { 602 return NT_STATUS_NO_MEMORY; 603 } 604 605 (*name)->full_name = talloc_asprintf(*name, "%s/%s", unix_dir, fname); 606 if ((*name)->full_name == NULL) { 607 return NT_STATUS_NO_MEMORY; 608 } 609 610 if (stat((*name)->full_name, &(*name)->st) == -1) { 611 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 612 } 613 614 (*name)->exists = true; 615 (*name)->stream_exists = true; 616 (*name)->has_wildcard = false; 617 (*name)->original_name = talloc_strdup(*name, fname); 618 (*name)->stream_name = NULL; 619 (*name)->stream_id = 0; 620 621 status = pvfs_fill_dos_info(pvfs, *name, flags, -1); 622 623 return status; 624} 625 626 627/* 628 fill in the pvfs_filename info for an open file, given the current 629 info for a (possibly) non-open file. This is used by places that need 630 to update the pvfs_filename stat information, and by pvfs_open() 631*/ 632NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd, 633 struct pvfs_filename *name, uint_t flags) 634{ 635 dev_t device = (dev_t)0; 636 ino_t inode = 0; 637 638 if (name->exists) { 639 device = name->st.st_dev; 640 inode = name->st.st_ino; 641 } 642 643 if (fd == -1) { 644 if (stat(name->full_name, &name->st) == -1) { 645 return NT_STATUS_INVALID_HANDLE; 646 } 647 } else { 648 if (fstat(fd, &name->st) == -1) { 649 return NT_STATUS_INVALID_HANDLE; 650 } 651 } 652 653 if (name->exists && 654 (device != name->st.st_dev || inode != name->st.st_ino)) { 655 /* the file we are looking at has changed! this could 656 be someone trying to exploit a race 657 condition. Certainly we don't want to continue 658 operating on this file */ 659 DEBUG(0,("pvfs: WARNING: file '%s' changed during resolve - failing\n", 660 name->full_name)); 661 return NT_STATUS_UNEXPECTED_IO_ERROR; 662 } 663 664 name->exists = true; 665 666 return pvfs_fill_dos_info(pvfs, name, flags, fd); 667} 668 669/* 670 fill in the pvfs_filename info for an open file, given the current 671 info for a (possibly) non-open file. This is used by places that need 672 to update the pvfs_filename stat information, and the path 673 after a possible rename on a different handle. 674*/ 675NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs, 676 struct pvfs_file_handle *h) 677{ 678 NTSTATUS status; 679 680 if (h->have_opendb_entry) { 681 struct odb_lock *lck; 682 const char *name = NULL; 683 684 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); 685 if (lck == NULL) { 686 DEBUG(0,("%s: failed to lock file '%s' in opendb\n", 687 __FUNCTION__, h->name->full_name)); 688 /* we were supposed to do a blocking lock, so something 689 is badly wrong! */ 690 return NT_STATUS_INTERNAL_DB_CORRUPTION; 691 } 692 693 status = odb_get_path(lck, &name); 694 if (NT_STATUS_IS_OK(status)) { 695 /* 696 * This relies an the fact that 697 * renames of open files are only 698 * allowed by setpathinfo() and setfileinfo() 699 * and there're only renames within the same 700 * directory supported 701 */ 702 if (strcmp(h->name->full_name, name) != 0) { 703 const char *orig_dir; 704 const char *new_file; 705 const char *new_orig; 706 char *delim; 707 708 delim = strrchr(name, '/'); 709 if (!delim) { 710 talloc_free(lck); 711 return NT_STATUS_INTERNAL_ERROR; 712 } 713 714 new_file = delim + 1; 715 delim = strrchr(h->name->original_name, '\\'); 716 if (delim) { 717 delim[0] = '\0'; 718 orig_dir = h->name->original_name; 719 new_orig = talloc_asprintf(h->name, "%s\\%s", 720 orig_dir, new_file); 721 if (!new_orig) { 722 talloc_free(lck); 723 return NT_STATUS_NO_MEMORY; 724 } 725 } else { 726 new_orig = talloc_strdup(h->name, new_file); 727 if (!new_orig) { 728 talloc_free(lck); 729 return NT_STATUS_NO_MEMORY; 730 } 731 } 732 733 talloc_free(h->name->original_name); 734 talloc_free(h->name->full_name); 735 h->name->full_name = talloc_steal(h->name, name); 736 h->name->original_name = new_orig; 737 } 738 } 739 740 talloc_free(lck); 741 } 742 743 /* 744 * TODO: pass PVFS_RESOLVE_NO_OPENDB and get 745 * the write time from odb_lock() above. 746 */ 747 status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, 0); 748 NT_STATUS_NOT_OK_RETURN(status); 749 750 if (!null_nttime(h->write_time.close_time)) { 751 h->name->dos.write_time = h->write_time.close_time; 752 } 753 754 return NT_STATUS_OK; 755} 756 757 758/* 759 resolve the parent of a given name 760*/ 761NTSTATUS pvfs_resolve_parent(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, 762 const struct pvfs_filename *child, 763 struct pvfs_filename **name) 764{ 765 NTSTATUS status; 766 char *p; 767 768 *name = talloc(mem_ctx, struct pvfs_filename); 769 if (*name == NULL) { 770 return NT_STATUS_NO_MEMORY; 771 } 772 773 (*name)->full_name = talloc_strdup(*name, child->full_name); 774 if ((*name)->full_name == NULL) { 775 return NT_STATUS_NO_MEMORY; 776 } 777 778 p = strrchr_m((*name)->full_name, '/'); 779 if (p == NULL) { 780 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD; 781 } 782 783 /* this handles the root directory */ 784 if (p == (*name)->full_name) { 785 p[1] = 0; 786 } else { 787 p[0] = 0; 788 } 789 790 if (stat((*name)->full_name, &(*name)->st) == -1) { 791 return NT_STATUS_OBJECT_NAME_NOT_FOUND; 792 } 793 794 (*name)->exists = true; 795 (*name)->stream_exists = true; 796 (*name)->has_wildcard = false; 797 /* we can't get the correct 'original_name', but for the purposes 798 of this call this is close enough */ 799 (*name)->original_name = talloc_strdup(*name, child->original_name); 800 if ((*name)->original_name == NULL) { 801 return NT_STATUS_NO_MEMORY; 802 } 803 (*name)->stream_name = NULL; 804 (*name)->stream_id = 0; 805 806 status = pvfs_fill_dos_info(pvfs, *name, PVFS_RESOLVE_NO_OPENDB, -1); 807 808 return status; 809} 810