From 4794666df619fbfd7d36620163b51bda31322773 Mon Sep 17 00:00:00 2001
From: Daira Hopwood <daira@jacaranda.org>
Date: Wed, 13 May 2015 14:42:31 +0100
Subject: [PATCH] On Windows, the user's home directory may be either
 %USERPROFILE% or %HOMEDRIVE%%HOMEPATH% depending on the Windows version.
 fixes ticket:2417

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
---
 src/allmydata/test/test_util.py | 13 ++++++++++---
 src/allmydata/util/fileutil.py  | 24 +++++++++++++++++++-----
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/src/allmydata/test/test_util.py b/src/allmydata/test/test_util.py
index f2da9c4b..a2bba112 100644
--- a/src/allmydata/test/test_util.py
+++ b/src/allmydata/test/test_util.py
@@ -539,10 +539,11 @@ class FileUtil(ReallyEqualMixin, unittest.TestCase):
         _cleanup()
         self.failIf(os.path.exists(long_path))
 
-    def test_windows_expanduser(self):
+    def _test_windows_expanduser(self, userprofile=None, homedrive=None, homepath=None):
         def call_windows_getenv(name):
-            if name == u"HOMEDRIVE": return u"C:"
-            if name == u"HOMEPATH": return u"\\Documents and Settings\\\u0100"
+            if name == u"USERPROFILE": return userprofile
+            if name == u"HOMEDRIVE":   return homedrive
+            if name == u"HOMEPATH":    return homepath
             self.fail("unexpected argument to call_windows_getenv")
         self.patch(fileutil, 'windows_getenv', call_windows_getenv)
 
@@ -553,6 +554,12 @@ class FileUtil(ReallyEqualMixin, unittest.TestCase):
         self.failUnlessReallyEqual(fileutil.windows_expanduser(u"a~"), u"a~")
         self.failUnlessReallyEqual(fileutil.windows_expanduser(u"a\\~\\foo"), u"a\\~\\foo")
 
+    def test_windows_expanduser_xp(self):
+        return self._test_windows_expanduser(homedrive=u"C:", homepath=u"\\Documents and Settings\\\u0100")
+
+    def test_windows_expanduser_win7(self):
+        return self._test_windows_expanduser(userprofile=os.path.join(u"C:", u"\\Documents and Settings\\\u0100"))
+
     def test_disk_stats(self):
         avail = fileutil.get_available_space('.', 2**14)
         if avail == 0:
diff --git a/src/allmydata/util/fileutil.py b/src/allmydata/util/fileutil.py
index 4dd501ce..0349669e 100644
--- a/src/allmydata/util/fileutil.py
+++ b/src/allmydata/util/fileutil.py
@@ -396,18 +396,28 @@ def expanduser(path):
 def windows_expanduser(path):
     if not path.startswith('~'):
         return path
-    home_drive = windows_getenv(u'HOMEDRIVE')
-    home_path = windows_getenv(u'HOMEPATH')
+
+    home_dir = windows_getenv(u'USERPROFILE')
+    if home_dir is None:
+        home_drive = windows_getenv(u'HOMEDRIVE')
+        home_path = windows_getenv(u'HOMEPATH')
+        if home_drive is None or home_path is None:
+            raise OSError("Could not find home directory: neither %USERPROFILE% nor (%HOMEDRIVE% and %HOMEPATH%) are set.")
+        home_dir = os.path.join(home_drive, home_path)
+
     if path == '~':
-        return os.path.join(home_drive, home_path)
+        return home_dir
     elif path.startswith('~/') or path.startswith('~\\'):
-        return os.path.join(home_drive, home_path, path[2 :])
+        return os.path.join(home_dir, path[2 :])
     else:
         return path
 
+# <https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382%28v=vs.85%29.aspx>
+ERROR_ENVVAR_NOT_FOUND = 203
+
 def windows_getenv(name):
     # Based on <http://stackoverflow.com/questions/2608200/problems-with-umlauts-in-python-appdata-environvent-variable/2608368#2608368>,
-    # with improved error handling.
+    # with improved error handling. Returns None if there is no enivronment variable of the given name.
     if not isinstance(name, unicode):
         raise AssertionError("name must be Unicode")
 
@@ -415,6 +425,8 @@ def windows_getenv(name):
     # GetEnvironmentVariableW returns DWORD, so n cannot be negative.
     if n == 0:
         err = GetLastError()
+        if err == ERROR_ENVVAR_NOT_FOUND:
+            return None
         raise OSError("Windows error %d attempting to read size of environment variable %r"
                       % (err, name))
     if n == 1:
@@ -426,6 +438,8 @@ def windows_getenv(name):
     retval = GetEnvironmentVariableW(name, buf, n)
     if retval == 0:
         err = GetLastError()
+        if err == ERROR_ENVVAR_NOT_FOUND:
+            return None
         raise OSError("Windows error %d attempting to read environment variable %r"
                       % (err, name))
     if retval >= n:
-- 
2.45.2