[project @ Arch-1:robey@lag.net--2005-master-shake%paramiko--dev--1--patch-32]

add the concept of a cwd to SFTPClient, and add a unit test for it
This commit is contained in:
Robey Pointer 2005-07-13 07:59:35 +00:00
parent e6e4c4bff7
commit 1f88224239
2 changed files with 104 additions and 6 deletions

View File

@ -46,6 +46,7 @@ class SFTPClient (BaseSFTP):
self.sock = sock self.sock = sock
self.ultra_debug = False self.ultra_debug = False
self.request_number = 1 self.request_number = 1
self._cwd = None
if type(sock) is Channel: if type(sock) is Channel:
# override default logger # override default logger
transport = self.sock.get_transport() transport = self.sock.get_transport()
@ -80,7 +81,7 @@ class SFTPClient (BaseSFTP):
""" """
self.sock.close() self.sock.close()
def listdir(self, path): def listdir(self, path='.'):
""" """
Return a list containing the names of the entries in the given C{path}. Return a list containing the names of the entries in the given C{path}.
The list is in arbitrary order. It does not include the special The list is in arbitrary order. It does not include the special
@ -88,27 +89,28 @@ class SFTPClient (BaseSFTP):
This method is meant to mirror C{os.listdir} as closely as possible. This method is meant to mirror C{os.listdir} as closely as possible.
For a list of full L{SFTPAttributes} objects, see L{listdir_attr}. For a list of full L{SFTPAttributes} objects, see L{listdir_attr}.
@param path: path to list. @param path: path to list (defaults to C{'.'})
@type path: str @type path: str
@return: list of filenames. @return: list of filenames
@rtype: list of str @rtype: list of str
""" """
return [f.filename for f in self.listdir_attr(path)] return [f.filename for f in self.listdir_attr(path)]
def listdir_attr(self, path): def listdir_attr(self, path='.'):
""" """
Return a list containing L{SFTPAttributes} objects corresponding to Return a list containing L{SFTPAttributes} objects corresponding to
files in the given C{path}. The list is in arbitrary order. It does files in the given C{path}. The list is in arbitrary order. It does
not include the special entries C{'.'} and C{'..'} even if they are not include the special entries C{'.'} and C{'..'} even if they are
present in the folder. present in the folder.
@param path: path to list. @param path: path to list (defaults to C{'.'})
@type path: str @type path: str
@return: list of attributes. @return: list of attributes
@rtype: list of L{SFTPAttributes} @rtype: list of L{SFTPAttributes}
@since: 1.2 @since: 1.2
""" """
path = self._adjust_cwd(path)
t, msg = self._request(CMD_OPENDIR, path) t, msg = self._request(CMD_OPENDIR, path)
if t != CMD_HANDLE: if t != CMD_HANDLE:
raise SFTPError('Expected handle') raise SFTPError('Expected handle')
@ -162,6 +164,7 @@ class SFTPClient (BaseSFTP):
@raise IOError: if the file could not be opened. @raise IOError: if the file could not be opened.
""" """
filename = self._adjust_cwd(filename)
imode = 0 imode = 0
if ('r' in mode) or ('+' in mode): if ('r' in mode) or ('+' in mode):
imode |= SFTP_FLAG_READ imode |= SFTP_FLAG_READ
@ -192,6 +195,7 @@ class SFTPClient (BaseSFTP):
@raise IOError: if the path refers to a folder (directory). Use @raise IOError: if the path refers to a folder (directory). Use
L{rmdir} to remove a folder. L{rmdir} to remove a folder.
""" """
path = self._adjust_cwd(path)
self._request(CMD_REMOVE, path) self._request(CMD_REMOVE, path)
unlink = remove unlink = remove
@ -208,6 +212,8 @@ class SFTPClient (BaseSFTP):
@raise IOError: if C{newpath} is a folder, or something else goes @raise IOError: if C{newpath} is a folder, or something else goes
wrong. wrong.
""" """
oldpath = self._adjust_cwd(oldpath)
newpath = self._adjust_cwd(newpath)
self._request(CMD_RENAME, oldpath, newpath) self._request(CMD_RENAME, oldpath, newpath)
def mkdir(self, path, mode=0777): def mkdir(self, path, mode=0777):
@ -221,6 +227,7 @@ class SFTPClient (BaseSFTP):
@param mode: permissions (posix-style) for the newly-created folder. @param mode: permissions (posix-style) for the newly-created folder.
@type mode: int @type mode: int
""" """
path = self._adjust_cwd(path)
attr = SFTPAttributes() attr = SFTPAttributes()
attr.st_mode = mode attr.st_mode = mode
self._request(CMD_MKDIR, path, attr) self._request(CMD_MKDIR, path, attr)
@ -232,6 +239,7 @@ class SFTPClient (BaseSFTP):
@param path: name of the folder to remove. @param path: name of the folder to remove.
@type path: string @type path: string
""" """
path = self._adjust_cwd(path)
self._request(CMD_RMDIR, path) self._request(CMD_RMDIR, path)
def stat(self, path): def stat(self, path):
@ -253,6 +261,7 @@ class SFTPClient (BaseSFTP):
@return: an object containing attributes about the given file. @return: an object containing attributes about the given file.
@rtype: SFTPAttributes @rtype: SFTPAttributes
""" """
path = self._adjust_cwd(path)
t, msg = self._request(CMD_STAT, path) t, msg = self._request(CMD_STAT, path)
if t != CMD_ATTRS: if t != CMD_ATTRS:
raise SFTPError('Expected attributes') raise SFTPError('Expected attributes')
@ -269,6 +278,7 @@ class SFTPClient (BaseSFTP):
@return: an object containing attributes about the given file. @return: an object containing attributes about the given file.
@rtype: SFTPAttributes @rtype: SFTPAttributes
""" """
path = self._adjust_cwd(path)
t, msg = self._request(CMD_LSTAT, path) t, msg = self._request(CMD_LSTAT, path)
if t != CMD_ATTRS: if t != CMD_ATTRS:
raise SFTPError('Expected attributes') raise SFTPError('Expected attributes')
@ -284,6 +294,7 @@ class SFTPClient (BaseSFTP):
@param dest: path of the newly created symlink. @param dest: path of the newly created symlink.
@type dest: string @type dest: string
""" """
dest = self._adjust_cwd(dest)
self._request(CMD_SYMLINK, source, dest) self._request(CMD_SYMLINK, source, dest)
def chmod(self, path, mode): def chmod(self, path, mode):
@ -297,6 +308,7 @@ class SFTPClient (BaseSFTP):
@param mode: new permissions. @param mode: new permissions.
@type mode: int @type mode: int
""" """
path = self._adjust_cwd(path)
attr = SFTPAttributes() attr = SFTPAttributes()
attr.st_mode = mode attr.st_mode = mode
self._request(CMD_SETSTAT, path, attr) self._request(CMD_SETSTAT, path, attr)
@ -315,6 +327,7 @@ class SFTPClient (BaseSFTP):
@param gid: new group id @param gid: new group id
@type gid: int @type gid: int
""" """
path = self._adjust_cwd(path)
attr = SFTPAttributes() attr = SFTPAttributes()
attr.st_uid, attr.st_gid = uid, gid attr.st_uid, attr.st_gid = uid, gid
self._request(CMD_SETSTAT, path, attr) self._request(CMD_SETSTAT, path, attr)
@ -334,6 +347,7 @@ class SFTPClient (BaseSFTP):
standard internet epoch time (seconds since 01 January 1970 GMT). standard internet epoch time (seconds since 01 January 1970 GMT).
@type times: tuple of int @type times: tuple of int
""" """
path = self._adjust_cwd(path)
if times is None: if times is None:
times = (time.time(), time.time()) times = (time.time(), time.time())
attr = SFTPAttributes() attr = SFTPAttributes()
@ -351,6 +365,7 @@ class SFTPClient (BaseSFTP):
@return: target path. @return: target path.
@rtype: str @rtype: str
""" """
path = self._adjust_cwd(path)
t, msg = self._request(CMD_READLINK, path) t, msg = self._request(CMD_READLINK, path)
if t != CMD_NAME: if t != CMD_NAME:
raise SFTPError('Expected name response') raise SFTPError('Expected name response')
@ -372,7 +387,10 @@ class SFTPClient (BaseSFTP):
@type path: str @type path: str
@return: normalized form of the given path. @return: normalized form of the given path.
@rtype: str @rtype: str
@raise IOError: if the path can't be resolved on the server
""" """
path = self._adjust_cwd(path)
t, msg = self._request(CMD_REALPATH, path) t, msg = self._request(CMD_REALPATH, path)
if t != CMD_NAME: if t != CMD_NAME:
raise SFTPError('Expected name response') raise SFTPError('Expected name response')
@ -380,6 +398,36 @@ class SFTPClient (BaseSFTP):
if count != 1: if count != 1:
raise SFTPError('Realpath returned %d results' % count) raise SFTPError('Realpath returned %d results' % count)
return msg.get_string() return msg.get_string()
def chdir(self, path):
"""
Change the "current directory" of this SFTP session. Since SFTP
doesn't really have the concept of a current working directory, this
is emulated by paramiko. Once you use this method to set a working
directory, all operations on this SFTPClient object will be relative
to that path.
@param path: new current working directory
@type path: str
@raise IOError: if the requested path doesn't exist on the server
@since: 1.4
"""
self._cwd = self.normalize(path)
def getcwd(self):
"""
Return the "current working directory" for this SFTP session, as
emulated by paramiko. If no directory has been set with L{chdir},
this method will return C{None}.
@return: the current working directory on the server, or C{None}
@rtype: str
@since: 1.4
"""
return self._cwd
### internals... ### internals...
@ -422,6 +470,18 @@ class SFTPClient (BaseSFTP):
raise EOFError(text) raise EOFError(text)
else: else:
raise IOError(text) raise IOError(text)
def _adjust_cwd(self, path):
"""
Return an adjusted path if we're emulating a "current working
directory" for the server.
"""
if self._cwd is None:
return path
if (len(path) > 0) and (path[0] == '/'):
# absolute path
return path
return self._cwd + '/' + path
class SFTP (SFTPClient): class SFTP (SFTPClient):

View File

@ -502,3 +502,41 @@ class SFTPTest (unittest.TestCase):
self.assert_(False, 'no exception removing nonexistent subfolder') self.assert_(False, 'no exception removing nonexistent subfolder')
except IOError: except IOError:
pass pass
def test_I_chdir(self):
"""
verify that chdir/getcwd work.
"""
root = sftp.normalize('.')
if root[-1] != '/':
root += '/'
try:
sftp.mkdir(FOLDER + '/alpha')
sftp.chdir(FOLDER + '/alpha')
sftp.mkdir('beta')
self.assertEquals(root + FOLDER + '/alpha', sftp.getcwd())
self.assertEquals(['beta'], sftp.listdir('.'))
sftp.chdir('beta')
f = sftp.open('fish', 'w')
f.write('hello\n')
f.close()
sftp.chdir('..')
self.assertEquals(['fish'], sftp.listdir('beta'))
sftp.chdir('..')
self.assertEquals(['fish'], sftp.listdir('alpha/beta'))
finally:
sftp.chdir(root)
try:
sftp.unlink(FOLDER + '/alpha/beta/fish')
except:
pass
try:
sftp.rmdir(FOLDER + '/alpha/beta')
except:
pass
try:
sftp.rmdir(FOLDER + '/alpha')
except:
pass