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