127
127
def send(self, data):
128
128
return os.write(self.proc.stdin.fileno(), data)
130
def recv_ready(self):
131
# TODO: jam 20051215 this function is necessary to support the
132
# pipelined() function. In reality, it probably should use
133
# poll() or select() to actually return if there is data
134
# available, otherwise we probably don't get any benefit
130
137
def recv(self, count):
131
138
return os.read(self.proc.stdout.fileno(), count)
192
199
self.lock_path = path + '.write-lock'
193
200
self.transport = transport
195
self.lock_file = transport._sftp_open_exclusive(self.lock_path)
202
abspath = transport._abspath(self.lock_path)
203
self.lock_file = transport._sftp_open_exclusive(abspath)
196
204
except FileExists:
197
205
raise LockError('File %r already locked' % (self.path,))
346
def put(self, relpath, f):
354
def put(self, relpath, f, mode=None):
348
356
Copy the file-like or string object into the location.
350
358
:param relpath: Location to put the contents, relative to base.
351
359
:param f: File-like or string object.
360
:param mode: The final mode for the file
353
362
final_path = self._abspath(relpath)
354
tmp_relpath = '%s.tmp.%.9f.%d.%d' % (relpath, time.time(),
363
self._put(final_path, f, mode=mode)
365
def _put(self, abspath, f, mode=None):
366
"""Helper function so both put() and copy_abspaths can reuse the code"""
367
tmp_abspath = '%s.tmp.%.9f.%d.%d' % (abspath, time.time(),
355
368
os.getpid(), random.randint(0,0x7FFFFFFF))
356
tmp_abspath = self._abspath(tmp_relpath)
357
fout = self._sftp_open_exclusive(tmp_relpath)
369
fout = self._sftp_open_exclusive(tmp_abspath, mode=mode)
373
fout.set_pipelined(True)
362
374
self._pump(f, fout)
363
375
except (IOError, paramiko.SSHException), e:
364
376
self._translate_io_exception(e, tmp_abspath)
378
self._sftp.chmod(tmp_abspath, mode)
367
self._rename(tmp_abspath, final_path)
381
self._rename(tmp_abspath, abspath)
368
382
except Exception, e:
369
383
# If we fail, try to clean up the temporary file
370
384
# before we throw the exception
371
385
# but don't let another exception mess things up
386
# Write out the traceback, because otherwise
387
# the catch and throw destroys it
389
mutter(traceback.format_exc())
392
def mkdir(self, relpath):
410
def mkdir(self, relpath, mode=None):
393
411
"""Create a directory at the given path."""
395
413
path = self._abspath(relpath)
414
# In the paramiko documentation, it says that passing a mode flag
415
# will filtered against the server umask.
416
# StubSFTPServer does not do this, which would be nice, because it is
417
# what we really want :)
418
# However, real servers do use umask, so we really should do it that way
396
419
self._sftp.mkdir(path)
421
self._sftp.chmod(path, mode=mode)
397
422
except (paramiko.SSHException, IOError), e:
398
self._translate_io_exception(e, relpath, ': unable to mkdir',
423
self._translate_io_exception(e, path, ': unable to mkdir',
399
424
failure_exc=FileExists)
401
426
def _translate_io_exception(self, e, path, more_info='', failure_exc=NoSuchFile):
422
447
# strange but true, for the paramiko server.
423
448
if (e.args == ('Failure',)):
424
449
raise failure_exc(path, str(e) + more_info)
450
mutter('Raising exception with args %s', e.args)
451
if hasattr(e, 'errno'):
452
mutter('Raising exception with errno %s', e.errno)
427
455
def append(self, relpath, f):
442
470
path_to = self._abspath(rel_to)
443
471
self._copy_abspaths(path_from, path_to)
445
def _copy_abspaths(self, path_from, path_to):
473
def _copy_abspaths(self, path_from, path_to, mode=None):
446
474
"""Copy files given an absolute path
448
476
:param path_from: Path on remote server to read
458
486
fin = self._sftp.file(path_from, 'rb')
460
fout = self._sftp.file(path_to, 'wb')
462
fout.set_pipelined(True)
463
self._pump(fin, fout)
488
self._put(path_to, fin, mode=mode)
468
491
except (IOError, paramiko.SSHException), e:
469
492
self._translate_io_exception(e, path_from, ': unable copy to: %r' % path_to)
471
def copy_to(self, relpaths, other, pb=None):
494
def copy_to(self, relpaths, other, mode=None, pb=None):
472
495
"""Copy a set of entries from self into another Transport.
474
497
:param relpaths: A list/generator of entries to be copied.
483
506
path_from = self._abspath(relpath)
484
507
path_to = other._abspath(relpath)
485
508
self._update_pb(pb, 'copy-to', count, total)
486
self._copy_abspaths(path_from, path_to)
509
self._copy_abspaths(path_from, path_to, mode=mode)
490
return super(SFTPTransport, self).copy_to(relpaths, other, pb=pb)
492
# The dummy implementation just does a simple get + put
493
def copy_entry(path):
494
other.put(path, self.get(path))
496
return self._iterate_over(relpaths, copy_entry, pb, 'copy_to', expand=False)
513
return super(SFTPTransport, self).copy_to(relpaths, other, mode=mode, pb=pb)
498
515
def _rename(self, abs_from, abs_to):
499
516
"""Do a fancy rename on the remote server.
771
def _sftp_open_exclusive(self, relpath):
788
def _sftp_open_exclusive(self, abspath, mode=None):
772
789
"""Open a remote path exclusively.
774
791
SFTP supports O_EXCL (SFTP_FLAG_EXCL), which fails if
779
796
WARNING: This breaks the SFTPClient abstraction, so it
780
797
could easily break against an updated version of paramiko.
782
:param relpath: The relative path, where the file should be opened
799
:param abspath: The remote absolute path where the file should be opened
800
:param mode: The mode permissions bits for the new file
784
path = self._sftp._adjust_cwd(self._abspath(relpath))
802
path = self._sftp._adjust_cwd(abspath)
785
803
attr = SFTPAttributes()
786
mode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE
806
omode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE
787
807
| SFTP_FLAG_TRUNC | SFTP_FLAG_EXCL)
789
t, msg = self._sftp._request(CMD_OPEN, path, mode, attr)
809
t, msg = self._sftp._request(CMD_OPEN, path, omode, attr)
790
810
if t != CMD_HANDLE:
791
811
raise TransportError('Expected an SFTP handle')
792
812
handle = msg.get_string()
793
813
return SFTPFile(self._sftp, handle, 'wb', -1)
794
814
except (paramiko.SSHException, IOError), e:
795
self._translate_io_exception(e, relpath, ': unable to open',
815
self._translate_io_exception(e, abspath, ': unable to open',
796
816
failure_exc=FileExists)