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;
+}