Example #1
0
    def test_setOwner_ok(self):
        """
        Take ownership of file/folder with valid owner ID.
        """
        file_name = mk.makeFilename()
        file_segments = self.filesystem.home_segments
        file_segments.append(file_name)
        file_object = self.filesystem.openFileForWriting(file_segments)
        file_object.close()

        root_avatar = SuperAvatar()
        root_avatar._home_folder_path = self.avatar.home_folder_path
        root_filesystem = LocalFilesystem(root_avatar)

        root_filesystem.setOwner(file_segments, TEST_ACCOUNT_USERNAME_OTHER)
        current_owner = self.filesystem.getOwner(file_segments)

        self.assertEqual(TEST_ACCOUNT_USERNAME_OTHER, current_owner)

        folder_name = mk.makeFilename()
        folder_segments = self.filesystem.home_segments
        folder_segments.append(folder_name)
        self.filesystem.createFolder(folder_segments)

        root_filesystem.setOwner(folder_segments, TEST_ACCOUNT_USERNAME_OTHER)
        current_owner = self.filesystem.getOwner(folder_segments)

        self.assertEqual(TEST_ACCOUNT_USERNAME_OTHER, current_owner)
Example #2
0
    def test_addGroup_ok_group_folder(self):
        """
        Check successful adding a group for a folder.
        """
        folder_name = mk.makeFilename()
        folder_segments = self.filesystem.home_segments
        folder_segments.append(folder_name)
        self.filesystem.createFolder(folder_segments)

        if os.name == 'posix':
            root_avatar = SuperAvatar()
            root_avatar._home_folder_path = self.avatar.home_folder_path
            root_avatar._root_folder_path = self.avatar.root_folder_path
            root_filesystem = LocalFilesystem(avatar=root_avatar)
        else:
            root_filesystem = self.filesystem

        self.assertFalse(
            self.filesystem.hasGroup(
                folder_segments, TEST_ACCOUNT_GROUP_OTHER))
        root_filesystem.addGroup(
            folder_segments, TEST_ACCOUNT_GROUP_OTHER)
        self.assertTrue(
            self.filesystem.hasGroup(
                folder_segments, TEST_ACCOUNT_GROUP_OTHER))
Example #3
0
    def _cleanFolder(cls, folder_segments):
        """
        Clean all test files from folder_segments.

        Return a list of members which were removed.
        """
        if not factory.fs.exists(folder_segments):
            return []

        # In case we are running the test suite as super user,
        # we use super filesystem for cleaning.
        if cls._environ_user == cls._drop_user:
            temp_avatar = SuperAvatar()
        else:
            temp_avatar = DefaultAvatar()

        temp_filesystem = LocalFilesystem(avatar=temp_avatar)
        temp_members = []
        for member in (temp_filesystem.getFolderContent(folder_segments)):
            if member.find(TEST_NAME_MARKER) != -1:
                temp_members.append(member)
                segments = folder_segments[:]
                segments.append(member)
                if temp_filesystem.isFolder(segments):
                    temp_filesystem.deleteFolder(segments, recursive=True)
                else:
                    temp_filesystem.deleteFile(segments)

        return temp_members
Example #4
0
    def test_generate_ssh_key_pair(self):
        """
        Private key is generated in the specified path, and the public
        key is generated on a path based on private key path.
        """
        private_path, self.private_segments = mk.fs.makePathInTemp()
        public_path = u"%s.pub" % (private_path)
        self.public_segments = self.private_segments[:]
        self.public_segments[-1] = u"%s.pub" % (self.public_segments[-1])
        comment = u"%s %s" % (mk.string(), mk.string())
        # The current code doesn't allow creating smaller keys, so at 1024
        # bit, this test is very slow.
        options = self.Bunch(key_size=1024, key_type="rsa", key_file=private_path, key_comment=comment)

        private_path = LocalFilesystem.getEncodedPath(private_path)
        public_path = LocalFilesystem.getEncodedPath(public_path)

        self.assertFalse(mk.fs.exists(self.private_segments))
        self.assertFalse(mk.fs.exists(self.public_segments))

        generate_ssh_key(options)

        self.assertTrue(mk.fs.exists(self.private_segments))
        self.assertTrue(mk.fs.exists(self.public_segments))

        # Check content of private key.
        private_key = Key.fromFile(filename=private_path)
        self.assertEqual(1024, private_key.size)
        self.assertIsFalse(private_key.isPublic())
        self.assertEqual("RSA", private_key.type())

        # Check content of public key.
        public_key = Key.fromFile(filename=public_path)
        self.assertEqual(1024, public_key.size)
        self.assertIsTrue(public_key.isPublic())
        self.assertEqual("RSA", public_key.type())

        # Check that public key is the pair of private key.
        private_data = private_key.data()
        public_data = public_key.data()
        self.assertEqual(private_data["e"], public_data["e"])
        self.assertEqual(private_data["n"], public_data["n"])
Example #5
0
def generate_ssh_key(options, key=None, open_method=None):
    """
    Generate a SSH RSA or DSA key.

    Return a pair of (exit_code, operation_message).

    For success, exit_code is 0.

    `key` and `open_method` are helpers for dependency injection
    during tests.
    """
    if key is None:
        from chevah.utils.crypto import Key
        key = Key()

    if open_method is None:
        open_method = open

    exit_code = 0
    message = ''
    try:
        key_size = options.key_size

        if options.key_type.lower() == u'rsa':
            key_type = crypto.TYPE_RSA
        elif options.key_type.lower() == u'dsa':
            key_type = crypto.TYPE_DSA
        else:
            key_type = options.key_type

        if not hasattr(options, 'key_file') or options.key_file is None:
            options.key_file = 'id_%s' % (options.key_type.lower())

        private_file = options.key_file

        public_file = u'%s%s' % (
            options.key_file, DEFAULT_PUBLIC_KEY_EXTENSION)

        key.generate(key_type=key_type, key_size=key_size)

        private_file_path = LocalFilesystem.getEncodedPath(private_file)
        public_file_path = LocalFilesystem.getEncodedPath(public_file)

        with open_method(private_file_path, 'wb') as file_handler:
            key.store(private_file=file_handler)

        key_comment = None
        if hasattr(options, 'key_comment') and options.key_comment:
            key_comment = options.key_comment
            message_comment = u'having comment "%s"' % key_comment
        else:
            message_comment = u'without a comment'

        with open_method(public_file_path, 'wb') as file_handler:
            key.store(public_file=file_handler, comment=key_comment)

        message = (
            u'SSH key of type "%s" and length "%d" generated as '
            u'public key file "%s" and private key file "%s" %s.') % (
            options.key_type,
            key_size,
            public_file,
            private_file,
            message_comment,
            )

        exit_code = 0

    except UtilsError, error:
        exit_code = 1
        message = unicode(error)
Example #6
0
 def __init__(self):
     self.name = process_capabilities.os_name
     self.fs = LocalFilesystem(SuperAvatar())
Example #7
0
class OSAdministrationUnix(object):

    shadow_segments = ['etc', 'shadow']
    passwd_segments = ['etc', 'passwd']
    group_segments = ['etc', 'group']
    gshadow_segments = ['etc', 'gshadow']

    def __init__(self):
        self.name = process_capabilities.os_name
        self.fs = LocalFilesystem(SuperAvatar())

    def addGroup(self, group):
        """
        Add the group to the local computer or domain.
        """
        add_group_method = getattr(self, '_addGroup_' + self.name)
        add_group_method(group=group)

    def _addGroup_unix(self, group):
        group_line = u'%s:x:%d:' % (group.name, group.gid)
        gshadow_line = u'%s:!::' % (group.name)

        self._appendUnixEntry(self.group_segments, group_line)

        if self.fs.exists(self.gshadow_segments):
            self._appendUnixEntry(self.gshadow_segments, gshadow_line)

        # Wait for group to be available.
        self._getUnixGroup(group.name)

    def _getUnixGroup(self, name):
        """
        Get unix group entry, retrying if group is not available yet.
        """
        import grp
        name_encoded = codecs.encode(name, 'utf-8')

        # Try to get the group in list of all groups.
        group_found = False
        for iterator in range(1000):
            if group_found:
                break
            for group in grp.getgrall():
                if group[0] == name_encoded:
                    group_found = True
                    break
            time.sleep(0.1)

        if not group_found:
            raise AssertionError('Failed to get group from all: %s' % (
                name_encoded))

        # Now we find the group in list of all groups, but
        # we need to make sure it is also available to be
        # retrieved by name.
        for iterator in range(1000):
            try:
                return grp.getgrnam(name_encoded)
            except KeyError:
                # Group not ready yet.
                pass
            time.sleep(0.1)

        raise AssertionError(
            'Group found in all, but not available by name %s' % (
                name_encoded))

    def _addGroup_aix(self, group):
        group_name = group.name.encode('utf-8')
        execute(['sudo', 'mkgroup', 'id=' + str(group.gid), group_name])

    def _addGroup_linux(self, group):
        self._addGroup_unix(group)

    def _addGroup_osx(self, group):
        groupdb_name = u'/Groups/' + group.name
        execute([
            'sudo', 'dscl', '.', '-create', groupdb_name,
            'gid', str(group.gid),
            'passwd', '"*"',
            ])

    def _addGroup_solaris(self, group):
        self._addGroup_unix(group)

    def _addGroup_hpux(self, group):
        self._addGroup_unix(group)

    def _addGroup_freebsd(self, group):
        group_name = group.name.encode('utf-8')
        execute([
            'sudo', 'pw', 'groupadd',
            '-g', str(group.gid),
            '-n', group_name,
            ])

    def _addGroup_openbsd(self, group):
        group_name = group.name.encode('utf-8')
        execute([
            'sudo', 'groupadd',
            '-g', str(group.gid),
            group_name,
            ])

    def addUsersToGroup(self, group, users=None):
        """
        Add the users to the specified group.
        """
        if users is None:
            users = []

        add_user_method = getattr(self, '_addUsersToGroup_' + self.name)
        add_user_method(group=group, users=users)

    def _addUsersToGroup_unix(self, group, users):
        segments = ['etc', 'group']
        members = u','.join(users)
        self._changeUnixEntry(
            segments=segments,
            name=group.name,
            field=4,
            value_when_empty=members,
            value_to_append=u',' + members,
            )

    def _addUsersToGroup_aix(self, group, users):
        if not len(users):
            return

        group_name = group.name.encode('utf-8')
        members_list = ','.join(users)
        members_list = 'users=' + members_list
        members_list = members_list.encode('utf-8')
        execute(['sudo', 'chgroup', members_list, group_name])

    def _addUsersToGroup_linux(self, group, users):
        self._addUsersToGroup_unix(group, users)

    def _addUsersToGroup_osx(self, group, users):
        groupdb_name = u'/Groups/' + group.name
        for member in users:
            execute([
                'sudo', 'dscl', '.', '-append', groupdb_name,
                'GroupMembership', member,
                ])

    def _addUsersToGroup_solaris(self, group, users):
        self._addUsersToGroup_unix(group, users)

    def _addUsersToGroup_hpux(self, group, users):
        self._addUsersToGroup_unix(group, users)

    def _addUsersToGroup_freebsd(self, group, users):
        if not len(users):
            return

        group_name = group.name.encode('utf-8')
        members_list = ','.join(users)
        execute([
            'sudo', 'pw', 'groupmod', group_name,
            '-M', members_list.encode('utf-8')])

    def _addUsersToGroup_openbsd(self, group, users):
        group_name = group.name.encode('utf-8')
        for user in users:
            execute([
                'sudo', 'usermod', '-G', group_name, user.encode('utf-8')])

    def addUser(self, user):
        """
        Add the user and set the corresponding passwords to local computer
        or domain.
        """
        add_user_method = getattr(self, '_addUser_' + self.name)

        add_user_method(user=user)
        if user.password:
            self.setUserPassword(user=user)

    def _addUser_unix(self, user):
        # Prevent circular import.
        from chevah.compat.testing import TestGroup
        group = TestGroup(name=user.name, posix_gid=user.uid)
        self._addGroup_unix(group)

        values = (
            user.name, user.uid, user.gid, user.posix_home_path, user.shell)
        passwd_line = u'%s:x:%d:%d::%s:%s' % values

        shadow_line = u'%s:!:15218:0:99999:7:::' % (user.name)

        self._appendUnixEntry(self.passwd_segments, passwd_line)

        if self.fs.exists(self.shadow_segments):
            # Only write shadow if exists.
            self._appendUnixEntry(self.shadow_segments, shadow_line)

        # Wait for user to be available before creating home folder.
        self._getUnixUser(user.name)

        if user.posix_home_path == u'/tmp':
            return

        encoded_home_path = user.posix_home_path.encode('utf-8')
        execute(['sudo', 'mkdir', encoded_home_path])
        execute([
            'sudo', 'chown', str(user.uid),
            encoded_home_path,
            ])
        if user.home_group:
            # On some Unix system we can change group as unicode,
            # so we get the ID and change using the group ID.
            group = self._getUnixGroup(user.home_group)
            execute([
                'sudo', 'chgrp', str(group[2]),
                encoded_home_path,
                ])
        else:
            execute([
                'sudo', 'chgrp', str(user.uid),
                encoded_home_path,
                ])

    def _getUnixUser(self, name):
        """
        Get Unix user entry, retrying if user is not available yet.
        """
        import pwd
        name_encoded = name.encode('utf-8')
        error = None
        for iterator in range(1000):
            try:
                user = pwd.getpwnam(name_encoded)
                return user
            except (KeyError, OSError) as e:
                error = e
                pass
            time.sleep(0.2)
        raise AssertionError(
            'Could not get user %s: %s' % (name_encoded, error))

    def _addUser_aix(self, user):
        # AIX will only allow creating users with shells from
        # /etc/security/login.cfg.
        user_shell = user.shell
        if user.shell == '/bin/false':
            user_shell = '/bin/sh'

        user_name = user.name.encode('utf-8')
        command = [
            'sudo', 'mkuser',
            'id=' + str(user.uid),
            'home=' + user.posix_home_path.encode('utf-8'),
            'shell=' + user_shell,
            ]

        if user.primary_group_name:
            command.append('pgrp=' + user.primary_group_name)

        command.append(user_name)

        execute(command)
        if user.home_group:
            execute([
                'sudo', 'chgrp', user.home_group.encode('utf-8'),
                user.posix_home_path.encode('utf-8')
                ])

    def _addUser_linux(self, user):
        self._addUser_unix(user)

    def _addUser_osx(self, user):
        userdb_name = u'/Users/' + user.name
        home_folder = u'/Users/' + user.name
        execute([
            'sudo', 'dscl', '.', '-create', userdb_name,
            'UserShell', '/bin/bash',
            ])
        execute([
            'sudo', 'dscl', '.', '-create', userdb_name,
            'UniqueID', str(user.uid),
            ])
        execute([
            'sudo', 'dscl', '.', '-create', userdb_name,
            'PrimaryGroupID', str(user.gid),
            ])
        execute([
            'sudo', 'dscl', '.', '-create', userdb_name,
            'NFSHomeDirectory', home_folder,
            ])

        # Create home folder.
        execute(['sudo', 'mkdir', home_folder])
        execute(['sudo', 'chown', user.name, home_folder])
        execute(['sudo', 'chgrp', str(user.gid), home_folder])

        if user.home_group:
            execute(['sudo', 'chgrp', user.home_group, user.posix_home_path])
        else:
            execute(['sudo', 'chgrp', user.name, home_folder])

    def _addUser_solaris(self, user):
        self._addUser_unix(user)

    def _addUser_hpux(self, user):
        self._addUser_unix(user)

    def _addUser_freebsd(self, user):
        user_name = user.name.encode('utf-8')
        home_path = user.posix_home_path.encode('utf-8')
        command = [
            'sudo', 'pw', 'user', 'add', user_name,
            '-u', str(user.uid),
            '-d', home_path,
            '-s', user.shell.encode('utf-8'),
            '-m',
            ]
        # Only add gid if required.
        if user.uid != user.gid:
            command.extend(['-g', str(user.gid)])

        execute(command)

        if user.home_group:
            execute([
                'sudo', 'chgrp', user.home_group.encode('utf-8'), home_path])

    def _addUser_openbsd(self, user):
        home_path = user.posix_home_path.encode('utf-8')
        command = [
            'sudo', 'useradd',
            '-u', str(user.uid).encode('utf-8'),
            '-d', home_path,
            '-s', user.shell.encode('utf-8'),
            ]

        if user.posix_home_path != '/tmp':
            command.append('-m'),

        # Only add gid if required.
        if user.uid != user.gid:
            command.extend(['-g', str(user.gid)])

        command.append(user.name.encode('utf-8'))

        execute(command)

        # Wait a bit for the user to be created.
        time.sleep(0.2)

        if user.home_group:
            execute([
                'sudo', 'chgrp', user.home_group.encode('utf-8'), home_path])

    def setUserPassword(self, user):
        """
        Set a password for the user. The password is an attribute of the
        'user'.
        """
        set_password_method = getattr(self, '_setUserPassword_' + self.name)
        set_password_method(user)

    def _setUserPassword_unix(self, user):
        """
        Set a password for the `user` on Unix.


        The password is an attribute of the 'user'.

        This function is common for Unix compliant OSes.
        It is implemented by writing directly to shadow or passwd file.
        """
        if self.fs.exists(self.shadow_segments):
            return self._setUserPassword_shadow(user, self.shadow_segments)
        else:
            return self._setUserPassword_passwd(user, self.passwd_segments)

    def _setUserPassword_shadow(self, user, segments):
        """
        Set a password in shadow file.
        """
        import crypt
        ALPHABET = (
            '0123456789'
            'abcdefghijklmnopqrstuvwxyz'
            'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            )
        salt = ''.join(random.choice(ALPHABET) for i in range(8))
        shadow_password = crypt.crypt(
            user.password.encode('utf-8'),
            '$1$' + salt + '$',
            )

        self._changeUnixEntry(
            segments=segments,
            name=user.name,
            field=2,
            value_to_replace=shadow_password,
            )

    def _setUserPassword_passwd(self, user, segments):
        """
        Set a password in passwd file.
        """
        import crypt
        ALPHABET = (
            '0123456789'
            'abcdefghijklmnopqrstuvwxyz'
            'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
            )
        salt = ''.join(random.choice(ALPHABET) for i in range(2))
        passwd_password = crypt.crypt(
            user.password.encode('utf-8'), salt)
        self._changeUnixEntry(
            segments=segments,
            name=user.name,
            field=2,
            value_to_replace=passwd_password,
            )

    def _setUserPassword_aix(self, user):
        """
        Set a password for the user on AIX. The password is an attribute
        of the 'user'.
        """
        input_text = u'%s:%s' % (user.name, user.password)
        execute(
            command=['sudo', 'chpasswd', '-c'],
            input_text=input_text.encode('utf-8'),
            )

    def _setUserPassword_linux(self, user):
        """
        Set a password for the user on Linux. The password is an attribute
        of the 'user'.
        """
        self._setUserPassword_unix(user)

    def _setUserPassword_osx(self, user):
        """
        Set a password for the user on Mac OS X. The password is an attribute
        of the 'user'.
        """
        userdb_name = u'/Users/' + user.name
        execute([
            'sudo', 'dscl', '.', '-passwd', userdb_name,
            user.password,
            ])

    def _setUserPassword_solaris(self, user):
        """
        Set a password for the user on Solaris. The password is an attribute
        of the 'user'.
        """
        self._setUserPassword_unix(user)

    def _setUserPassword_hpux(self, user):
        self._setUserPassword_unix(user)

    def _setUserPassword_freebsd(self, user):
        execute(
            command=[
                'sudo',
                'pw', 'mod', 'user', user.name.encode('utf-8'), '-h', '0',
                ],
            input_text=user.password.encode('utf-8'),
            )

    def _setUserPassword_openbsd(self, user):
        code, out = execute(
            command=['encrypt'],
            input_text=user.password.encode('utf-8'),
            )

        execute(
            command=[
                'sudo',
                'usermod', '-p', out.strip(), user.name.encode('utf-8'),
                ],
            )

    def deleteUser(self, user):
        """
        Delete user from the local operating system.
        """
        delete_user_method = getattr(self, '_deleteUser_' + self.name)
        delete_user_method(user)

    def deleteHomeFolder(self, user):
        """
        Removes user's home folder if outside temporary folder.
        """
        if user.posix_home_path and user.posix_home_path.startswith(u'/tmp'):
            return

        delete_folder_method = getattr(self, '_deleteHomeFolder_' + self.name)
        delete_folder_method(user)

    def _deleteHomeFolder_linux(self, user):
        self._deleteHomeFolder_unix(user)

    def _deleteHomeFolder_solaris(self, user):
        self._deleteHomeFolder_unix(user)

    def _deleteHomeFolder_hpux(self, user):
        self._deleteHomeFolder_unix(user)

    def _deleteHomeFolder_aix(self, user):
        self._deleteHomeFolder_unix(user)

    def _deleteHomeFolder_freebsd(self, user):
        self._deleteHomeFolder_unix(user)

    def _deleteHomeFolder_openbsd(self, user):
        self._deleteHomeFolder_unix(user)

    def _deleteHomeFolder_unix(self, user):
        encoded_home_path = user.posix_home_path.encode('utf-8')
        execute(['sudo', 'rm', '-rf', encoded_home_path])

    def _deleteHomeFolder_osx(self, user):
        home_folder = u'/Users/%s' % user.name
        execute(['sudo', 'rm', '-rf', home_folder])

    def _deleteUser_unix(self, user):
        self._deleteUnixEntry(
            kind='user',
            name=user.name,
            files=[['etc', 'passwd'], ['etc', 'shadow']])

        # Prevent circular import.
        from chevah.compat.testing import TestGroup
        group = TestGroup(name=user.name, posix_gid=user.uid)
        self._deleteGroup_unix(group)
        self.deleteHomeFolder(user)

    def _deleteUser_aix(self, user):
        execute(['sudo', 'rmuser', '-p', user.name.encode('utf-8')])
        self.deleteHomeFolder(user)

    def _deleteUser_linux(self, user):
        self._deleteUser_unix(user)

    def _deleteUser_osx(self, user):
        userdb_name = u'/Users/' + user.name
        execute(['sudo', 'dscl', '.', '-delete', userdb_name])
        self.deleteHomeFolder(user)

    def _deleteUser_solaris(self, user):
        self._deleteUser_unix(user)

    def _deleteUser_hpux(self, user):
        self._deleteUser_unix(user)

    def _deleteUser_freebsd(self, user):
        execute(['sudo', 'pw', 'userdel', user.name.encode('utf-8')])
        self.deleteHomeFolder(user)

    def _deleteUser_openbsd(self, user):
        execute(['sudo', 'userdel', user.name.encode('utf-8')])
        self.deleteHomeFolder(user)

    def deleteGroup(self, group):
        """
        Delete group from the local operating system.
        """
        delete_group_method = getattr(self, '_deleteGroup_' + self.name)
        delete_group_method(group=group)

    def _deleteGroup_unix(self, group):
        self._deleteUnixEntry(
            kind='group',
            name=group.name,
            files=[['etc', 'group'], ['etc', 'gshadow']])

    def _deleteGroup_aix(self, group):
        execute(['sudo', 'rmgroup', group.name.encode('utf-8')])

    def _deleteGroup_linux(self, group):
        self._deleteGroup_unix(group)

    def _deleteGroup_osx(self, group):
        groupdb_name = u'/groups/' + group.name
        execute(['sudo', 'dscl', '.', '-delete', groupdb_name])

    def _deleteGroup_solaris(self, group):
        self._deleteGroup_unix(group)

    def _deleteGroup_hpux(self, group):
        self._deleteGroup_unix(group)

    def _deleteGroup_freebsd(self, group):
        execute(['sudo', 'pw', 'group', 'del', group.name.encode('utf-8')])

    def _deleteGroup_openbsd(self, group):
        execute(['sudo', 'groupdel', group.name.encode('utf-8')])

    def _appendUnixEntry(self, segments, new_line):
        """
        Add the new_line to the end of `segments`.
        """
        temp_segments = segments[:]
        temp_segments[-1] = temp_segments[-1] + '-'
        content = self._getFileContent(segments)
        opened_file = self.fs.openFileForWriting(temp_segments, utf8=True)
        try:
            for line in content:
                opened_file.write(line + '\n')
            opened_file.write(new_line + '\n')
        finally:
            opened_file.close()

        self._replaceFile(temp_segments, segments)

    def _deleteUnixEntry(self, files, name, kind):
        """
        Delete a generic unix entry with 'name' from all `files`.
        """
        exists = False
        for segments in files:

            if not self.fs.exists(segments):
                continue

            exists = False
            temp_segments = segments[:]
            temp_segments[-1] = temp_segments[-1] + '-'

            content = self._getFileContent(segments)
            opened_file = self.fs.openFileForWriting(
                temp_segments, utf8=True)
            try:

                for line in content:
                    entry_name = line.split(':')[0]
                    if entry_name == name:
                        exists = True
                        continue
                    opened_file.write(line + '\n')
            finally:
                if opened_file:
                    opened_file.close()

            if exists:
                self._replaceFile(temp_segments, segments)

        if not exists:
            raise AssertionError((
                'No such %s: %s' % (kind, name)).encode('utf-8'))

    def _changeUnixEntry(
        self, segments, name, field,
        value_when_empty=None, value_to_append=None,
        value_to_replace=None,
            ):
        """
        Update entry 'name' with a new value or an appended value.
        Field is the number of entry filed to update, counting with 1.
        """
        exists = False
        temp_segments = segments[:]
        temp_segments[-1] = temp_segments[-1] + '-'

        content = self._getFileContent(segments)
        opened_file = self.fs.openFileForWriting(
            temp_segments, utf8=True)
        try:
            for line in content:
                fields = line.split(':')
                field_name = fields[0]
                if name == field_name:
                    exists = True

                    if fields[field - 1] == '':
                        if value_when_empty:
                            fields[field - 1] = value_when_empty
                        elif value_to_replace:
                            fields[field - 1] = value_to_replace
                        else:
                            pass
                    elif value_to_append:
                        fields[field - 1] = (
                            fields[field - 1] + value_to_append)
                    elif value_to_replace:
                        fields[field - 1] = value_to_replace
                    else:
                        pass

                    new_line = u':'.join(fields)
                else:
                    new_line = line

                opened_file.write(new_line + '\n')
        finally:
                opened_file.close()

        if exists:
            self._replaceFile(temp_segments, segments)
        else:
            raise AssertionError(u'No such entry: %s' % (name))

    def _replaceFile(self, from_segments, to_segments):
        attributes = self.fs.getAttributes(to_segments)
        self.fs.setAttributes(
            from_segments,
            {
                'mode': attributes.mode,
                'uid': attributes.uid,
                'gid': attributes.gid,
                },
            )
        self.fs.rename(from_segments, to_segments)

    def _getFileContent(self, segments):
        """
        Return a list of all lines from file.
        """
        opened_file = self.fs.openFileForReading(segments, utf8=True)
        content = []
        try:
            for line in opened_file:
                content.append(line.rstrip())
        finally:
            opened_file.close()

        return content