Commit 7d4cf224 by rfkelly0

dokan: make the module importable even if dokan is not installed.

This is useful for programs that bundle the dokan libraries and want to install
them if not available.  Check the "is_available" attribute to see if dokan is
actually available on the system.
parent 7f37704d
...@@ -72,15 +72,14 @@ from fs.functools import wraps ...@@ -72,15 +72,14 @@ from fs.functools import wraps
try: try:
import libdokan import libdokan
except EnvironmentError: except (NotImplementedError,EnvironmentError,ImportError):
raise ImportError("Dokan not found") is_available = False
except NotImplementedError: sys.modules.pop("fs.expose.dokan.libdokan",None)
raise ImportError("Dokan found but not usable") libdokan = None
else:
is_available = True
DokanMain = libdokan.DokanMain
DokanOperations = libdokan.DokanOperations
# Options controlling the behaiour of the Dokan filesystem # Options controlling the behaiour of the Dokan filesystem
DOKAN_OPTION_DEBUG = 1 DOKAN_OPTION_DEBUG = 1
DOKAN_OPTION_STDERR = 2 DOKAN_OPTION_STDERR = 2
...@@ -172,11 +171,12 @@ def handle_fs_errors(func): ...@@ -172,11 +171,12 @@ def handle_fs_errors(func):
MIN_FH = 100 MIN_FH = 100
class FSOperations(DokanOperations): class FSOperations:
"""DokanOperations interface delegating all activities to an FS object.""" """Object delegating all DOKAN_OPERTAIONS pointers to an FS object."""
def __init__(self, fs, fsname="Dokan FS", volname="Dokan Volume"): def __init__(self, fs, fsname="Dokan FS", volname="Dokan Volume"):
super(FSOperations,self).__init__() if libdokan is None:
raise OSError("dokan library is not available")
self.fs = fs self.fs = fs
self.fsname = fsname self.fsname = fsname
self.volname = volname self.volname = volname
...@@ -190,6 +190,17 @@ class FSOperations(DokanOperations): ...@@ -190,6 +190,17 @@ class FSOperations(DokanOperations):
# We explicitly keep track of the size FUSE expects a file to be. # We explicitly keep track of the size FUSE expects a file to be.
# This dict is indexed by path, then file handle. # This dict is indexed by path, then file handle.
self._files_size_written = {} self._files_size_written = {}
def get_ops_struct(self):
"""Get a DOKAN_OPERATIONS struct mapping to our methods."""
struct = libdokan.DOKAN_OPERATIONS()
for (nm,typ) in libdokan.DOKAN_OPERATIONS._fields_:
try:
setattr(struct,nm,typ(getattr(self,nm)))
except AttributeError:
# This bizarre syntax creates a NULL function pointer.
setattr(struct,nm,typ())
return struct
def _get_file(self, fh): def _get_file(self, fh):
try: try:
...@@ -591,13 +602,6 @@ def _datetime2filetime(dtime): ...@@ -591,13 +602,6 @@ def _datetime2filetime(dtime):
return _timestamp2filetime(_datetime2timestamp(dtime)) return _timestamp2filetime(_datetime2timestamp(dtime))
d = datetime.datetime.now()
t = _datetime2timestamp(d)
f = _datetime2filetime(d)
assert d == _timestamp2datetime(t)
assert t == _filetime2timestamp(_timestamp2filetime(t))
assert d == _filetime2datetime(f)
ERROR_FILE_EXISTS = 80 ERROR_FILE_EXISTS = 80
ERROR_DIR_NOT_EMPTY = 145 ERROR_DIR_NOT_EMPTY = 145
ERROR_NOT_SUPPORTED = 50 ERROR_NOT_SUPPORTED = 50
...@@ -651,6 +655,8 @@ def mount(fs, drive, foreground=False, ready_callback=None, unmount_callback=Non ...@@ -651,6 +655,8 @@ def mount(fs, drive, foreground=False, ready_callback=None, unmount_callback=Non
* FSOperationsClass: custom FSOperations subclass to use * FSOperationsClass: custom FSOperations subclass to use
""" """
if libdokan is None:
raise OSError("the dokan library is not available")
drive = _normalise_drive_string(drive) drive = _normalise_drive_string(drive)
# This function captures the logic of checking whether the Dokan mount # This function captures the logic of checking whether the Dokan mount
# is up and running. Unfortunately I can't find a way to get this # is up and running. Unfortunately I can't find a way to get this
...@@ -689,7 +695,8 @@ def mount(fs, drive, foreground=False, ready_callback=None, unmount_callback=Non ...@@ -689,7 +695,8 @@ def mount(fs, drive, foreground=False, ready_callback=None, unmount_callback=Non
check_thread = threading.Thread(target=check_ready) check_thread = threading.Thread(target=check_ready)
check_thread.daemon = True check_thread.daemon = True
check_thread.start() check_thread.start()
res = DokanMain(ctypes.byref(opts),ctypes.byref(ops.buffer)) opstruct = ops.get_ops_struct()
res = libdokan.DokanMain(ctypes.byref(opts),ctypes.byref(opstruct))
if res != DOKAN_SUCCESS: if res != DOKAN_SUCCESS:
raise OSError("Dokan failed with error: %d" % (res,)) raise OSError("Dokan failed with error: %d" % (res,))
if unmount_callback: if unmount_callback:
...@@ -745,6 +752,8 @@ class MountProcess(subprocess.Popen): ...@@ -745,6 +752,8 @@ class MountProcess(subprocess.Popen):
unmount_timeout = 5 unmount_timeout = 5
def __init__(self, fs, drive, dokan_opts={}, nowait=False, **kwds): def __init__(self, fs, drive, dokan_opts={}, nowait=False, **kwds):
if libdokan is None:
raise OSError("the dokan library is not available")
self.drive = _normalise_drive_string(drive) self.drive = _normalise_drive_string(drive)
self.path = self.drive + ":\\" self.path = self.drive + ":\\"
cmd = 'from fs.expose.dokan import MountProcess; ' cmd = 'from fs.expose.dokan import MountProcess; '
......
...@@ -209,23 +209,6 @@ class DOKAN_OPERATIONS(Structure): ...@@ -209,23 +209,6 @@ class DOKAN_OPERATIONS(Structure):
class DokanOperations(object):
"""Object interface to defining a DOKAN_OPERATIONS structure."""
def __init__(self):
self.buffer = DOKAN_OPERATIONS()
for (nm,typ) in DOKAN_OPERATIONS._fields_:
try:
setattr(self.buffer,nm,typ(getattr(self,nm)))
except AttributeError:
# This bizarre syntax creates a NULL function pointer.
setattr(self.buffer,nm,typ())
def _noop(self,*args):
return -1
DokanMain.restype = c_int DokanMain.restype = c_int
DokanMain.argtypes = ( DokanMain.argtypes = (
POINTER(DOKAN_OPTIONS), POINTER(DOKAN_OPTIONS),
......
...@@ -133,11 +133,8 @@ else: ...@@ -133,11 +133,8 @@ else:
return self.mounted_fs.exists(p) return self.mounted_fs.exists(p)
try: from fs.expose import dokan
from fs.expose import dokan if dokan.is_available:
except ImportError:
pass
else:
from fs.osfs import OSFS from fs.osfs import OSFS
class DokanTestCases(FSTestCases): class DokanTestCases(FSTestCases):
"""Specialised testcases for filesystems exposed via Dokan. """Specialised testcases for filesystems exposed via Dokan.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment