LCOV - code coverage report
Current view: top level - source3/lib - util_path.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 110 122 90.2 %
Date: 2024-02-28 12:06:22 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * Samba utility functions
       4             :  * Copyright (C) Andrew Tridgell 1992-1998
       5             :  * Copyright (C) Jeremy Allison 2001-2007
       6             :  * Copyright (C) Simo Sorce 2001
       7             :  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
       8             :  * Copyright (C) James Peach 2006
       9             :  *
      10             :  * This program is free software; you can redistribute it and/or modify
      11             :  * it under the terms of the GNU General Public License as published by
      12             :  * the Free Software Foundation; either version 3 of the License, or
      13             :  * (at your option) any later version.
      14             :  *
      15             :  * This program is distributed in the hope that it will be useful,
      16             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  * GNU General Public License for more details.
      19             :  *
      20             :  * You should have received a copy of the GNU General Public License
      21             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             :  */
      23             : 
      24             : #include "replace.h"
      25             : #include <talloc.h>
      26             : #include "lib/util/debug.h"
      27             : #include "lib/util/samba_util.h"
      28             : #include "lib/util_path.h"
      29             : 
      30             : struct loadparm_substitution;
      31             : struct share_params;
      32             : #include "source3/param/param_proto.h"
      33             : 
      34             : /**
      35             :  * @brief Returns an absolute path to a file concatenating the provided
      36             :  * @a rootpath and @a basename
      37             :  *
      38             :  * @param name Filename, relative to @a rootpath
      39             :  *
      40             :  * @retval Pointer to a string containing the full path.
      41             :  **/
      42             : 
      43      169025 : static char *xx_path(TALLOC_CTX *mem_ctx,
      44             :                      const char *name,
      45             :                      const char *rootpath)
      46             : {
      47      169025 :         char *fname = NULL;
      48             : 
      49      169025 :         fname = talloc_strdup(mem_ctx, rootpath);
      50      169025 :         if (!fname) {
      51           0 :                 return NULL;
      52             :         }
      53      169025 :         trim_string(fname,"","/");
      54             : 
      55      169025 :         if (!directory_create_or_exist(fname, 0755)) {
      56           0 :                 return NULL;
      57             :         }
      58             : 
      59      169025 :         return talloc_asprintf_append(fname, "/%s", name);
      60             : }
      61             : 
      62             : /**
      63             :  * @brief Returns an absolute path to a file in the Samba lock directory.
      64             :  *
      65             :  * @param name File to find, relative to LOCKDIR.
      66             :  *
      67             :  * @retval Pointer to a talloc'ed string containing the full path.
      68             :  **/
      69             : 
      70       78396 : char *lock_path(TALLOC_CTX *mem_ctx, const char *name)
      71             : {
      72       78396 :         return xx_path(mem_ctx, name, lp_lock_directory());
      73             : }
      74             : 
      75             : /**
      76             :  * @brief Returns an absolute path to a file in the Samba state directory.
      77             :  *
      78             :  * @param name File to find, relative to STATEDIR.
      79             :  *
      80             :  * @retval Pointer to a talloc'ed string containing the full path.
      81             :  **/
      82             : 
      83       89266 : char *state_path(TALLOC_CTX *mem_ctx, const char *name)
      84             : {
      85       89266 :         return xx_path(mem_ctx, name, lp_state_directory());
      86             : }
      87             : 
      88             : /**
      89             :  * @brief Returns an absolute path to a file in the Samba cache directory.
      90             :  *
      91             :  * @param name File to find, relative to CACHEDIR.
      92             :  *
      93             :  * @retval Pointer to a talloc'ed string containing the full path.
      94             :  **/
      95             : 
      96        1363 : char *cache_path(TALLOC_CTX *mem_ctx, const char *name)
      97             : {
      98        1363 :         return xx_path(mem_ctx, name, lp_cache_directory());
      99             : }
     100             : 
     101             : /**
     102             :  * @brief Removes any invalid path components in an absolute POSIX path.
     103             :  *
     104             :  * @param ctx Talloc context to return string.
     105             :  *
     106             :  * @param abs_path Absolute path string to process.
     107             :  *
     108             :  * @retval Pointer to a talloc'ed string containing the absolute full path.
     109             :  **/
     110             : 
     111      455475 : char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *pathname_in)
     112             : {
     113             :         /*
     114             :          * Note we use +2 here so if pathname_in=="" then we
     115             :          * have space to return "/".
     116             :          */
     117      455475 :         char *pathname = talloc_array(ctx, char, strlen(pathname_in)+2);
     118      455475 :         const char *s = pathname_in;
     119      455475 :         char *p = pathname;
     120             : 
     121      455475 :         if (pathname == NULL) {
     122           0 :                 return NULL;
     123             :         }
     124             : 
     125             :         /* Always start with a '/'. */
     126      455475 :         *p++ = '/';
     127             : 
     128    35852706 :         while (*s) {
     129             :                 /* Deal with '/' or multiples of '/'. */
     130    35397231 :                 if (s[0] == '/') {
     131     8753933 :                         while (s[0] == '/') {
     132             :                                 /* Eat trailing '/' */
     133     4381919 :                                 s++;
     134             :                         }
     135             :                         /* Update target with one '/' */
     136     4372014 :                         if (p[-1] != '/') {
     137     3916542 :                                 *p++ = '/';
     138             :                         }
     139     4372014 :                         continue;
     140             :                 }
     141    31025217 :                 if (p[-1] == '/') {
     142             :                         /* Deal with "./" or ".\0" */
     143     4359984 :                         if (s[0] == '.' &&
     144       85935 :                                         (s[1] == '/' || s[1] == '\0')) {
     145             :                                 /* Eat the dot. */
     146       55895 :                                 s++;
     147       55991 :                                 while (s[0] == '/') {
     148             :                                         /* Eat any trailing '/' */
     149          96 :                                         s++;
     150             :                                 }
     151             :                                 /* Don't write anything to target. */
     152       55895 :                                 continue;
     153             :                         }
     154             :                         /* Deal with "../" or "..\0" */
     155     4304089 :                         if (s[0] == '.' && s[1] == '.' &&
     156        3647 :                                         (s[2] == '/' || s[2] == '\0')) {
     157             :                                 /* Eat the dot dot. */
     158        3646 :                                 s += 2;
     159        6944 :                                 while (s[0] == '/') {
     160             :                                         /* Eat any trailing '/' */
     161        3298 :                                         s++;
     162             :                                 }
     163             :                                 /*
     164             :                                  * As we're on the slash, we go back
     165             :                                  * one character to point p at the
     166             :                                  * slash we just saw.
     167             :                                  */
     168        3646 :                                 if (p > pathname) {
     169        3646 :                                         p--;
     170             :                                 }
     171             :                                 /*
     172             :                                  * Now go back to the slash
     173             :                                  * before the one that p currently points to.
     174             :                                  */
     175       17594 :                                 while (p > pathname) {
     176       17582 :                                         p--;
     177       17582 :                                         if (p[0] == '/') {
     178        3625 :                                                 break;
     179             :                                         }
     180             :                                 }
     181             :                                 /*
     182             :                                  * Step forward one to leave the
     183             :                                  * last written '/' alone.
     184             :                                  */
     185        3646 :                                 p++;
     186             : 
     187             :                                 /* Don't write anything to target. */
     188        3646 :                                 continue;
     189             :                         }
     190             :                 }
     191             :                 /* Non-separator character, just copy. */
     192    30965676 :                 *p++ = *s++;
     193             :         }
     194      455475 :         if (p[-1] == '/') {
     195             :                 /*
     196             :                  * We finished on a '/'.
     197             :                  * Remove the trailing '/', but not if it's
     198             :                  * the sole character in the path.
     199             :                  */
     200       71574 :                 if (p > pathname + 1) {
     201       54069 :                         p--;
     202             :                 }
     203             :         }
     204             :         /* Terminate and we're done ! */
     205      455475 :         *p++ = '\0';
     206      455475 :         return pathname;
     207             : }
     208             : 
     209       95280 : static bool find_snapshot_token(
     210             :         const char *filename,
     211             :         char sep,
     212             :         const char **_start,
     213             :         const char **_next_component,
     214             :         NTTIME *twrp)
     215             : {
     216       95280 :         const char *start = NULL;
     217       95280 :         const char *end = NULL;
     218       95280 :         struct tm tm = {};
     219           0 :         time_t t;
     220             : 
     221       95280 :         start = strstr_m(filename, "@GMT-");
     222             : 
     223       95280 :         if (start == NULL) {
     224       82940 :                 return false;
     225             :         }
     226             : 
     227       12340 :         if ((start > filename) && (start[-1] != sep)) {
     228             :                 /* the GMT-token does not start a path-component */
     229           0 :                 return false;
     230             :         }
     231             : 
     232       12340 :         end = strptime(start, GMT_FORMAT, &tm);
     233       12340 :         if (end == NULL) {
     234             :                 /* Not a valid timestring. */
     235           0 :                 return false;
     236             :         }
     237             : 
     238       12340 :         if ((end[0] != '\0') && (end[0] != sep)) {
     239             :                 /*
     240             :                  * It is not a complete path component, i.e. the path
     241             :                  * component continues after the gmt-token.
     242             :                  */
     243           0 :                 return false;
     244             :         }
     245             : 
     246       12340 :         tm.tm_isdst = -1;
     247       12340 :         t = timegm(&tm);
     248       12340 :         unix_to_nt_time(twrp, t);
     249             : 
     250       12340 :         DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
     251             :                   nt_time_string(talloc_tos(), *twrp));
     252             : 
     253       12340 :         *_start = start;
     254             : 
     255       12340 :         if (end[0] == sep) {
     256       12336 :                 end += 1;
     257             :         }
     258       12340 :         *_next_component = end;
     259             : 
     260       12340 :         return true;
     261             : }
     262             : 
     263       21906 : bool clistr_is_previous_version_path(const char *path)
     264             : {
     265       21906 :         const char *start = NULL;
     266       21906 :         const char *next = NULL;
     267           0 :         NTTIME twrp;
     268           0 :         bool ok;
     269             : 
     270       21906 :         ok = find_snapshot_token(path, '\\', &start, &next, &twrp);
     271       21906 :         return ok;
     272             : }
     273             : 
     274       73374 : static bool extract_snapshot_token_internal(char *fname, NTTIME *twrp, char sep)
     275             : {
     276       73374 :         const char *start = NULL;
     277       73374 :         const char *next = NULL;
     278           0 :         size_t remaining;
     279           0 :         bool found;
     280             : 
     281       73374 :         found = find_snapshot_token(fname, sep, &start, &next, twrp);
     282       73374 :         if (!found) {
     283       65210 :                 return false;
     284             :         }
     285             : 
     286        8164 :         remaining = strlen(next);
     287        8164 :         memmove(discard_const_p(char, start), next, remaining+1);
     288             : 
     289        8164 :         return true;
     290             : }
     291             : 
     292        4306 : bool extract_snapshot_token(char *fname, NTTIME *twrp)
     293             : {
     294        4306 :         return extract_snapshot_token_internal(fname, twrp, '/');
     295             : }
     296             : 
     297       69068 : bool clistr_smb2_extract_snapshot_token(char *fname, NTTIME *twrp)
     298             : {
     299       69068 :         return extract_snapshot_token_internal(fname, twrp, '\\');
     300             : }
     301             : 
     302             : /*
     303             :  * Take two absolute paths, figure out if "subdir" is a proper
     304             :  * subdirectory of "parent". Return the component relative to the
     305             :  * "parent" without the potential "/". Take care of "parent"
     306             :  * possibly ending in "/".
     307             :  */
     308     3684576 : bool subdir_of(const char *parent,
     309             :                size_t parent_len,
     310             :                const char *subdir,
     311             :                const char **_relative)
     312             : {
     313     3684576 :         const char *relative = NULL;
     314       10573 :         bool matched;
     315             : 
     316     3684576 :         SMB_ASSERT(parent[0] == '/');
     317     3684576 :         SMB_ASSERT(subdir[0] == '/');
     318             : 
     319     3684576 :         if (parent_len == 1) {
     320             :                 /*
     321             :                  * Everything is below "/"
     322             :                  */
     323       14916 :                 *_relative = subdir+1;
     324       14916 :                 return true;
     325             :         }
     326             : 
     327     3669660 :         if (parent[parent_len-1] == '/') {
     328           0 :                 parent_len -= 1;
     329             :         }
     330             : 
     331     3669660 :         matched = (strncmp(subdir, parent, parent_len) == 0);
     332     3669660 :         if (!matched) {
     333      169146 :                 return false;
     334             :         }
     335             : 
     336     3498643 :         relative = &subdir[parent_len];
     337             : 
     338     3498643 :         if (relative[0] == '\0') {
     339     2613199 :                 *_relative = relative; /* nothing left */
     340     2613199 :                 return true;
     341             :         }
     342             : 
     343      885444 :         if (relative[0] == '/') {
     344             :                 /* End of parent must match a '/' in subdir. */
     345      885398 :                 *_relative = relative+1;
     346      885398 :                 return true;
     347             :         }
     348             : 
     349          46 :         return false;
     350             : }

Generated by: LCOV version 1.14