autoar_extractor_step_scan_toplevel (AutoarExtractor *self)
{
  /* Step 0: Scan all file names in the archive
   * We have to check whether the archive contains a top-level directory
   * before performing the extraction. We emit the "scanned" signal when
   * the checking is completed. */

  struct archive *a;
  struct archive_entry *entry;

  int r;

  g_debug ("autoar_extractor_step_scan_toplevel: called");

  r = libarchive_create_read_object (FALSE, self, &a);
  if (r != ARCHIVE_OK) {
    archive_read_free (a);
    r = libarchive_create_read_object (TRUE, self, &a);
    if (r != ARCHIVE_OK) {
      if (self->error == NULL)
        self->error = autoar_common_g_error_new_a (a, self->source_basename);
      return;
    } else if (archive_filter_count (a) <= 1){
      /* If we only use raw format and filter count is one, libarchive will
       * not do anything except for just copying the source file. We do not
       * want this thing to happen because it does unnecesssary copying. */
      if (self->error == NULL)
        self->error = g_error_new (AUTOAR_EXTRACTOR_ERROR,
                                        NOT_AN_ARCHIVE_ERRNO,
                                        "\'%s\': %s",
                                        self->source_basename,
                                        "not an archive");
      return;
    }
    self->use_raw_format = TRUE;
  }

  while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {
    const char *pathname;
    g_autofree char *utf8_pathname = NULL;

    if (g_cancellable_is_cancelled (self->cancellable)) {
      archive_read_free (a);
      return;
    }

    if (archive_entry_is_encrypted (entry)) {
      autoar_extractor_request_passphrase (self);
    }

    if (self->use_raw_format) {
      pathname = autoar_common_get_basename_remove_extension (g_file_peek_path (self->source_file));
      g_debug ("autoar_extractor_step_scan_toplevel: %d: raw pathname = %s",
               self->total_files, pathname);
    } else {
      const char *symlink_pathname;
      const char *hardlink_pathname;

      pathname = archive_entry_pathname (entry);
      utf8_pathname = autoar_common_get_utf8_pathname (pathname);
      symlink_pathname = archive_entry_symlink (entry);
      hardlink_pathname = archive_entry_hardlink (entry);

      g_debug ("autoar_extractor_step_scan_toplevel: %d: pathname = %s%s%s%s%s%s%s",
               self->total_files, pathname,
               utf8_pathname ? " utf8 pathname = " : "",
               utf8_pathname ? utf8_pathname : "",
               symlink_pathname ? " symlink = " : "",
               symlink_pathname ? symlink_pathname : "",
               hardlink_pathname ? " hardlink = " : "",
               hardlink_pathname ? hardlink_pathname : "");
    }
    self->files_list =
      g_list_prepend (self->files_list,
                      g_file_get_child (self->output_file,
                                        utf8_pathname ? utf8_pathname : pathname));
    self->total_files++;
    self->total_size += archive_entry_size (entry);
    archive_read_data_skip (a);
  }

  if (self->files_list == NULL) {
    if (self->error == NULL) {
      self->error = g_error_new (AUTOAR_EXTRACTOR_ERROR,
                                      EMPTY_ARCHIVE_ERRNO,
                                      "\'%s\': %s",
                                      self->source_basename,
                                      "empty archive");
    }
    archive_read_free (a);
    return;
  }

  if (r != ARCHIVE_EOF) {
    if (self->error == NULL) {
      self->error =
        autoar_common_g_error_new_a (a, self->source_basename);
    }
    archive_read_free (a);
    return;
  }

  /* If we are unable to determine the total size, set it to a positive
   * number to prevent strange percentage. */
  if (self->total_size <= 0)
    self->total_size = G_MAXUINT64;

  archive_read_free (a);

  g_debug ("autoar_extractor_step_scan_toplevel: files = %d",
           self->total_files);

  self->files_list = g_list_reverse (self->files_list);

  autoar_extractor_signal_scanned (self);
}