source: branches/samba-3.2.x/source/smbd/filename.c@ 205

Last change on this file since 205 was 149, checked in by Paul Smedley, 17 years ago

Update trunk to v3.2.2

File size: 24.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 filename handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 1999-2007
6 Copyright (C) Ying Chen 2000
7 Copyright (C) Volker Lendecke 2007
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23/*
24 * New hash table stat cache code added by Ying Chen.
25 */
26
27#include "includes.h"
28
29static bool scan_directory(connection_struct *conn, const char *path,
30 char *name, char **found_name);
31static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
32 connection_struct *conn,
33 const char *orig_path,
34 const char *basepath,
35 const char *streamname,
36 SMB_STRUCT_STAT *pst,
37 char **path);
38
39/****************************************************************************
40 Mangle the 2nd name and check if it is then equal to the first name.
41****************************************************************************/
42
43static bool mangled_equal(const char *name1,
44 const char *name2,
45 const struct share_params *p)
46{
47 char mname[13];
48
49 if (!name_to_8_3(name2, mname, False, p)) {
50 return False;
51 }
52 return strequal(name1, mname);
53}
54
55/****************************************************************************
56 Cope with the differing wildcard and non-wildcard error cases.
57****************************************************************************/
58
59static NTSTATUS determine_path_error(const char *name,
60 bool allow_wcard_last_component)
61{
62 const char *p;
63
64 if (!allow_wcard_last_component) {
65 /* Error code within a pathname. */
66 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
67 }
68
69 /* We're terminating here so we
70 * can be a little slower and get
71 * the error code right. Windows
72 * treats the last part of the pathname
73 * separately I think, so if the last
74 * component is a wildcard then we treat
75 * this ./ as "end of component" */
76
77 p = strchr(name, '/');
78
79 if (!p && (ms_has_wild(name) || ISDOT(name))) {
80 /* Error code at the end of a pathname. */
81 return NT_STATUS_OBJECT_NAME_INVALID;
82 } else {
83 /* Error code within a pathname. */
84 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
85 }
86}
87
88/****************************************************************************
89This routine is called to convert names from the dos namespace to unix
90namespace. It needs to handle any case conversions, mangling, format
91changes etc.
92
93We assume that we have already done a chdir() to the right "root" directory
94for this service.
95
96The function will return an NTSTATUS error if some part of the name except for
97the last part cannot be resolved, else NT_STATUS_OK.
98
99Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't
100get any fatal errors that should immediately terminate the calling
101SMB processing whilst resolving.
102
103If the saved_last_component != 0, then the unmodified last component
104of the pathname is returned there. This is used in an exceptional
105case in reply_mv (so far). If saved_last_component == 0 then nothing
106is returned there.
107
108If last_component_wcard is true then a MS wildcard was detected and
109should be allowed in the last component of the path only.
110
111On exit from unix_convert, if *pst was not null, then the file stat
112struct will be returned if the file exists and was found, if not this
113stat struct will be filled with zeros (and this can be detected by checking
114for nlinks = 0, which can never be true for any file).
115****************************************************************************/
116
117NTSTATUS unix_convert(TALLOC_CTX *ctx,
118 connection_struct *conn,
119 const char *orig_path,
120 bool allow_wcard_last_component,
121 char **pp_conv_path,
122 char **pp_saved_last_component,
123 SMB_STRUCT_STAT *pst)
124{
125 SMB_STRUCT_STAT st;
126 char *start, *end;
127 char *dirpath = NULL;
128 char *name = NULL;
129 char *stream = NULL;
130 bool component_was_mangled = False;
131 bool name_has_wildcard = False;
132 NTSTATUS result;
133
134 SET_STAT_INVALID(*pst);
135 *pp_conv_path = NULL;
136 if(pp_saved_last_component) {
137 *pp_saved_last_component = NULL;
138 }
139
140 if (conn->printer) {
141 /* we don't ever use the filenames on a printer share as a
142 filename - so don't convert them */
143 if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) {
144 return NT_STATUS_NO_MEMORY;
145 }
146 return NT_STATUS_OK;
147 }
148
149 DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
150
151 /*
152 * Conversion to basic unix format is already done in
153 * check_path_syntax().
154 */
155
156 /*
157 * Names must be relative to the root of the service - any leading /.
158 * and trailing /'s should have been trimmed by check_path_syntax().
159 */
160
161#ifdef DEVELOPER
162 SMB_ASSERT(*orig_path != '/');
163#endif
164
165 /*
166 * If we trimmed down to a single '\0' character
167 * then we should use the "." directory to avoid
168 * searching the cache, but not if we are in a
169 * printing share.
170 * As we know this is valid we can return true here.
171 */
172
173 if (!*orig_path) {
174 if (!(name = talloc_strdup(ctx,"."))) {
175 return NT_STATUS_NO_MEMORY;
176 }
177 if (SMB_VFS_STAT(conn,name,&st) == 0) {
178 *pst = st;
179 } else {
180 return map_nt_error_from_unix(errno);
181 }
182 DEBUG(5,("conversion finished \"\" -> %s\n",name));
183 goto done;
184 }
185
186 if (orig_path[0] == '.' && (orig_path[1] == '/' ||
187 orig_path[1] == '\0')) {
188 /* Start of pathname can't be "." only. */
189 if (orig_path[1] == '\0' || orig_path[2] == '\0') {
190 result = NT_STATUS_OBJECT_NAME_INVALID;
191 } else {
192 result =determine_path_error(
193 &orig_path[2], allow_wcard_last_component);
194 }
195 return result;
196 }
197
198 /*
199 * Ensure saved_last_component is valid even if file exists.
200 */
201
202 if(pp_saved_last_component) {
203 end = strrchr_m(orig_path, '/');
204 if (end) {
205 *pp_saved_last_component = talloc_strdup(ctx, end + 1);
206 } else {
207 *pp_saved_last_component = talloc_strdup(ctx,
208 orig_path);
209 }
210 }
211
212 if (!(name = talloc_strdup(ctx, orig_path))) {
213 DEBUG(0, ("talloc_strdup failed\n"));
214 return NT_STATUS_NO_MEMORY;
215 }
216
217 if (!lp_posix_pathnames()) {
218 stream = strchr_m(name, ':');
219
220 if (stream != NULL) {
221 char *tmp = talloc_strdup(ctx, stream);
222 if (tmp == NULL) {
223 TALLOC_FREE(name);
224 return NT_STATUS_NO_MEMORY;
225 }
226 *stream = '\0';
227 stream = tmp;
228 }
229 }
230
231 /*
232 * Large directory fix normalization. If we're case sensitive, and
233 * the case preserving parameters are set to "no", normalize the case of
234 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
235 * This is in conflict with the current (3.0.20) man page, but is
236 * what people expect from the "large directory howto". I'll update
237 * the man page. Thanks to jht@samba.org for finding this. JRA.
238 */
239
240 if (conn->case_sensitive && !conn->case_preserve &&
241 !conn->short_case_preserve) {
242 strnorm(name, lp_defaultcase(SNUM(conn)));
243 }
244
245 start = name;
246
247 /* If we're providing case insentive semantics or
248 * the underlying filesystem is case insensitive,
249 * then a case-normalized hit in the stat-cache is
250 * authoratitive. JRA.
251 */
252
253 if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
254 stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
255 *pst = st;
256 goto done;
257 }
258
259 /*
260 * Make sure "dirpath" is an allocated string, we use this for
261 * building the directories with asprintf and free it.
262 */
263
264 if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
265 DEBUG(0, ("talloc_strdup failed\n"));
266 TALLOC_FREE(name);
267 return NT_STATUS_NO_MEMORY;
268 }
269
270 /*
271 * stat the name - if it exists then we are all done!
272 */
273
274 if (SMB_VFS_STAT(conn,name,&st) == 0) {
275 /* Ensure we catch all names with in "/."
276 this is disallowed under Windows. */
277 const char *p = strstr(name, "/."); /* mb safe. */
278 if (p) {
279 if (p[2] == '/') {
280 /* Error code within a pathname. */
281 result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
282 goto fail;
283 } else if (p[2] == '\0') {
284 /* Error code at the end of a pathname. */
285 result = NT_STATUS_OBJECT_NAME_INVALID;
286 goto fail;
287 }
288 }
289 stat_cache_add(orig_path, name, conn->case_sensitive);
290 DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
291 *pst = st;
292 goto done;
293 }
294
295 DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
296 name, dirpath, start));
297
298 /*
299 * A special case - if we don't have any mangling chars and are case
300 * sensitive or the underlying filesystem is case insentive then searching
301 * won't help.
302 */
303
304 if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
305 !mangle_is_mangled(name, conn->params)) {
306 goto done;
307 }
308
309 /*
310 * is_mangled() was changed to look at an entire pathname, not
311 * just a component. JRA.
312 */
313
314 if (mangle_is_mangled(start, conn->params)) {
315 component_was_mangled = True;
316 }
317
318 /*
319 * Now we need to recursively match the name against the real
320 * directory structure.
321 */
322
323 /*
324 * Match each part of the path name separately, trying the names
325 * as is first, then trying to scan the directory for matching names.
326 */
327
328 for (; start ; start = (end?end+1:(char *)NULL)) {
329 /*
330 * Pinpoint the end of this section of the filename.
331 */
332 /* mb safe. '/' can't be in any encoded char. */
333 end = strchr(start, '/');
334
335 /*
336 * Chop the name at this point.
337 */
338 if (end) {
339 *end = 0;
340 }
341
342 if (pp_saved_last_component) {
343 TALLOC_FREE(*pp_saved_last_component);
344 *pp_saved_last_component = talloc_strdup(ctx,
345 end ? end + 1 : start);
346 if (!*pp_saved_last_component) {
347 DEBUG(0, ("talloc failed\n"));
348 return NT_STATUS_NO_MEMORY;
349 }
350 }
351
352 /* The name cannot have a component of "." */
353
354 if (ISDOT(start)) {
355 if (!end) {
356 /* Error code at the end of a pathname. */
357 result = NT_STATUS_OBJECT_NAME_INVALID;
358 } else {
359 result = determine_path_error(end+1,
360 allow_wcard_last_component);
361 }
362 goto fail;
363 }
364
365 /* The name cannot have a wildcard if it's not
366 the last component. */
367
368 name_has_wildcard = ms_has_wild(start);
369
370 /* Wildcard not valid anywhere. */
371 if (name_has_wildcard && !allow_wcard_last_component) {
372 result = NT_STATUS_OBJECT_NAME_INVALID;
373 goto fail;
374 }
375
376 /* Wildcards never valid within a pathname. */
377 if (name_has_wildcard && end) {
378 result = NT_STATUS_OBJECT_NAME_INVALID;
379 goto fail;
380 }
381
382 /*
383 * Check if the name exists up to this point.
384 */
385
386 if (SMB_VFS_STAT(conn,name, &st) == 0) {
387 /*
388 * It exists. it must either be a directory or this must
389 * be the last part of the path for it to be OK.
390 */
391 if (end && !(st.st_mode & S_IFDIR)) {
392 /*
393 * An intermediate part of the name isn't
394 * a directory.
395 */
396 DEBUG(5,("Not a dir %s\n",start));
397 *end = '/';
398 /*
399 * We need to return the fact that the
400 * intermediate name resolution failed. This
401 * is used to return an error of ERRbadpath
402 * rather than ERRbadfile. Some Windows
403 * applications depend on the difference between
404 * these two errors.
405 */
406 result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
407 goto fail;
408 }
409
410 if (!end) {
411 /*
412 * We just scanned for, and found the end of
413 * the path. We must return the valid stat
414 * struct. JRA.
415 */
416
417 *pst = st;
418 }
419
420 } else {
421 char *found_name = NULL;
422
423 /* Stat failed - ensure we don't use it. */
424 SET_STAT_INVALID(st);
425
426 /*
427 * Reset errno so we can detect
428 * directory open errors.
429 */
430 errno = 0;
431
432 /*
433 * Try to find this part of the path in the directory.
434 */
435
436 if (name_has_wildcard ||
437 !scan_directory(conn, dirpath,
438 start, &found_name)) {
439 char *unmangled;
440
441 if (end) {
442 /*
443 * An intermediate part of the name
444 * can't be found.
445 */
446 DEBUG(5,("Intermediate not found %s\n",
447 start));
448 *end = '/';
449
450 /*
451 * We need to return the fact that the
452 * intermediate name resolution failed.
453 * This is used to return an error of
454 * ERRbadpath rather than ERRbadfile.
455 * Some Windows applications depend on
456 * the difference between these two
457 * errors.
458 */
459
460 /*
461 * ENOENT, ENOTDIR and ELOOP all map
462 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
463 * in the filename walk.
464 */
465
466 if (errno == ENOENT ||
467 errno == ENOTDIR ||
468 errno == ELOOP) {
469 DEBUG( 0, ( "PS - ENOTDIR3\n" ) );
470 result =
471 NT_STATUS_OBJECT_PATH_NOT_FOUND;
472 }
473 else {
474 result =
475 map_nt_error_from_unix(errno);
476 }
477 goto fail;
478 }
479
480 /* ENOENT is the only valid error here. */
481 if ((errno != 0) && (errno != ENOENT)) {
482 /*
483 * ENOTDIR and ELOOP both map to
484 * NT_STATUS_OBJECT_PATH_NOT_FOUND
485 * in the filename walk.
486 */
487 if (errno == ENOTDIR ||
488 errno == ELOOP) {
489 result =
490 NT_STATUS_OBJECT_PATH_NOT_FOUND;
491 }
492 else {
493 result =
494 map_nt_error_from_unix(errno);
495 }
496 goto fail;
497 }
498
499 /*
500 * Just the last part of the name doesn't exist.
501 * We need to strupper() or strlower() it as
502 * this conversion may be used for file creation
503 * purposes. Fix inspired by
504 * Thomas Neumann <t.neumann@iku-ag.de>.
505 */
506 if (!conn->case_preserve ||
507 (mangle_is_8_3(start, False,
508 conn->params) &&
509 !conn->short_case_preserve)) {
510 strnorm(start,
511 lp_defaultcase(SNUM(conn)));
512 }
513
514 /*
515 * check on the mangled stack to see if we can
516 * recover the base of the filename.
517 */
518
519 if (mangle_is_mangled(start, conn->params)
520 && mangle_lookup_name_from_8_3(ctx,
521 start,
522 &unmangled,
523 conn->params)) {
524 char *tmp;
525 size_t start_ofs = start - name;
526
527 if (*dirpath != '\0') {
528 tmp = talloc_asprintf(ctx,
529 "%s/%s", dirpath,
530 unmangled);
531 TALLOC_FREE(unmangled);
532 }
533 else {
534 tmp = unmangled;
535 }
536 if (tmp == NULL) {
537 DEBUG(0, ("talloc failed\n"));
538 return NT_STATUS_NO_MEMORY;
539 }
540 TALLOC_FREE(name);
541 name = tmp;
542 start = name + start_ofs;
543 end = start + strlen(start);
544 }
545
546 DEBUG(5,("New file %s\n",start));
547 goto done;
548 }
549
550
551 /*
552 * Restore the rest of the string. If the string was
553 * mangled the size may have changed.
554 */
555 if (end) {
556 char *tmp;
557 size_t start_ofs = start - name;
558
559 if (*dirpath != '\0') {
560 tmp = talloc_asprintf(ctx,
561 "%s/%s/%s", dirpath,
562 found_name, end+1);
563 }
564 else {
565 tmp = talloc_asprintf(ctx,
566 "%s/%s", found_name,
567 end+1);
568 }
569 if (tmp == NULL) {
570 DEBUG(0, ("talloc_asprintf failed\n"));
571 return NT_STATUS_NO_MEMORY;
572 }
573 TALLOC_FREE(name);
574 name = tmp;
575 start = name + start_ofs;
576 end = start + strlen(found_name);
577 *end = '\0';
578 } else {
579 char *tmp;
580 size_t start_ofs = start - name;
581
582 if (*dirpath != '\0') {
583 tmp = talloc_asprintf(ctx,
584 "%s/%s", dirpath,
585 found_name);
586 } else {
587 tmp = talloc_strdup(ctx,
588 found_name);
589 }
590 if (tmp == NULL) {
591 DEBUG(0, ("talloc failed\n"));
592 return NT_STATUS_NO_MEMORY;
593 }
594 TALLOC_FREE(name);
595 name = tmp;
596 start = name + start_ofs;
597
598 /*
599 * We just scanned for, and found the end of
600 * the path. We must return a valid stat struct
601 * if it exists. JRA.
602 */
603
604 if (SMB_VFS_STAT(conn,name, &st) == 0) {
605 *pst = st;
606 } else {
607 SET_STAT_INVALID(st);
608 }
609 }
610
611 TALLOC_FREE(found_name);
612 } /* end else */
613
614#ifdef DEVELOPER
615 /*
616 * This sucks!
617 * We should never provide different behaviors
618 * depending on DEVELOPER!!!
619 */
620 if (VALID_STAT(st)) {
621 bool delete_pending;
622 get_file_infos(vfs_file_id_from_sbuf(conn, &st),
623 &delete_pending, NULL);
624 if (delete_pending) {
625 result = NT_STATUS_DELETE_PENDING;
626 goto fail;
627 }
628 }
629#endif
630
631 /*
632 * Add to the dirpath that we have resolved so far.
633 */
634
635 if (*dirpath != '\0') {
636 char *tmp = talloc_asprintf(ctx,
637 "%s/%s", dirpath, start);
638 if (!tmp) {
639 DEBUG(0, ("talloc_asprintf failed\n"));
640 return NT_STATUS_NO_MEMORY;
641 }
642 TALLOC_FREE(dirpath);
643 dirpath = tmp;
644 }
645 else {
646 TALLOC_FREE(dirpath);
647 if (!(dirpath = talloc_strdup(ctx,start))) {
648 DEBUG(0, ("talloc_strdup failed\n"));
649 return NT_STATUS_NO_MEMORY;
650 }
651 }
652
653 /*
654 * Don't cache a name with mangled or wildcard components
655 * as this can change the size.
656 */
657
658 if(!component_was_mangled && !name_has_wildcard) {
659 stat_cache_add(orig_path, dirpath,
660 conn->case_sensitive);
661 }
662
663 /*
664 * Restore the / that we wiped out earlier.
665 */
666 if (end) {
667 *end = '/';
668 }
669 }
670
671 /*
672 * Don't cache a name with mangled or wildcard components
673 * as this can change the size.
674 */
675
676 if(!component_was_mangled && !name_has_wildcard) {
677 stat_cache_add(orig_path, name, conn->case_sensitive);
678 }
679
680 /*
681 * The name has been resolved.
682 */
683
684 DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
685
686 done:
687 if (stream != NULL) {
688 char *tmp = NULL;
689
690 result = build_stream_path(ctx, conn, orig_path, name, stream,
691 pst, &tmp);
692 if (!NT_STATUS_IS_OK(result)) {
693 goto fail;
694 }
695
696 DEBUG(10, ("build_stream_path returned %s\n", tmp));
697
698 TALLOC_FREE(name);
699 name = tmp;
700 }
701 *pp_conv_path = name;
702 TALLOC_FREE(dirpath);
703 return NT_STATUS_OK;
704 fail:
705 DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
706 if (*dirpath != '\0') {
707 *pp_conv_path = talloc_asprintf(ctx,
708 "%s/%s", dirpath, start);
709 } else {
710 *pp_conv_path = talloc_strdup(ctx, start);
711 }
712 if (!*pp_conv_path) {
713 DEBUG(0, ("talloc_asprintf failed\n"));
714 return NT_STATUS_NO_MEMORY;
715 }
716 TALLOC_FREE(name);
717 TALLOC_FREE(dirpath);
718 return result;
719}
720
721/****************************************************************************
722 Check a filename - possibly calling check_reduced_name.
723 This is called by every routine before it allows an operation on a filename.
724 It does any final confirmation necessary to ensure that the filename is
725 a valid one for the user to access.
726****************************************************************************/
727
728NTSTATUS check_name(connection_struct *conn, const char *name)
729{
730 if (IS_VETO_PATH(conn, name)) {
731 /* Is it not dot or dot dot. */
732 if (!((name[0] == '.') && (!name[1] ||
733 (name[1] == '.' && !name[2])))) {
734 DEBUG(5,("check_name: file path name %s vetoed\n",
735 name));
736 return map_nt_error_from_unix(ENOENT);
737 }
738 }
739
740 if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) {
741 NTSTATUS status = check_reduced_name(conn,name);
742 if (!NT_STATUS_IS_OK(status)) {
743 DEBUG(5,("check_name: name %s failed with %s\n",name,
744 nt_errstr(status)));
745 return status;
746 }
747 }
748
749 return NT_STATUS_OK;
750}
751
752/****************************************************************************
753 Check if two filenames are equal.
754 This needs to be careful about whether we are case sensitive.
755****************************************************************************/
756
757static bool fname_equal(const char *name1, const char *name2,
758 bool case_sensitive)
759{
760 /* Normal filename handling */
761 if (case_sensitive) {
762 return(strcmp(name1,name2) == 0);
763 }
764
765 return(strequal(name1,name2));
766}
767
768/****************************************************************************
769 Scan a directory to find a filename, matching without case sensitivity.
770 If the name looks like a mangled name then try via the mangling functions
771****************************************************************************/
772
773static bool scan_directory(connection_struct *conn, const char *path,
774 char *name, char **found_name)
775{
776 struct smb_Dir *cur_dir;
777 const char *dname;
778 bool mangled;
779 char *unmangled_name = NULL;
780 long curpos;
781 TALLOC_CTX *ctx = talloc_tos();
782
783 mangled = mangle_is_mangled(name, conn->params);
784
785 /* handle null paths */
786 if ((path == NULL) || (*path == 0)) {
787 path = ".";
788 }
789
790 /* If we have a case-sensitive filesystem, it doesn't do us any
791 * good to search for a name. If a case variation of the name was
792 * there, then the original stat(2) would have found it.
793 */
794 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
795 errno = ENOENT;
796 return False;
797 }
798
799 /*
800 * The incoming name can be mangled, and if we de-mangle it
801 * here it will not compare correctly against the filename (name2)
802 * read from the directory and then mangled by the name_to_8_3()
803 * call. We need to mangle both names or neither.
804 * (JRA).
805 *
806 * Fix for bug found by Dina Fine. If in case sensitive mode then
807 * the mangle cache is no good (3 letter extension could be wrong
808 * case - so don't demangle in this case - leave as mangled and
809 * allow the mangling of the directory entry read (which is done
810 * case insensitively) to match instead. This will lead to more
811 * false positive matches but we fail completely without it. JRA.
812 */
813
814 if (mangled && !conn->case_sensitive) {
815 mangled = !mangle_lookup_name_from_8_3(ctx,
816 name,
817 &unmangled_name,
818 conn->params);
819 if (!mangled) {
820 /* Name is now unmangled. */
821 name = unmangled_name;
822 }
823 }
824
825 /* open the directory */
826 if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
827 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
828 TALLOC_FREE(unmangled_name);
829 return(False);
830 }
831
832 /* now scan for matching names */
833 curpos = 0;
834 while ((dname = ReadDirName(cur_dir, &curpos))) {
835
836 /* Is it dot or dot dot. */
837 if (ISDOT(dname) || ISDOTDOT(dname)) {
838 continue;
839 }
840
841 /*
842 * At this point dname is the unmangled name.
843 * name is either mangled or not, depending on the state
844 * of the "mangled" variable. JRA.
845 */
846
847 /*
848 * Check mangled name against mangled name, or unmangled name
849 * against unmangled name.
850 */
851
852 if ((mangled && mangled_equal(name,dname,conn->params)) ||
853 fname_equal(name, dname, conn->case_sensitive)) {
854 /* we've found the file, change it's name and return */
855 *found_name = talloc_strdup(ctx,dname);
856 TALLOC_FREE(unmangled_name);
857 TALLOC_FREE(cur_dir);
858 if (!*found_name) {
859 errno = ENOMEM;
860 return False;
861 }
862 return(True);
863 }
864 }
865
866 TALLOC_FREE(unmangled_name);
867 TALLOC_FREE(cur_dir);
868 errno = ENOENT;
869 return False;
870}
871
872static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
873 connection_struct *conn,
874 const char *orig_path,
875 const char *basepath,
876 const char *streamname,
877 SMB_STRUCT_STAT *pst,
878 char **path)
879{
880 SMB_STRUCT_STAT st;
881 char *result = NULL;
882 NTSTATUS status;
883 unsigned int i, num_streams;
884 struct stream_struct *streams = NULL;
885
886 result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname);
887 if (result == NULL) {
888 return NT_STATUS_NO_MEMORY;
889 }
890
891 if (SMB_VFS_STAT(conn, result, &st) == 0) {
892 *pst = st;
893 *path = result;
894 return NT_STATUS_OK;
895 }
896
897 if (errno != ENOENT) {
898 status = map_nt_error_from_unix(errno);
899 DEBUG(10, ("vfs_stat failed: %s\n", nt_errstr(status)));
900 goto fail;
901 }
902
903 status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx,
904 &num_streams, &streams);
905
906 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
907 SET_STAT_INVALID(*pst);
908 *path = result;
909 return NT_STATUS_OK;
910 }
911
912 if (!NT_STATUS_IS_OK(status)) {
913 DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
914 goto fail;
915 }
916
917 for (i=0; i<num_streams; i++) {
918 DEBUG(10, ("comparing [%s] and [%s]: ",
919 streamname, streams[i].name));
920 if (fname_equal(streamname, streams[i].name,
921 conn->case_sensitive)) {
922 DEBUGADD(10, ("equal\n"));
923 break;
924 }
925 DEBUGADD(10, ("not equal\n"));
926 }
927
928 if (i == num_streams) {
929 SET_STAT_INVALID(*pst);
930 *path = result;
931 TALLOC_FREE(streams);
932 return NT_STATUS_OK;
933 }
934
935 TALLOC_FREE(result);
936
937 result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name);
938 if (result == NULL) {
939 status = NT_STATUS_NO_MEMORY;
940 goto fail;
941 }
942
943 SET_STAT_INVALID(*pst);
944
945 if (SMB_VFS_STAT(conn, result, pst) == 0) {
946 stat_cache_add(orig_path, result, conn->case_sensitive);
947 }
948
949 *path = result;
950 TALLOC_FREE(streams);
951 return NT_STATUS_OK;
952
953 fail:
954 TALLOC_FREE(result);
955 TALLOC_FREE(streams);
956 return status;
957}
Note: See TracBrowser for help on using the repository browser.