110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project/** 210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * @file op_file.c 310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * Useful file management helpers 410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * 510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * @remark Copyright 2002 OProfile authors 610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * @remark Read the file COPYING 710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * 810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * @author John Levon 910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * @author Philippe Elie 1010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project */ 1110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 1210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <sys/stat.h> 1310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <unistd.h> 1410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <fcntl.h> 1510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <dirent.h> 1610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <fnmatch.h> 1710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <stdlib.h> 1810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <stdio.h> 1910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <errno.h> 2010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <string.h> 2110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include <limits.h> 2210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 2310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include "op_file.h" 2410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#include "op_libiberty.h" 2510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 2610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projectint op_file_readable(char const * file) 2710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 2810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project struct stat st; 2910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return !stat(file, &st) && S_ISREG(st.st_mode) && !access(file, R_OK); 3010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 3110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 3210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 3310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projecttime_t op_get_mtime(char const * file) 3410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 3510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project struct stat st; 3610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 3710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (stat(file, &st)) 3810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return 0; 3910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 4010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return st.st_mtime; 4110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 4210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 4310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 4410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projectint create_dir(char const * dir) 4510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 4610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (mkdir(dir, 0755)) { 4710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project /* FIXME: Does not verify existing is a dir */ 4810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (errno == EEXIST) 4910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return 0; 5010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return errno; 5110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 5210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 5310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return 0; 5410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 5510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 5610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 5710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projectint create_path(char const * path) 5810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 5910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project int ret = 0; 6010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 6110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project char * str = xstrdup(path); 6210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 6310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project char * pos = str[0] == '/' ? str + 1 : str; 6410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 6510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project for ( ; (pos = strchr(pos, '/')) != NULL; ++pos) { 6610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project *pos = '\0'; 6710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project ret = create_dir(str); 6810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project *pos = '/'; 6910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (ret) 7010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project break; 7110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 7210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 7310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project free(str); 7410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return ret; 7510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 7610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 7710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 7810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projectinline static int is_dot_or_dotdot(char const * name) 7910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 8010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return name[0] == '.' && 8110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project (name[1] == '\0' || 8210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project (name[1] == '.' && name[2] == '\0')); 8310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 8410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 8510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 8610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project/* If non-null is returned, the caller is responsible for freeing 8710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * the memory allocated for the return value. */ 8810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projectstatic char * make_pathname_from_dirent(char const * basedir, 8910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project struct dirent * ent, 9010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project struct stat * st_buf) 9110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 9210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project int name_len; 9310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project char * name; 9410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name_len = strlen(basedir) + strlen("/") + strlen(ent->d_name) + 1; 9510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name = xmalloc(name_len); 9610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project sprintf(name, "%s/%s", basedir, ent->d_name); 975a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng if (stat(name, st_buf) != 0) 985a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng { 995a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng struct stat lstat_buf; 1005a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng int err = errno; 1015a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng if (lstat(name, &lstat_buf) == 0 && 1025a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng S_ISLNK(lstat_buf.st_mode)) { 1035a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng // dangling symlink -- silently ignore 1045a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng } else { 1055a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng fprintf(stderr, "stat failed for %s (%s)\n", 1065a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng name, strerror(err)); 1075a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng } 10810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project free(name); 10910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name = NULL; 11010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 11110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return name; 11210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 11310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 11410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 11510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Projectint get_matching_pathnames(void * name_list, get_pathname_callback getpathname, 11610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project char const * base_dir, char const * filter, 11710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project enum recursion_type recursion) 11810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project{ 11910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project/* The algorithm below depends on recursion type (of which there are 3) 12010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * and whether the current dirent matches the filter. There are 6 possible 12110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * different behaviors, which is why we define 6 case below in the switch 12210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * statement of the algorithm. Actually, when the recursion type is 12310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * MATCH_DIR_ONLY_RECURSION, the behavior is the same, whether or not the dir 12410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * entry matches the filter. However, the behavior of the recursion types 12510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * NO_RECURSION and MATCH_ANY_ENTRY_RECURSION do depend on the dir entry 12610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * filter match, so for simplicity, we perform this match for all recursion 12710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * types and logically OR the match result with the value of the passed 12810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * recursion_type. 12910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project */ 13010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#define NO_MATCH 0 13110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project#define MATCH 1 13210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 13310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project DIR * dir; 13410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project struct dirent * ent; 13510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project struct stat stat_buffer; 13610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project int match; 13710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project char * name = NULL; 13810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 13910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (!(dir = opendir(base_dir))) 14010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return -1; 14110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project while ((ent = readdir(dir)) != 0) { 14210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (is_dot_or_dotdot(ent->d_name)) 14310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project continue; 14410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (fnmatch(filter, ent->d_name, 0) == 0) 14510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project match = 1; 14610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project else 14710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project match = 0; 14810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 14910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project switch (recursion | match) { 15010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project case NO_RECURSION + NO_MATCH: 15110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project case MATCH_ANY_ENTRY_RECURSION + NO_MATCH: 15210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project // nothing to do but continue the loop 15310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project break; 15410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project case NO_RECURSION + MATCH: 15510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project getpathname(ent->d_name, name_list); 15610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project break; 15710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project case MATCH_ANY_ENTRY_RECURSION + MATCH: 15810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name = make_pathname_from_dirent(base_dir, ent, 15910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project &stat_buffer); 1605a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng if (name) { 1615a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng if (S_ISDIR(stat_buffer.st_mode)) { 1625a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng get_matching_pathnames( 1635a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng name_list, getpathname, 1645a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng name, filter, recursion); 1655a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng } else { 1665a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng getpathname(name, name_list); 1675a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng } 16810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 16910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project free(name); 17010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project break; 17110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project case MATCH_DIR_ONLY_RECURSION + NO_MATCH: 17210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project case MATCH_DIR_ONLY_RECURSION + MATCH: 17310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name = make_pathname_from_dirent(base_dir, ent, 17410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project &stat_buffer); 1755a4eb4eb367eccd4b976d1feae96cea96d2c50f2Ben Cheng if (name && S_ISDIR(stat_buffer.st_mode)) { 17610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project /* Check if full directory name contains 17710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * match to the filter; if so, add it to 17810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project * name_list and quit; else, recurse. 17910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project */ 18010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project if (!fnmatch(filter, name, 0)) { 18110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project getpathname(name, name_list); 18210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } else { 18310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project get_matching_pathnames( 18410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name_list, getpathname, 18510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project name, filter, recursion); 18610e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 18710e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 18810e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project free(name); 18910e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project break; 19010e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 19110e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project } 19210e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project closedir(dir); 19310e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project 19410e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project return 0; 19510e23eebca4175a8dfe3a788b2bebacb1fcfce54The Android Open Source Project} 196