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