source: trunk/server/source4/ntvfs/posix/pvfs_resolve.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 20.5 KB
Line 
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 unsigned int 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 pvfs_filename *name,
190 const char *s)
191{
192 char *p, *stream_name;
193 if (s[1] == '\0') {
194 return NT_STATUS_OBJECT_NAME_INVALID;
195 }
196 name->stream_name = stream_name = talloc_strdup(name, s+1);
197 if (name->stream_name == NULL) {
198 return NT_STATUS_NO_MEMORY;
199 }
200
201 p = stream_name;
202
203 while (*p) {
204 size_t c_size;
205 codepoint_t c = next_codepoint(p, &c_size);
206
207 switch (c) {
208 case '/':
209 case '\\':
210 return NT_STATUS_OBJECT_NAME_INVALID;
211 case ':':
212 *p= 0;
213 p++;
214 if (*p == '\0') {
215 return NT_STATUS_OBJECT_NAME_INVALID;
216 }
217 if (strcasecmp_m(p, "$DATA") != 0) {
218 if (strchr_m(p, ':')) {
219 return NT_STATUS_OBJECT_NAME_INVALID;
220 }
221 return NT_STATUS_INVALID_PARAMETER;
222 }
223 c_size = 0;
224 p--;
225 break;
226 }
227
228 p += c_size;
229 }
230
231 if (strcmp(name->stream_name, "") == 0) {
232 /*
233 * we don't set stream_name to NULL, here
234 * as this would be wrong for directories
235 *
236 * pvfs_fill_dos_info() will set it to NULL
237 * if it's not a directory.
238 */
239 name->stream_id = 0;
240 } else {
241 name->stream_id = pvfs_name_hash(name->stream_name,
242 strlen(name->stream_name));
243 }
244
245 return NT_STATUS_OK;
246}
247
248
249/*
250 convert a CIFS pathname to a unix pathname. Note that this does NOT
251 take into account case insensitivity, and in fact does not access
252 the filesystem at all. It is merely a reformatting and charset
253 checking routine.
254
255 errors are returned if the filename is illegal given the flags
256*/
257static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
258 unsigned int flags, struct pvfs_filename *name)
259{
260 char *ret, *p, *p_start;
261 NTSTATUS status;
262
263 name->original_name = talloc_strdup(name, cifs_name);
264
265 /* remove any :$DATA */
266 p = strrchr(name->original_name, ':');
267 if (p && strcasecmp_m(p, ":$DATA") == 0) {
268 if (p > name->original_name && p[-1] == ':') {
269 p--;
270 }
271 *p = 0;
272 }
273
274 name->stream_name = NULL;
275 name->stream_id = 0;
276 name->has_wildcard = false;
277
278 while (*cifs_name == '\\') {
279 cifs_name++;
280 }
281
282 if (*cifs_name == 0) {
283 name->full_name = talloc_asprintf(name, "%s/.", pvfs->base_directory);
284 if (name->full_name == NULL) {
285 return NT_STATUS_NO_MEMORY;
286 }
287 return NT_STATUS_OK;
288 }
289
290 ret = talloc_asprintf(name, "%s/%s", pvfs->base_directory, cifs_name);
291 if (ret == NULL) {
292 return NT_STATUS_NO_MEMORY;
293 }
294
295 p = ret + strlen(pvfs->base_directory) + 1;
296
297 /* now do an in-place conversion of '\' to '/', checking
298 for legal characters */
299 p_start = p;
300
301 while (*p) {
302 size_t c_size;
303 codepoint_t c = next_codepoint(p, &c_size);
304
305 if (c <= 0x1F) {
306 return NT_STATUS_OBJECT_NAME_INVALID;
307 }
308
309 switch (c) {
310 case '\\':
311 if (name->has_wildcard) {
312 /* wildcards are only allowed in the last part
313 of a name */
314 return NT_STATUS_OBJECT_NAME_INVALID;
315 }
316 if (p > p_start && (p[1] == '\\' || p[1] == '\0')) {
317 /* see if it is definately a "\\" or
318 * a trailing "\". If it is then fail here,
319 * and let the next layer up try again after
320 * pvfs_reduce_name() if it wants to. This is
321 * much more efficient on average than always
322 * scanning for these separately
323 */
324 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
325 } else {
326 *p = '/';
327 }
328 break;
329 case ':':
330 if (!(flags & PVFS_RESOLVE_STREAMS)) {
331 return NT_STATUS_OBJECT_NAME_INVALID;
332 }
333 if (name->has_wildcard) {
334 return NT_STATUS_OBJECT_NAME_INVALID;
335 }
336 status = parse_stream_name(name, p);
337 if (!NT_STATUS_IS_OK(status)) {
338 return status;
339 }
340 *p-- = 0;
341 break;
342 case '*':
343 case '>':
344 case '<':
345 case '?':
346 case '"':
347 if (!(flags & PVFS_RESOLVE_WILDCARD)) {
348 return NT_STATUS_OBJECT_NAME_INVALID;
349 }
350 name->has_wildcard = true;
351 break;
352 case '/':
353 case '|':
354 return NT_STATUS_OBJECT_NAME_INVALID;
355 case '.':
356 /* see if it is definately a .. or
357 . component. If it is then fail here, and
358 let the next layer up try again after
359 pvfs_reduce_name() if it wants to. This is
360 much more efficient on average than always
361 scanning for these separately */
362 if (p[1] == '.' &&
363 (p[2] == 0 || p[2] == '\\') &&
364 (p == p_start || p[-1] == '/')) {
365 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
366 }
367 if ((p[1] == 0 || p[1] == '\\') &&
368 (p == p_start || p[-1] == '/')) {
369 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
370 }
371 break;
372 }
373
374 p += c_size;
375 }
376
377 name->full_name = ret;
378
379 return NT_STATUS_OK;
380}
381
382
383/*
384 reduce a name that contains .. components or repeated \ separators
385 return NULL if it can't be reduced
386*/
387static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx,
388 const char **fname, unsigned int flags)
389{
390 codepoint_t c;
391 size_t c_size, len;
392 int i, num_components, err_count;
393 char **components;
394 char *p, *s, *ret;
395
396 s = talloc_strdup(mem_ctx, *fname);
397 if (s == NULL) return NT_STATUS_NO_MEMORY;
398
399 for (num_components=1, p=s; *p; p += c_size) {
400 c = next_codepoint(p, &c_size);
401 if (c == '\\') num_components++;
402 }
403
404 components = talloc_array(s, char *, num_components+1);
405 if (components == NULL) {
406 talloc_free(s);
407 return NT_STATUS_NO_MEMORY;
408 }
409
410 components[0] = s;
411 for (i=0, p=s; *p; p += c_size) {
412 c = next_codepoint(p, &c_size);
413 if (c == '\\') {
414 *p = 0;
415 components[++i] = p+1;
416 }
417 }
418 components[i+1] = NULL;
419
420 /*
421 rather bizarre!
422
423 '.' components are not allowed, but the rules for what error
424 code to give don't seem to make sense. This is a close
425 approximation.
426 */
427 for (err_count=i=0;components[i];i++) {
428 if (strcmp(components[i], "") == 0) {
429 continue;
430 }
431 if (ISDOT(components[i]) || err_count) {
432 err_count++;
433 }
434 }
435 if (err_count) {
436 if (flags & PVFS_RESOLVE_WILDCARD) err_count--;
437
438 if (err_count==1) {
439 return NT_STATUS_OBJECT_NAME_INVALID;
440 } else {
441 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
442 }
443 }
444
445 /* remove any null components */
446 for (i=0;components[i];i++) {
447 if (strcmp(components[i], "") == 0) {
448 memmove(&components[i], &components[i+1],
449 sizeof(char *)*(num_components-i));
450 i--;
451 continue;
452 }
453 if (ISDOTDOT(components[i])) {
454 if (i < 1) return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
455 memmove(&components[i-1], &components[i+1],
456 sizeof(char *)*(num_components-i));
457 i -= 2;
458 continue;
459 }
460 }
461
462 if (components[0] == NULL) {
463 talloc_free(s);
464 *fname = talloc_strdup(mem_ctx, "\\");
465 return NT_STATUS_OK;
466 }
467
468 for (len=i=0;components[i];i++) {
469 len += strlen(components[i]) + 1;
470 }
471
472 /* rebuild the name */
473 ret = talloc_array(mem_ctx, char, len+1);
474 if (ret == NULL) {
475 talloc_free(s);
476 return NT_STATUS_NO_MEMORY;
477 }
478
479 for (len=0,i=0;components[i];i++) {
480 size_t len1 = strlen(components[i]);
481 ret[len] = '\\';
482 memcpy(ret+len+1, components[i], len1);
483 len += len1 + 1;
484 }
485 ret[len] = 0;
486
487 talloc_set_name_const(ret, ret);
488
489 talloc_free(s);
490
491 *fname = ret;
492
493 return NT_STATUS_OK;
494}
495
496
497/*
498 resolve a name from relative client format to a struct pvfs_filename
499 the memory for the filename is made as a talloc child of 'name'
500
501 flags include:
502 PVFS_RESOLVE_NO_WILDCARD = wildcards are considered illegal characters
503 PVFS_RESOLVE_STREAMS = stream names are allowed
504
505 TODO: ../ collapsing, and outside share checking
506*/
507NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs,
508 struct ntvfs_request *req,
509 const char *cifs_name,
510 unsigned int flags, struct pvfs_filename **name)
511{
512 NTSTATUS status;
513
514 *name = talloc(req, struct pvfs_filename);
515 if (*name == NULL) {
516 return NT_STATUS_NO_MEMORY;
517 }
518
519 (*name)->exists = false;
520 (*name)->stream_exists = false;
521
522 if (!(pvfs->fs_attribs & FS_ATTR_NAMED_STREAMS)) {
523 flags &= ~PVFS_RESOLVE_STREAMS;
524 }
525
526 /* SMB2 doesn't allow a leading slash */
527 if (req->ctx->protocol == PROTOCOL_SMB2 &&
528 *cifs_name == '\\') {
529 return NT_STATUS_INVALID_PARAMETER;
530 }
531
532 /* do the basic conversion to a unix formatted path,
533 also checking for allowable characters */
534 status = pvfs_unix_path(pvfs, cifs_name, flags, *name);
535
536 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
537 /* it might contain .. components which need to be reduced */
538 status = pvfs_reduce_name(*name, &cifs_name, flags);
539 if (!NT_STATUS_IS_OK(status)) {
540 return status;
541 }
542 status = pvfs_unix_path(pvfs, cifs_name, flags, *name);
543 }
544
545 if (!NT_STATUS_IS_OK(status)) {
546 return status;
547 }
548
549 /* if it has a wildcard then no point doing a stat() of the
550 full name. Instead We need check if the directory exists
551 */
552 if ((*name)->has_wildcard) {
553 const char *p;
554 char *dir_name, *saved_name;
555 p = strrchr((*name)->full_name, '/');
556 if (p == NULL) {
557 /* root directory wildcard is OK */
558 return NT_STATUS_OK;
559 }
560 dir_name = talloc_strndup(*name, (*name)->full_name, (p-(*name)->full_name));
561 if (stat(dir_name, &(*name)->st) == 0) {
562 talloc_free(dir_name);
563 return NT_STATUS_OK;
564 }
565 /* we need to search for a matching name */
566 saved_name = (*name)->full_name;
567 (*name)->full_name = dir_name;
568 status = pvfs_case_search(pvfs, *name, flags);
569 if (!NT_STATUS_IS_OK(status)) {
570 /* the directory doesn't exist */
571 (*name)->full_name = saved_name;
572 return status;
573 }
574 /* it does exist, but might need a case change */
575 if (dir_name != (*name)->full_name) {
576 (*name)->full_name = talloc_asprintf(*name, "%s%s",
577 (*name)->full_name, p);
578 NT_STATUS_HAVE_NO_MEMORY((*name)->full_name);
579 } else {
580 (*name)->full_name = saved_name;
581 talloc_free(dir_name);
582 }
583 return NT_STATUS_OK;
584 }
585
586 /* if we can stat() the full name now then we are done */
587 if (stat((*name)->full_name, &(*name)->st) == 0) {
588 (*name)->exists = true;
589 return pvfs_fill_dos_info(pvfs, *name, flags, -1);
590 }
591
592 /* search for a matching filename */
593 status = pvfs_case_search(pvfs, *name, flags);
594
595 return status;
596}
597
598
599/*
600 do a partial resolve, returning a pvfs_filename structure given a
601 base path and a relative component. It is an error if the file does
602 not exist. No case-insensitive matching is done.
603
604 this is used in places like directory searching where we need a pvfs_filename
605 to pass to a function, but already know the unix base directory and component
606*/
607NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
608 const char *unix_dir, const char *fname,
609 unsigned int flags, struct pvfs_filename **name)
610{
611 NTSTATUS status;
612
613 *name = talloc(mem_ctx, struct pvfs_filename);
614 if (*name == NULL) {
615 return NT_STATUS_NO_MEMORY;
616 }
617
618 (*name)->full_name = talloc_asprintf(*name, "%s/%s", unix_dir, fname);
619 if ((*name)->full_name == NULL) {
620 return NT_STATUS_NO_MEMORY;
621 }
622
623 if (stat((*name)->full_name, &(*name)->st) == -1) {
624 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
625 }
626
627 (*name)->exists = true;
628 (*name)->stream_exists = true;
629 (*name)->has_wildcard = false;
630 (*name)->original_name = talloc_strdup(*name, fname);
631 (*name)->stream_name = NULL;
632 (*name)->stream_id = 0;
633
634 status = pvfs_fill_dos_info(pvfs, *name, flags, -1);
635
636 return status;
637}
638
639
640/*
641 fill in the pvfs_filename info for an open file, given the current
642 info for a (possibly) non-open file. This is used by places that need
643 to update the pvfs_filename stat information, and by pvfs_open()
644*/
645NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
646 struct pvfs_filename *name, unsigned int flags)
647{
648 dev_t device = (dev_t)0;
649 ino_t inode = 0;
650
651 if (name->exists) {
652 device = name->st.st_dev;
653 inode = name->st.st_ino;
654 }
655
656 if (fd == -1) {
657 if (stat(name->full_name, &name->st) == -1) {
658 return NT_STATUS_INVALID_HANDLE;
659 }
660 } else {
661 if (fstat(fd, &name->st) == -1) {
662 return NT_STATUS_INVALID_HANDLE;
663 }
664 }
665
666 if (name->exists &&
667 (device != name->st.st_dev || inode != name->st.st_ino)) {
668 /* the file we are looking at has changed! this could
669 be someone trying to exploit a race
670 condition. Certainly we don't want to continue
671 operating on this file */
672 DEBUG(0,("pvfs: WARNING: file '%s' changed during resolve - failing\n",
673 name->full_name));
674 return NT_STATUS_UNEXPECTED_IO_ERROR;
675 }
676
677 name->exists = true;
678
679 return pvfs_fill_dos_info(pvfs, name, flags, fd);
680}
681
682/*
683 fill in the pvfs_filename info for an open file, given the current
684 info for a (possibly) non-open file. This is used by places that need
685 to update the pvfs_filename stat information, and the path
686 after a possible rename on a different handle.
687*/
688NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs,
689 struct pvfs_file_handle *h)
690{
691 NTSTATUS status;
692
693 if (h->have_opendb_entry) {
694 struct odb_lock *lck;
695 char *name = NULL;
696
697 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
698 if (lck == NULL) {
699 DEBUG(0,("%s: failed to lock file '%s' in opendb\n",
700 __FUNCTION__, h->name->full_name));
701 /* we were supposed to do a blocking lock, so something
702 is badly wrong! */
703 return NT_STATUS_INTERNAL_DB_CORRUPTION;
704 }
705
706 status = odb_get_path(lck, (const char **) &name);
707 if (NT_STATUS_IS_OK(status)) {
708 /*
709 * This relies an the fact that
710 * renames of open files are only
711 * allowed by setpathinfo() and setfileinfo()
712 * and there're only renames within the same
713 * directory supported
714 */
715 if (strcmp(h->name->full_name, name) != 0) {
716 const char *orig_dir;
717 const char *new_file;
718 char *new_orig;
719 char *delim;
720
721 delim = strrchr(name, '/');
722 if (!delim) {
723 talloc_free(lck);
724 return NT_STATUS_INTERNAL_ERROR;
725 }
726
727 new_file = delim + 1;
728 delim = strrchr(h->name->original_name, '\\');
729 if (delim) {
730 delim[0] = '\0';
731 orig_dir = h->name->original_name;
732 new_orig = talloc_asprintf(h->name, "%s\\%s",
733 orig_dir, new_file);
734 if (!new_orig) {
735 talloc_free(lck);
736 return NT_STATUS_NO_MEMORY;
737 }
738 } else {
739 new_orig = talloc_strdup(h->name, new_file);
740 if (!new_orig) {
741 talloc_free(lck);
742 return NT_STATUS_NO_MEMORY;
743 }
744 }
745
746 talloc_free(h->name->original_name);
747 talloc_free(h->name->full_name);
748 h->name->full_name = talloc_steal(h->name, name);
749 h->name->original_name = new_orig;
750 }
751 }
752
753 talloc_free(lck);
754 }
755
756 /*
757 * TODO: pass PVFS_RESOLVE_NO_OPENDB and get
758 * the write time from odb_lock() above.
759 */
760 status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, 0);
761 NT_STATUS_NOT_OK_RETURN(status);
762
763 if (!null_nttime(h->write_time.close_time)) {
764 h->name->dos.write_time = h->write_time.close_time;
765 }
766
767 return NT_STATUS_OK;
768}
769
770
771/*
772 resolve the parent of a given name
773*/
774NTSTATUS pvfs_resolve_parent(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
775 const struct pvfs_filename *child,
776 struct pvfs_filename **name)
777{
778 NTSTATUS status;
779 char *p;
780
781 *name = talloc(mem_ctx, struct pvfs_filename);
782 if (*name == NULL) {
783 return NT_STATUS_NO_MEMORY;
784 }
785
786 (*name)->full_name = talloc_strdup(*name, child->full_name);
787 if ((*name)->full_name == NULL) {
788 return NT_STATUS_NO_MEMORY;
789 }
790
791 p = strrchr_m((*name)->full_name, '/');
792 if (p == NULL) {
793 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
794 }
795
796 /* this handles the root directory */
797 if (p == (*name)->full_name) {
798 p[1] = 0;
799 } else {
800 p[0] = 0;
801 }
802
803 if (stat((*name)->full_name, &(*name)->st) == -1) {
804 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
805 }
806
807 (*name)->exists = true;
808 (*name)->stream_exists = true;
809 (*name)->has_wildcard = false;
810 /* we can't get the correct 'original_name', but for the purposes
811 of this call this is close enough */
812 (*name)->original_name = talloc_strdup(*name, child->original_name);
813 if ((*name)->original_name == NULL) {
814 return NT_STATUS_NO_MEMORY;
815 }
816 (*name)->stream_name = NULL;
817 (*name)->stream_id = 0;
818
819 status = pvfs_fill_dos_info(pvfs, *name, PVFS_RESOLVE_NO_OPENDB, -1);
820
821 return status;
822}
Note: See TracBrowser for help on using the repository browser.