Mercurial > nomad > old-fuse
changeset 161:2d0546bd3c3f draft
WIP - add initial nomadsocket implementation
fs is now executable and specifies python2 in the shebang.
author | Steve Dougherty <steve@asksteved.com> |
---|---|
date | Sat, 17 Oct 2015 22:56:40 -0400 |
parents | e0eac67d92b2 |
children | 9edefbbd208f |
files | src/fs/fs src/fs/nomad/__init__.py src/fs/nomad/nomadsocket.py src/fs/nomad/xdrsock.py src/fs/nomadfs.py src/fs/nomadsocket.py src/fs/xdrsock.py |
diffstat | 6 files changed, 263 insertions(+), 155 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fs/fs Sat Oct 17 22:56:40 2015 -0400 @@ -0,0 +1,53 @@ +#!/usr/bin/env python2 +# +# Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +import errno +import fuse +import socket +from nomad import nomadsocket + +fuse.fuse_python_api = (0, 2) + + +class Nomad(fuse.Fuse): + def __init__(self, *args, **kw): + fuse.Fuse.__init__(self, *args, **kw) + # TODO: take hostname and port as arguments + # TODO: where to close these? fsdestroy? + self.sock = socket.create_connection(("localhost", 2323)) + self.conn = nomadsocket.NomadSocket(self.sock) + self.conn.nop() + + def getattr(self, path): + return -errno.ENOSYS + + def getdir(self, path): + return -errno.ENOSYS + + +if __name__ == "__main__": + fs = Nomad() + fs.flags = 0 + fs.multithreaded = 0 + fs.parse(errex=1) + fs.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fs/nomad/nomadsocket.py Sat Oct 17 22:56:40 2015 -0400 @@ -0,0 +1,126 @@ +from collections import namedtuple +import datetime +import nomad.xdrsock + +# TODO: use constantsgen +NOP = 0 +LOGIN = 1 +STAT = 2 +LOOKUP = 3 +CREATE = 4 +REMOVE = 5 + +# TODO: move this somewhere else +attributes = namedtuple("attributes", [ + "mode", + "nlink", # TODO: what is this? + "size", + "access_time", + "birth_time", + "creation_time", + "modification_time", +]) + +ZERO = datetime.timedelta(0) + + +class UTC(datetime.tzinfo): + """UTC""" + + def utcoffset(self, dt): + return ZERO + + def tzname(self, dt): + return "UTC" + + def dst(self, dt): + return ZERO + + +class NomadSocket(object): + + def __init__(self, sock): + self.conn = nomad.xdrsock.XDRSock(sock) + + def nop(self): + self._send_header(NOP) + self._recv_header() + + def login(self, conn_name, vg_name): + self._send_header(LOGIN) + self.conn.send_string(conn_name) + self.conn.send_string(vg_name) + + self._recv_header() + return self._recv_handle() + + def stat(self, handle): + self._send_header(STAT) + self._send_handle(handle) + + self._recv_header() + return attributes( + mode=self.conn.recv_u32(), + nlink=self.conn.recv_u32(), + size=self.conn.recv_u64(), + atime=self._recv_timestamp(), + btime=self._recv_timestamp(), + ctime=self._recv_timestamp(), + mtime=self._recv_timestamp(), + ) + + def lookup(self, parent_handle, name): + self._send_header(LOOKUP) + self._send_handle(parent_handle) + self.conn.send_string(name) + + self._recv_header() + return self._recv_handle() + + def create(self, parent_handle, name, mode): + self._send_header(CREATE) + self._send_handle(parent_handle) + self.conn.send_string(name) + self.conn.send_u32(mode) + + self._recv_header() + return self._recv_handle() + + def remove(self, parent_handle, name): + self._send_header(REMOVE) + self._send_handle(parent_handle) + self.conn.send_string(name) + + # TODO: what return codes? only exceptions? + self._recv_header() + + def _send_header(self, command): + self.conn.send_u32(command) + + def _recv_header(self): + value = self.conn.recv_u32() + # TODO: raise on nonzero instead? errors map? + assert value == 0 + return value + + # TODO: may want parsing of structures; can treat as opaque currently + #def _send_object_id(self, object_id): + # self.conn.send_fixed_string(object_id) + + #def _recv_object_id(self): + # # See xdr_noid: u32 and u64 + # return self.conn.recv_fixed_string(12) + + def _send_handle(self, handle): + self.conn.send_fixed_string(handle) + + def _recv_handle(self): + # oid - 12: u32 and u64 + # clock - 256: 16 * 2 * u64 + return self.conn.recv_fixed_string(12 + 256) + + def _recv_timestamp(self): + # Timestamps are returned in nanoseconds. + return datetime.datetime.fromtimestamp(self.conn.recv_u64() / 10 ** 9, + UTC()) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fs/nomad/xdrsock.py Sat Oct 17 22:56:40 2015 -0400 @@ -0,0 +1,84 @@ +# Copyright (c) 2015 Steve Dougherty <steve@asksteved.com> +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import xdrlib + + +class XDRSock(object): + + def __init__(self, sock): + """ + xdrlib socket wrapper. + + :type sock: socket.socket + """ + self.sock = sock + self.packer = xdrlib.Packer() + + def send_u32(self, value): + self.packer.reset() + self.packer.pack_uint(value) + self.sock.sendall(self.packer.get_buffer()) + + def send_u64(self, value): + self.packer.reset() + self.packer.pack_uhyper(value) + self.sock.sendall(self.packer.get_buffer()) + + def send_fixed_string(self, value): + self.packer.reset() + self.packer.pack_fstring(len(value), value) + self.sock.sendall(self.packer.get_buffer()) + + def send_string(self, value): + self.packer.reset() + self.packer.pack_string(value) + self.sock.sendall(self.packer.get_buffer()) + + def recv_u32(self): + unpacker = xdrlib.Unpacker(self.__recv(4)) + return unpacker.unpack_uint() + + def recv_u64(self): + unpacker = xdrlib.Unpacker(self.__recv(8)) + return unpacker.unpack_uhyper() + + def recv_fixed_string(self, length): + if length % 4: + padded_length = length + (4 - (length % 4)) + else: + padded_length = length + + unpacker = xdrlib.Unpacker(self.__recv(padded_length)) + return unpacker.unpack_fstring(length) + + def recv_string(self): + length = self.recv_u32() + return self.recv_fixed_string(length) + + def __recv(self, num_bytes): + chunks = [] + remaining_bytes = num_bytes + while remaining_bytes > 0: + chunk = self.sock.recv(remaining_bytes) + remaining_bytes -= len(chunk) + chunks.append(chunk) + + return b"".join(chunks)
--- a/src/fs/nomadfs.py Sat Oct 17 20:59:47 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -import errno -import fuse -import socket -import nomadsocket - -fuse.fuse_python_api = (0, 2) - - -class Nomad(fuse.Fuse): - def __init__(self, *args, **kw): - fuse.Fuse.__init__(self, *args, **kw) - # TODO: take hostname and port as arguments - # TODO: where to close these? fsdestroy? - self.sock = socket.create_connection(("localhost", 2323)) - self.conn = nomadsocket.NomadSocket(self.sock) - self.conn.nop() - - def getattr(self, path): - return -errno.ENOSYS - - def getdir(self, path): - return -errno.ENOSYS - - -if __name__ == "__main__": - fs = Nomad() - fs.flags = 0 - fs.multithreaded = 0 - fs.parse(errex=1) - fs.main()
--- a/src/fs/nomadsocket.py Sat Oct 17 20:59:47 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -import xdrsock - -# TODO: use constantsgen -NOP = 0 -LOGIN = 1 - - -class NomadSocket(object): - - def __init__(self, sock): - self.conn = xdrsock.XDRSock(sock) - - def _send_header(self, command): - self.conn.send_u32(command) - - def nop(self): - self._send_header(NOP) - assert self.conn.recv_u32() == 0
--- a/src/fs/xdrsock.py Sat Oct 17 20:59:47 2015 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -# Copyright (c) 2015 Steve Dougherty <steve@asksteved.com> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import xdrlib - - -class XDRSock(object): - - def __init__(self, sock): - """ - xdrlib socket wrapper. - - :type sock: socket.socket - """ - self.sock = sock - self.packer = xdrlib.Packer() - - def send_u32(self, value): - self.packer.reset() - self.packer.pack_uint(value) - self.sock.sendall(self.packer.get_buffer()) - - def send_u64(self, value): - self.packer.reset() - self.packer.pack_uhyper(value) - self.sock.sendall(self.packer.get_buffer()) - - def send_fixed_string(self, value): - self.packer.reset() - self.packer.pack_fstring(len(value), value) - self.sock.sendall(self.packer.get_buffer()) - - def send_string(self, value): - self.packer.reset() - self.packer.pack_string(value) - self.sock.sendall(self.packer.get_buffer()) - - def recv_u32(self): - unpacker = xdrlib.Unpacker(self.__recv(4)) - return unpacker.unpack_uint() - - def recv_u64(self): - unpacker = xdrlib.Unpacker(self.__recv(8)) - return unpacker.unpack_uhyper() - - def recv_fixed_string(self, length): - if length % 4: - padded_length = length + (4 - (length % 4)) - else: - padded_length = length - - unpacker = xdrlib.Unpacker(self.__recv(padded_length)) - return unpacker.unpack_fstring(length) - - def recv_string(self): - length = self.recv_u32() - return self.recv_fixed_string(length) - - def __recv(self, num_bytes): - chunks = [] - remaining_bytes = num_bytes - while remaining_bytes > 0: - chunk = self.sock.recv(remaining_bytes) - remaining_bytes -= len(chunk) - chunks.append(chunk) - - return b"".join(chunks)