LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_resolve.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 321 399 80.5 %
Date: 2024-04-21 15:09:00 Functions: 10 10 100.0 %

          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             : }

Generated by: LCOV version 1.14