op_file.c

Go to the documentation of this file.
00001 
00012 #include <sys/stat.h>
00013 #include <unistd.h>
00014 #include <fcntl.h>
00015 #include <dirent.h>
00016 #include <fnmatch.h>
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include <errno.h>
00020 #include <string.h>
00021 #include <limits.h>
00022 
00023 #include "op_file.h"
00024 #include "op_libiberty.h"
00025 
00026 int op_file_readable(char const * file)
00027 {
00028     struct stat st;
00029     return !stat(file, &st) && S_ISREG(st.st_mode) && !access(file, R_OK);
00030 }
00031 
00032 
00033 time_t op_get_mtime(char const * file)
00034 {
00035     struct stat st;
00036 
00037     if (stat(file, &st))
00038         return 0;
00039 
00040     return st.st_mtime;
00041 }
00042 
00043 
00044 int create_dir(char const * dir)
00045 {
00046     if (mkdir(dir, 0755)) {
00047         /* FIXME: Does not verify existing is a dir */
00048         if (errno == EEXIST)
00049             return 0;
00050         return errno;
00051     }
00052 
00053     return 0;
00054 }
00055 
00056 
00057 int create_path(char const * path)
00058 {
00059     int ret = 0;
00060 
00061     char * str = xstrdup(path);
00062 
00063     char * pos = str[0] == '/' ? str + 1 : str;
00064 
00065     for ( ; (pos = strchr(pos, '/')) != NULL; ++pos) {
00066         *pos = '\0';
00067         ret = create_dir(str);
00068         *pos = '/';
00069         if (ret)
00070             break;
00071     }
00072 
00073     free(str);
00074     return ret;
00075 }
00076 
00077 
00078 inline static int is_dot_or_dotdot(char const * name)
00079 {
00080     return name[0] == '.' &&
00081         (name[1] == '\0' ||
00082          (name[1] == '.' && name[2] == '\0'));
00083 }
00084 
00085 
00086 /* If non-null is returned, the caller is responsible for freeing
00087  * the memory allocated for the return value. */
00088 static char * make_pathname_from_dirent(char const * basedir,
00089                       struct dirent * ent,
00090                       struct stat * st_buf)
00091 {
00092     int name_len;
00093     char * name;
00094     name_len = strlen(basedir) + strlen("/") + strlen(ent->d_name) + 1;
00095     name = xmalloc(name_len);
00096     sprintf(name, "%s/%s", basedir, ent->d_name);
00097     if (stat(name, st_buf) != 0)
00098     {
00099         struct stat lstat_buf;
00100         int err = errno;
00101         if (lstat(name, &lstat_buf) == 0 &&
00102                 S_ISLNK(lstat_buf.st_mode)) {
00103             // dangling symlink -- silently ignore
00104         } else {
00105             fprintf(stderr, "stat failed for %s (%s)\n",
00106                             name, strerror(err));
00107         }
00108         free(name);
00109         name = NULL;
00110     }
00111     return name;
00112 }
00113 
00114 
00115 int get_matching_pathnames(void * name_list, get_pathname_callback getpathname,
00116                char const * base_dir, char const * filter,
00117                enum recursion_type recursion)
00118 {
00119 /* The algorithm below depends on recursion type (of which there are 3)
00120  * and whether the current dirent matches the filter.  There are 6 possible
00121  * different behaviors, which is why we define 6 case below in the switch
00122  * statement of the algorithm.  Actually, when the recursion type is
00123  * MATCH_DIR_ONLY_RECURSION, the behavior is the same, whether or not the dir
00124  * entry matches the filter.  However, the behavior of the recursion types
00125  * NO_RECURSION and MATCH_ANY_ENTRY_RECURSION do depend on the dir entry
00126  * filter match, so for simplicity, we perform this match for all recursion
00127  * types and logically OR the match result with the  value of the passed
00128  * recursion_type.
00129  */
00130 #define NO_MATCH 0
00131 #define MATCH 1
00132 
00133     DIR * dir;
00134     struct dirent * ent;
00135     struct stat stat_buffer;
00136     int match;
00137     char * name = NULL;
00138 
00139     if (!(dir = opendir(base_dir)))
00140         return -1;
00141     while ((ent = readdir(dir)) != 0) {
00142         if (is_dot_or_dotdot(ent->d_name))
00143             continue;
00144         if (fnmatch(filter, ent->d_name, 0) == 0)
00145             match = 1;
00146         else
00147             match = 0;
00148 
00149         switch (recursion | match) {
00150         case NO_RECURSION + NO_MATCH:
00151         case MATCH_ANY_ENTRY_RECURSION + NO_MATCH:
00152             // nothing to do but continue the loop
00153             break;
00154         case NO_RECURSION + MATCH:
00155             getpathname(ent->d_name, name_list);
00156             break;
00157         case MATCH_ANY_ENTRY_RECURSION + MATCH:
00158             name = make_pathname_from_dirent(base_dir, ent,
00159                                &stat_buffer);
00160             if (name) {
00161                 if (S_ISDIR(stat_buffer.st_mode)) {
00162                     get_matching_pathnames(
00163                         name_list, getpathname,
00164                         name, filter, recursion);
00165                 } else {
00166                     getpathname(name, name_list);
00167                 }
00168             }
00169             free(name);
00170             break;
00171         case MATCH_DIR_ONLY_RECURSION + NO_MATCH:
00172         case MATCH_DIR_ONLY_RECURSION + MATCH:
00173             name = make_pathname_from_dirent(base_dir, ent,
00174                                &stat_buffer);
00175             if (name && S_ISDIR(stat_buffer.st_mode)) {
00176                 /* Check if full directory name contains
00177                  * match to the filter; if so, add it to
00178                  * name_list and quit; else, recurse.
00179                  */
00180                 if (!fnmatch(filter, name, 0)) {
00181                     getpathname(name, name_list);
00182                 } else {
00183                     get_matching_pathnames(
00184                         name_list, getpathname,
00185                         name, filter, recursion);
00186                 }
00187             }
00188             free(name);
00189             break;
00190         }
00191     }
00192     closedir(dir);
00193 
00194     return 0;
00195 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1