From c20a3525b7db8631a7541745efbc80b8718ca274 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Fri, 30 Jan 2015 00:05:14 +0000 Subject: [PATCH] Use "long" paths prefixed with \\?\ on Windows. refs #2235 Signed-off-by: Daira Hopwood --- src/allmydata/scripts/debug.py | 4 ++-- src/allmydata/test/test_cli.py | 14 +++++++------- src/allmydata/test/test_client.py | 11 ++++++----- src/allmydata/test/test_util.py | 29 +++++++++++++++++++++++++++-- src/allmydata/util/fileutil.py | 23 ++++++++++++++++++++++- 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/allmydata/scripts/debug.py b/src/allmydata/scripts/debug.py index 8ef82eca..1bba9d5f 100644 --- a/src/allmydata/scripts/debug.py +++ b/src/allmydata/scripts/debug.py @@ -650,7 +650,7 @@ def find_shares(options): out = options.stdout sharedir = storage_index_to_dir(si_a2b(options.si_s)) for d in options.nodedirs: - d = os.path.join(d, "storage/shares", sharedir) + d = os.path.join(d, "storage", "shares", sharedir) if os.path.exists(d): for shnum in listdir_unicode(d): print >>out, os.path.join(d, shnum) @@ -832,7 +832,7 @@ def catalog_shares(options): err = options.stderr now = time.time() for d in options.nodedirs: - d = os.path.join(d, "storage/shares") + d = os.path.join(d, "storage", "shares") try: abbrevs = listdir_unicode(d) except EnvironmentError: diff --git a/src/allmydata/test/test_cli.py b/src/allmydata/test/test_cli.py index 6bc5fc1c..a277f0b6 100644 --- a/src/allmydata/test/test_cli.py +++ b/src/allmydata/test/test_cli.py @@ -3779,7 +3779,7 @@ class Webopen(GridTestMixin, CLITestMixin, unittest.TestCase): raise return d -class Options(unittest.TestCase): +class Options(ReallyEqualMixin, unittest.TestCase): # this test case only looks at argument-processing and simple stuff. def parse(self, args, stdout=None): @@ -3861,17 +3861,17 @@ class Options(unittest.TestCase): # option after, or a basedir argument after, but none in the wrong # place, and not more than one of the three. o = self.parse(["start"]) - self.failUnlessEqual(o["basedir"], os.path.join(os.path.expanduser("~"), - ".tahoe")) + self.failUnlessReallyEqual(o["basedir"], os.path.join(fileutil.abspath_expanduser_unicode(u"~"), + u".tahoe")) o = self.parse(["start", "here"]) - self.failUnlessEqual(o["basedir"], os.path.abspath("here")) + self.failUnlessReallyEqual(o["basedir"], fileutil.abspath_expanduser_unicode(u"here")) o = self.parse(["start", "--basedir", "there"]) - self.failUnlessEqual(o["basedir"], os.path.abspath("there")) + self.failUnlessReallyEqual(o["basedir"], fileutil.abspath_expanduser_unicode(u"there")) o = self.parse(["--node-directory", "there", "start"]) - self.failUnlessEqual(o["basedir"], os.path.abspath("there")) + self.failUnlessReallyEqual(o["basedir"], fileutil.abspath_expanduser_unicode(u"there")) o = self.parse(["start", "here", "--nodaemon"]) - self.failUnlessEqual(o["basedir"], os.path.abspath("here")) + self.failUnlessReallyEqual(o["basedir"], fileutil.abspath_expanduser_unicode(u"here")) self.failUnlessRaises(usage.UsageError, self.parse, ["--basedir", "there", "start"]) diff --git a/src/allmydata/test/test_client.py b/src/allmydata/test/test_client.py index 531215f6..f5b0526b 100644 --- a/src/allmydata/test/test_client.py +++ b/src/allmydata/test/test_client.py @@ -1,4 +1,4 @@ -import os +import os, sys from twisted.trial import unittest from twisted.application import service @@ -68,10 +68,11 @@ class Basic(testutil.ReallyEqualMixin, unittest.TestCase): fileutil.write(os.path.join(basedir, "debug_discard_storage"), "") e = self.failUnlessRaises(OldConfigError, client.Client, basedir) - self.failUnlessIn(os.path.abspath(os.path.join(basedir, "introducer.furl")), e.args[0]) - self.failUnlessIn(os.path.abspath(os.path.join(basedir, "no_storage")), e.args[0]) - self.failUnlessIn(os.path.abspath(os.path.join(basedir, "readonly_storage")), e.args[0]) - self.failUnlessIn(os.path.abspath(os.path.join(basedir, "debug_discard_storage")), e.args[0]) + abs_basedir = fileutil.abspath_expanduser_unicode(unicode(basedir)).encode(sys.getfilesystemencoding()) + self.failUnlessIn(os.path.join(abs_basedir, "introducer.furl"), e.args[0]) + self.failUnlessIn(os.path.join(abs_basedir, "no_storage"), e.args[0]) + self.failUnlessIn(os.path.join(abs_basedir, "readonly_storage"), e.args[0]) + self.failUnlessIn(os.path.join(abs_basedir, "debug_discard_storage"), e.args[0]) for oldfile in ['introducer.furl', 'no_storage', 'readonly_storage', 'debug_discard_storage']: diff --git a/src/allmydata/test/test_util.py b/src/allmydata/test/test_util.py index 20f157b9..16e8383f 100644 --- a/src/allmydata/test/test_util.py +++ b/src/allmydata/test/test_util.py @@ -15,6 +15,8 @@ from allmydata.util import limiter, time_format, pollmixin, cachedir from allmydata.util import statistics, dictutil, pipeline from allmydata.util import log as tahoe_log from allmydata.util.spans import Spans, overlap, DataSpans +from allmydata.test.common_util import ReallyEqualMixin + class Base32(unittest.TestCase): def test_b2a_matches_Pythons(self): @@ -370,7 +372,7 @@ class Asserts(unittest.TestCase): m = self.should_assert(f, False, othermsg="message2") self.failUnlessEqual("postcondition: othermsg: 'message2' ", m) -class FileUtil(unittest.TestCase): +class FileUtil(ReallyEqualMixin, unittest.TestCase): def mkdir(self, basedir, path, mode=0777): fn = os.path.join(basedir, path) fileutil.make_dirs(fn, mode) @@ -472,7 +474,16 @@ class FileUtil(unittest.TestCase): abspath_cwd = fileutil.abspath_expanduser_unicode(u".") self.failUnless(isinstance(saved_cwd, unicode), saved_cwd) self.failUnless(isinstance(abspath_cwd, unicode), abspath_cwd) - self.failUnlessEqual(abspath_cwd, saved_cwd) + if sys.platform == "win32": + self.failUnlessReallyEqual(abspath_cwd, fileutil.to_windows_long_path(saved_cwd)) + else: + self.failUnlessReallyEqual(abspath_cwd, saved_cwd) + + self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"\\\\?\\foo"), u"\\\\?\\foo") + self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"\\\\.\\foo"), u"\\\\.\\foo") + self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"\\\\server\\foo"), u"\\\\?\\UNC\\server\\foo") + self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"C:\\foo"), u"\\\\?\\C:\\foo") + self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"C:\\foo/bar"), u"\\\\?\\C:\\foo\\bar") # adapted from @@ -496,6 +507,20 @@ class FileUtil(unittest.TestCase): finally: os.chdir(saved_cwd) + def test_create_long_path(self): + workdir = u"test_create_long_path" + fileutil.make_dirs(workdir) + long_path = fileutil.abspath_expanduser_unicode(os.path.join(workdir, u'x'*255)) + def _cleanup(): + fileutil.remove(long_path) + self.addCleanup(_cleanup) + + fileutil.write(long_path, "test") + self.failUnless(os.path.exists(long_path)) + self.failUnlessEqual(fileutil.read(long_path), "test") + _cleanup() + self.failIf(os.path.exists(long_path)) + 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 9446a3f6..9bacf130 100644 --- a/src/allmydata/util/fileutil.py +++ b/src/allmydata/util/fileutil.py @@ -305,7 +305,28 @@ def abspath_expanduser_unicode(path): # We won't hit because # there is always at least one Unicode path component. - return os.path.normpath(path) + path = os.path.normpath(path) + + if sys.platform == "win32": + path = to_windows_long_path(path) + + return path + +def to_windows_long_path(path): + # '/' is normally a perfectly valid path component separator in Windows. + # However, when using the "\\?\" syntax it is not recognized, so we + # replace it with '\' here. + path = path.replace(u"/", u"\\") + + # Note that other normalizations such as removing '.' and '..' should + # be done outside this function. + + if path.startswith(u"\\\\?\\") or path.startswith(u"\\\\.\\"): + return path + elif path.startswith(u"\\\\"): + return u"\\\\?\\UNC\\" + path[2 :] + else: + return u"\\\\?\\" + path have_GetDiskFreeSpaceExW = False -- 2.37.2