コード例 #1
0
ファイル: files.py プロジェクト: gsnedders/gecko
    def copy(self, dest, skip_if_older=True):
        assert isinstance(dest, basestring)

        if not hasattr(os, 'link'):
            return super(HardlinkFile, self).copy(
                dest, skip_if_older=skip_if_older
            )

        try:
            path_st = os.stat(self.path)
        except OSError as e:
            if e.errno == errno.ENOENT:
                raise ErrorMessage('Hard link target path does not exist: %s' % self.path)
            else:
                raise

        st = None
        try:
            st = os.lstat(dest)
        except OSError as e:
            if e.errno != errno.ENOENT:
                raise

        if st:
            # The dest already points to the right place.
            if st.st_dev == path_st.st_dev and st.st_ino == path_st.st_ino:
                return False
            # The dest exists and it points to the wrong place
            os.remove(dest)

        # At this point, either the dest used to exist and we just deleted it,
        # or it never existed. We can now safely create the hard link.
        try:
            os.link(self.path, dest)
        except OSError:
            # If we can't hard link, fall back to copying
            return super(HardlinkFile, self).copy(
                dest, skip_if_older=skip_if_older
            )
        return True
コード例 #2
0
ファイル: files.py プロジェクト: imiklos/gecko-dev
    def copy(self, dest, skip_if_older=True):
        assert isinstance(dest, basestring)

        # The logic in this function is complicated by the fact that symlinks
        # aren't universally supported. So, where symlinks aren't supported, we
        # fall back to file copying. Keep in mind that symlink support is
        # per-filesystem, not per-OS.

        # Handle the simple case where symlinks are definitely not supported by
        # falling back to file copy.
        if not hasattr(os, 'symlink'):
            return File.copy(self, dest, skip_if_older=skip_if_older)

        # Always verify the symlink target path exists.
        if not os.path.exists(self.path):
            raise ErrorMessage('Symlink target path does not exist: %s' %
                               self.path)

        st = None

        try:
            st = os.lstat(dest)
        except OSError as ose:
            if ose.errno != errno.ENOENT:
                raise

        # If the dest is a symlink pointing to us, we have nothing to do.
        # If it's the wrong symlink, the filesystem must support symlinks,
        # so we replace with a proper symlink.
        if st and stat.S_ISLNK(st.st_mode):
            link = os.readlink(dest)
            if link == self.path:
                return False

            os.remove(dest)
            os.symlink(self.path, dest)
            return True

        # If the destination doesn't exist, we try to create a symlink. If that
        # fails, we fall back to copy code.
        if not st:
            try:
                os.symlink(self.path, dest)
                return True
            except OSError:
                return File.copy(self, dest, skip_if_older=skip_if_older)

        # Now the complicated part. If the destination exists, we could be
        # replacing a file with a symlink. Or, the filesystem may not support
        # symlinks. We want to minimize I/O overhead for performance reasons,
        # so we keep the existing destination file around as long as possible.
        # A lot of the system calls would be eliminated if we cached whether
        # symlinks are supported. However, even if we performed a single
        # up-front test of whether the root of the destination directory
        # supports symlinks, there's no guarantee that all operations for that
        # dest (or source) would be on the same filesystem and would support
        # symlinks.
        #
        # Our strategy is to attempt to create a new symlink with a random
        # name. If that fails, we fall back to copy mode. If that works, we
        # remove the old destination and move the newly-created symlink into
        # its place.

        temp_dest = os.path.join(os.path.dirname(dest), str(uuid.uuid4()))
        try:
            os.symlink(self.path, temp_dest)
        # TODO Figure out exactly how symlink creation fails and only trap
        # that.
        except EnvironmentError:
            return File.copy(self, dest, skip_if_older=skip_if_older)

        # If removing the original file fails, don't forget to clean up the
        # temporary symlink.
        try:
            os.remove(dest)
        except EnvironmentError:
            os.remove(temp_dest)
            raise

        os.rename(temp_dest, dest)
        return True