Line data Source code
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 38107250 : static int component_compare(struct pvfs_state *pvfs, const char *comp, const char *name)
38 : {
39 0 : int ret;
40 :
41 38107250 : ret = strcasecmp_m(comp, name);
42 :
43 38107250 : if (ret != 0) {
44 38106917 : char *shortname = pvfs_short_name_component(pvfs, name);
45 38106917 : if (shortname) {
46 359922 : ret = strcasecmp_m(comp, shortname);
47 359922 : talloc_free(shortname);
48 : }
49 : }
50 :
51 38107250 : 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 172325 : static 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 0 : size_t num_components;
66 0 : char **components;
67 0 : char *p, *partial_name;
68 0 : size_t i;
69 :
70 : /* break up the full name into pathname components */
71 172325 : num_components=2;
72 172325 : p = name->full_name + strlen(pvfs->base_directory) + 1;
73 :
74 3417036 : for (;*p;p++) {
75 3244711 : if (*p == '/') {
76 290778 : num_components++;
77 : }
78 : }
79 :
80 172325 : components = talloc_array(name, char *, num_components);
81 172325 : p = name->full_name + strlen(pvfs->base_directory);
82 172325 : *p++ = 0;
83 :
84 172325 : components[0] = name->full_name;
85 :
86 635428 : for (i=1;i<num_components;i++) {
87 463103 : components[i] = p;
88 463103 : p = strchr(p, '/');
89 463103 : if (p) *p++ = 0;
90 463103 : if (pvfs_is_reserved_name(pvfs, components[i])) {
91 0 : return NT_STATUS_ACCESS_DENIED;
92 : }
93 : }
94 :
95 172325 : partial_name = talloc_strdup(name, components[0]);
96 172325 : if (!partial_name) {
97 0 : 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 635304 : for (i=1;i<num_components;i++) {
103 0 : char *test_name;
104 0 : DIR *dir;
105 0 : struct dirent *de;
106 0 : char *long_component;
107 :
108 : /* possibly remap from the short name cache */
109 463024 : long_component = pvfs_mangled_lookup(pvfs, name, components[i]);
110 463024 : if (long_component) {
111 26 : components[i] = long_component;
112 : }
113 :
114 463024 : test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]);
115 463024 : if (!test_name) {
116 0 : return NT_STATUS_NO_MEMORY;
117 : }
118 :
119 : /* check if this component exists as-is */
120 463024 : if (stat(test_name, &name->st) == 0) {
121 290591 : if (i<num_components-1 && !S_ISDIR(name->st.st_mode)) {
122 5 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
123 : }
124 290586 : talloc_free(partial_name);
125 290586 : partial_name = test_name;
126 290586 : if (i == num_components - 1) {
127 178 : name->exists = true;
128 : }
129 290586 : 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 172433 : if ((pvfs->flags & PVFS_FLAG_CI_FILESYSTEM) &&
136 0 : !pvfs_is_mangled_component(pvfs, components[i])) {
137 0 : if (i < num_components-1) {
138 0 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
139 : }
140 0 : partial_name = test_name;
141 0 : continue;
142 : }
143 :
144 172433 : dir = opendir(partial_name);
145 172433 : if (!dir) {
146 0 : return pvfs_map_errno(pvfs, errno);
147 : }
148 :
149 38279350 : while ((de = readdir(dir))) {
150 38107250 : if (component_compare(pvfs, components[i], de->d_name) == 0) {
151 333 : break;
152 : }
153 : }
154 :
155 172433 : if (!de) {
156 172100 : if (i < num_components-1) {
157 40 : closedir(dir);
158 40 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
159 : }
160 : } else {
161 333 : components[i] = talloc_strdup(name, de->d_name);
162 : }
163 172393 : test_name = talloc_asprintf(name, "%s/%s", partial_name, components[i]);
164 172393 : talloc_free(partial_name);
165 172393 : partial_name = test_name;
166 :
167 172393 : closedir(dir);
168 : }
169 :
170 172280 : if (!name->exists) {
171 172102 : if (stat(partial_name, &name->st) == 0) {
172 42 : name->exists = true;
173 : }
174 : }
175 :
176 172280 : talloc_free(name->full_name);
177 172280 : name->full_name = partial_name;
178 :
179 172280 : if (name->exists) {
180 220 : return pvfs_fill_dos_info(pvfs, name, flags, -1);
181 : }
182 :
183 172060 : return NT_STATUS_OK;
184 : }
185 :
186 : /*
187 : parse a alternate data stream name
188 : */
189 425 : static NTSTATUS parse_stream_name(struct pvfs_filename *name,
190 : const char *s)
191 : {
192 0 : char *p, *stream_name;
193 425 : if (s[1] == '\0') {
194 1 : return NT_STATUS_OBJECT_NAME_INVALID;
195 : }
196 424 : name->stream_name = stream_name = talloc_strdup(name, s+1);
197 424 : if (name->stream_name == NULL) {
198 0 : return NT_STATUS_NO_MEMORY;
199 : }
200 :
201 424 : p = stream_name;
202 :
203 5179 : while (*p) {
204 0 : size_t c_size;
205 4776 : codepoint_t c = next_codepoint(p, &c_size);
206 :
207 4776 : switch (c) {
208 4 : case '/':
209 : case '\\':
210 21 : return NT_STATUS_OBJECT_NAME_INVALID;
211 340 : case ':':
212 340 : *p= 0;
213 340 : p++;
214 340 : if (*p == '\0') {
215 6 : return NT_STATUS_OBJECT_NAME_INVALID;
216 : }
217 334 : if (strcasecmp_m(p, "$DATA") != 0) {
218 11 : if (strchr_m(p, ':')) {
219 2 : return NT_STATUS_OBJECT_NAME_INVALID;
220 : }
221 9 : return NT_STATUS_INVALID_PARAMETER;
222 : }
223 323 : c_size = 0;
224 323 : p--;
225 323 : break;
226 : }
227 :
228 4755 : p += c_size;
229 : }
230 :
231 403 : 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 11 : name->stream_id = 0;
240 : } else {
241 392 : name->stream_id = pvfs_name_hash(name->stream_name,
242 392 : strlen(name->stream_name));
243 : }
244 :
245 403 : 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 : */
257 336293 : static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
258 : unsigned int flags, struct pvfs_filename *name)
259 : {
260 0 : char *ret, *p, *p_start;
261 0 : NTSTATUS status;
262 :
263 336293 : name->original_name = talloc_strdup(name, cifs_name);
264 :
265 : /* remove any :$DATA */
266 336293 : p = strrchr(name->original_name, ':');
267 336293 : if (p && strcasecmp_m(p, ":$DATA") == 0) {
268 332 : if (p > name->original_name && p[-1] == ':') {
269 11 : p--;
270 : }
271 332 : *p = 0;
272 : }
273 :
274 336293 : name->stream_name = NULL;
275 336293 : name->stream_id = 0;
276 336293 : name->has_wildcard = false;
277 :
278 462703 : while (*cifs_name == '\\') {
279 126410 : cifs_name++;
280 : }
281 :
282 336293 : if (*cifs_name == 0) {
283 6437 : name->full_name = talloc_asprintf(name, "%s/.", pvfs->base_directory);
284 6437 : if (name->full_name == NULL) {
285 0 : return NT_STATUS_NO_MEMORY;
286 : }
287 6437 : return NT_STATUS_OK;
288 : }
289 :
290 329856 : ret = talloc_asprintf(name, "%s/%s", pvfs->base_directory, cifs_name);
291 329856 : if (ret == NULL) {
292 0 : return NT_STATUS_NO_MEMORY;
293 : }
294 :
295 329856 : p = ret + strlen(pvfs->base_directory) + 1;
296 :
297 : /* now do an in-place conversion of '\' to '/', checking
298 : for legal characters */
299 329856 : p_start = p;
300 :
301 6362369 : while (*p) {
302 0 : size_t c_size;
303 6032971 : codepoint_t c = next_codepoint(p, &c_size);
304 :
305 6032971 : if (c <= 0x1F) {
306 248 : return NT_STATUS_OBJECT_NAME_INVALID;
307 : }
308 :
309 6032723 : switch (c) {
310 474321 : case '\\':
311 474321 : if (name->has_wildcard) {
312 : /* wildcards are only allowed in the last part
313 : of a name */
314 0 : return NT_STATUS_OBJECT_NAME_INVALID;
315 : }
316 474321 : if (p > p_start && (p[1] == '\\' || p[1] == '\0')) {
317 : /* see if it is definitely 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 61 : return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
325 : } else {
326 474260 : *p = '/';
327 : }
328 514793 : break;
329 440 : case ':':
330 440 : if (!(flags & PVFS_RESOLVE_STREAMS)) {
331 15 : return NT_STATUS_OBJECT_NAME_INVALID;
332 : }
333 425 : if (name->has_wildcard) {
334 0 : return NT_STATUS_OBJECT_NAME_INVALID;
335 : }
336 425 : status = parse_stream_name(name, p);
337 425 : if (!NT_STATUS_IS_OK(status)) {
338 22 : return status;
339 : }
340 403 : *p-- = 0;
341 403 : break;
342 6440 : case '*':
343 : case '>':
344 : case '<':
345 : case '?':
346 : case '"':
347 6440 : if (!(flags & PVFS_RESOLVE_WILDCARD)) {
348 16 : return NT_STATUS_OBJECT_NAME_INVALID;
349 : }
350 6424 : name->has_wildcard = true;
351 6424 : break;
352 9 : case '/':
353 : case '|':
354 9 : return NT_STATUS_OBJECT_NAME_INVALID;
355 33793 : case '.':
356 : /* see if it is definitely 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 33793 : if (p[1] == '.' &&
363 61 : (p[2] == 0 || p[2] == '\\') &&
364 21 : (p == p_start || p[-1] == '/')) {
365 25 : return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
366 : }
367 33768 : if ((p[1] == 0 || p[1] == '\\') &&
368 90 : (p == p_start || p[-1] == '/')) {
369 62 : return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
370 : }
371 33706 : break;
372 : }
373 :
374 6032513 : p += c_size;
375 : }
376 :
377 329398 : name->full_name = ret;
378 :
379 329398 : 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 : */
387 148 : static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx,
388 : const char **fname, unsigned int flags)
389 : {
390 0 : codepoint_t c;
391 0 : size_t c_size, len;
392 0 : size_t i, num_components, err_count;
393 0 : char **components;
394 0 : char *p, *s, *ret;
395 :
396 148 : s = talloc_strdup(mem_ctx, *fname);
397 148 : if (s == NULL) return NT_STATUS_NO_MEMORY;
398 :
399 2650 : for (num_components=1, p=s; *p; p += c_size) {
400 2502 : c = next_codepoint(p, &c_size);
401 2502 : if (c == '\\') num_components++;
402 : }
403 :
404 148 : components = talloc_array(s, char *, num_components+1);
405 148 : if (components == NULL) {
406 0 : talloc_free(s);
407 0 : return NT_STATUS_NO_MEMORY;
408 : }
409 :
410 148 : components[0] = s;
411 2650 : for (i=0, p=s; *p; p += c_size) {
412 2502 : c = next_codepoint(p, &c_size);
413 2502 : if (c == '\\') {
414 471 : *p = 0;
415 471 : components[++i] = p+1;
416 : }
417 : }
418 148 : 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 767 : for (err_count=i=0;components[i];i++) {
428 619 : if (strcmp(components[i], "") == 0) {
429 257 : continue;
430 : }
431 362 : if (ISDOT(components[i]) || err_count) {
432 136 : err_count++;
433 : }
434 : }
435 148 : if (err_count > 0) {
436 62 : if (flags & PVFS_RESOLVE_WILDCARD) err_count--;
437 :
438 62 : if (err_count==1) {
439 25 : return NT_STATUS_OBJECT_NAME_INVALID;
440 : } else {
441 37 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
442 : }
443 : }
444 :
445 : /* remove any null components */
446 407 : for (i=0;components[i];i++) {
447 333 : if (strcmp(components[i], "") == 0) {
448 141 : memmove(&components[i], &components[i+1],
449 141 : sizeof(char *)*(num_components-i));
450 141 : i--;
451 141 : continue;
452 : }
453 192 : if (ISDOTDOT(components[i])) {
454 34 : if (i < 1) return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
455 22 : memmove(&components[i-1], &components[i+1],
456 22 : sizeof(char *)*(num_components-i));
457 22 : i -= 2;
458 22 : continue;
459 : }
460 : }
461 :
462 74 : if (components[0] == NULL) {
463 3 : talloc_free(s);
464 3 : *fname = talloc_strdup(mem_ctx, "\\");
465 3 : return NT_STATUS_OK;
466 : }
467 :
468 207 : for (len=i=0;components[i];i++) {
469 136 : len += strlen(components[i]) + 1;
470 : }
471 :
472 : /* rebuild the name */
473 71 : ret = talloc_array(mem_ctx, char, len+1);
474 71 : if (ret == NULL) {
475 0 : talloc_free(s);
476 0 : return NT_STATUS_NO_MEMORY;
477 : }
478 :
479 207 : for (len=0,i=0;components[i];i++) {
480 136 : size_t len1 = strlen(components[i]);
481 136 : ret[len] = '\\';
482 136 : memcpy(ret+len+1, components[i], len1);
483 136 : len += len1 + 1;
484 : }
485 71 : ret[len] = 0;
486 :
487 71 : talloc_set_name_const(ret, ret);
488 :
489 71 : talloc_free(s);
490 :
491 71 : *fname = ret;
492 :
493 71 : 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 : */
507 336223 : NTSTATUS 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 0 : NTSTATUS status;
513 :
514 336223 : *name = talloc(req, struct pvfs_filename);
515 336223 : if (*name == NULL) {
516 0 : return NT_STATUS_NO_MEMORY;
517 : }
518 :
519 336223 : (*name)->exists = false;
520 336223 : (*name)->stream_exists = false;
521 336223 : (*name)->allow_override = false;
522 :
523 336223 : if (!(pvfs->fs_attribs & FS_ATTR_NAMED_STREAMS)) {
524 0 : flags &= ~PVFS_RESOLVE_STREAMS;
525 : }
526 :
527 : /* SMB2 doesn't allow a leading slash */
528 336223 : if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
529 209406 : *cifs_name == '\\') {
530 4 : return NT_STATUS_INVALID_PARAMETER;
531 : }
532 :
533 : /* do the basic conversion to a unix formatted path,
534 : also checking for allowable characters */
535 336219 : status = pvfs_unix_path(pvfs, cifs_name, flags, *name);
536 :
537 336219 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
538 : /* it might contain .. components which need to be reduced */
539 148 : status = pvfs_reduce_name(*name, &cifs_name, flags);
540 148 : if (!NT_STATUS_IS_OK(status)) {
541 74 : return status;
542 : }
543 74 : status = pvfs_unix_path(pvfs, cifs_name, flags, *name);
544 : }
545 :
546 336145 : if (!NT_STATUS_IS_OK(status)) {
547 310 : return status;
548 : }
549 :
550 : /* if it has a wildcard then no point doing a stat() of the
551 : full name. Instead We need check if the directory exists
552 : */
553 335835 : if ((*name)->has_wildcard) {
554 0 : const char *p;
555 0 : char *dir_name, *saved_name;
556 5410 : p = strrchr((*name)->full_name, '/');
557 5410 : if (p == NULL) {
558 : /* root directory wildcard is OK */
559 0 : return NT_STATUS_OK;
560 : }
561 5410 : dir_name = talloc_strndup(*name, (*name)->full_name, (p-(*name)->full_name));
562 5410 : if (stat(dir_name, &(*name)->st) == 0) {
563 5405 : talloc_free(dir_name);
564 5405 : return NT_STATUS_OK;
565 : }
566 : /* we need to search for a matching name */
567 5 : saved_name = (*name)->full_name;
568 5 : (*name)->full_name = dir_name;
569 5 : status = pvfs_case_search(pvfs, *name, flags);
570 5 : if (!NT_STATUS_IS_OK(status)) {
571 : /* the directory doesn't exist */
572 0 : (*name)->full_name = saved_name;
573 0 : return status;
574 : }
575 : /* it does exist, but might need a case change */
576 5 : if (dir_name != (*name)->full_name) {
577 10 : (*name)->full_name = talloc_asprintf(*name, "%s%s",
578 5 : (*name)->full_name, p);
579 5 : NT_STATUS_HAVE_NO_MEMORY((*name)->full_name);
580 : } else {
581 0 : (*name)->full_name = saved_name;
582 0 : talloc_free(dir_name);
583 : }
584 5 : return NT_STATUS_OK;
585 : }
586 :
587 : /* if we can stat() the full name now then we are done */
588 330425 : if (stat((*name)->full_name, &(*name)->st) == 0) {
589 158105 : (*name)->exists = true;
590 158105 : return pvfs_fill_dos_info(pvfs, *name, flags, -1);
591 : }
592 :
593 : /* search for a matching filename */
594 172320 : status = pvfs_case_search(pvfs, *name, flags);
595 :
596 172320 : return status;
597 : }
598 :
599 :
600 : /*
601 : do a partial resolve, returning a pvfs_filename structure given a
602 : base path and a relative component. It is an error if the file does
603 : not exist. No case-insensitive matching is done.
604 :
605 : this is used in places like directory searching where we need a pvfs_filename
606 : to pass to a function, but already know the unix base directory and component
607 : */
608 129311 : NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
609 : const char *unix_dir, const char *fname,
610 : unsigned int flags, struct pvfs_filename **name)
611 : {
612 0 : NTSTATUS status;
613 :
614 129311 : *name = talloc(mem_ctx, struct pvfs_filename);
615 129311 : if (*name == NULL) {
616 0 : return NT_STATUS_NO_MEMORY;
617 : }
618 :
619 129311 : (*name)->full_name = talloc_asprintf(*name, "%s/%s", unix_dir, fname);
620 129311 : if ((*name)->full_name == NULL) {
621 0 : return NT_STATUS_NO_MEMORY;
622 : }
623 :
624 129311 : if (stat((*name)->full_name, &(*name)->st) == -1) {
625 6 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
626 : }
627 :
628 129305 : (*name)->exists = true;
629 129305 : (*name)->stream_exists = true;
630 129305 : (*name)->has_wildcard = false;
631 129305 : (*name)->original_name = talloc_strdup(*name, fname);
632 129305 : (*name)->stream_name = NULL;
633 129305 : (*name)->stream_id = 0;
634 129305 : (*name)->allow_override = false;
635 :
636 129305 : status = pvfs_fill_dos_info(pvfs, *name, flags, -1);
637 :
638 129305 : return status;
639 : }
640 :
641 :
642 : /*
643 : fill in the pvfs_filename info for an open file, given the current
644 : info for a (possibly) non-open file. This is used by places that need
645 : to update the pvfs_filename stat information, and by pvfs_open()
646 : */
647 194581 : NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
648 : struct pvfs_filename *name, unsigned int flags)
649 : {
650 194581 : dev_t device = (dev_t)0;
651 194581 : ino_t inode = 0;
652 :
653 194581 : if (name->exists) {
654 97513 : device = name->st.st_dev;
655 97513 : inode = name->st.st_ino;
656 : }
657 :
658 194581 : if (fd == -1) {
659 556 : if (stat(name->full_name, &name->st) == -1) {
660 0 : return NT_STATUS_INVALID_HANDLE;
661 : }
662 : } else {
663 194025 : if (fstat(fd, &name->st) == -1) {
664 0 : return NT_STATUS_INVALID_HANDLE;
665 : }
666 : }
667 :
668 194581 : if (name->exists &&
669 97513 : (device != name->st.st_dev || inode != name->st.st_ino)) {
670 : /* the file we are looking at has changed! this could
671 : be someone trying to exploit a race
672 : condition. Certainly we don't want to continue
673 : operating on this file */
674 0 : DEBUG(0,("pvfs: WARNING: file '%s' changed during resolve - failing\n",
675 : name->full_name));
676 0 : return NT_STATUS_UNEXPECTED_IO_ERROR;
677 : }
678 :
679 194581 : name->exists = true;
680 :
681 194581 : return pvfs_fill_dos_info(pvfs, name, flags, fd);
682 : }
683 :
684 : /*
685 : fill in the pvfs_filename info for an open file, given the current
686 : info for a (possibly) non-open file. This is used by places that need
687 : to update the pvfs_filename stat information, and the path
688 : after a possible rename on a different handle.
689 : */
690 8392 : NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs,
691 : struct pvfs_file_handle *h)
692 : {
693 0 : NTSTATUS status;
694 :
695 8392 : if (h->have_opendb_entry) {
696 0 : struct odb_lock *lck;
697 8392 : const char *name = NULL;
698 :
699 8392 : lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
700 8392 : if (lck == NULL) {
701 0 : DEBUG(0,("%s: failed to lock file '%s' in opendb\n",
702 : __FUNCTION__, h->name->full_name));
703 : /* we were supposed to do a blocking lock, so something
704 : is badly wrong! */
705 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
706 : }
707 :
708 8392 : status = odb_get_path(lck, &name);
709 8392 : if (NT_STATUS_IS_OK(status)) {
710 : /*
711 : * This relies on the fact that
712 : * renames of open files are only
713 : * allowed by setpathinfo() and setfileinfo()
714 : * and there're only renames within the same
715 : * directory supported
716 : */
717 8392 : if (strcmp(h->name->full_name, name) != 0) {
718 0 : const char *orig_dir;
719 0 : const char *new_file;
720 0 : char *new_orig;
721 0 : char *delim;
722 11 : char *full_name = discard_const_p(char, name);
723 :
724 11 : delim = strrchr(name, '/');
725 11 : if (!delim) {
726 0 : talloc_free(lck);
727 0 : return NT_STATUS_INTERNAL_ERROR;
728 : }
729 :
730 11 : new_file = delim + 1;
731 11 : delim = strrchr(h->name->original_name, '\\');
732 11 : if (delim) {
733 11 : delim[0] = '\0';
734 11 : orig_dir = h->name->original_name;
735 11 : new_orig = talloc_asprintf(h->name, "%s\\%s",
736 : orig_dir, new_file);
737 11 : if (!new_orig) {
738 0 : talloc_free(lck);
739 0 : return NT_STATUS_NO_MEMORY;
740 : }
741 : } else {
742 0 : new_orig = talloc_strdup(h->name, new_file);
743 0 : if (!new_orig) {
744 0 : talloc_free(lck);
745 0 : return NT_STATUS_NO_MEMORY;
746 : }
747 : }
748 :
749 11 : talloc_free(h->name->original_name);
750 11 : talloc_free(h->name->full_name);
751 11 : h->name->full_name = talloc_steal(h->name, full_name);
752 11 : h->name->original_name = new_orig;
753 : }
754 : }
755 :
756 8392 : talloc_free(lck);
757 : }
758 :
759 : /*
760 : * TODO: pass PVFS_RESOLVE_NO_OPENDB and get
761 : * the write time from odb_lock() above.
762 : */
763 8392 : status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, 0);
764 8392 : NT_STATUS_NOT_OK_RETURN(status);
765 :
766 8392 : if (!null_nttime(h->write_time.close_time)) {
767 0 : h->name->dos.write_time = h->write_time.close_time;
768 : }
769 :
770 8392 : return NT_STATUS_OK;
771 : }
772 :
773 :
774 : /*
775 : resolve the parent of a given name
776 : */
777 324323 : NTSTATUS pvfs_resolve_parent(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
778 : const struct pvfs_filename *child,
779 : struct pvfs_filename **name)
780 : {
781 0 : NTSTATUS status;
782 0 : char *p;
783 :
784 324323 : *name = talloc(mem_ctx, struct pvfs_filename);
785 324323 : if (*name == NULL) {
786 0 : return NT_STATUS_NO_MEMORY;
787 : }
788 :
789 324323 : (*name)->full_name = talloc_strdup(*name, child->full_name);
790 324323 : if ((*name)->full_name == NULL) {
791 0 : return NT_STATUS_NO_MEMORY;
792 : }
793 :
794 324323 : p = strrchr_m((*name)->full_name, '/');
795 324323 : if (p == NULL) {
796 0 : return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
797 : }
798 :
799 : /* this handles the root directory */
800 324323 : if (p == (*name)->full_name) {
801 0 : p[1] = 0;
802 : } else {
803 324323 : p[0] = 0;
804 : }
805 :
806 324323 : if (stat((*name)->full_name, &(*name)->st) == -1) {
807 3 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
808 : }
809 :
810 324320 : (*name)->exists = true;
811 324320 : (*name)->stream_exists = true;
812 324320 : (*name)->has_wildcard = false;
813 : /* we can't get the correct 'original_name', but for the purposes
814 : of this call this is close enough */
815 324320 : (*name)->original_name = talloc_strdup(*name, child->original_name);
816 324320 : if ((*name)->original_name == NULL) {
817 0 : return NT_STATUS_NO_MEMORY;
818 : }
819 324320 : (*name)->stream_name = NULL;
820 324320 : (*name)->stream_id = 0;
821 324320 : (*name)->allow_override = false;
822 :
823 324320 : status = pvfs_fill_dos_info(pvfs, *name, PVFS_RESOLVE_NO_OPENDB, -1);
824 :
825 324320 : return status;
826 : }
|