LCOV - code coverage report
Current view: top level - vhd/lib - relative-path.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 106 0.0 %
Date: 2024-12-18 23:41:32 Functions: 0 4 0.0 %
Branches: 0 72 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016, Citrix Systems, Inc.
       3                 :            :  *
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions are met:
       8                 :            :  * 
       9                 :            :  *  1. Redistributions of source code must retain the above copyright
      10                 :            :  *     notice, this list of conditions and the following disclaimer.
      11                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *     notice, this list of conditions and the following disclaimer in the
      13                 :            :  *     documentation and/or other materials provided with the distribution.
      14                 :            :  *  3. Neither the name of the copyright holder nor the names of its 
      15                 :            :  *     contributors may be used to endorse or promote products derived from 
      16                 :            :  *     this software without specific prior written permission.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21                 :            :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
      22                 :            :  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      23                 :            :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      24                 :            :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      25                 :            :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      26                 :            :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      27                 :            :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28                 :            :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #ifdef HAVE_CONFIG_H
      32                 :            : #include "config.h"
      33                 :            : #endif
      34                 :            : 
      35                 :            : #include <stdio.h>
      36                 :            : #include <errno.h>
      37                 :            : #include <stdlib.h>
      38                 :            : #include <string.h>
      39                 :            : #include <limits.h>
      40                 :            : 
      41                 :            : #include "relative-path.h"
      42                 :            : #include "canonpath.h"
      43                 :            : 
      44                 :            : #define sfree(ptr)         \
      45                 :            : do {                       \
      46                 :            :         free(ptr);         \
      47                 :            :         ptr = NULL;        \
      48                 :            : } while (0)
      49                 :            : 
      50                 :            : /*
      51                 :            :  * count number of tokens between DELIMETER characters
      52                 :            :  */
      53                 :            : static int
      54                 :            : count_nodes(char *path)
      55                 :            : {
      56                 :            :         int i;
      57                 :            :         char *tmp;
      58                 :            : 
      59         [ #  # ]:          0 :         if (!path)
      60                 :            :                 return 0;
      61                 :            : 
      62         [ #  # ]:          0 :         for (i = 0, tmp = path; *tmp != '\0'; tmp++)
      63         [ #  # ]:          0 :                 if (*tmp == DELIMITER)
      64                 :          0 :                         i++;
      65                 :            : 
      66                 :            :         return i;
      67                 :            : }
      68                 :            : 
      69                 :            : /*
      70                 :            :  * return copy of next node in @path, or NULL
      71                 :            :  * @path is moved to the end of the next node
      72                 :            :  * @err is set to -errno on failure
      73                 :            :  * copy should be freed
      74                 :            :  */
      75                 :            : static char *
      76                 :          0 : next_node(char **path, int *err)
      77                 :            : {
      78                 :            :         int ret;
      79                 :            :         char *tmp, *start;
      80                 :            : 
      81 [ #  # ][ #  # ]:          0 :         if (!path || !*path) {
      82                 :          0 :                 *err = -EINVAL;
      83                 :          0 :                 return NULL;
      84                 :            :         }
      85                 :            : 
      86                 :          0 :         *err  = 0;
      87                 :          0 :         start = *path;
      88                 :            : 
      89         [ #  # ]:          0 :         for (tmp = *path; *tmp != '\0'; tmp++)
      90         [ #  # ]:          0 :                 if (*tmp == DELIMITER) {
      91                 :            :                         int size;
      92                 :            :                         char *node;
      93                 :            : 
      94                 :          0 :                         size = tmp - start + 1;
      95                 :          0 :                         node = malloc(size);
      96         [ #  # ]:          0 :                         if (!node) {
      97                 :          0 :                                 *err = -ENOMEM;
      98                 :          0 :                                 return NULL;
      99                 :            :                         }
     100                 :            : 
     101                 :          0 :                         ret = snprintf(node, size, "%s", start);
     102         [ #  # ]:          0 :                         if (ret < 0) {
     103                 :          0 :                                 free(node);
     104                 :          0 :                                 *err = -EINVAL;
     105                 :          0 :                                 return NULL;
     106                 :            :                         }
     107                 :            : 
     108                 :          0 :                         *path = tmp;
     109                 :          0 :                         return node;
     110                 :            :                 }
     111                 :            : 
     112                 :            :         return NULL;
     113                 :            : }
     114                 :            : 
     115                 :            : /*
     116                 :            :  * count number of nodes in common betwee @to and @from
     117                 :            :  * returns number of common nodes, or -errno on failure
     118                 :            :  */
     119                 :            : static int
     120                 :          0 : count_common_nodes(char *to, char *from)
     121                 :            : {
     122                 :            :         int err, common;
     123                 :            :         char *to_node, *from_node;
     124                 :            : 
     125         [ #  # ]:          0 :         if (!to || !from)
     126                 :          0 :                 return -EINVAL;
     127                 :            : 
     128                 :          0 :         err       = 0;
     129                 :          0 :         common    = 0;
     130                 :          0 :         to_node   = NULL;
     131                 :          0 :         from_node = NULL;
     132                 :            : 
     133                 :            :         do {
     134                 :          0 :                 to_node = next_node(&to, &err);
     135 [ #  # ][ #  # ]:          0 :                 if (err || !to_node)
     136                 :            :                         break;
     137                 :            : 
     138                 :          0 :                 from_node = next_node(&from, &err);
     139 [ #  # ][ #  # ]:          0 :                 if (err || !from_node)
     140                 :            :                         break;
     141                 :            : 
     142         [ #  # ]:          0 :                 if (strncmp(to_node, from_node, MAX_NAME_LEN))
     143                 :            :                         break;
     144                 :            : 
     145                 :          0 :                 ++to;
     146                 :          0 :                 ++from;
     147                 :          0 :                 ++common;
     148                 :          0 :                 sfree(to_node);
     149                 :          0 :                 sfree(from_node);
     150                 :            : 
     151                 :          0 :         } while (1);
     152                 :            : 
     153                 :          0 :         sfree(to_node);
     154                 :          0 :         sfree(from_node);
     155                 :            : 
     156         [ #  # ]:          0 :         if (err)
     157                 :            :                 return err;
     158                 :            : 
     159                 :          0 :         return common;
     160                 :            : }
     161                 :            : 
     162                 :            : /*
     163                 :            :  * construct path of @count '../', './' if @count is zero, or NULL on error
     164                 :            :  * result should be freed
     165                 :            :  */
     166                 :            : static char *
     167                 :          0 : up_nodes(int count)
     168                 :            : {
     169                 :            :         char *path, *tmp;
     170                 :            :         int i, ret, len, size;
     171                 :            : 
     172         [ #  # ]:          0 :         if (!count)
     173         [ #  # ]:          0 :                 return strdup("./");
     174                 :            : 
     175                 :          0 :         len  = strlen("../");
     176                 :          0 :         size = len * count;
     177         [ #  # ]:          0 :         if (size >= MAX_NAME_LEN)
     178                 :            :                 return NULL;
     179                 :            : 
     180                 :          0 :         path = malloc(size + 1);
     181         [ #  # ]:          0 :         if (!path)
     182                 :            :                 return NULL;
     183                 :            : 
     184                 :            :         tmp = path;
     185         [ #  # ]:          0 :         for (i = 0; i < count; i++) {
     186                 :          0 :                 ret = sprintf(tmp, "../");
     187         [ #  # ]:          0 :                 if (ret < 0 || ret != len) {
     188                 :          0 :                         free(path);
     189                 :          0 :                         return NULL;
     190                 :            :                 }
     191                 :          0 :                 tmp += ret;
     192                 :            :         }
     193                 :            : 
     194                 :            :         return path;
     195                 :            : }
     196                 :            : 
     197                 :            : /*
     198                 :            :  * return pointer to @offset'th node of path or NULL on error
     199                 :            :  */
     200                 :            : static char *
     201                 :            : node_offset(char *from, int offset)
     202                 :            : {
     203                 :            :         char *path;
     204                 :            : 
     205         [ #  # ]:          0 :         if (!from || !offset)
     206                 :            :                 return NULL;
     207                 :            : 
     208         [ #  # ]:          0 :         for (path = from; *path != '\0'; path++) {
     209         [ #  # ]:          0 :                 if (*path == DELIMITER)
     210         [ #  # ]:          0 :                         if (--offset == 0)
     211                 :          0 :                                 return path + 1;
     212                 :            :         }
     213                 :            : 
     214                 :            :         return NULL;
     215                 :            : }
     216                 :            : 
     217                 :            : /*
     218                 :            :  * return a relative path from @from to @to
     219                 :            :  * result should be freed
     220                 :            :  */
     221                 :            : char *
     222                 :          0 : relative_path_to(char *from, char *to, int *err)
     223                 :            : {
     224                 :            :         int from_nodes, common;
     225                 :            :         char *to_absolute, __to_absolute[PATH_MAX];
     226                 :            :         char *from_absolute, __from_absolute[PATH_MAX];
     227                 :            :         char *up, *common_target_path, *relative_path;
     228                 :            : 
     229                 :          0 :         *err          = 0;
     230                 :          0 :         up            = NULL;
     231                 :          0 :         to_absolute   = NULL;
     232                 :          0 :         from_absolute = NULL;
     233                 :          0 :         relative_path = NULL;
     234                 :            : 
     235   [ #  #  #  # ]:          0 :         if (strnlen(to, MAX_NAME_LEN)   == MAX_NAME_LEN ||
     236                 :          0 :             strnlen(from, MAX_NAME_LEN) == MAX_NAME_LEN) {
     237                 :            :                 EPRINTF("invalid input; max path length is %d\n",
     238                 :            :                         MAX_NAME_LEN);
     239                 :          0 :                 *err = -ENAMETOOLONG;
     240                 :          0 :                 return NULL;
     241                 :            :         }
     242                 :            : 
     243                 :          0 :         to_absolute = canonpath(to, __to_absolute, sizeof(__to_absolute));
     244         [ #  # ]:          0 :         if (!to_absolute) {
     245                 :            :                 EPRINTF("failed to get absolute path of %s\n", to);
     246                 :          0 :                 *err = -errno;
     247                 :          0 :                 goto out;
     248                 :            :         }
     249                 :            : 
     250                 :          0 :         from_absolute = canonpath(from, __from_absolute, sizeof(__from_absolute));
     251         [ #  # ]:          0 :         if (!from_absolute) {
     252                 :            :                 EPRINTF("failed to get absolute path of %s\n", from);
     253                 :          0 :                 *err = -errno;
     254                 :          0 :                 goto out;
     255                 :            :         }
     256                 :            : 
     257   [ #  #  #  # ]:          0 :         if (strnlen(to_absolute, MAX_NAME_LEN)   == MAX_NAME_LEN ||
     258                 :          0 :             strnlen(from_absolute, MAX_NAME_LEN) == MAX_NAME_LEN) {
     259                 :            :                 EPRINTF("invalid input; max path length is %d\n",
     260                 :            :                         MAX_NAME_LEN);
     261                 :          0 :                 *err = -ENAMETOOLONG;
     262                 :          0 :                 goto out;
     263                 :            :         }
     264                 :            : 
     265                 :            :         /* count nodes in source path */
     266                 :          0 :         from_nodes = count_nodes(from_absolute);
     267                 :            : 
     268                 :            :         /* count nodes in common */
     269                 :          0 :         common = count_common_nodes(to_absolute + 1, from_absolute + 1);
     270         [ #  # ]:          0 :         if (common < 0) {
     271                 :            :                 EPRINTF("failed to count common nodes of %s and %s: %d\n",
     272                 :            :                         to_absolute, from_absolute, common);
     273                 :          0 :                 *err = common;
     274                 :          0 :                 goto out;
     275                 :            :         }
     276                 :            : 
     277                 :            :         /* move up to common node */
     278                 :          0 :         up = up_nodes(from_nodes - common - 1);
     279         [ #  # ]:          0 :         if (!up) {
     280                 :            :                 EPRINTF("failed to allocate relative path for %s: %d\n",
     281                 :            :                         from_absolute, -ENOMEM);
     282                 :          0 :                 *err = -ENOMEM;
     283                 :          0 :                 goto out;
     284                 :            :         }
     285                 :            : 
     286                 :            :         /* get path from common node to target */
     287                 :          0 :         common_target_path = node_offset(to_absolute, common + 1);
     288         [ #  # ]:          0 :         if (!common_target_path) {
     289                 :            :                 EPRINTF("failed to find common target path to %s: %d\n",
     290                 :            :                         to_absolute, -EINVAL);
     291                 :          0 :                 *err = -EINVAL;
     292                 :          0 :                 goto out;
     293                 :            :         }
     294                 :            : 
     295                 :            :         /* get relative path */
     296         [ #  # ]:          0 :         if (asprintf(&relative_path, "%s%s", up, common_target_path) == -1) {
     297                 :            :                 EPRINTF("failed to construct final path %s%s: %d\n",
     298                 :            :                         up, common_target_path, -ENOMEM);
     299                 :          0 :                 relative_path = NULL;
     300                 :          0 :                 *err = -ENOMEM;
     301                 :          0 :                 goto out;
     302                 :            :         }
     303                 :            : 
     304                 :            : out:
     305                 :          0 :         sfree(up);
     306                 :            : 
     307                 :          0 :         return relative_path;
     308                 :            : }

Generated by: LCOV version 1.13