Skip to content

Commit

Permalink
[fusell] Support for character encoding
Browse files Browse the repository at this point in the history
The bytes<->unicode mismatch between Python 2 and 3 made fusell impossible to use on Py3 until now.

Previously, on PR #89, I made the minimal modifications necessary to have it working on Py3, but it basically left the duty of character encoding/decoding to the application.

Instead, this PR fully implements encoding/decoding of strings on the fuse_xxx, reply_readdir and reply_readlink functions, so that the applications only needs to handle unicode strings, similar to how it's done on fuse.py.
  • Loading branch information
paulo-raca committed Mar 22, 2018
1 parent 174664c commit 54761ac
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
2 changes: 1 addition & 1 deletion examples/memoryll.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def create_ino(self):
def init(self, userdata, conn):
self.ino = 1
self.attr = defaultdict(dict)
self.data = defaultdict(str)
self.data = defaultdict(bytes)
self.parent = {}
self.children = defaultdict(dict)

Expand Down
46 changes: 39 additions & 7 deletions fusell.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ def setattr_mask_to_list(mask):
class FUSELL(object):
use_ns = False

def __init__(self, mountpoint):
def __init__(self, mountpoint, encoding='utf-8'):
if not self.use_ns:
warnings.warn(
'Time as floating point seconds for utimens is deprecated!\n'
Expand All @@ -477,6 +477,7 @@ def __init__(self, mountpoint):
DeprecationWarning)

self.libfuse = LibFUSE()
self.encoding = encoding

fuse_ops = fuse_lowlevel_ops()

Expand All @@ -486,11 +487,11 @@ def __init__(self, mountpoint):
setattr(fuse_ops, name, prototype(method))

args = ['fuse']
argv = fuse_args(len(args), (ctypes.c_char_p * len(args))(*args), 0)
argv = fuse_args(len(args), (ctypes.c_char_p * len(args))(*[arg.encode(self.encoding) for arg in args]), 0)

# TODO: handle initialization errors

chan = self.libfuse.fuse_mount(mountpoint, argv)
chan = self.libfuse.fuse_mount(mountpoint.encode(encoding), argv)
assert chan

session = self.libfuse.fuse_lowlevel_new(
Expand Down Expand Up @@ -520,7 +521,7 @@ def __init__(self, mountpoint):

self.libfuse.fuse_session_remove_chan(chan)
self.libfuse.fuse_session_destroy(session)
self.libfuse.fuse_unmount(mountpoint, chan)
self.libfuse.fuse_unmount(mountpoint.encode(encoding), chan)

def reply_err(self, req, err):
return self.libfuse.fuse_reply_err(req, err)
Expand All @@ -543,7 +544,7 @@ def reply_attr(self, req, attr, attr_timeout):

def reply_readlink(self, req, link):
return self.libfuse.fuse_reply_readlink(
req, link)
req, link.encode(self.encoding))

def reply_open(self, req, d):
fi = fuse_file_info(**d)
Expand All @@ -559,6 +560,7 @@ def reply_readdir(self, req, size, off, entries):
bufsize = 0
sized_entries = []
for name, attr in entries:
name = name.encode(self.encoding)
entsize = self.libfuse.fuse_add_direntry(req, None, 0, name, None, 0)
sized_entries.append((name, attr, entsize))
bufsize += entsize
Expand All @@ -584,6 +586,9 @@ def reply_readdir(self, req, size, off, entries):
# If you override the following methods you should reply directly
# with the self.libfuse.fuse_reply_* methods.

def fuse_lookup(self, req, parent, name):
self.lookup(req, parent, name.decode(self.encoding))

def fuse_getattr(self, req, ino, fi):
self.getattr(req, ino, struct_to_dict(fi))

Expand All @@ -593,6 +598,27 @@ def fuse_setattr(self, req, ino, attr, to_set, fi):
fi_dict = struct_to_dict(fi)
self.setattr(req, ino, attr_dict, to_set_list, fi_dict)

def fuse_mknod(self, req, parent, name, mode, rdev):
self.mknod(req, parent, name.decode(self.encoding), mode, rdev)

def fuse_mkdir(self, req, parent, name, mode):
self.mkdir(req, parent, name.decode(self.encoding), mode)

def fuse_unlink(self, req, parent, name):
self.unlink(req, parent, name.decode(self.encoding))

def fuse_rmdir(self, req, parent, name):
self.rmdir(req, parent, name.decode(self.encoding))

def fuse_symlink(self, req, link, parent, name):
self.symlink(req, link.decode(self.encoding), parent, name.decode(self.encoding))

def fuse_rename(self, req, parent, name, newparent, newname):
self.rename(req, parent, name.decode(self.encoding), newparent, newname.decode(self.encoding))

def fuse_link(self, req, ino, newparent, newname):
self.link(req, ino, newparent, newname.decode(self.encoding))

def fuse_open(self, req, ino, fi):
self.open(req, ino, struct_to_dict(fi))

Expand Down Expand Up @@ -626,10 +652,16 @@ def fuse_fsyncdir(self, req, ino, datasync, fi):
self.fsyncdir(req, ino, datasync, struct_to_dict(fi))

def fuse_setxattr(self, req, ino, name, value, size, flags):
self.setxattr(req, ino, name, ctypes.string_at(value, size), flags)
self.setxattr(req, ino, name.decode(self.encoding), ctypes.string_at(value, size), flags)

def fuse_getxattr(self, req, ino, name, size):
self.getxattr(req, ino, name.decode(self.encoding), size)

def fuse_removexattr(self, req, ino, name):
self.removexattr(req, ino, name.decode(self.encoding))

def fuse_create(self, req, parent, name, mode, fi):
self.create(req, parent, name, mode, struct_to_dict(fi))
self.create(req, parent, name.decode(self.encoding), mode, struct_to_dict(fi))

# Utility methods

Expand Down

0 comments on commit 54761ac

Please sign in to comment.