summaryrefslogtreecommitdiffstats
path: root/gluster
diff options
context:
space:
mode:
Diffstat (limited to 'gluster')
-rwxr-xr-xgluster/api.py315
-rwxr-xr-xgluster/gfapi.py44
2 files changed, 193 insertions, 166 deletions
diff --git a/gluster/api.py b/gluster/api.py
index 62135c5..c7270bb 100755
--- a/gluster/api.py
+++ b/gluster/api.py
@@ -11,6 +11,7 @@
import ctypes
from ctypes.util import find_library
+from ctypes import sizeof
# LD_LIBRARY_PATH is not looked up by ctypes.util.find_library()
@@ -41,6 +42,18 @@ except OSError:
raise ImportError("ctypes.CDLL() cannot load {0}. You might want to set "
"LD_LIBRARY_PATH env variable".format(so_file_name))
+# c_ssize_t was only added in py27. Manually backporting it here for py26
+try:
+ import ctypes.c_ssize_t
+except ImportError:
+ if sizeof(ctypes.c_uint) == sizeof(ctypes.c_void_p):
+ setattr(ctypes, 'c_ssize_t', ctypes.c_int)
+ elif sizeof(ctypes.c_ulong) == sizeof(ctypes.c_void_p):
+ setattr(ctypes, 'c_ssize_t', ctypes.c_long)
+ elif sizeof(ctypes.c_ulonglong) == sizeof(ctypes.c_void_p):
+ setattr(ctypes, 'c_ssize_t', ctypes.c_longlong)
+
+
# Wow, the Linux kernel folks really play nasty games with this structure. If
# you look at the man page for stat(2) and then at this definition you'll note
# two discrepancies. First, we seem to have st_nlink and st_mode reversed. In
@@ -244,212 +257,224 @@ class Dirent (ctypes.Structure):
# }
#
+def gfapi_prototype(method_name, restype, *argtypes):
+ """
+ Create a named foreign function belonging to gfapi
+
+ :param method_name: Name of the foreign function
+ :param restype: resulting type
+ :param argtypes: arguments that represent argument types
+ :returns: foreign function of gfapi library
+ """
+ # use_errno=True ensures that errno is exposed by ctypes.get_errno()
+ return ctypes.CFUNCTYPE(restype, *argtypes, use_errno=True)(
+ (method_name, client)
+ )
+
# Define function prototypes for the wrapper functions.
-glfs_init = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p)(('glfs_init', client))
+glfs_init = gfapi_prototype('glfs_init', ctypes.c_int, ctypes.c_void_p)
-glfs_statvfs = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_void_p)(('glfs_statvfs', client))
+glfs_statvfs = gfapi_prototype('glfs_statvfs', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_void_p)
-glfs_new = ctypes.CFUNCTYPE(
- ctypes.c_void_p, ctypes.c_char_p)(('glfs_new', client))
+glfs_new = gfapi_prototype('glfs_new', ctypes.c_void_p, ctypes.c_char_p)
-glfs_set_volfile_server = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_char_p,
- ctypes.c_int)(('glfs_set_volfile_server', client)) # noqa
+glfs_set_volfile_server = gfapi_prototype(
+ 'glfs_set_volfile_server', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int)
-glfs_set_logging = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_int)(('glfs_set_logging', client))
+glfs_set_logging = gfapi_prototype('glfs_set_logging', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_int)
+
+glfs_fini = gfapi_prototype('glfs_fini', ctypes.c_int,
+ ctypes.c_void_p)
-glfs_fini = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p)(('glfs_fini', client))
+glfs_creat = gfapi_prototype('glfs_creat', ctypes.c_void_p, ctypes.c_void_p,
+ ctypes.c_char_p, ctypes.c_int, ctypes.c_uint)
+glfs_open = gfapi_prototype('glfs_open', ctypes.c_void_p, ctypes.c_void_p,
+ ctypes.c_char_p, ctypes.c_int)
-glfs_close = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p)(('glfs_close', client))
+glfs_close = gfapi_prototype('glfs_close', ctypes.c_int,
+ ctypes.c_void_p)
-glfs_lstat = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_char_p,
- ctypes.POINTER(Stat))(('glfs_lstat', client))
+glfs_lstat = gfapi_prototype('glfs_lstat', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_char_p,
+ ctypes.POINTER(Stat))
-glfs_stat = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_char_p,
- ctypes.POINTER(Stat))(('glfs_stat', client))
+glfs_stat = gfapi_prototype('glfs_stat', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_char_p,
+ ctypes.POINTER(Stat))
-glfs_fstat = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.POINTER(
- Stat))(('glfs_fstat', client))
+glfs_fstat = gfapi_prototype('glfs_fstat', ctypes.c_int,
+ ctypes.c_void_p, ctypes.POINTER(Stat))
-glfs_chmod = ctypes.CFUNCTYPE(ctypes.c_int,
+glfs_chmod = gfapi_prototype('glfs_chmod', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_ushort)
+
+glfs_fchmod = gfapi_prototype('glfs_fchmod', ctypes.c_int,
ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_ushort)(('glfs_chmod', client))
+ ctypes.c_ushort)
-glfs_fchmod = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_ushort)(('glfs_fchmod', client))
+glfs_chown = gfapi_prototype('glfs_chown', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_uint,
+ ctypes.c_uint)
-glfs_chown = ctypes.CFUNCTYPE(ctypes.c_int,
+glfs_lchown = gfapi_prototype('glfs_lchown', ctypes.c_int,
ctypes.c_void_p,
ctypes.c_char_p,
ctypes.c_uint,
- ctypes.c_uint)(('glfs_chown', client))
+ ctypes.c_uint)
-glfs_lchown = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_uint,
- ctypes.c_uint)(('glfs_lchown', client))
+glfs_fchown = gfapi_prototype('glfs_fchown', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_uint,
+ ctypes.c_uint)
-glfs_fchown = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_uint,
- ctypes.c_uint)(('glfs_fchown', client))
+glfs_dup = gfapi_prototype('glfs_dup', ctypes.c_void_p,
+ ctypes.c_void_p)
-glfs_dup = ctypes.CFUNCTYPE(
- ctypes.c_void_p, ctypes.c_void_p)(('glfs_dup', client))
+glfs_fdatasync = gfapi_prototype('glfs_fdatasync', ctypes.c_int,
+ ctypes.c_void_p)
-glfs_fdatasync = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p)(('glfs_fdatasync', client))
+glfs_fsync = gfapi_prototype('glfs_fsync', ctypes.c_int,
+ ctypes.c_void_p)
-glfs_fsync = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p)(('glfs_fsync', client))
+glfs_lseek = gfapi_prototype('glfs_lseek', ctypes.c_ulong,
+ ctypes.c_void_p, ctypes.c_ulong,
+ ctypes.c_int)
-glfs_lseek = ctypes.CFUNCTYPE(ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong,
- ctypes.c_int)(('glfs_lseek', client))
+glfs_read = gfapi_prototype('glfs_read', ctypes.c_ssize_t,
+ ctypes.c_void_p,
+ ctypes.c_void_p,
+ ctypes.c_size_t,
+ ctypes.c_int)
-glfs_read = ctypes.CFUNCTYPE(ctypes.c_ssize_t,
+glfs_write = gfapi_prototype('glfs_write', ctypes.c_ssize_t,
ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_size_t,
- ctypes.c_int)(('glfs_read', client))
+ ctypes.c_int)
-glfs_write = ctypes.CFUNCTYPE(ctypes.c_ssize_t,
- ctypes.c_void_p,
- ctypes.c_void_p,
- ctypes.c_size_t,
- ctypes.c_int)(('glfs_write', client))
+glfs_getxattr = gfapi_prototype('glfs_getxattr', ctypes.c_ssize_t,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_char_p,
+ ctypes.c_void_p,
+ ctypes.c_size_t)
-glfs_getxattr = ctypes.CFUNCTYPE(ctypes.c_ssize_t,
+glfs_listxattr = gfapi_prototype('glfs_listxattr', ctypes.c_ssize_t,
ctypes.c_void_p,
ctypes.c_char_p,
- ctypes.c_char_p,
ctypes.c_void_p,
- ctypes.c_size_t)(('glfs_getxattr', client))
+ ctypes.c_size_t)
-glfs_listxattr = ctypes.CFUNCTYPE(ctypes.c_ssize_t,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_void_p,
- ctypes.c_size_t)(('glfs_listxattr', client))
+glfs_removexattr = gfapi_prototype('glfs_removexattr', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_char_p)
-glfs_removexattr = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_char_p)(('glfs_removexattr', client)) # noqa
+glfs_setxattr = gfapi_prototype('glfs_setxattr', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_char_p,
+ ctypes.c_void_p,
+ ctypes.c_size_t,
+ ctypes.c_int)
-glfs_setxattr = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_char_p,
- ctypes.c_void_p,
- ctypes.c_size_t,
- ctypes.c_int)(('glfs_setxattr', client))
+glfs_rename = gfapi_prototype('glfs_rename', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_char_p)
-glfs_rename = ctypes.CFUNCTYPE(ctypes.c_int,
+glfs_symlink = gfapi_prototype('glfs_symlink', ctypes.c_int,
ctypes.c_void_p,
ctypes.c_char_p,
- ctypes.c_char_p)(('glfs_rename', client))
+ ctypes.c_char_p)
-glfs_symlink = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_char_p)(('glfs_symlink', client))
+glfs_unlink = gfapi_prototype('glfs_unlink', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_char_p)
-glfs_unlink = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p, ctypes.c_char_p)(('glfs_unlink', client))
+glfs_readdir_r = gfapi_prototype('glfs_readdir_r', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.POINTER(Dirent),
+ ctypes.POINTER(ctypes.POINTER(Dirent)))
-glfs_readdir_r = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p,
- ctypes.POINTER(Dirent),
- ctypes.POINTER(ctypes.POINTER(Dirent)))(('glfs_readdir_r', client)) # noqa
+glfs_closedir = gfapi_prototype('glfs_closedir', ctypes.c_int,
+ ctypes.c_void_p)
-glfs_closedir = ctypes.CFUNCTYPE(
- ctypes.c_int, ctypes.c_void_p)(('glfs_closedir', client))
+glfs_mkdir = gfapi_prototype('glfs_mkdir', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_char_p,
+ ctypes.c_ushort)
+glfs_opendir = gfapi_prototype('glfs_opendir', ctypes.c_void_p,
+ ctypes.c_void_p,
+ ctypes.c_char_p)
-glfs_mkdir = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_char_p,
- ctypes.c_ushort)(('glfs_mkdir', client))
+glfs_rmdir = gfapi_prototype('glfs_rmdir', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p)
-glfs_opendir = ctypes.CFUNCTYPE(ctypes.c_void_p,
- ctypes.c_void_p,
- ctypes.c_char_p)(('glfs_opendir', client))
+glfs_setfsuid = gfapi_prototype('glfs_setfsuid', ctypes.c_int,
+ ctypes.c_uint)
-glfs_rmdir = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p)(('glfs_rmdir', client))
+glfs_setfsgid = gfapi_prototype('glfs_setfsgid', ctypes.c_int,
+ ctypes.c_uint)
-glfs_setfsuid = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_uint)(('glfs_setfsuid', client))
+glfs_ftruncate = gfapi_prototype('glfs_ftruncate', ctypes.c_int,
+ ctypes.c_void_p, ctypes.c_int)
-glfs_setfsgid = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_uint)(('glfs_setfsgid', client))
-
-glfs_ftruncate = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p,
- ctypes.c_int)(('glfs_ftruncate', client))
+glfs_fgetxattr = gfapi_prototype('glfs_fgetxattr', ctypes.c_ssize_t,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_void_p,
+ ctypes.c_size_t)
-glfs_fgetxattr = ctypes.CFUNCTYPE(ctypes.c_ssize_t,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_void_p,
- ctypes.c_size_t)(('glfs_fgetxattr', client))
+glfs_fremovexattr = gfapi_prototype('glfs_fremovexattr', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p)
-glfs_fremovexattr = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p)(('glfs_fremovexattr',
- client))
+glfs_fsetxattr = gfapi_prototype('glfs_fsetxattr', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_void_p,
+ ctypes.c_size_t,
+ ctypes.c_int)
-glfs_fsetxattr = ctypes.CFUNCTYPE(ctypes.c_int,
+glfs_flistxattr = gfapi_prototype('glfs_flistxattr', ctypes.c_ssize_t,
ctypes.c_void_p,
- ctypes.c_char_p,
ctypes.c_void_p,
- ctypes.c_size_t,
- ctypes.c_int)(('glfs_fsetxattr', client))
+ ctypes.c_size_t)
-glfs_flistxattr = ctypes.CFUNCTYPE(ctypes.c_ssize_t,
- ctypes.c_void_p,
- ctypes.c_void_p,
- ctypes.c_size_t)(('glfs_flistxattr',
- client))
+glfs_access = gfapi_prototype('glfs_access', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_int)
-glfs_access = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_int)(('glfs_access', client))
+glfs_readlink = gfapi_prototype('glfs_readlink', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p,
+ ctypes.c_char_p,
+ ctypes.c_size_t)
-glfs_readlink = ctypes.CFUNCTYPE(ctypes.c_int,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_char_p,
- ctypes.c_size_t)(('glfs_readlink', client))
+glfs_chdir = gfapi_prototype('glfs_chdir', ctypes.c_int,
+ ctypes.c_void_p,
+ ctypes.c_char_p)
-glfs_chdir = ctypes.CFUNCTYPE(ctypes.c_int,
+glfs_getcwd = gfapi_prototype('glfs_getcwd', ctypes.c_char_p,
ctypes.c_void_p,
- ctypes.c_char_p)(('glfs_chdir', client))
-
-glfs_getcwd = ctypes.CFUNCTYPE(ctypes.c_char_p,
- ctypes.c_void_p,
- ctypes.c_char_p,
- ctypes.c_size_t)(('glfs_getcwd', client))
+ ctypes.c_char_p,
+ ctypes.c_size_t)
-# TODO: creat and open fails on test_create_file_already_exists & test_open_file_not_exist functional testing, # noqa
-# when defined via function prototype.. Need to find RCA. For time being, using it from 'api.glfs_' # noqa
-#_glfs_creat = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_uint) # noqa
- # (('glfs_creat', client)) # noqa
-#_glfs_open = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int) # noqa
-# (('glfs_open', client)) # noqa
# TODO: # discard and fallocate fails with "AttributeError: /lib64/libgfapi.so.0: undefined symbol: glfs_discard", # noqa
# for time being, using it from api.* # noqa
# glfs_discard = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_ulong, ctypes.c_size_t)(('glfs_discard', client)) # noqa
@@ -457,8 +482,6 @@ glfs_getcwd = ctypes.CFUNCTYPE(ctypes.c_char_p,
# (('glfs_fallocate', client)) # noqa
-#glfs_creat = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_uint)(('glfs_creat', client)) # noqa
-#glfs_open = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int)(('glfs_open', client)) # noqa
#glfs_discard = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_ulong, ctypes.c_size_t)(('glfs_discard', client)) # noqa
#glfs_fallocate = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_ulong, ctypes.c_size_t)(('glfs_fallocate', client)) # noqa
diff --git a/gluster/gfapi.py b/gluster/gfapi.py
index 5bbb8cb..3a344c8 100755
--- a/gluster/gfapi.py
+++ b/gluster/gfapi.py
@@ -432,28 +432,31 @@ class Volume(object):
self.fs = api.glfs_new(self.volname)
if not self.fs:
- raise LibgfapiException("glfs_new(%s) failed." % (self.volname))
+ err = ctypes.get_errno()
+ raise LibgfapiException("glfs_new(%s) failed: %s" %
+ (self.volname, os.strerror(err)))
ret = api.glfs_set_volfile_server(self.fs, self.protocol,
self.host, self.port)
if ret < 0:
- # FIXME: For some reason, get_errno() is not able to capture
- # proper errno. Until then..
- # https://bugzilla.redhat.com/show_bug.cgi?id=1196161
+ err = ctypes.get_errno()
raise LibgfapiException("glfs_set_volfile_server(%s, %s, %s, "
- "%s) failed." % (self.fs, self.protocol,
- self.host, self.port))
+ "%s) failed: %s" % (self.fs, self.protocol,
+ self.host, self.port,
+ os.strerror(err)))
self.set_logging(self.log_file, self.log_level)
if self.fs and not self._mounted:
ret = api.glfs_init(self.fs)
if ret < 0:
- raise LibgfapiException("glfs_init(%s) failed." % (self.fs))
+ err = ctypes.get_errno()
+ raise LibgfapiException("glfs_init(%s) failed: %s" %
+ (self.fs, os.strerror(err)))
else:
self._mounted = True
- def unmount(self):
+ def umount(self):
"""
Unmount a mounted GlusterFS volume.
@@ -463,15 +466,17 @@ class Volume(object):
if self.fs:
ret = self._api.glfs_fini(self.fs)
if ret < 0:
- raise LibgfapiException("glfs_fini(%s) failed." % (self.fs))
+ err = ctypes.get_errno()
+ raise LibgfapiException("glfs_fini(%s) failed: %s" %
+ (self.fs, os.strerror(err)))
else:
- # Succeeded. Protect against multiple unmount() calls.
+ # Succeeded. Protect against multiple umount() calls.
self._mounted = False
self.fs = None
def __del__(self):
try:
- self.unmount()
+ self.umount()
except LibgfapiException:
pass
@@ -497,8 +502,10 @@ class Volume(object):
if self.fs:
ret = api.glfs_set_logging(self.fs, self.log_file, self.log_level)
if ret < 0:
- raise LibgfapiException("glfs_set_logging(%s, %s) failed." %
- (self.log_file, self.log_level))
+ err = ctypes.get_errno()
+ raise LibgfapiException("glfs_set_logging(%s, %s) failed: %s" %
+ (self.log_file, self.log_level,
+ os.strerror(err)))
self.log_file = log_file
self.log_level = log_level
@@ -777,9 +784,9 @@ class Volume(object):
raise ValueError("Invalid mode")
else:
if (os.O_CREAT & flags) == os.O_CREAT:
- fd = api.client.glfs_creat(self.fs, path, flags, 0666)
+ fd = api.glfs_creat(self.fs, path, flags, 0666)
else:
- fd = api.client.glfs_open(self.fs, path, flags)
+ fd = api.glfs_open(self.fs, path, flags)
if not fd:
err = ctypes.get_errno()
raise OSError(err, os.strerror(err))
@@ -803,12 +810,9 @@ class Volume(object):
raise TypeError("flags must evaluate to an integer")
if (os.O_CREAT & flags) == os.O_CREAT:
- # FIXME:
- # Without direct call to _api the functest fails on creat and open.
-
- fd = api.client.glfs_creat(self.fs, path, flags, mode)
+ fd = api.glfs_creat(self.fs, path, flags, mode)
else:
- fd = api.client.glfs_open(self.fs, path, flags)
+ fd = api.glfs_open(self.fs, path, flags)
if not fd:
err = ctypes.get_errno()
raise OSError(err, os.strerror(err))