LCOV - code coverage report
Current view: top level - path_utils - path_utils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 254 298 85.2 %
Date: 2014-04-01 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         John Dennis <jdennis.redhat.com>
       4             : 
       5             :     Copyright (C) 2009 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU Lesser General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU Lesser General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU Lesser General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : /*****************************************************************************/
      22             : /******************************** Documentation ******************************/
      23             : /*****************************************************************************/
      24             : 
      25             : /*****************************************************************************/
      26             : /******************************* Include Files *******************************/
      27             : /*****************************************************************************/
      28             : 
      29             : #include <stdio.h>
      30             : #include <string.h>
      31             : #include <stdlib.h>
      32             : #include <unistd.h>
      33             : #include <dirent.h>
      34             : #include <sys/errno.h>
      35             : #include <sys/stat.h>
      36             : 
      37             : #include <libgen.h>
      38             : 
      39             : #include "path_utils.h"
      40             : 
      41             : /*****************************************************************************/
      42             : /****************************** Internal Defines *****************************/
      43             : /*****************************************************************************/
      44             : 
      45             : /*****************************************************************************/
      46             : /************************** Internal Type Definitions ************************/
      47             : /*****************************************************************************/
      48             : 
      49             : /*****************************************************************************/
      50             : /**********************  External Function Declarations  *********************/
      51             : /*****************************************************************************/
      52             : 
      53             : /*****************************************************************************/
      54             : /**********************  Internal Function Declarations  *********************/
      55             : /*****************************************************************************/
      56             : 
      57             : /*****************************************************************************/
      58             : /*************************  External Global Variables  ***********************/
      59             : /*****************************************************************************/
      60             : 
      61             : /*****************************************************************************/
      62             : /*************************  Internal Global Variables  ***********************/
      63             : /*****************************************************************************/
      64             : 
      65             : /*****************************************************************************/
      66             : /****************************  Inline Functions  *****************************/
      67             : /*****************************************************************************/
      68             : 
      69             : /*****************************************************************************/
      70             : /***************************  Internal Functions  ****************************/
      71             : /*****************************************************************************/
      72             : 
      73             : /*****************************************************************************/
      74             : /****************************  Exported Functions  ***************************/
      75             : /*****************************************************************************/
      76             : 
      77           0 : const char *path_utils_error_string(int error)
      78             : {
      79           0 :     switch(error) {
      80           0 :     case SUCCESS:                               return _("Success");
      81           0 :     case PATH_UTILS_ERROR_NOT_FULLY_NORMALIZED: return _("Path could not be fully normalized");
      82             :     }
      83           0 :     return NULL;
      84             : }
      85             : 
      86          27 : static int dot_to_absolute(char *rel_path, int rel_path_size)
      87             : {
      88             :     char tmp_path[PATH_MAX];
      89             : 
      90          27 :     if (strcmp(rel_path, ".") == 0) {
      91          10 :         if (getcwd(rel_path, rel_path_size) == NULL) {
      92           0 :             if (errno == ERANGE)
      93           0 :                 return ENOBUFS;
      94             :             else
      95           0 :                 return errno;
      96             :         }
      97          17 :     } else if (strcmp(rel_path, "..") == 0) {
      98           0 :         if (getcwd(tmp_path, sizeof(tmp_path)) == NULL)  {
      99           0 :             if (errno == ERANGE)
     100           0 :                 return ENOBUFS;
     101             :             else
     102           0 :                 return errno;
     103             :         }
     104           0 :         strncpy(rel_path, dirname(tmp_path), rel_path_size);
     105           0 :         if (rel_path[rel_path_size-1] != '\0') return ENOBUFS;
     106             :     }
     107             : 
     108          27 :     return SUCCESS;
     109             : }
     110             : 
     111           8 : int get_basename(char *base_name, size_t base_name_size, const char *path)
     112             : {
     113             :     char tmp_path[PATH_MAX];
     114             :     int ret;
     115             : 
     116           8 :     if (!path) return EINVAL;
     117           7 :     if (!base_name || base_name_size < 1) return ENOBUFS;
     118             : 
     119           7 :     strncpy(tmp_path, path, sizeof(tmp_path));
     120           7 :     if (tmp_path[sizeof(tmp_path)-1] != '\0') return ENOBUFS;
     121           7 :     strncpy(base_name, basename(tmp_path), base_name_size);
     122           7 :     if (base_name[base_name_size-1] != '\0') return ENOBUFS;
     123             : 
     124           6 :     ret = dot_to_absolute(base_name, base_name_size);
     125           6 :     if (ret != SUCCESS) {
     126           0 :         return ret;
     127             :     }
     128             : 
     129           6 :     return SUCCESS;
     130             : }
     131             : 
     132          17 : int get_dirname(char *dir_path, size_t dir_path_size, const char *path)
     133             : {
     134             :     char tmp_path[PATH_MAX];
     135             :     int ret;
     136             : 
     137          17 :     if (!path) return EINVAL;
     138          16 :     if (!dir_path || dir_path_size < 1) return ENOBUFS;
     139             : 
     140          16 :     strncpy(tmp_path, path, sizeof(tmp_path));
     141          16 :     if (tmp_path[sizeof(tmp_path)-1] != '\0') return ENOBUFS;
     142          16 :     strncpy(dir_path, dirname(tmp_path), dir_path_size);
     143          16 :     if (dir_path[dir_path_size-1] != '\0') return ENOBUFS;
     144             : 
     145          15 :     ret = dot_to_absolute(dir_path, dir_path_size);
     146          15 :     if (ret != SUCCESS) {
     147           0 :         return ret;
     148             :     }
     149             : 
     150          15 :     return SUCCESS;
     151             : }
     152             : 
     153           7 : int get_directory_and_base_name(char *dir_path, size_t dir_path_size,
     154             :                                 char *base_name, size_t base_name_size,
     155             :                                 const char *path)
     156             : {
     157             :     char tmp_path[PATH_MAX];
     158             :     int ret;
     159             : 
     160           7 :     if (!path) return EINVAL;
     161           6 :     if (!dir_path || dir_path_size < 1) return ENOBUFS;
     162           6 :     if (!base_name || base_name_size < 1) return ENOBUFS;
     163             : 
     164           6 :     strncpy(tmp_path, path, sizeof(tmp_path));
     165           6 :     if (tmp_path[sizeof(tmp_path)-1] != '\0') return ENOBUFS;
     166           6 :     strncpy(base_name, basename(tmp_path), base_name_size);
     167           6 :     if (base_name[base_name_size-1] != '\0') return ENOBUFS;
     168             : 
     169           6 :     strncpy(tmp_path, path, sizeof(tmp_path));
     170           6 :     if (tmp_path[sizeof(tmp_path)-1] != '\0') return ENOBUFS;
     171           6 :     strncpy(dir_path, dirname(tmp_path), dir_path_size);
     172           6 :     if (dir_path[dir_path_size-1] != '\0') return ENOBUFS;
     173             : 
     174           6 :     ret = dot_to_absolute(dir_path, dir_path_size);
     175           6 :     if (ret != SUCCESS) {
     176           0 :         return ret;
     177             :     }
     178             : 
     179           6 :     if (strcmp(base_name, ".") == 0) {
     180           2 :         strncpy(base_name, "", base_name_size);
     181           2 :         if (base_name[base_name_size-1] != '\0') return ENOBUFS;
     182             :     }
     183             : 
     184           6 :     return SUCCESS;
     185             : }
     186             : 
     187         231 : bool is_absolute_path(const char *path)
     188             : {
     189         231 :     if (!path) return false;
     190         231 :     return path[0] == '/';
     191             : }
     192             : 
     193          19 : int path_concat(char *path, size_t path_size, const char *head, const char *tail)
     194             : {
     195             :     int ret;
     196             :     const char *p, *src;
     197             :     char *dst, *dst_end;
     198             : 
     199          19 :     if (!path || path_size < 1) return ENOBUFS;
     200             : 
     201          19 :     dst = path;
     202          19 :     dst_end = path + path_size - 1;             /* -1 allows for NULL terminator */
     203             : 
     204          19 :     if (head && *head) {
     205             :         /* walk to end of head */
     206          17 :         for (p = head; *p; p++);
     207             : 
     208             :         /* skip any trailing slashes in head */
     209          17 :         for (p--; p > head && *p == '/'; p--);
     210             : 
     211             :         /* If the length of head exceeds the buffer size, fail */
     212          17 :         if ((p - head) > path_size-1) {
     213           1 :             ret = ENOBUFS;
     214           1 :             goto fail;
     215             :         }
     216             : 
     217             :         /* Copy head into path */
     218         223 :         for (src = head; src <= p && dst < dst_end;) {
     219         191 :             *dst++ = *src++;
     220             :         }
     221             :     }
     222          18 :     if (tail && *tail) {
     223             :         /* skip any leading slashes in tail */
     224          16 :         for (p = tail; *p && *p == '/'; p++);
     225             : 
     226          16 :         if (dst > path)
     227             :             /* insert single slash between head & tail
     228             :              * Making sure not to add an extra if the
     229             :              * preceding character is also a slash
     230             :              * (such as the case where head was the
     231             :              * special-case "/".
     232             :              */
     233          14 :             if (dst < dst_end && *(dst-1) != '/') {
     234          12 :                 *dst++ = '/';
     235             :             }
     236             : 
     237             :         /* Copy the tail into the path */
     238         167 :         for (src = p; *src && dst < dst_end;) {
     239         135 :             *dst++ = *src++;
     240             :         }
     241             : 
     242             :         /* If we got past dst_end and there is more data
     243             :          * in the src buffer, we should return ENOBUFS
     244             :          */
     245          16 :         if (*src) {
     246           3 :             ret = ENOBUFS; /* failed to copy everything */
     247           3 :             goto fail;
     248             :         }
     249             :     }
     250          15 :     *dst = 0;
     251             : 
     252          15 :     return SUCCESS;
     253             : 
     254             : fail:
     255             :     /* On failure, set the buffer to the empty string for safety */
     256           4 :     *path = '\0';
     257           4 :     return ret;
     258             : }
     259             : 
     260         228 : int make_path_absolute(char *absolute_path, size_t absolute_path_size, const char *path)
     261             : {
     262         228 :     int result = SUCCESS;
     263             :     const char *src;
     264             :     char *dst, *dst_end;
     265             : 
     266         228 :     if (!absolute_path || absolute_path_size < 1) return ENOBUFS;
     267             : 
     268         226 :     dst = absolute_path;
     269         226 :     dst_end = absolute_path + absolute_path_size - 1; /* -1 allows for NULL terminator */
     270             : 
     271         226 :     if (is_absolute_path(path)) {
     272           5 :         for (src = path; *src && dst < dst_end;) *dst++ = *src++;
     273           5 :         *dst = 0;
     274           5 :         if (dst > dst_end || *src) result = ENOBUFS;
     275           5 :         return result;
     276             :     }
     277             : 
     278         221 :     if ((getcwd(absolute_path, absolute_path_size) == NULL)) {
     279           0 :         if (errno == ERANGE)
     280           0 :             return ENOBUFS;
     281             :         else
     282           0 :             return errno;
     283             :     }
     284             : 
     285         221 :     for (dst = absolute_path; *dst && dst < dst_end; dst++);
     286         221 :     if (!(path && *path)) return result;
     287         220 :     if (dst > dst_end) {
     288           0 :         *absolute_path = 0;
     289           0 :         return ENOBUFS;
     290             :     }
     291             : 
     292         220 :     *dst++ = '/';
     293         220 :     if (dst > dst_end) {
     294           1 :         *absolute_path = 0;
     295           1 :         return ENOBUFS;
     296             :     }
     297             : 
     298         219 :     for (src = path; *src && dst < dst_end;) *dst++ = *src++;
     299         219 :     if (*src) return ENOBUFS; /* failed to copy everything */
     300         218 :     *dst = 0;
     301             : 
     302         218 :     return result;
     303             : }
     304             : 
     305          41 : char **split_path(const char *path, int *count)
     306             : {
     307             :     int n_components, component_len, total_component_len, alloc_len;
     308             :     const char *start, *end;
     309             :     char *mem_block, **array_ptr, *component_ptr;
     310             : 
     311          41 :     if (count) *count = 0;
     312          41 :     if (!path) return NULL;
     313             : 
     314             :     /* If path is absolute add in special "/" root component */
     315          34 :     if (*path == '/') {
     316          26 :         n_components = 1;
     317          26 :         total_component_len = 2;
     318             :     } else {
     319           8 :         n_components = 0;
     320           8 :         total_component_len = 0;
     321             :     }
     322             : 
     323             :     /* Scan for components, keep several counts */
     324         102 :     for (start = end = path; *start; start = end) {
     325          70 :         for (start = end; *start && *start == '/'; start++);
     326          70 :         for (end = start; *end && *end != '/'; end++);
     327          70 :         if ((component_len = end - start) == 0) break;
     328          68 :         n_components++;
     329          68 :         total_component_len += component_len + 1;
     330             :     }
     331             : 
     332             :     /*
     333             :      * Allocate a block big enough for component array (with trailing NULL
     334             :      * entry, hence n_components+1) and enough room for a copy of each NULL
     335             :      * terminated component. We'll copy the components into the same allocation
     336             :      * block after the end of the pointer array.
     337             :      */
     338          34 :     alloc_len = ((n_components+1) * sizeof(char *)) + total_component_len;
     339             : 
     340          34 :     if ((mem_block = malloc(alloc_len)) == NULL) {
     341           0 :         if (count) *count = -1;
     342           0 :         return NULL;
     343             :     }
     344             : 
     345             :     /* component array */
     346          34 :     array_ptr = (char **)mem_block;
     347             :     /* components copied after end of array */
     348          34 :     component_ptr = mem_block + ((n_components+1)*sizeof(char *));
     349             : 
     350             :     /* If path is absolute add in special "/" root component */
     351          34 :     if (*path == '/') {
     352          26 :         *array_ptr++ = component_ptr;
     353          26 :         *component_ptr++ = '/';
     354          26 :         *component_ptr++ = 0;
     355             :     }
     356             : 
     357         102 :     for (start = end = path; *start; start = end) {
     358          70 :         for (start = end; *start && *start == '/'; start++);
     359          70 :         for (end = start; *end && *end != '/'; end++);
     360          70 :         if ((end - start) == 0) break;
     361             : 
     362          68 :         *array_ptr++ = component_ptr;
     363          68 :         while (start < end) *component_ptr++ = *start++;
     364          68 :         *component_ptr++ = 0;
     365             :     }
     366          34 :     *array_ptr = NULL;
     367          34 :     if (count) *count = n_components;
     368          34 :     return (char **)mem_block;
     369             : }
     370             : 
     371         229 : int normalize_path(char *normalized_path, size_t normalized_path_size, const char *path)
     372             : {
     373         229 :     int result = SUCCESS;
     374             :     int component_len;
     375             :     bool is_absolute, can_backup;
     376             :     const char *start, *end;
     377             :     char *dst, *dst_end, *p, *limit;
     378             : 
     379         229 :     if (!normalized_path || normalized_path_size < 1) return ENOBUFS;
     380             : 
     381         229 :     dst = normalized_path;
     382         229 :     dst_end = normalized_path + normalized_path_size - 1; /* -1 allows for NULL terminator */
     383         229 :     can_backup = true;
     384             : 
     385         229 :     if (!path || !*path) {
     386           1 :         if (dst > dst_end) {
     387           0 :             *dst = 0;
     388           0 :             return ENOBUFS;
     389             :         }
     390           1 :         *dst++ = '.';
     391           1 :         *dst = 0;
     392           1 :         return result;
     393             :     }
     394             : 
     395         228 :     if ((is_absolute = *path == '/')) {
     396         225 :         if (dst < dst_end) {
     397         225 :             *dst++ = '/';
     398             :         } else {
     399           0 :             *dst = 0;
     400           0 :             return ENOBUFS;
     401             :         }
     402             :     }
     403             : 
     404        1649 :     for (start = end = path; *start; start = end) {
     405        1422 :         for (start = end; *start && *start == '/'; start++);
     406        1422 :         for (end = start; *end && *end != '/'; end++);
     407        1422 :         if ((component_len = end - start) == 0) break;
     408        1422 :         if (component_len == 1 && start[0] == '.') continue;
     409        1206 :         if (component_len == 2 && start[0] == '.' && start[1] == '.' && can_backup) {
     410             :             /* back up one level */
     411          13 :             if ((is_absolute && dst == normalized_path+1) || (!is_absolute && dst == normalized_path)) {
     412           3 :                 if (is_absolute) continue;
     413           1 :                 can_backup = false;
     414           1 :                 result = PATH_UTILS_ERROR_NOT_FULLY_NORMALIZED;
     415             :             } else {
     416          10 :                 if (is_absolute)
     417           7 :                     limit = normalized_path+1;
     418             :                 else
     419           3 :                     limit = normalized_path;
     420          10 :                 for (p = dst-1; p >= limit && *p != '/'; p--);
     421          10 :                 if (p <  limit)
     422           7 :                     dst = limit;
     423             :                 else
     424           3 :                     dst = p;
     425          10 :                 continue;
     426             :             }
     427             :         }
     428             : 
     429        1194 :         if ((end-start) > (dst_end-dst)) {
     430           1 :             return ENOBUFS;
     431             :         }
     432             : 
     433        1193 :         if ((dst > normalized_path) && (dst < dst_end) && (dst[-1] != '/')) *dst++ = '/';
     434        1193 :         while ((start < end) && (dst < dst_end)) *dst++ = *start++;
     435             :     }
     436             : 
     437         227 :     if (dst == normalized_path) {
     438           0 :         if (is_absolute)
     439           0 :             *dst++ = '/';
     440             :         else
     441           0 :             *dst++ = '.';
     442             :     }
     443         227 :     *dst = 0;
     444         227 :     return result;
     445             : }
     446             : 
     447          10 : int common_path_prefix(char *common_path,
     448             :                        size_t common_path_size,
     449             :                        int *common_count,
     450             :                        const char *path1, const char *path2)
     451             : {
     452             :     int count1, count2, min_count, i, n_common, result;
     453             :     char **split1, **split2;
     454             :     char *dst, *dst_end, *src;
     455             : 
     456          10 :     if (!common_path || common_path_size < 1) return ENOBUFS;
     457             : 
     458           9 :     result = SUCCESS;
     459           9 :     n_common = 0;
     460           9 :     split1 = split_path(path1, &count1);
     461           9 :     split2 = split_path(path2, &count2);
     462             : 
     463           9 :     if (count1 <= count2)
     464           9 :         min_count = count1;
     465             :     else
     466           0 :         min_count = count2;
     467             : 
     468           9 :     if (min_count <= 0 || !split1 || !split2 ) {
     469           1 :         result = SUCCESS;
     470           1 :         *common_path = 0;
     471           1 :         goto done;
     472             :     }
     473             : 
     474          21 :     for (n_common = 0; n_common < min_count; n_common++) {
     475          20 :         if (strcmp(split1[n_common], split2[n_common]) != 0) break;
     476             :     }
     477             : 
     478           8 :     if (n_common == 0) {
     479           1 :         result = SUCCESS;
     480           1 :         *common_path = 0;
     481           1 :         goto done;
     482             :     }
     483             : 
     484           7 :     dst = common_path;
     485           7 :     dst_end = common_path + common_path_size - 1; /* -1 allows for NULL terminator */
     486          17 :     for (i = 0; i < n_common; i++) {
     487          12 :         for (src = split1[i]; *src && dst < dst_end;) *dst++ = *src++;
     488          12 :         if (dst == dst_end && *src) {
     489           2 :             *dst = 0;
     490           2 :             result = ENOBUFS;
     491           2 :             goto done;
     492             :         }
     493          10 :         if (dst[-1] != '/' && i < n_common-1) {   /* insert path separator */
     494           0 :             if (dst == dst_end) {
     495           0 :                 *dst = 0;
     496           0 :                 result = ENOBUFS;
     497           0 :                 goto done;
     498             :             }
     499           0 :             *dst++ = '/';
     500             :         }
     501             :     }
     502           5 :     *dst = 0;
     503             : 
     504             :  done:
     505           9 :     free(split1);
     506           9 :     free(split2);
     507           9 :     if (common_count) *common_count = n_common;
     508           9 :     return result;
     509             : }
     510             : 
     511         218 : int make_normalized_absolute_path(char *result_path, size_t result_path_size, const char *path)
     512             : {
     513             :     int error;
     514             :     char absolute_path[PATH_MAX];
     515             : 
     516         218 :     if (!result_path || result_path_size < 1) return ENOBUFS;
     517         218 :     *result_path = 0;
     518         218 :     if ((error = make_path_absolute(absolute_path, sizeof(absolute_path), path)) != SUCCESS) return error;
     519         218 :     if ((error = normalize_path(result_path, result_path_size, absolute_path)) != SUCCESS) return error;
     520         218 :     return SUCCESS;
     521             : }
     522             : 
     523           4 : int find_existing_directory_ancestor(char *ancestor, size_t ancestor_size, const char *path)
     524             : {
     525             :     int error;
     526             :     char dir_path[PATH_MAX];
     527             :     struct stat info;
     528             : 
     529           4 :     if (!ancestor || ancestor_size < 1) return ENOBUFS;
     530           3 :     *ancestor = 0;
     531           3 :     strncpy(dir_path, path, sizeof(dir_path));
     532           3 :     if (dir_path[sizeof(dir_path)-1] != '\0') return ENOBUFS;
     533             : 
     534          10 :     while (strcmp(dir_path, "/") != 0) {
     535           7 :         if (lstat(dir_path, &info) < 0) {
     536           2 :             error = errno;
     537           2 :             if (error != ENOENT) return error;
     538             :         } else {
     539           5 :             if (S_ISDIR(info.st_mode)) break;
     540             :         }
     541           4 :         error = get_dirname(dir_path, sizeof(dir_path), dir_path);
     542           4 :         if (error != SUCCESS) {
     543           0 :             return error;
     544             :         }
     545             :     }
     546             : 
     547           3 :     strncpy(ancestor, dir_path, ancestor_size);
     548           3 :     if (ancestor[ancestor_size-1] != '\0') return ENOBUFS;
     549           2 :     return SUCCESS;
     550             : }
     551             : 
     552           7 : int directory_list(const char *path, bool recursive,
     553             :                    directory_list_callback_t callback, void *user_data)
     554             : {
     555             :     DIR *dir;
     556             :     struct dirent *entry;
     557             :     struct stat info;
     558           7 :     int error = 0;
     559             :     char entry_path[PATH_MAX];
     560           7 :     bool prune = false;
     561             : 
     562           7 :     if (!(dir = opendir(path))) {
     563           2 :         error = errno;
     564           2 :         return error;
     565             :     }
     566             : 
     567          19 :     for (entry = readdir(dir); entry; entry = readdir(dir)) {
     568             : 
     569          23 :         if (strcmp(entry->d_name, ".") == 0 ||
     570           9 :             strcmp(entry->d_name, "..") == 0) {
     571          10 :             continue;
     572             :         }
     573             : 
     574           4 :         error = path_concat(entry_path, sizeof(entry_path),
     575           4 :                             path, entry->d_name);
     576           4 :         if (error != SUCCESS) {
     577           0 :             closedir(dir);
     578             :             /* Don't bother checking the return here.
     579             :              * The path_concat error is more important
     580             :              */
     581           0 :             return error;
     582             :         }
     583             : 
     584           4 :         if (lstat(entry_path, &info) < 0) {
     585           0 :             continue;
     586             :         }
     587             : 
     588           4 :         prune = !callback(path, entry->d_name, entry_path, &info, user_data);
     589           4 :         if (S_ISDIR(info.st_mode)) {
     590           4 :             if (recursive && !prune) {
     591           2 :                 error = directory_list(entry_path, recursive,
     592             :                                        callback, user_data);
     593           2 :                 if (error != SUCCESS) {
     594           0 :                     closedir(dir);
     595             :                     /* Don't bother checking the return here.
     596             :                      * The directory_list error is more important
     597             :                      */
     598           0 :                     return error;
     599             :                 }
     600             :             }
     601             :         }
     602             :     }
     603           5 :     error = closedir(dir);
     604           5 :     if (error) {
     605           0 :         return error;
     606             :     }
     607           5 :     return SUCCESS;
     608             : }
     609             : 
     610           7 : bool is_ancestor_path(const char *ancestor, const char *path)
     611             : {
     612             :     char **path_components, **ancestor_components;
     613             :     int i, path_count, ancestor_count;
     614           7 :     bool result = false;
     615             : 
     616           7 :     path_components = split_path(path, &path_count);
     617           7 :     ancestor_components = split_path(ancestor, &ancestor_count);
     618             : 
     619           7 :     if (!path_components || !ancestor_components) {
     620             :         goto exit;
     621             :     }
     622             : 
     623           4 :     if (ancestor_count >= path_count) {
     624           2 :         goto exit;
     625             :     }
     626             : 
     627           8 :     for (i = 0; i < ancestor_count; i++) {
     628           7 :         if (strcmp(path_components[i], ancestor_components[i]) != 0) {
     629           1 :             goto exit;
     630             :         }
     631             :     }
     632             : 
     633           1 :     result = true;
     634             : 
     635             :  exit:
     636           7 :     free(path_components);
     637           7 :     free(ancestor_components);
     638           7 :     return result;
     639             : }
     640             : 

Generated by: LCOV version 1.10