root/opal/mca/pmix/pmix4x/pmix/src/util/os_dirpath.c

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

DEFINITIONS

This source file includes following definitions.
  1. pmix_os_dirpath_create
  2. pmix_os_dirpath_destroy
  3. pmix_os_dirpath_is_empty
  4. pmix_os_dirpath_access

   1 /*
   2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2005 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2015-2017 Research Organization for Information Science
  13  *                         and Technology (RIST). All rights reserved.
  14  * Copyright (c) 2016-2019 Intel, Inc.  All rights reserved.
  15  * $COPYRIGHT$
  16  *
  17  * Additional copyrights may follow
  18  *
  19  * $HEADER$
  20  */
  21 
  22 
  23 #include "pmix_config.h"
  24 
  25 #include <errno.h>
  26 #include <string.h>
  27 #ifdef HAVE_UNISTD_H
  28 #include <unistd.h>
  29 #endif  /* HAVE_UNISTD_H */
  30 #include <stdlib.h>
  31 #if HAVE_SYS_STAT_H
  32 #include <sys/stat.h>
  33 #endif /* HAVE_SYS_STAT_H */
  34 #ifdef HAVE_SYS_TYPES_H
  35 #include <sys/types.h>
  36 #endif  /* HAVE_SYS_TYPES_H */
  37 #ifdef HAVE_DIRENT_H
  38 #include <dirent.h>
  39 #endif  /* HAVE_DIRENT_H */
  40 
  41 #include "src/util/error.h"
  42 #include "src/util/output.h"
  43 #include "src/util/os_dirpath.h"
  44 #include "src/util/show_help.h"
  45 #include "src/util/argv.h"
  46 #include "src/util/os_path.h"
  47 #include "pmix_common.h"
  48 
  49 static const char path_sep[] = PMIX_PATH_SEP;
  50 
  51 int pmix_os_dirpath_create(const char *path, const mode_t mode)
  52 {
  53     struct stat buf;
  54     char **parts, *tmp;
  55     int i, len;
  56     int ret;
  57 
  58     if (NULL == path) { /* protect ourselves from errors */
  59         return(PMIX_ERR_BAD_PARAM);
  60     }
  61 
  62     if (0 == (ret = stat(path, &buf))) { /* already exists */
  63         if (mode == (mode & buf.st_mode)) { /* has correct mode */
  64             return(PMIX_SUCCESS);
  65         }
  66         if (0 == (ret = chmod(path, (buf.st_mode | mode)))) { /* successfully change mode */
  67             return(PMIX_SUCCESS);
  68         }
  69         pmix_show_help("help-pmix-util.txt", "dir-mode", true,
  70                     path, mode, strerror(errno));
  71         return(PMIX_ERR_PERM); /* can't set correct mode */
  72     }
  73 
  74     /* quick -- try to make directory */
  75     if (0 == mkdir(path, mode)) {
  76         return(PMIX_SUCCESS);
  77     }
  78 
  79     /* didnt work, so now have to build our way down the tree */
  80     /* Split the requested path up into its individual parts */
  81 
  82     parts = pmix_argv_split(path, path_sep[0]);
  83 
  84     /* Ensure to allocate enough space for tmp: the strlen of the
  85        incoming path + 1 (for \0) */
  86 
  87     tmp = (char*)malloc(strlen(path) + 1);
  88     tmp[0] = '\0';
  89 
  90     /* Iterate through all the subdirectory names in the path,
  91        building up a directory name.  Check to see if that dirname
  92        exists.  If it doesn't, create it. */
  93 
  94     len = pmix_argv_count(parts);
  95     for (i = 0; i < len; ++i) {
  96         if (i == 0) {
  97             /* If in POSIX-land, ensure that we never end a directory
  98                name with path_sep */
  99 
 100             if ('/' == path[0]) {
 101                 strcat(tmp, path_sep);
 102             }
 103             strcat(tmp, parts[i]);
 104         }
 105 
 106         /* If it's not the first part, ensure that there's a
 107            preceeding path_sep and then append this part */
 108 
 109         else {
 110             if (path_sep[0] != tmp[strlen(tmp) - 1]) {
 111                 strcat(tmp, path_sep);
 112             }
 113             strcat(tmp, parts[i]);
 114         }
 115 
 116         /* Now that we have the name, try to create it */
 117         mkdir(tmp, mode);
 118         ret = errno;  // save the errno for an error msg, if needed
 119         if (0 != stat(tmp, &buf)) {
 120             pmix_show_help("help-pmix-util.txt", "mkdir-failed", true,
 121                         tmp, strerror(ret));
 122             pmix_argv_free(parts);
 123             free(tmp);
 124             return PMIX_ERROR;
 125         } else if (i == (len-1) && (mode != (mode & buf.st_mode)) && (0 > chmod(tmp, (buf.st_mode | mode)))) {
 126             pmix_show_help("help-pmix-util.txt", "dir-mode", true,
 127                            tmp, mode, strerror(errno));
 128             pmix_argv_free(parts);
 129             free(tmp);
 130             return(PMIX_ERR_PERM); /* can't set correct mode */
 131         }
 132     }
 133 
 134     /* All done */
 135 
 136     pmix_argv_free(parts);
 137     free(tmp);
 138     return PMIX_SUCCESS;
 139 }
 140 
 141 /**
 142  * This function attempts to remove a directory along with all the
 143  * files in it.  If the recursive variable is non-zero, then it will
 144  * try to recursively remove all directories.  If provided, the
 145  * callback function is executed prior to the directory or file being
 146  * removed.  If the callback returns non-zero, then no removal is
 147  * done.
 148  */
 149 int pmix_os_dirpath_destroy(const char *path,
 150                             bool recursive,
 151                             pmix_os_dirpath_destroy_callback_fn_t cbfunc)
 152 {
 153     int rc, exit_status = PMIX_SUCCESS;
 154     bool is_dir = false;
 155     DIR *dp;
 156     struct dirent *ep;
 157     char *filenm;
 158     struct stat buf;
 159 
 160     if (NULL == path) {  /* protect against error */
 161         return PMIX_ERROR;
 162     }
 163 
 164     /*
 165      * Make sure we have access to the the base directory
 166      */
 167     if (PMIX_SUCCESS != (rc = pmix_os_dirpath_access(path, 0))) {
 168         exit_status = rc;
 169         goto cleanup;
 170     }
 171 
 172     /* Open up the directory */
 173     dp = opendir(path);
 174     if (NULL == dp) {
 175         return PMIX_ERROR;
 176     }
 177 
 178     while (NULL != (ep = readdir(dp))) {
 179         /* skip:
 180          *  - . and ..
 181          */
 182         if ((0 == strcmp(ep->d_name, ".")) ||
 183             (0 == strcmp(ep->d_name, ".."))) {
 184             continue;
 185         }
 186 
 187         /* Check to see if it is a directory */
 188         is_dir = false;
 189 
 190         /* Create a pathname.  This is not always needed, but it makes
 191          * for cleaner code just to create it here.  Note that we are
 192          * allocating memory here, so we need to free it later on.
 193          */
 194         filenm = pmix_os_path(false, path, ep->d_name, NULL);
 195 
 196         rc = stat(filenm, &buf);
 197         if (0 > rc) {
 198             /* Handle a race condition. filenm might have been deleted by an
 199              * other process running on the same node. That typically occurs
 200              * when one task is removing the job_session_dir and an other task
 201              * is still removing its proc_session_dir.
 202              */
 203             free(filenm);
 204             continue;
 205         }
 206         if (S_ISDIR(buf.st_mode)) {
 207             is_dir = true;
 208         }
 209 
 210         /*
 211          * If not recursively decending, then if we find a directory then fail
 212          * since we were not told to remove it.
 213          */
 214         if (is_dir && !recursive) {
 215             /* Set the error indicating that we found a directory,
 216              * but continue removing files
 217              */
 218             exit_status = PMIX_ERROR;
 219             free(filenm);
 220             continue;
 221         }
 222 
 223         /* Will the caller allow us to remove this file/directory? */
 224         if (NULL != cbfunc) {
 225             /*
 226              * Caller does not wish to remove this file/directory,
 227              * continue with the rest of the entries
 228              */
 229             if (!(cbfunc(path, ep->d_name))) {
 230                 free(filenm);
 231                 continue;
 232             }
 233         }
 234         /* Directories are recursively destroyed */
 235         if (is_dir) {
 236             rc = pmix_os_dirpath_destroy(filenm, recursive, cbfunc);
 237             free(filenm);
 238             if (PMIX_SUCCESS != rc) {
 239                 exit_status = rc;
 240                 closedir(dp);
 241                 goto cleanup;
 242             }
 243         } else {
 244             /* Files are removed right here */
 245             if (0 != (rc = unlink(filenm))) {
 246                 exit_status = PMIX_ERROR;
 247             }
 248             free(filenm);
 249         }
 250     }
 251 
 252     /* Done with this directory */
 253     closedir(dp);
 254 
 255  cleanup:
 256 
 257     /*
 258      * If the directory is empty, them remove it
 259      */
 260     if(pmix_os_dirpath_is_empty(path)) {
 261         rmdir(path);
 262     }
 263 
 264     return exit_status;
 265 }
 266 
 267 bool pmix_os_dirpath_is_empty(const char *path ) {
 268     DIR *dp;
 269     struct dirent *ep;
 270 
 271     if (NULL != path) {  /* protect against error */
 272         dp = opendir(path);
 273         if (NULL != dp) {
 274             while ((ep = readdir(dp))) {
 275                         if ((0 != strcmp(ep->d_name, ".")) &&
 276                             (0 != strcmp(ep->d_name, ".."))) {
 277                             closedir(dp);
 278                             return false;
 279                         }
 280             }
 281             closedir(dp);
 282             return true;
 283         }
 284         return false;
 285     }
 286 
 287     return true;
 288 }
 289 
 290 int pmix_os_dirpath_access(const char *path, const mode_t in_mode ) {
 291     struct stat buf;
 292     mode_t loc_mode = S_IRWXU;  /* looking for full rights */
 293 
 294     /*
 295      * If there was no mode specified, use the default mode
 296      */
 297     if (0 != in_mode) {
 298         loc_mode = in_mode;
 299     }
 300 
 301     if (0 == stat(path, &buf)) { /* exists - check access */
 302         if ((buf.st_mode & loc_mode) == loc_mode) { /* okay, I can work here */
 303             return(PMIX_SUCCESS);
 304         } else {
 305             /* Don't have access rights to the existing path */
 306             return(PMIX_ERROR);
 307         }
 308     } else {
 309         /* We could not find the path */
 310         return( PMIX_ERR_NOT_FOUND );
 311     }
 312 }

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