auto import from //depot/cupcake/@135843
diff --git a/libutil/op_file.c b/libutil/op_file.c
new file mode 100644
index 0000000..e3e6cb6
--- /dev/null
+++ b/libutil/op_file.c
@@ -0,0 +1,185 @@
+/**
+ * @file op_file.c
+ * Useful file management helpers
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+
+#include "op_file.h"
+#include "op_libiberty.h"
+
+int op_file_readable(char const * file)
+{
+ struct stat st;
+ return !stat(file, &st) && S_ISREG(st.st_mode) && !access(file, R_OK);
+}
+
+
+time_t op_get_mtime(char const * file)
+{
+ struct stat st;
+
+ if (stat(file, &st))
+ return 0;
+
+ return st.st_mtime;
+}
+
+
+int create_dir(char const * dir)
+{
+ if (mkdir(dir, 0755)) {
+ /* FIXME: Does not verify existing is a dir */
+ if (errno == EEXIST)
+ return 0;
+ return errno;
+ }
+
+ return 0;
+}
+
+
+int create_path(char const * path)
+{
+ int ret = 0;
+
+ char * str = xstrdup(path);
+
+ char * pos = str[0] == '/' ? str + 1 : str;
+
+ for ( ; (pos = strchr(pos, '/')) != NULL; ++pos) {
+ *pos = '\0';
+ ret = create_dir(str);
+ *pos = '/';
+ if (ret)
+ break;
+ }
+
+ free(str);
+ return ret;
+}
+
+
+inline static int is_dot_or_dotdot(char const * name)
+{
+ return name[0] == '.' &&
+ (name[1] == '\0' ||
+ (name[1] == '.' && name[2] == '\0'));
+}
+
+
+/* If non-null is returned, the caller is responsible for freeing
+ * the memory allocated for the return value. */
+static char * make_pathname_from_dirent(char const * basedir,
+ struct dirent * ent,
+ struct stat * st_buf)
+{
+ int name_len;
+ char * name;
+ name_len = strlen(basedir) + strlen("/") + strlen(ent->d_name) + 1;
+ name = xmalloc(name_len);
+ sprintf(name, "%s/%s", basedir, ent->d_name);
+ if (stat(name, st_buf) != 0) {
+ free(name);
+ name = NULL;
+ }
+ return name;
+}
+
+
+int get_matching_pathnames(void * name_list, get_pathname_callback getpathname,
+ char const * base_dir, char const * filter,
+ enum recursion_type recursion)
+{
+/* The algorithm below depends on recursion type (of which there are 3)
+ * and whether the current dirent matches the filter. There are 6 possible
+ * different behaviors, which is why we define 6 case below in the switch
+ * statement of the algorithm. Actually, when the recursion type is
+ * MATCH_DIR_ONLY_RECURSION, the behavior is the same, whether or not the dir
+ * entry matches the filter. However, the behavior of the recursion types
+ * NO_RECURSION and MATCH_ANY_ENTRY_RECURSION do depend on the dir entry
+ * filter match, so for simplicity, we perform this match for all recursion
+ * types and logically OR the match result with the value of the passed
+ * recursion_type.
+ */
+#define NO_MATCH 0
+#define MATCH 1
+
+ DIR * dir;
+ struct dirent * ent;
+ struct stat stat_buffer;
+ int match;
+ char * name = NULL;
+
+ if (!(dir = opendir(base_dir)))
+ return -1;
+ while ((ent = readdir(dir)) != 0) {
+ if (is_dot_or_dotdot(ent->d_name))
+ continue;
+ if (fnmatch(filter, ent->d_name, 0) == 0)
+ match = 1;
+ else
+ match = 0;
+
+ switch (recursion | match) {
+ case NO_RECURSION + NO_MATCH:
+ case MATCH_ANY_ENTRY_RECURSION + NO_MATCH:
+ // nothing to do but continue the loop
+ break;
+ case NO_RECURSION + MATCH:
+ getpathname(ent->d_name, name_list);
+ break;
+ case MATCH_ANY_ENTRY_RECURSION + MATCH:
+ name = make_pathname_from_dirent(base_dir, ent,
+ &stat_buffer);
+ if (name && S_ISDIR(stat_buffer.st_mode) &&
+ !S_ISLNK(stat_buffer.st_mode)) {
+ get_matching_pathnames(
+ name_list, getpathname,
+ name, filter, recursion);
+ } else {
+ getpathname(name, name_list);
+ }
+ free(name);
+ break;
+ case MATCH_DIR_ONLY_RECURSION + NO_MATCH:
+ case MATCH_DIR_ONLY_RECURSION + MATCH:
+ name = make_pathname_from_dirent(base_dir, ent,
+ &stat_buffer);
+ if (name && S_ISDIR(stat_buffer.st_mode) &&
+ !S_ISLNK(stat_buffer.st_mode)) {
+ /* Check if full directory name contains
+ * match to the filter; if so, add it to
+ * name_list and quit; else, recurse.
+ */
+ if (!fnmatch(filter, name, 0)) {
+ getpathname(name, name_list);
+ } else {
+ get_matching_pathnames(
+ name_list, getpathname,
+ name, filter, recursion);
+ }
+ }
+ free(name);
+ break;
+ }
+ }
+ closedir(dir);
+
+ return 0;
+}