+#ifndef WITH_NTDLL
+ if (win32func_FindFirstStreamW == NULL)
+ goto unnamed_only;
+#endif
+
+#ifdef WITH_NTDLL
+ buf = _buf;
+ bufsize = sizeof(_buf);
+
+ /* Get a buffer containing the stream information. */
+ for (;;) {
+ status = NtQueryInformationFile(hFile, &io_status, buf, bufsize,
+ FileStreamInformation);
+ if (status == STATUS_SUCCESS) {
+ break;
+ } else if (status == STATUS_BUFFER_OVERFLOW) {
+ u8 *newbuf;
+
+ bufsize *= 2;
+ if (buf == _buf)
+ newbuf = MALLOC(bufsize);
+ else
+ newbuf = REALLOC(buf, bufsize);
+
+ if (!newbuf) {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_free_buf;
+ }
+ buf = newbuf;
+ } else {
+ errno = win32_error_to_errno(RtlNtStatusToDosError(status));
+ ERROR_WITH_ERRNO("Failed to read streams of %ls", path);
+ ret = WIMLIB_ERR_READ;
+ goto out_free_buf;
+ }
+ }
+
+ if (io_status.Information == 0) {
+ /* No stream information. */
+ ret = 0;
+ goto out_free_buf;
+ }
+
+ /* Parse one or more stream information structures. */
+ info = (const FILE_STREAM_INFORMATION*)buf;
+ for (;;) {
+ if (info->StreamNameLength <= sizeof(dat.cStreamName) - 2) {
+ dat.StreamSize = info->StreamSize;
+ memcpy(dat.cStreamName, info->StreamName, info->StreamNameLength);
+ dat.cStreamName[info->StreamNameLength / 2] = L'\0';
+
+ /* Capture the stream. */
+ ret = win32_capture_stream(path, path_num_chars, inode,
+ lookup_table, &dat);
+ if (ret)
+ goto out_free_buf;
+ }
+ if (info->NextEntryOffset == 0) {
+ /* No more stream information. */
+ ret = 0;
+ break;
+ }
+ /* Advance to next stream information. */
+ info = (const FILE_STREAM_INFORMATION*)
+ ((const u8*)info + info->NextEntryOffset);
+ }
+out_free_buf:
+ /* Free buffer if allocated on heap. */
+ if (buf != _buf)
+ FREE(buf);
+ return ret;