From d21f4071c3229e18b5038909c2371ab58702d559 Mon Sep 17 00:00:00 2001 From: david-sarah Date: Tue, 18 Jan 2011 23:59:11 -0800 Subject: [PATCH] Eliminate direct dependencies of Tahoe-LAFS on pywin32 (rebased to trunk). refs #1274 --- src/allmydata/_auto_deps.py | 3 -- src/allmydata/util/fileutil.py | 65 ++++++++++++++++++++++----------- src/allmydata/windows/fixups.py | 19 +++++++--- 3 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/allmydata/_auto_deps.py b/src/allmydata/_auto_deps.py index f02155d4..f77db1c0 100644 --- a/src/allmydata/_auto_deps.py +++ b/src/allmydata/_auto_deps.py @@ -69,9 +69,6 @@ if sys.version_info < (2, 5): ## # it is going to offer iocp reactor. We currently require process management. It would be ## # better if Twisted would declare that it requires pywin32 if it is going to offer process ## # management. That is twisted ticket #3238 -- http://twistedmatrix.com/trac/ticket/3238 . -## # On the other hand, Tahoe also depends on pywin32 for getting free disk space statistics -## # (although that is not a hard requirement: if win32api can't be imported then we don't -## # rely on having the disk stats). ## install_requires.append('pywin32') if hasattr(sys, 'frozen'): # for py2exe diff --git a/src/allmydata/util/fileutil.py b/src/allmydata/util/fileutil.py index 9a41c237..bfcffd8f 100644 --- a/src/allmydata/util/fileutil.py +++ b/src/allmydata/util/fileutil.py @@ -305,16 +305,27 @@ def abspath_expanduser_unicode(path): # there is always at least one Unicode path component. return os.path.normpath(path) -windows = False -try: - import win32api, win32con -except ImportError: - pass -else: - windows = True - # - win32api.SetErrorMode(win32con.SEM_FAILCRITICALERRORS | - win32con.SEM_NOOPENFILEERRORBOX) + +have_GetDiskFreeSpaceExW = False +if sys.platform == "win32": + try: + from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_ulonglong + from ctypes.wintypes import BOOL, DWORD, LPCWSTR + + # + PULARGE_INTEGER = POINTER(c_ulonglong) + + # + GetDiskFreeSpaceExW = WINFUNCTYPE(BOOL, LPCWSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)( + ("GetDiskFreeSpaceExW", windll.kernel32)) + + # + GetLastError = WINFUNCTYPE(DWORD)(("GetLastError", windll.kernel32)) + + have_GetDiskFreeSpaceExW = True + except Exception: + import traceback + traceback.print_exc() def get_disk_stats(whichdir, reserved_space=0): """Return disk statistics for the storage disk, in the form of a dict @@ -338,15 +349,24 @@ def get_disk_stats(whichdir, reserved_space=0): filesystem as reserved_space. """ - if windows: - # For Windows systems, where os.statvfs is not available, use GetDiskFreeSpaceEx. - # - # - # Although the docs say that the argument should be the root directory - # of a disk, GetDiskFreeSpaceEx actually accepts any path on that disk - # (like its Win32 equivalent). - - (free_for_nonroot, total, free_for_root) = win32api.GetDiskFreeSpaceEx(whichdir) + if have_GetDiskFreeSpaceExW: + # If this is a Windows system and GetDiskFreeSpaceExW is available, use it. + # (This might put up an error dialog unless + # SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX) has been called, + # which we do in allmydata.windows.fixups.initialize().) + + n_free_for_nonroot = c_ulonglong(0) + n_total = c_ulonglong(0) + n_free_for_root = c_ulonglong(0) + retval = GetDiskFreeSpaceExW(whichdir, byref(n_free_for_nonroot), + byref(n_total), + byref(n_free_for_root)) + if retval == 0: + raise OSError("Windows error %d attempting to get disk statistics for %r" + % (GetLastError(), whichdir)) + free_for_nonroot = n_free_for_nonroot.value + total = n_total.value + free_for_root = n_free_for_root.value else: # For Unix-like systems. # @@ -372,9 +392,12 @@ def get_disk_stats(whichdir, reserved_space=0): used = total - free_for_root avail = max(free_for_nonroot - reserved_space, 0) - return { 'total': total, 'free_for_root': free_for_root, + return { 'total': total, + 'free_for_root': free_for_root, 'free_for_nonroot': free_for_nonroot, - 'used': used, 'avail': avail, } + 'used': used, + 'avail': avail, + } def get_available_space(whichdir, reserved_space): """Returns available space for share storage in bytes, or None if no diff --git a/src/allmydata/windows/fixups.py b/src/allmydata/windows/fixups.py index 35e048b7..719abd2d 100644 --- a/src/allmydata/windows/fixups.py +++ b/src/allmydata/windows/fixups.py @@ -8,6 +8,19 @@ def initialize(): return True done = True + import codecs, re + from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int + from ctypes.wintypes import BOOL, HANDLE, DWORD, UINT, LPWSTR, LPCWSTR, LPVOID + from allmydata.util import log + from allmydata.util.encodingutil import canonical_encoding + + # + SetErrorMode = WINFUNCTYPE(UINT, UINT)(("SetErrorMode", windll.kernel32)) + SEM_FAILCRITICALERRORS = 0x0001 + SEM_NOOPENFILEERRORBOX = 0x8000 + + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX) + original_stderr = sys.stderr # If any exception occurs in this code, we'll probably try to print it on stderr, @@ -18,12 +31,6 @@ def initialize(): print >>original_stderr, isinstance(message, str) and message or repr(message) log.msg(message, level=log.WEIRD) - import codecs, re - from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int - from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR, LPVOID - from allmydata.util import log - from allmydata.util.encodingutil import canonical_encoding - # Work around . codecs.register(lambda name: name == 'cp65001' and codecs.lookup('utf-8') or None) -- 2.45.2