+ path_len = strlen(input_path);
+
+ dir_fd = dirfd(dir);
+ if (dir_fd < 0) {
+ PERROR("dirfd");
+ return -1;
+ }
+
+ while ((entry = readdir(dir))) {
+ struct stat st;
+ size_t name_len;
+ char filename[PATH_MAX];
+
+ if (!strcmp(entry->d_name, ".")
+ || !strcmp(entry->d_name, "..")) {
+ continue;
+ }
+
+ name_len = strlen(entry->d_name);
+ if (path_len + name_len + 2 > sizeof(filename)) {
+ ERR("Failed to remove file: path name too long (%s/%s)",
+ input_path, entry->d_name);
+ continue;
+ }
+
+ if (snprintf(filename, sizeof(filename), "%s/%s",
+ input_path, entry->d_name) < 0) {
+ ERR("Failed to format path.");
+ continue;
+ }
+
+ if (stat(filename, &st)) {
+ PERROR("stat");
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ char output_subpath[PATH_MAX];
+ char input_subpath[PATH_MAX];
+
+ strncpy(output_subpath, output_path,
+ sizeof(output_subpath));
+ output_subpath[sizeof(output_subpath) - 1] = '\0';
+ strncat(output_subpath, "/",
+ sizeof(output_subpath) - strlen(output_subpath) - 1);
+ strncat(output_subpath, entry->d_name,
+ sizeof(output_subpath) - strlen(output_subpath) - 1);
+
+ ret = mkdir(output_subpath, S_IRWXU | S_IRWXG);
+ if (ret) {
+ PERROR("mkdir");
+ has_warning = 1;
+ goto end;
+ }
+
+ strncpy(input_subpath, input_path,
+ sizeof(input_subpath));
+ input_subpath[sizeof(input_subpath) - 1] = '\0';
+ strncat(input_subpath, "/",
+ sizeof(input_subpath) - strlen(input_subpath) - 1);
+ strncat(input_subpath, entry->d_name,
+ sizeof(input_subpath) - strlen(input_subpath) - 1);
+
+ ret = extract_trace_recursive(output_subpath,
+ input_subpath);
+ if (ret) {
+ has_warning = 1;
+ }
+ } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+ if (!strcmp(entry->d_name, "metadata")) {
+ ret = extract_one_trace(output_path,
+ input_path);
+ if (ret) {
+ WARN("Error extracting trace '%s', continuing anyway.",
+ input_path);
+ has_warning = 1;
+ }
+ }
+ } else {