root/source4/ntvfs/posix/pvfs_resolve.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. component_compare
  2. pvfs_case_search
  3. parse_stream_name
  4. pvfs_unix_path
  5. pvfs_reduce_name
  6. pvfs_resolve_name
  7. pvfs_resolve_partial
  8. pvfs_resolve_name_fd
  9. pvfs_resolve_name_handle
  10. pvfs_resolve_parent

   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)
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
  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 smb_iconv_convenience *ic,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 258 static NTSTATUS pvfs_unix_path(struct pvfs_state *pvfs, const char *cifs_name,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 380 static NTSTATUS pvfs_reduce_name(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 501 NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 594 NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 632 NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 675 NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 761 NTSTATUS pvfs_resolve_parent(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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_reference(*name, child->original_name);
 800         (*name)->stream_name = NULL;
 801         (*name)->stream_id = 0;
 802 
 803         status = pvfs_fill_dos_info(pvfs, *name, PVFS_RESOLVE_NO_OPENDB, -1);
 804 
 805         return status;
 806 }

/* [<][>][^][v][top][bottom][index][help] */