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