/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_LIBGEN_H #include #endif #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_DIRENT_H #include #endif #include "opal/util/os_dirpath.h" #include "opal/util/argv.h" #include "opal/util/os_path.h" #include "opal/constants.h" #ifdef __WINDOWS__ #define PATH_SEP "\\" #else #define PATH_SEP "/" #endif static const char *path_sep = PATH_SEP; int opal_os_dirpath_create(const char *path, const mode_t mode) { struct stat buf; char **parts, *tmp; int i, len; if (NULL == path) { /* protect ourselves from errors */ return(OPAL_ERROR); } if (0 == stat(path, &buf)) { /* already exists */ if (mode == (mode & buf.st_mode)) { /* has correct mode */ return(OPAL_SUCCESS); } if (0 == chmod(path, (buf.st_mode | mode))) { /* successfully change mode */ return(OPAL_SUCCESS); } return(OPAL_ERROR); /* can't set correct mode */ } /* quick -- try to make directory */ if (0 == mkdir(path, mode)) { return(OPAL_SUCCESS); } /* didnt work, so now have to build our way down the tree */ /* Split the requested path up into its individual parts */ parts = opal_argv_split(path, path_sep[0]); /* Ensure to allocate enough space for tmp: the strlen of the incoming path + 1 (for \0) */ tmp = malloc(strlen(path) + 1); tmp[0] = '\0'; /* Iterate through all the subdirectory names in the path, building up a directory name. Check to see if that dirname exists. If it doesn't, create it. */ /* Notes about stat(): Windows has funny definitions of what will return 0 from stat(). "C:" will return failure, while "C:\" will return success. Similarly, "C:\foo" will return success, while "C:\foo\" will return failure (assuming that a folder named "foo" exists under C:\). POSIX implementations of stat() are generally a bit more forgiving; most will return true for "/foo" and "/foo/" (assuming /foo exists). But we might as well abide by the same rules as Windows and generally disallow checking for names ending with path_sep (the only possible allowable one is checking for "/", which is the root directory, and is guaranteed to exist on valid POSIX filesystems, and is therefore not worth checking for). */ len = opal_argv_count(parts); for (i = 0; i < len; ++i) { if (i == 0) { #ifdef __WINDOWS__ /* In the Windows case, check for ":" case (i.e., an absolute pathname). If this is the case, ensure that it ends in a path_sep. */ if (2 == strlen(parts[0]) && isalpha(parts[0][0]) && ':' == parts[0][1]) { strcat(tmp, parts[i]); strcat(tmp, path_sep); } /* Otherwise, it's a relative path. Per the comment above, we don't want a '\' at the end, so just append this part. */ else { strcat(tmp, parts[i]); } #else /* If in POSIX-land, ensure that we never end a directory name with path_sep */ if ('/' == path[0]) { strcat(tmp, path_sep); } strcat(tmp, parts[i]); #endif } /* If it's not the first part, ensure that there's a preceeding path_sep and then append this part */ else { if (path_sep[0] != tmp[strlen(tmp) - 1]) { strcat(tmp, path_sep); } strcat(tmp, parts[i]); } /* Now that we finally have the name to check, check it. Create it if it doesn't exist. */ if (0 != stat(tmp, &buf)) { if (0 != mkdir(tmp, mode) && 0 != stat(tmp, &buf)) { opal_argv_free(parts); free(tmp); return OPAL_ERROR; } } } /* All done */ opal_argv_free(parts); free(tmp); return OPAL_SUCCESS; } int opal_os_dirpath_destroy(const char *path, bool recursive, opal_os_dirpath_destroy_callback_fn_t cbfunc) { int rc, exit_status = OPAL_SUCCESS; bool is_dir = false; #ifndef WIN32 DIR *dp; struct dirent *ep; char *filenm; #ifndef HAVE_STRUCT_DIRENT_D_TYPE int ret; struct stat buf; #endif if (NULL == path) { /* protect against error */ return OPAL_ERROR; } /* * Make sure we have access to the the base directory */ if( OPAL_SUCCESS != (rc = opal_os_dirpath_access(path, 0) ) ) { exit_status = rc; goto cleanup; } /* * Open up the directory */ dp = opendir(path); if (NULL == dp) { return OPAL_ERROR; } while (NULL != (ep = readdir(dp)) ) { /* skip: * - . and .. */ if ((0 == strcmp(ep->d_name, ".")) || (0 == strcmp(ep->d_name, "..")) ) { continue; } /* Check to see if it is a directory */ is_dir = false; #ifdef HAVE_STRUCT_DIRENT_D_TYPE if (DT_DIR == ep->d_type) { is_dir = true; } #else /* have dirent.d_type */ rc = stat(filenm, &buf); if (rc < 0 || S_ISDIR(buf.st_mode)) { is_dir = true; } #endif /* have dirent.d_type */ /* * If not recursively decending, then if we find a directory then fail * since we were not told to remove it. */ if( is_dir && !recursive) { /* Set the error indicating that we found a directory, * but continue removing files */ exit_status = OPAL_ERROR; continue; } /* Will the caller allow us to remove this file/directory? */ if(NULL != cbfunc) { /* * Caller does not wish to remove this file/directory, * continue with the rest of the entries */ if( ! (cbfunc(path, ep->d_name)) ) { continue; } } /* Directories are recursively destroyed */ filenm = opal_os_path(false, path, ep->d_name, NULL); if(is_dir) { if( OPAL_SUCCESS != (rc = opal_os_dirpath_destroy(filenm, recursive, cbfunc) ) ) { exit_status = rc; goto cleanup; } } /* Files are removed right here */ else { if( 0 != (rc = unlink(filenm) ) ) { exit_status = OPAL_ERROR; } free(filenm); } } /* * Done with this directory */ closedir(dp); #else bool empty = false; char search_path[MAX_PATH]; HANDLE file; WIN32_FIND_DATA file_data; TCHAR *file_name; if (NULL == path) { return OPAL_ERROR; } strncpy(search_path, path, strlen(path)+1); strncat (search_path, "\\*", 3); file = FindFirstFile(search_path, &file_data); if (INVALID_HANDLE_VALUE == file) { FindClose(&file_data); return; } do { /* * Skip * - . and .. */ if ((0 == strcmp(file_data.cFileName, ".")) || (0 == strcmp(file_data.cFileName, "..")) ) { continue; } is_dir = false; if(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { is_dir = true; } /* * If not recursively decending, then if we find a directory then fail * since we were not told to remove it. */ if( is_dir && !recursive) { /* Set the error indicating that we found a directory, * but continue removing files */ exit_status = OPAL_ERROR; continue; } /* Will the caller allow us to remove this file/directory */ if( NULL != cbfunc) { if( !cbfunc(path, file_data.cFileName) ) { continue; } } file_name = opal_os_path(false, path, file_data.cFileName, NULL); if( is_dir ) { if( OPAL_SUCCESS != (rc = opal_os_dirpath_destroy(file_name, recursive, cbfunc) ) ) { exit_status = rc; goto cleanup; } } else { DeleteFile(file_name); } /* * Are we done yet? */ if (0 == FindNextFile(file, &file_data)) { empty = true; } } while(!empty); FindClose(&file_data); #endif cleanup: /* * If the directory is empty, them remove it */ if(opal_os_dirpath_is_empty(path)) { rmdir(path); } return exit_status; } bool opal_os_dirpath_is_empty(const char *path ) { #ifndef __WINDOWS__ DIR *dp; struct dirent *ep; if (NULL != path) { /* protect against error */ dp = opendir(path); if (NULL != dp) { while ((ep = readdir(dp))) { if ((0 != strcmp(ep->d_name, ".")) && (0 != strcmp(ep->d_name, ".."))) { closedir(dp); return false; } } closedir(dp); return true; } return false; } return true; #else char search_path[MAX_PATH]; HANDLE file; WIN32_FIND_DATA file_data; if (NULL != path) { strncpy(search_path, path, strlen(path)+1); strncat (search_path, "\\*", 3); file = FindFirstFile(search_path, &file_data); if (INVALID_HANDLE_VALUE == file) { FindClose(&file_data); return true; } if (0 != strcmp(file_data.cFileName, ".") || 0 != strcmp(file_data.cFileName, "..")) { FindClose(&file_data); return false; } while (0 != FindNextFile(file, &file_data)) { if (0 != strcmp(file_data.cFileName, ".") || 0 != strcmp(file_data.cFileName, "..")) { FindClose(&file_data); return false; } } } FindClose(&file_data); return true; #endif /* ifndef __WINDOWS__ */ } int opal_os_dirpath_access(const char *path, const mode_t in_mode ) { #ifndef __WINDOWS__ struct stat buf; mode_t loc_mode = S_IRWXU; /* at the least, I need to be able to do anything */ #else struct __stat64 buf; mode_t loc_mode = _S_IREAD | _S_IWRITE | _S_IEXEC; #endif /* * If there was no mode specified, use the default mode */ if( 0 != in_mode ) { loc_mode = in_mode; } #ifndef __WINDOWS__ if (0 == stat(path, &buf)) { /* exists - check access */ #else if (0 == _stat64(path, &buf)) { /* exist -- check */ #endif if ((buf.st_mode & loc_mode) == loc_mode) { /* okay, I can work here */ return(OPAL_SUCCESS); } else { /* Don't have access rights to the existing path */ return(OPAL_ERROR); } } else { /* We could not find the path */ return( OPAL_ERR_NOT_FOUND ); } }