Change get_real_filename() to unix syscall conventions, make it non-static
[kai/samba.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 int get_real_filename(connection_struct *conn, const char *path,
30                              const char *name, TALLOC_CTX *mem_ctx,
31                              char **found_name);
32 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
33                                   connection_struct *conn,
34                                   const char *orig_path,
35                                   const char *basepath,
36                                   const char *streamname,
37                                   SMB_STRUCT_STAT *pst,
38                                   char **path);
39
40 /****************************************************************************
41  Mangle the 2nd name and check if it is then equal to the first name.
42 ****************************************************************************/
43
44 static bool mangled_equal(const char *name1,
45                         const char *name2,
46                         const struct share_params *p)
47 {
48         char mname[13];
49
50         if (!name_to_8_3(name2, mname, False, p)) {
51                 return False;
52         }
53         return strequal(name1, mname);
54 }
55
56 /****************************************************************************
57  Cope with the differing wildcard and non-wildcard error cases.
58 ****************************************************************************/
59
60 static NTSTATUS determine_path_error(const char *name,
61                         bool allow_wcard_last_component)
62 {
63         const char *p;
64
65         if (!allow_wcard_last_component) {
66                 /* Error code within a pathname. */
67                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
68         }
69
70         /* We're terminating here so we
71          * can be a little slower and get
72          * the error code right. Windows
73          * treats the last part of the pathname
74          * separately I think, so if the last
75          * component is a wildcard then we treat
76          * this ./ as "end of component" */
77
78         p = strchr(name, '/');
79
80         if (!p && (ms_has_wild(name) || ISDOT(name))) {
81                 /* Error code at the end of a pathname. */
82                 return NT_STATUS_OBJECT_NAME_INVALID;
83         } else {
84                 /* Error code within a pathname. */
85                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
86         }
87 }
88
89 /****************************************************************************
90 This routine is called to convert names from the dos namespace to unix
91 namespace. It needs to handle any case conversions, mangling, format
92 changes etc.
93
94 We assume that we have already done a chdir() to the right "root" directory
95 for this service.
96
97 The function will return an NTSTATUS error if some part of the name except for
98 the last part cannot be resolved, else NT_STATUS_OK.
99
100 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't
101 get any fatal errors that should immediately terminate the calling
102 SMB processing whilst resolving.
103
104 If the saved_last_component != 0, then the unmodified last component
105 of the pathname is returned there. If saved_last_component == 0 then nothing
106 is returned there.
107
108 If last_component_wcard is true then a MS wildcard was detected and
109 should be allowed in the last component of the path only.
110
111 On exit from unix_convert, if *pst was not null, then the file stat
112 struct will be returned if the file exists and was found, if not this
113 stat struct will be filled with zeros (and this can be detected by checking
114 for nlinks = 0, which can never be true for any file).
115 ****************************************************************************/
116
117 NTSTATUS 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         if (!(name = talloc_strdup(ctx, orig_path))) {
199                 DEBUG(0, ("talloc_strdup failed\n"));
200                 return NT_STATUS_NO_MEMORY;
201         }
202
203         /*
204          * Large directory fix normalization. If we're case sensitive, and
205          * the case preserving parameters are set to "no", normalize the case of
206          * the incoming filename from the client WHETHER IT EXISTS OR NOT !
207          * This is in conflict with the current (3.0.20) man page, but is
208          * what people expect from the "large directory howto". I'll update
209          * the man page. Thanks to jht@samba.org for finding this. JRA.
210          */
211
212         if (conn->case_sensitive && !conn->case_preserve &&
213                         !conn->short_case_preserve) {
214                 strnorm(name, lp_defaultcase(SNUM(conn)));
215         }
216
217         /*
218          * Ensure saved_last_component is valid even if file exists.
219          */
220
221         if(pp_saved_last_component) {
222                 end = strrchr_m(name, '/');
223                 if (end) {
224                         *pp_saved_last_component = talloc_strdup(ctx, end + 1);
225                 } else {
226                         *pp_saved_last_component = talloc_strdup(ctx,
227                                                         name);
228                 }
229         }
230
231         if (!lp_posix_pathnames()) {
232                 stream = strchr_m(name, ':');
233
234                 if (stream != NULL) {
235                         char *tmp = talloc_strdup(ctx, stream);
236                         if (tmp == NULL) {
237                                 TALLOC_FREE(name);
238                                 return NT_STATUS_NO_MEMORY;
239                         }
240                         *stream = '\0';
241                         stream = tmp;
242                 }
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                             (get_real_filename(
438                                      conn, dirpath, start,
439                                      talloc_tos(), &found_name) == -1)) {
440                                 char *unmangled;
441
442                                 if (end) {
443                                         /*
444                                          * An intermediate part of the name
445                                          * can't be found.
446                                          */
447                                         DEBUG(5,("Intermediate not found %s\n",
448                                                         start));
449                                         *end = '/';
450
451                                         /*
452                                          * We need to return the fact that the
453                                          * intermediate name resolution failed.
454                                          * This is used to return an error of
455                                          * ERRbadpath rather than ERRbadfile.
456                                          * Some Windows applications depend on
457                                          * the difference between these two
458                                          * errors.
459                                          */
460
461                                         /*
462                                          * ENOENT, ENOTDIR and ELOOP all map
463                                          * to NT_STATUS_OBJECT_PATH_NOT_FOUND
464                                          * in the filename walk.
465                                          */
466
467                                         if (errno == ENOENT ||
468                                                         errno == ENOTDIR ||
469                                                         errno == ELOOP) {
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
728 NTSTATUS 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
757 static 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
773 int get_real_filename(connection_struct *conn, const char *path,
774                       const char *name, TALLOC_CTX *mem_ctx,
775                       char **found_name)
776 {
777         struct smb_Dir *cur_dir;
778         const char *dname;
779         bool mangled;
780         char *unmangled_name = NULL;
781         long curpos;
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 -1;
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(talloc_tos(), name,
816                                                        &unmangled_name,
817                                                        conn->params);
818                 if (!mangled) {
819                         /* Name is now unmangled. */
820                         name = unmangled_name;
821                 }
822         }
823
824         /* open the directory */
825         if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
826                 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
827                 TALLOC_FREE(unmangled_name);
828                 return -1;
829         }
830
831         /* now scan for matching names */
832         curpos = 0;
833         while ((dname = ReadDirName(cur_dir, &curpos))) {
834
835                 /* Is it dot or dot dot. */
836                 if (ISDOT(dname) || ISDOTDOT(dname)) {
837                         continue;
838                 }
839
840                 /*
841                  * At this point dname is the unmangled name.
842                  * name is either mangled or not, depending on the state
843                  * of the "mangled" variable. JRA.
844                  */
845
846                 /*
847                  * Check mangled name against mangled name, or unmangled name
848                  * against unmangled name.
849                  */
850
851                 if ((mangled && mangled_equal(name,dname,conn->params)) ||
852                         fname_equal(name, dname, conn->case_sensitive)) {
853                         /* we've found the file, change it's name and return */
854                         *found_name = talloc_strdup(mem_ctx, dname);
855                         TALLOC_FREE(unmangled_name);
856                         TALLOC_FREE(cur_dir);
857                         if (!*found_name) {
858                                 errno = ENOMEM;
859                                 return -1;
860                         }
861                         return 0;
862                 }
863         }
864
865         TALLOC_FREE(unmangled_name);
866         TALLOC_FREE(cur_dir);
867         errno = ENOENT;
868         return -1;
869 }
870
871 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
872                                   connection_struct *conn,
873                                   const char *orig_path,
874                                   const char *basepath,
875                                   const char *streamname,
876                                   SMB_STRUCT_STAT *pst,
877                                   char **path)
878 {
879         SMB_STRUCT_STAT st;
880         char *result = NULL;
881         NTSTATUS status;
882         unsigned int i, num_streams;
883         struct stream_struct *streams = NULL;
884
885         result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname);
886         if (result == NULL) {
887                 return NT_STATUS_NO_MEMORY;
888         }
889
890         if (SMB_VFS_STAT(conn, result, &st) == 0) {
891                 *pst = st;
892                 *path = result;
893                 return NT_STATUS_OK;
894         }
895
896         if (errno != ENOENT) {
897                 status = map_nt_error_from_unix(errno);
898                 DEBUG(10, ("vfs_stat failed: %s\n", nt_errstr(status)));
899                 goto fail;
900         }
901
902         status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx,
903                                     &num_streams, &streams);
904
905         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
906                 SET_STAT_INVALID(*pst);
907                 *path = result;
908                 return NT_STATUS_OK;
909         }
910
911         if (!NT_STATUS_IS_OK(status)) {
912                 DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
913                 goto fail;
914         }
915
916         for (i=0; i<num_streams; i++) {
917                 DEBUG(10, ("comparing [%s] and [%s]: ",
918                            streamname, streams[i].name));
919                 if (fname_equal(streamname, streams[i].name,
920                                 conn->case_sensitive)) {
921                         DEBUGADD(10, ("equal\n"));
922                         break;
923                 }
924                 DEBUGADD(10, ("not equal\n"));
925         }
926
927         if (i == num_streams) {
928                 SET_STAT_INVALID(*pst);
929                 *path = result;
930                 TALLOC_FREE(streams);
931                 return NT_STATUS_OK;
932         }
933
934         TALLOC_FREE(result);
935
936         result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name);
937         if (result == NULL) {
938                 status = NT_STATUS_NO_MEMORY;
939                 goto fail;
940         }
941
942         SET_STAT_INVALID(*pst);
943
944         if (SMB_VFS_STAT(conn, result, pst) == 0) {
945                 stat_cache_add(orig_path, result, conn->case_sensitive);
946         }
947
948         *path = result;
949         TALLOC_FREE(streams);
950         return NT_STATUS_OK;
951
952  fail:
953         TALLOC_FREE(result);
954         TALLOC_FREE(streams);
955         return status;
956 }