~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

Basic implementation of non_atomic_put for sftp

Show diffs side-by-side

added added

removed removed

Lines of Context:
604
604
            # raise the original with its traceback if we can.
605
605
            raise
606
606
 
 
607
    def non_atomic_put(self, relpath, f, mode=None):
 
608
        """Copy the file-like object into the target location.
 
609
 
 
610
        This function is not strictly safe to use. It is only meant to
 
611
        be used when you already know that the target does not exist.
 
612
        It is not safe, because it will open and truncate the remote
 
613
        file. So there may be a time when the file has invalid contents.
 
614
 
 
615
        :param relpath: The remote location to put the contents.
 
616
        :param f:       File-like object.
 
617
        :param mode:    Possible access permissions for new file.
 
618
                        None means do not set remote permissions.
 
619
        """
 
620
        abspath = self._remote_path(relpath)
 
621
        path = self._sftp._adjust_cwd(abspath)
 
622
        attr = SFTPAttributes()
 
623
        if mode is not None:
 
624
            attr.st_mode = mode
 
625
        omode = (SFTP_FLAG_WRITE | SFTP_FLAG_CREATE | SFTP_FLAG_TRUNC)
 
626
 
 
627
        fout = None
 
628
        try:
 
629
            t, msg = self._sftp._request(CMD_OPEN, path, omode, attr)
 
630
            if t != CMD_HANDLE:
 
631
                raise TransportError('Expected an SFTP handle')
 
632
            handle = msg.get_string()
 
633
            fout = SFTPFile(self._sftp, handle, 'wb', -1)
 
634
        except (paramiko.SSHException, IOError), e:
 
635
            self._translate_io_exception(e, abspath, ': unable to open',
 
636
                failure_exc=FileExists)
 
637
 
 
638
        try:
 
639
            fout.set_pipelined(True)
 
640
            self._pump(f, fout)
 
641
        except (IOError, paramiko.SSHException), e:
 
642
            self._translate_io_exception(e, tmp_abspath)
 
643
        # XXX: This doesn't truly help like we would like it to.
 
644
        #      The problem is that openssh strips sticky bits. So while we
 
645
        #      can properly set group write permission, we lose the group
 
646
        #      sticky bit. So it is probably best to stop chmodding, and
 
647
        #      just tell users that they need to set the umask correctly.
 
648
        #      The attr.st_mode = mode, will handle when the user wants the
 
649
        #      final mode to be more restrictive. And then we avoid a round 
 
650
        #      trip. Unless paramiko decides to expose an async chmod()
 
651
        #
 
652
        #      This is designed to chmod() right before we close.
 
653
        #      Because we set_pipelined() earlier, theoretically we might avoid
 
654
        #      The round trip for fout.close()
 
655
        if mode is not None:
 
656
            self._sftp.chmod(tmp_abspath, mode)
 
657
        fout.close()
 
658
 
607
659
    def iter_files_recursive(self):
608
660
        """Walk the relative paths of all files in this transport."""
609
661
        queue = list(self.list_dir('.'))