From 992c52ce7f2b6527b23922b26e256564373a73a6 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Tue, 20 Feb 2018 22:46:54 +0100
Subject: [PATCH 01/18] python/build/autotools.py: add autoreconf support

---
 python/build/autotools.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/python/build/autotools.py b/python/build/autotools.py
index 58d5d8c54..9abd418ff 100644
--- a/python/build/autotools.py
+++ b/python/build/autotools.py
@@ -5,6 +5,7 @@ from build.makeproject import MakeProject
 class AutotoolsProject(MakeProject):
     def __init__(self, url, md5, installed, configure_args=[],
                  autogen=False,
+                 autoreconf=False,
                  cppflags='',
                  ldflags='',
                  libs='',
@@ -13,6 +14,7 @@ class AutotoolsProject(MakeProject):
         MakeProject.__init__(self, url, md5, installed, **kwargs)
         self.configure_args = configure_args
         self.autogen = autogen
+        self.autoreconf = autoreconf
         self.cppflags = cppflags
         self.ldflags = ldflags
         self.libs = libs
@@ -28,6 +30,8 @@ class AutotoolsProject(MakeProject):
             subprocess.check_call(['aclocal'], cwd=src)
             subprocess.check_call(['automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
             subprocess.check_call(['autoconf'], cwd=src)
+        if self.autoreconf:
+            subprocess.check_call(['autoreconf', '-vif'], cwd=src)
 
         build = self.make_build_path(toolchain)
 

From c5c1c64a81baf737656647c0db601e5f85d63858 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Tue, 20 Feb 2018 22:45:15 +0100
Subject: [PATCH 02/18] python/build/libs.py: add libnfs

Enable the NFS storage plugin on Android.

Closes #226
---
 NEWS                 |  2 ++
 android/build.py     |  1 +
 python/build/libs.py | 15 +++++++++++++++
 3 files changed, 18 insertions(+)

diff --git a/NEWS b/NEWS
index d27757eb2..ff296191a 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ ver 0.20.18 (not yet released)
 * decoder
   - flac: improve seeking precision
 * fix gapless CUE song transitions
+* Android
+  - enable the NFS storage plugin
 
 ver 0.20.17 (2018/02/11)
 * output
diff --git a/android/build.py b/android/build.py
index 3e2e71dcc..43261152d 100755
--- a/android/build.py
+++ b/android/build.py
@@ -127,6 +127,7 @@ thirdparty_libs = [
     libmad,
     ffmpeg,
     curl,
+    libnfs,
     boost,
 ]
 
diff --git a/python/build/libs.py b/python/build/libs.py
index 7d93799d8..59aa103b9 100644
--- a/python/build/libs.py
+++ b/python/build/libs.py
@@ -364,6 +364,21 @@ curl = AutotoolsProject(
     patches='src/lib/curl/patches',
 )
 
+libnfs = AutotoolsProject(
+    'https://github.com/sahlberg/libnfs/archive/libnfs-2.0.0.tar.gz',
+    '7ea6cd8fa6c461d01091e584d424d28e137d23ff4b65b95d01a3fd0ef95d120e',
+    'lib/libnfs.a',
+    [
+        '--disable-shared', '--enable-static',
+        '--disable-debug',
+
+        # work around -Wtautological-compare
+        '--disable-werror',
+    ],
+    base='libnfs-libnfs-2.0.0',
+    autoreconf=True,
+)
+
 boost = BoostProject(
     'http://downloads.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.bz2',
     '5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9',

From a7582aaf15c33cc098ad59369fc843e82a7e1d1f Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 10:47:46 +0100
Subject: [PATCH 03/18] python/build/libs.py: update FFmpeg to 3.4.2

---
 python/build/libs.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/python/build/libs.py b/python/build/libs.py
index 59aa103b9..43c2c4fb1 100644
--- a/python/build/libs.py
+++ b/python/build/libs.py
@@ -100,8 +100,8 @@ liblame = AutotoolsProject(
 )
 
 ffmpeg = FfmpegProject(
-    'http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.xz',
-    '5a77278a63741efa74e26bf197b9bb09ac6381b9757391b922407210f0f991c0',
+    'http://ffmpeg.org/releases/ffmpeg-3.4.2.tar.xz',
+    '2b92e9578ef8b3e49eeab229e69305f5f4cbc1fdaa22e927fc7fca18acccd740',
     'lib/libavcodec.a',
     [
         '--disable-shared', '--enable-static',

From a4de96508d7d74b66d7c2a22983b682d95b625eb Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 10:49:05 +0100
Subject: [PATCH 04/18] python/build/libs.py: re-enable FFmpeg MP3 decoder

libmad has been unmaintained for a long time, and it fails to build on
Windows.  I could go and fix libmad's broken configure script, but I
prefer to just assign MP3 decoding to FFmpeg for now.

Closes #228
---
 python/build/libs.py | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/python/build/libs.py b/python/build/libs.py
index 43c2c4fb1..64a1ab303 100644
--- a/python/build/libs.py
+++ b/python/build/libs.py
@@ -142,7 +142,6 @@ ffmpeg = FfmpegProject(
         '--disable-parser=mjpeg',
         '--disable-parser=mlp',
         '--disable-parser=mpeg4video',
-        '--disable-parser=mpegaudio',
         '--disable-parser=mpegvideo',
         '--disable-parser=opus',
         '--disable-parser=vc1',
@@ -194,16 +193,6 @@ ffmpeg = FfmpegProject(
         # we don't need these decoders, because we have the dedicated
         # libraries
         '--disable-decoder=flac',
-        '--disable-decoder=mp1',
-        '--disable-decoder=mp1float',
-        '--disable-decoder=mp2',
-        '--disable-decoder=mp2float',
-        '--disable-decoder=mp3',
-        '--disable-decoder=mp3adu',
-        '--disable-decoder=mp3adufloat',
-        '--disable-decoder=mp3float',
-        '--disable-decoder=mp3on4',
-        '--disable-decoder=mp3on4float',
         '--disable-decoder=opus',
         '--disable-decoder=vorbis',
 

From 139a4054c55d0a7d8e9d33c307529afb51b005e0 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 10:52:05 +0100
Subject: [PATCH 05/18] python/build/libs.py: remove duplicate FFmpeg option
 and fix typo

Closes #232
---
 python/build/libs.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/python/build/libs.py b/python/build/libs.py
index 64a1ab303..4cbab63ee 100644
--- a/python/build/libs.py
+++ b/python/build/libs.py
@@ -124,7 +124,6 @@ ffmpeg = FfmpegProject(
         '--disable-protocols',
         '--disable-devices',
         '--disable-filters',
-        '--disable-filters',
         '--disable-v4l2_m2m',
 
         '--disable-parser=bmp',
@@ -306,7 +305,7 @@ ffmpeg = FfmpegProject(
         '--disable-decoder=svq1',
         '--disable-decoder=svq3',
         '--disable-decoder=tiff',
-        '--disable-decoder=mottiertexseqvideo',
+        '--disable-decoder=tiertexseqvideo',
         '--disable-decoder=truemotion1',
         '--disable-decoder=truemotion2',
         '--disable-decoder=truemotion2rt',

From 53f5d4c7107d65d691288aee26d17eda7b59f48a Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 10:52:40 +0100
Subject: [PATCH 06/18] android/build.py: disable libmad

Let FFmpeg do the MP3 decoding.  See commit
a4de96508d7d74b66d7c2a22983b682d95b625eb
---
 android/build.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/android/build.py b/android/build.py
index 43261152d..4c4f77ae7 100755
--- a/android/build.py
+++ b/android/build.py
@@ -124,7 +124,6 @@ thirdparty_libs = [
     opus,
     flac,
     libid3tag,
-    libmad,
     ffmpeg,
     curl,
     libnfs,

From ebed7e214752b7aafad35113fc35e37b608e8837 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 21:29:16 +0100
Subject: [PATCH 07/18] playlist/cue/Parser: parse tags after "INDEX 01"

Instead of setting state=IGNORE_TRACK, ignore only the following
"INDEX" lines.

Correction for commit 8461d71b520.  Closes #227
---
 src/playlist/cue/CueParser.cxx | 7 ++++++-
 src/playlist/cue/CueParser.hxx | 7 +++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/playlist/cue/CueParser.cxx b/src/playlist/cue/CueParser.cxx
index acdd55483..c61fb09d0 100644
--- a/src/playlist/cue/CueParser.cxx
+++ b/src/playlist/cue/CueParser.cxx
@@ -229,6 +229,8 @@ CueParser::Feed2(char *p) noexcept
 		}
 
 		state = TRACK;
+		ignore_index = false;
+
 		current.reset(new DetachedSong(filename));
 		assert(!current->GetTag().IsDefined());
 
@@ -238,6 +240,9 @@ CueParser::Feed2(char *p) noexcept
 	} else if (state == IGNORE_TRACK) {
 		return;
 	} else if (state == TRACK && strcmp(command, "INDEX") == 0) {
+		if (ignore_index)
+			return;
+
 		const char *nr = cue_next_token(&p);
 		if (nr == nullptr)
 			return;
@@ -255,7 +260,7 @@ CueParser::Feed2(char *p) noexcept
 
 		current->SetStartTime(SongTime::FromMS(position_ms));
 		if(strcmp(nr, "00") != 0 || previous == nullptr)
-			state = IGNORE_TRACK;
+			ignore_index = true;
 	}
 }
 
diff --git a/src/playlist/cue/CueParser.hxx b/src/playlist/cue/CueParser.hxx
index 6c84ddd4f..fd368c605 100644
--- a/src/playlist/cue/CueParser.hxx
+++ b/src/playlist/cue/CueParser.hxx
@@ -87,6 +87,13 @@ class CueParser {
 	 */
 	std::unique_ptr<DetachedSong> finished;
 
+	/**
+	 * Ignore "INDEX" lines?  Only up the first one after "00" is
+	 * used.  If there is a pregap (INDEX 00..01), it is assigned
+	 * to the previous song.
+	 */
+	bool ignore_index;
+
 	/**
 	 * Tracks whether Finish() has been called.  If true, then all
 	 * remaining (partial) results will be delivered by Get().

From 3f3e0739c4df2454118ca5bd114525d031b28840 Mon Sep 17 00:00:00 2001
From: tpoeiras <thiagopoeirassilva@gmail.com>
Date: Wed, 21 Feb 2018 20:15:28 -0300
Subject: [PATCH 08/18] Fix curl storage plugin failure if the authentication
 method is different than basic.

---
 NEWS                     | 2 ++
 src/lib/curl/Request.cxx | 1 +
 2 files changed, 3 insertions(+)

diff --git a/NEWS b/NEWS
index ff296191a..e54deb58c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.20.18 (not yet released)
+* input
+  - curl: allow authentication methods other than "Basic"
 * decoder
   - flac: improve seeking precision
 * fix gapless CUE song transitions
diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx
index d8301cbba..e0f4c67f9 100644
--- a/src/lib/curl/Request.cxx
+++ b/src/lib/curl/Request.cxx
@@ -62,6 +62,7 @@ CurlRequest::CurlRequest(CurlGlobal &_global, const char *url,
 	easy.SetOption(CURLOPT_NOPROGRESS, 1l);
 	easy.SetOption(CURLOPT_NOSIGNAL, 1l);
 	easy.SetOption(CURLOPT_CONNECTTIMEOUT, 10l);
+	easy.SetOption(CURLOPT_HTTPAUTH, (long) CURLAUTH_ANY);
 	easy.SetOption(CURLOPT_URL, url);
 }
 

From 2141fdf06e17918898f016f38fc0c4c9d13b7dee Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:02:42 +0100
Subject: [PATCH 09/18] lib/nfs/Connection: use winsock2.h instead of poll.h on
 Windows

---
 src/lib/nfs/Connection.cxx | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index b417f2fab..f9792f41b 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -31,7 +31,11 @@ extern "C" {
 
 #include <utility>
 
+#ifdef _WIN32
+#include <winsock2.h>
+#else
 #include <poll.h> /* for POLLIN, POLLOUT */
+#endif
 
 static constexpr std::chrono::steady_clock::duration NFS_MOUNT_TIMEOUT =
 	std::chrono::minutes(1);

From 31794ac376346b55951b0ec7ae5a155ca2e38b31 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:03:38 +0100
Subject: [PATCH 10/18] lib/nfs/FileReader: move sys/stat.h to header because
 "struct stat" may be macro

It indeed is a macro on Windows.
---
 src/lib/nfs/FileReader.cxx | 1 -
 src/lib/nfs/FileReader.hxx | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx
index 21eadc950..4bf7a43da 100644
--- a/src/lib/nfs/FileReader.cxx
+++ b/src/lib/nfs/FileReader.cxx
@@ -31,7 +31,6 @@
 #include <assert.h>
 #include <string.h>
 #include <fcntl.h>
-#include <sys/stat.h>
 
 NfsFileReader::NfsFileReader()
 	:DeferredMonitor(io_thread_get()), state(State::INITIAL)
diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx
index 911e62053..fdbd039e3 100644
--- a/src/lib/nfs/FileReader.hxx
+++ b/src/lib/nfs/FileReader.hxx
@@ -31,6 +31,7 @@
 
 #include <stdint.h>
 #include <stddef.h>
+#include <sys/stat.h>
 
 struct nfsfh;
 class NfsConnection;

From 666e456551f963e62ce6c84f5047d6a8fe983c84 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:42:19 +0100
Subject: [PATCH 11/18] win32/build.py: add -DWINVER=0x0600
 -D_WIN32_WINNT=0x0600

configure.ac sets this, but this wasn't used for compiling third-party
libraries.  This setting however is important for libnfs, which adds
fallback definitions for POLLIN and POLLOUT with bogus values.
---
 win32/build.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/win32/build.py b/win32/build.py
index 45c5dfa4c..8b0a3fc71 100755
--- a/win32/build.py
+++ b/win32/build.py
@@ -58,7 +58,8 @@ class CrossGccToolchain:
 
         self.cflags = common_flags
         self.cxxflags = common_flags
-        self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include')
+        self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include') + \
+                        ' -DWINVER=0x0600 -D_WIN32_WINNT=0x0600'
         self.ldflags = '-L' + os.path.join(install_prefix, 'lib')
         self.libs = ''
 

From 5b80711d75ea6b958aa7702e9857f7c51c43584f Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:31:40 +0100
Subject: [PATCH 12/18] Main: move WinSock initialization to class ScopeNetInit

---
 Makefile.am      |  1 +
 src/Main.cxx     | 32 +++-----------------------------
 src/net/Init.hxx | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 29 deletions(-)
 create mode 100644 src/net/Init.hxx

diff --git a/Makefile.am b/Makefile.am
index 409f784e1..266a61c6a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -497,6 +497,7 @@ libthread_a_SOURCES = \
 
 libnet_a_SOURCES = \
 	src/net/Features.hxx \
+	src/net/Init.hxx \
 	src/net/ToString.cxx src/net/ToString.hxx \
 	src/net/Resolver.cxx src/net/Resolver.hxx \
 	src/net/StaticSocketAddress.cxx src/net/StaticSocketAddress.hxx \
diff --git a/src/Main.cxx b/src/Main.cxx
index 121ae9c78..def4aed30 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -50,6 +50,7 @@
 #include "unix/SignalHandlers.hxx"
 #include "system/FatalError.hxx"
 #include "thread/Slack.hxx"
+#include "net/Init.hxx"
 #include "lib/icu/Init.hxx"
 #include "config/ConfigGlobal.hxx"
 #include "config/Param.hxx"
@@ -106,11 +107,6 @@
 #include <locale.h>
 #endif
 
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-
 #ifdef __BLOCKS__
 #include <dispatch/dispatch.h>
 #endif
@@ -284,25 +280,6 @@ glue_state_file_init()
 	instance->state_file->Read();
 }
 
-/**
- * Windows-only initialization of the Winsock2 library.
- */
-static void winsock_init(void)
-{
-#ifdef _WIN32
-	WSADATA sockinfo;
-
-	int retval = WSAStartup(MAKEWORD(2, 2), &sockinfo);
-	if(retval != 0)
-		FormatFatalError("Attempt to open Winsock2 failed; error code %d",
-				 retval);
-
-	if (LOBYTE(sockinfo.wVersion) != 2)
-		FatalError("We use Winsock2 but your version is either too new "
-			   "or old; please install Winsock 2.x");
-#endif
-}
-
 /**
  * Initialize the decoder and player core, including the music pipe.
  */
@@ -451,7 +428,8 @@ try {
 
 	IcuInit();
 
-	winsock_init();
+	const ScopeNetInit net_init;
+
 	io_thread_init();
 	config_global_init();
 
@@ -702,10 +680,6 @@ try {
 	daemonize_finish();
 #endif
 
-#ifdef _WIN32
-	WSACleanup();
-#endif
-
 	IcuFinish();
 
 	log_deinit();
diff --git a/src/net/Init.hxx b/src/net/Init.hxx
new file mode 100644
index 000000000..9e4581438
--- /dev/null
+++ b/src/net/Init.hxx
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2017 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef NET_INIT_HXX
+#define NET_INIT_HXX
+
+#include "check.h"
+#include "SocketError.hxx"
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+class ScopeNetInit {
+#ifdef _WIN32
+public:
+	ScopeNetInit() {
+		WSADATA sockinfo;
+		int retval = WSAStartup(MAKEWORD(2, 2), &sockinfo);
+		if (retval != 0)
+			throw MakeSocketError(retval, "WSAStartup() failed");
+	}
+
+	~ScopeNetInit() noexcept {
+		WSACleanup();
+	}
+#endif
+};
+
+#endif

From 50ce0c0d9d8f34bb8bd4a45152cff5da803710d5 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:33:30 +0100
Subject: [PATCH 13/18] test/run_storage: initialize WinSock

---
 test/run_storage.cxx | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/run_storage.cxx b/test/run_storage.cxx
index 805211fe0..ba889283f 100644
--- a/test/run_storage.cxx
+++ b/test/run_storage.cxx
@@ -23,6 +23,7 @@
 #include "storage/Registry.hxx"
 #include "storage/StorageInterface.hxx"
 #include "storage/FileInfo.hxx"
+#include "net/Init.hxx"
 
 #include <memory>
 #include <stdexcept>
@@ -95,6 +96,7 @@ try {
 	const char *const command = argv[1];
 	const char *const storage_uri = argv[2];
 
+	const ScopeNetInit net_init;
 	const ScopeIOThread io_thread;
 
 	if (strcmp(command, "ls") == 0) {

From f3e683bd6ff464295826e2e760c7a67588038a04 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:27:15 +0100
Subject: [PATCH 14/18] test/run_storage: fallback for %F on Windows

---
 test/run_storage.cxx | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/test/run_storage.cxx b/test/run_storage.cxx
index ba889283f..a86444dd5 100644
--- a/test/run_storage.cxx
+++ b/test/run_storage.cxx
@@ -71,7 +71,12 @@ Ls(Storage &storage, const char *path)
 		char mtime_buffer[32];
 		const char *mtime = "          ";
 		if (info.mtime > 0) {
-			strftime(mtime_buffer, sizeof(mtime_buffer), "%F",
+			strftime(mtime_buffer, sizeof(mtime_buffer),
+#ifdef _WIN32
+				 "%Y-%m-%d",
+#else
+				 "%F",
+#endif
 				 gmtime(&info.mtime));
 			mtime = mtime_buffer;
 		}

From 774d26b982aa317f98d2ff6a5cee80f6e2babb33 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:13:16 +0100
Subject: [PATCH 15/18] storage/nfs: assume UTF-8 when accessing NFS from
 Windows

Fixes two build failures with libnfs on Windows.
---
 src/storage/plugins/NfsStorage.cxx | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx
index 53549bead..e7e5eb828 100644
--- a/src/storage/plugins/NfsStorage.cxx
+++ b/src/storage/plugins/NfsStorage.cxx
@@ -219,7 +219,12 @@ UriToNfsPath(const char *_uri_utf8)
 	std::string uri_utf8("/");
 	uri_utf8.append(_uri_utf8);
 
+#ifdef _WIN32
+	/* assume UTF-8 when accessing NFS from Windows */
+	return uri_utf8;
+#else
 	return AllocatedPath::FromUTF8Throw(uri_utf8.c_str()).Steal();
+#endif
 }
 
 std::string
@@ -358,7 +363,14 @@ NfsListDirectoryOperation::CollectEntries(struct nfsdir *dir)
 
 	const struct nfsdirent *ent;
 	while ((ent = connection.ReadDirectory(dir)) != nullptr) {
+#ifdef _WIN32
+		/* assume UTF-8 when accessing NFS from Windows */
+		const auto name_fs = AllocatedPath::FromUTF8Throw(ent->name);
+		if (name_fs.IsNull())
+			continue;
+#else
 		const Path name_fs = Path::FromFS(ent->name);
+#endif
 		if (SkipNameFS(name_fs.c_str()))
 			continue;
 

From cd48d981b53d5639bad17a58ee8bbd914714d99b Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:13:58 +0100
Subject: [PATCH 16/18] storage/nfs: use PathTraitsFS::const_pointer_type

---
 src/storage/plugins/NfsStorage.cxx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx
index e7e5eb828..6ef6266aa 100644
--- a/src/storage/plugins/NfsStorage.cxx
+++ b/src/storage/plugins/NfsStorage.cxx
@@ -296,7 +296,7 @@ NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow)
 
 gcc_pure
 static bool
-SkipNameFS(const char *name) noexcept
+SkipNameFS(PathTraitsFS::const_pointer_type name) noexcept
 {
 	return name[0] == '.' &&
 		(name[1] == 0 ||

From 25cd47b8dcaac19d33dd272fee7282f943180db6 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:14:44 +0100
Subject: [PATCH 17/18] win32/build.py: enable libnfs

Now that all build failures have been fixed, we can enable the
feature.
---
 NEWS           | 2 +-
 win32/build.py | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index e54deb58c..98e8902f7 100644
--- a/NEWS
+++ b/NEWS
@@ -4,7 +4,7 @@ ver 0.20.18 (not yet released)
 * decoder
   - flac: improve seeking precision
 * fix gapless CUE song transitions
-* Android
+* Android, Windows
   - enable the NFS storage plugin
 
 ver 0.20.17 (2018/02/11)
diff --git a/win32/build.py b/win32/build.py
index 8b0a3fc71..38cc9c271 100755
--- a/win32/build.py
+++ b/win32/build.py
@@ -85,6 +85,7 @@ thirdparty_libs = [
     liblame,
     ffmpeg,
     curl,
+    libnfs,
     boost,
 ]
 

From 0ebeaa9ac266ed112f21c0f961b76d441f422e4f Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 24 Feb 2018 22:55:06 +0100
Subject: [PATCH 18/18] release v0.20.18

---
 NEWS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 98e8902f7..b35157d59 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-ver 0.20.18 (not yet released)
+ver 0.20.18 (2018/02/24)
 * input
   - curl: allow authentication methods other than "Basic"
 * decoder