+ struct timeval tv[2];
+ wim_timestamp_to_timeval(inode->last_access_time, &tv[0]);
+ wim_timestamp_to_timeval(inode->last_write_time, &tv[1]);
+ #ifdef HAVE_LUTIMES
+ ret = lutimes(output_path, tv);
+ #else
+ ret = -1;
+ errno = ENOSYS;
+ #endif
+ if (ret != 0) {
+ #ifdef HAVE_UTIME
+ if (errno == ENOSYS) {
+ struct utimbuf buf;
+ buf.actime = wim_timestamp_to_unix(inode->last_access_time);
+ buf.modtime = wim_timestamp_to_unix(inode->last_write_time);
+ if (utime(output_path, &buf) == 0)
+ return 0;
+ }
+ #endif
+ if (errno != ENOSYS || args->num_lutimes_warnings < 10) {
+ /*WARNING("Failed to set timestamp on file `%s': %s",*/
+ /*output_path, strerror(errno));*/
+ args->num_lutimes_warnings++;
+ }
+ }
+ return 0;
+}
+
+static int cmp_streams_by_wim_position(const void *p1, const void *p2)
+{
+ const struct lookup_table_entry *lte1, *lte2;
+ lte1 = *(const struct lookup_table_entry**)p1;
+ lte2 = *(const struct lookup_table_entry**)p2;
+ if (lte1->resource_entry.offset < lte2->resource_entry.offset)
+ return -1;
+ else if (lte1->resource_entry.offset > lte2->resource_entry.offset)
+ return 1;
+ else
+ return 0;
+}
+
+static int sort_stream_list_by_wim_position(struct list_head *stream_list)
+{
+ struct list_head *cur;
+ size_t num_streams;
+ struct lookup_table_entry **array;
+ size_t i;
+ size_t array_size;
+
+ num_streams = 0;
+ list_for_each(cur, stream_list)
+ num_streams++;
+ array_size = num_streams * sizeof(array[0]);
+ array = MALLOC(array_size);
+ if (!array) {
+ ERROR("Failed to allocate %zu bytes to sort stream entries",
+ array_size);
+ return WIMLIB_ERR_NOMEM;
+ }
+ cur = stream_list->next;
+ for (i = 0; i < num_streams; i++) {
+ array[i] = container_of(cur, struct lookup_table_entry, staging_list);
+ cur = cur->next;
+ }
+
+ qsort(array, num_streams, sizeof(array[0]), cmp_streams_by_wim_position);
+
+ INIT_LIST_HEAD(stream_list);
+ for (i = 0; i < num_streams; i++)
+ list_add_tail(&array[i]->staging_list, stream_list);
+ FREE(array);
+ return 0;
+}
+
+static void calculate_bytes_to_extract(struct list_head *stream_list,
+ int extract_flags,
+ union wimlib_progress_info *progress)
+{
+ struct lookup_table_entry *lte;
+ struct inode *inode;
+ u64 total_bytes = 0;
+ u64 num_streams = 0;
+
+ /* For each stream to be extracted... */
+ list_for_each_entry(lte, stream_list, staging_list) {
+ if (extract_flags &
+ (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
+ {
+ /* In the symlink or hard link extraction mode, each
+ * stream will be extracted one time regardless of how
+ * many dentries share the stream. */
+ wimlib_assert(!(extract_flags & WIMLIB_EXTRACT_FLAG_NTFS));
+ if (!lte->extracted_file) {
+ num_streams++;
+ total_bytes += wim_resource_size(lte);
+ }
+ } else {
+ list_for_each_entry(inode, <e->inode_list,
+ lte_inode_list)
+ {
+ num_streams++;
+ total_bytes += wim_resource_size(lte);
+ }
+ }
+ }
+ progress->extract.num_streams = num_streams;
+ progress->extract.total_bytes = total_bytes;
+ progress->extract.completed_bytes = 0;
+}
+
+static void maybe_add_stream_for_extraction(struct lookup_table_entry *lte,
+ struct list_head *stream_list)
+{
+ if (lte->out_refcnt == 0) {
+ lte->out_refcnt = 1;
+ INIT_LIST_HEAD(<e->inode_list);
+ list_add_tail(<e->staging_list, stream_list);
+ }
+}
+
+static void inode_find_streams_for_extraction(struct inode *inode,
+ struct list_head *stream_list,
+ int extract_flags)
+{
+ struct lookup_table_entry *lte;
+ bool inode_added = false;
+
+ lte = inode_unnamed_lte_resolved(inode);
+
+ if (lte) {
+ maybe_add_stream_for_extraction(lte, stream_list);
+ list_add_tail(&inode->lte_inode_list, <e->inode_list);
+ inode_added = true;
+ }
+#ifdef WITH_NTFS_3G
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+ for (unsigned i = 0; i < inode->num_ads; i++) {
+ if (inode->ads_entries[i].stream_name_len != 0) {
+ lte = inode_stream_lte_resolved(inode, i + 1);
+ if (lte) {
+ maybe_add_stream_for_extraction(lte,
+ stream_list);
+ if (!inode_added) {
+ list_add_tail(&inode->lte_inode_list,
+ <e->inode_list);
+ inode_added = true;
+ }
+ }
+ }
+ }
+ }
+#endif
+}
+
+static void find_streams_for_extraction(struct hlist_head *inode_list,
+ struct list_head *stream_list,
+ struct lookup_table *lookup_table,
+ int extract_flags)
+{
+ struct inode *inode;
+ struct hlist_node *cur;
+ struct dentry *dentry;
+
+ for_lookup_table_entry(lookup_table, lte_zero_out_refcnt, NULL);
+ INIT_LIST_HEAD(stream_list);
+ hlist_for_each_entry(inode, cur, inode_list, hlist) {
+ if (!inode->resolved)
+ inode_resolve_ltes(inode, lookup_table);
+ inode_for_each_dentry(dentry, inode)
+ dentry->is_extracted = 0;
+ inode_find_streams_for_extraction(inode, stream_list,
+ extract_flags);