struct perf_data_file *files = NULL;
        int i, ret = -1;
 
+       if (WARN_ON(!data->is_dir))
+               return -EINVAL;
+
        files = zalloc(nr * sizeof(*files));
        if (!files)
                return -ENOMEM;
        DIR *dir;
        int nr = 0;
 
+       if (WARN_ON(!data->is_dir))
+               return -EINVAL;
+
        dir = opendir(data->path);
        if (!dir)
                return -EINVAL;
        return 0;
 }
 
+static bool is_dir(struct perf_data *data)
+{
+       struct stat st;
+
+       if (stat(data->path, &st))
+               return false;
+
+       return (st.st_mode & S_IFMT) == S_IFDIR;
+}
+
 static int open_file_read(struct perf_data *data)
 {
        struct stat st;
        return open_file(data);
 }
 
+static int open_dir(struct perf_data *data)
+{
+       int ret;
+
+       /*
+        * So far we open only the header, so we can read the data version and
+        * layout.
+        */
+       if (asprintf(&data->file.path, "%s/header", data->path) < 0)
+               return -1;
+
+       if (perf_data__is_write(data) &&
+           mkdir(data->path, S_IRWXU) < 0)
+               return -1;
+
+       ret = open_file(data);
+
+       /* Cleanup whatever we managed to create so far. */
+       if (ret && perf_data__is_write(data))
+               rm_rf_perf_data(data->path);
+
+       return ret;
+}
+
 int perf_data__open(struct perf_data *data)
 {
        if (check_pipe(data))
        if (check_backup(data))
                return -1;
 
-       return open_file_dup(data);
+       if (perf_data__is_read(data))
+               data->is_dir = is_dir(data);
+
+       return perf_data__is_dir(data) ?
+              open_dir(data) : open_file_dup(data);
 }
 
 void perf_data__close(struct perf_data *data)
 {
+       if (perf_data__is_dir(data))
+               perf_data__close_dir(data);
+
        zfree(&data->file.path);
        close(data->file.fd);
 }