/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
366
366
            # on to the next
367
367
            cur_coalesced = cur_coalesced_stack.next()
368
368
 
369
 
    def put(self, relpath, f, mode=None):
 
369
    def put_file(self, relpath, f, mode=None):
370
370
        """
371
 
        Copy the file-like or string object into the location.
 
371
        Copy the file-like object into the location.
372
372
 
373
373
        :param relpath: Location to put the contents, relative to base.
374
 
        :param f:       File-like or string object.
 
374
        :param f:       File-like object.
375
375
        :param mode: The final mode for the file
376
376
        """
377
377
        final_path = self._remote_path(relpath)
389
389
                self._pump(f, fout)
390
390
            except (IOError, paramiko.SSHException), e:
391
391
                self._translate_io_exception(e, tmp_abspath)
 
392
            # XXX: This doesn't truly help like we would like it to.
 
393
            #      The problem is that openssh strips sticky bits. So while we
 
394
            #      can properly set group write permission, we lose the group
 
395
            #      sticky bit. So it is probably best to stop chmodding, and
 
396
            #      just tell users that they need to set the umask correctly.
 
397
            #      The attr.st_mode = mode, in _sftp_open_exclusive
 
398
            #      will handle when the user wants the final mode to be more 
 
399
            #      restrictive. And then we avoid a round trip. Unless 
 
400
            #      paramiko decides to expose an async chmod()
 
401
 
 
402
            # This is designed to chmod() right before we close.
 
403
            # Because we set_pipelined() earlier, theoretically we might 
 
404
            # avoid the round trip for fout.close()
392
405
            if mode is not None:
393
406
                self._sftp.chmod(tmp_abspath, mode)
394
407
            fout.close()
412
425
            # raise the original with its traceback if we can.
413
426
            raise
414
427
 
 
428
    def _put_non_atomic_helper(self, relpath, writer, mode=None,
 
429
                               create_parent_dir=False,
 
430
                               dir_mode=None):
 
431
        abspath = self._remote_path(relpath)
 
432
 
 
433
        # TODO: jam 20060816 paramiko doesn't publicly expose a way to
 
434
        #       set the file mode at create time. If it does, use it.
 
435
        #       But for now, we just chmod later anyway.
 
436
 
 
437
        def _open_and_write_file():
 
438
            """Try to open the target file, raise error on failure"""
 
439
            fout = None
 
440
            try:
 
441
                try:
 
442
                    fout = self._sftp.file(abspath, mode='wb')
 
443
                    fout.set_pipelined(True)
 
444
                    writer(fout)
 
445
                except (paramiko.SSHException, IOError), e:
 
446
                    self._translate_io_exception(e, abspath,
 
447
                                                 ': unable to open')
 
448
 
 
449
                # This is designed to chmod() right before we close.
 
450
                # Because we set_pipelined() earlier, theoretically we might 
 
451
                # avoid the round trip for fout.close()
 
452
                if mode is not None:
 
453
                    self._sftp.chmod(abspath, mode)
 
454
            finally:
 
455
                if fout is not None:
 
456
                    fout.close()
 
457
 
 
458
        if not create_parent_dir:
 
459
            _open_and_write_file()
 
460
            return
 
461
 
 
462
        # Try error handling to create the parent directory if we need to
 
463
        try:
 
464
            _open_and_write_file()
 
465
        except NoSuchFile:
 
466
            # Try to create the parent directory, and then go back to
 
467
            # writing the file
 
468
            parent_dir = os.path.dirname(abspath)
 
469
            self._mkdir(parent_dir, dir_mode)
 
470
            _open_and_write_file()
 
471
 
 
472
    def put_file_non_atomic(self, relpath, f, mode=None,
 
473
                            create_parent_dir=False,
 
474
                            dir_mode=None):
 
475
        """Copy the file-like object into the target location.
 
476
 
 
477
        This function is not strictly safe to use. It is only meant to
 
478
        be used when you already know that the target does not exist.
 
479
        It is not safe, because it will open and truncate the remote
 
480
        file. So there may be a time when the file has invalid contents.
 
481
 
 
482
        :param relpath: The remote location to put the contents.
 
483
        :param f:       File-like object.
 
484
        :param mode:    Possible access permissions for new file.
 
485
                        None means do not set remote permissions.
 
486
        :param create_parent_dir: If we cannot create the target file because
 
487
                        the parent directory does not exist, go ahead and
 
488
                        create it, and then try again.
 
489
        """
 
490
        def writer(fout):
 
491
            self._pump(f, fout)
 
492
        self._put_non_atomic_helper(relpath, writer, mode=mode,
 
493
                                    create_parent_dir=create_parent_dir,
 
494
                                    dir_mode=dir_mode)
 
495
 
 
496
    def put_bytes_non_atomic(self, relpath, bytes, mode=None,
 
497
                             create_parent_dir=False,
 
498
                             dir_mode=None):
 
499
        def writer(fout):
 
500
            fout.write(bytes)
 
501
        self._put_non_atomic_helper(relpath, writer, mode=mode,
 
502
                                    create_parent_dir=create_parent_dir,
 
503
                                    dir_mode=dir_mode)
 
504
 
415
505
    def iter_files_recursive(self):
416
506
        """Walk the relative paths of all files in this transport."""
417
507
        queue = list(self.list_dir('.'))
424
514
            else:
425
515
                yield relpath
426
516
 
 
517
    def _mkdir(self, abspath, mode=None):
 
518
        if mode is None:
 
519
            local_mode = 0777
 
520
        else:
 
521
            local_mode = mode
 
522
        try:
 
523
            self._sftp.mkdir(abspath, local_mode)
 
524
            if mode is not None:
 
525
                self._sftp.chmod(abspath, mode=mode)
 
526
        except (paramiko.SSHException, IOError), e:
 
527
            self._translate_io_exception(e, abspath, ': unable to mkdir',
 
528
                failure_exc=FileExists)
 
529
 
427
530
    def mkdir(self, relpath, mode=None):
428
531
        """Create a directory at the given path."""
429
 
        path = self._remote_path(relpath)
430
 
        try:
431
 
            # In the paramiko documentation, it says that passing a mode flag 
432
 
            # will filtered against the server umask.
433
 
            # StubSFTPServer does not do this, which would be nice, because it is
434
 
            # what we really want :)
435
 
            # However, real servers do use umask, so we really should do it that way
436
 
            self._sftp.mkdir(path)
437
 
            if mode is not None:
438
 
                self._sftp.chmod(path, mode=mode)
439
 
        except (paramiko.SSHException, IOError), e:
440
 
            self._translate_io_exception(e, path, ': unable to mkdir',
441
 
                failure_exc=FileExists)
 
532
        self._mkdir(self._remote_path(relpath), mode=mode)
442
533
 
443
534
    def _translate_io_exception(self, e, path, more_info='', 
444
535
                                failure_exc=PathError):
456
547
        """
457
548
        # paramiko seems to generate detailless errors.
458
549
        self._translate_error(e, path, raise_generic=False)
459
 
        if hasattr(e, 'args'):
 
550
        if getattr(e, 'args', None) is not None:
460
551
            if (e.args == ('No such file or directory',) or
461
552
                e.args == ('No such file',)):
462
553
                raise NoSuchFile(path, str(e) + more_info)
466
557
            if (e.args == ('Failure',)):
467
558
                raise failure_exc(path, str(e) + more_info)
468
559
            mutter('Raising exception with args %s', e.args)
469
 
        if hasattr(e, 'errno'):
 
560
        if getattr(e, 'errno', None) is not None:
470
561
            mutter('Raising exception with errno %s', e.errno)
471
562
        raise e
472
563
 
473
 
    def append(self, relpath, f, mode=None):
 
564
    def append_file(self, relpath, f, mode=None):
474
565
        """
475
566
        Append the text in the file-like object into the final
476
567
        location.
641
732
        :param abspath: The remote absolute path where the file should be opened
642
733
        :param mode: The mode permissions bits for the new file
643
734
        """
 
735
        # TODO: jam 20060816 Paramiko >= 1.6.2 (probably earlier) supports
 
736
        #       using the 'x' flag to indicate SFTP_FLAG_EXCL.
 
737
        #       However, there is no way to set the permission mode at open 
 
738
        #       time using the sftp_client.file() functionality.
644
739
        path = self._sftp._adjust_cwd(abspath)
645
740
        # mutter('sftp abspath %s => %s', abspath, path)
646
741
        attr = SFTPAttributes()
658
753
            self._translate_io_exception(e, abspath, ': unable to open',
659
754
                failure_exc=FileExists)
660
755
 
 
756
    def _can_roundtrip_unix_modebits(self):
 
757
        if sys.platform == 'win32':
 
758
            # anyone else?
 
759
            return False
 
760
        else:
 
761
            return True
661
762
 
662
763
# ------------- server test implementation --------------
663
764
import threading