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)