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