From 941b4c392d2ec535dd3fd9577427e0b927dbcab8 Mon Sep 17 00:00:00 2001 From: spiv Date: Mon, 6 Feb 2006 09:22:43 +0000 Subject: [PATCH] Start adding setMetadata to twisted.vfs, including the SFTP adapter and osfs backend. This work is contributed by Canonical Ltd -- I've updated the list of copyright holders in LICENSE to reflect this. git-svn-id: svn://svn.twistedmatrix.com/svn/Twisted/trunk@15836 bbbe8e31-12d6-0310-92fd-ac37d47ddeeb --- LICENSE | 1 + twisted/vfs/adapters/sftp.py | 19 ++++++++++++++++--- twisted/vfs/backends/osfs.py | 14 ++++++++++++++ twisted/vfs/ivfs.py | 16 ++++++++++++++++ twisted/vfs/test/test_sftp.py | 13 +++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 40d69150763..997b8d0dce5 100644 --- a/LICENSE +++ b/LICENSE @@ -4,6 +4,7 @@ Andrew Bennetts Apple Computer, Inc. Benjamin Bruheim Bob Ippolito +Canonical Limited Christopher Armstrong Donovan Preston Eric Mangold diff --git a/twisted/vfs/adapters/sftp.py b/twisted/vfs/adapters/sftp.py index 274c1b491bc..fb95fa31e35 100644 --- a/twisted/vfs/adapters/sftp.py +++ b/twisted/vfs/adapters/sftp.py @@ -172,11 +172,24 @@ def _attrify(self, node): } def getAttrs(self, path, followLinks): - return self._attrify(self.filesystem.fetch(path)) - + try: + node = self.filesystem.fetch(path) + except ivfs.NotFoundError, e: + raise SFTPError(FX_NO_SUCH_FILE, e.args[0]) + return self._attrify(node) def setAttrs(self, path, attrs): - raise NotImplementedError("NO SETATTR") + try: + node = self.filesystem.fetch(path) + except ivfs.NotFoundError, e: + raise SFTPError(FX_NO_SUCH_FILE, e.args[0]) + try: + # XXX: setMetadata isn't yet part of the IFileSystemNode interface + # (but it should be). So we catch AttributeError, and translate it + # to NotImplementedError because it's slightly nicer for clients. + node.setMetadata(attrs) + except AttributeError: + raise NotImplementedError("NO SETATTR") def readLink(self, path): raise NotImplementedError("NO LINK") diff --git a/twisted/vfs/backends/osfs.py b/twisted/vfs/backends/osfs.py index 69fda67da36..d5a93d758da 100644 --- a/twisted/vfs/backends/osfs.py +++ b/twisted/vfs/backends/osfs.py @@ -41,6 +41,20 @@ def getMetadata(self): "nlink" : s.st_nlink } + def setMetadata(self, attrs): + if 'uid' in attrs and 'gid' in attrs: + os.chown(self.realPath, attrs["uid"], attrs["gid"]) + if 'permissions' in attrs: + os.chmod(self.realPath, attrs["permissions"]) + if 'atime' in attrs or 'mtime' in attrs: + if None in (attrs.get("atime"), attrs.get("mtime")): + st = os.stat(self.realPath) + atime = attrs.get("atime", st.st_atime) + mtime = attrs.get("mtime", st.st_mtime) + else: + atime = attrs['atime'] + mtime = attrs['mtime'] + os.utime(self.realPath, (atime, mtime)) def rename(self, newName): from twisted.vfs import pathutils diff --git a/twisted/vfs/ivfs.py b/twisted/vfs/ivfs.py index 768da255090..ea2640c8b06 100644 --- a/twisted/vfs/ivfs.py +++ b/twisted/vfs/ivfs.py @@ -33,6 +33,22 @@ def getMetadata(): particular value isn't available as gracefully as possible. """ + # XXX: There should be a setMetadata, probably taking a map of the same form + # returned by getMetadata (although obviously keys like 'nlink' aren't + # settable. Something like: + # def setMetadata(metadata): + # """Sets metadata for a node. + # + # Unrecognised keys will be ignored (but invalid values for a recognised + # key may cause an error to be raised). + # + # Typical keys are 'permissions', 'uid', 'gid', 'atime' and 'mtime'. + # + # @param metadata: a dict, like the one getMetadata returns. + # """ + # osfs.OSNode implements this; other backends should be similarly updated. + # -- spiv, 2006-06-02 + def remove(): """ Removes this node. diff --git a/twisted/vfs/test/test_sftp.py b/twisted/vfs/test/test_sftp.py index ea04142baf0..d104f89645c 100644 --- a/twisted/vfs/test/test_sftp.py +++ b/twisted/vfs/test/test_sftp.py @@ -1,4 +1,5 @@ import os +import time from twisted.conch.ssh.filetransfer import FXF_READ, FXF_WRITE, FXF_CREAT from twisted.conch.ssh.filetransfer import FXF_APPEND, FXF_EXCL @@ -129,6 +130,18 @@ def test_getAttrs(self): attrs.sort() self.failUnless(sftpAttrs, attrs) + def test_setAttrs(self): + for mtime in [1, 2, int(time.time())]: + try: + self.sftp.setAttrs('/ned', {'mtime': mtime}) + except NotImplementedError: + raise unittest.SkipTest( + "The VFS backend %r doesn't support setAttrs" + % (self.root,)) + else: + self.assertEqual(mtime, + self.sftp.getAttrs('/ned', False)['mtime']) + def test_dirlistWithoutAttrs(self): self.ned.getMetadata = self.f.getMetadata = lambda: {} for name, lsline, attrs in self.sftp.openDirectory('/'):