示例#1
0
def wait_for_objects(object_list, timeout=0, wait_for_all=False):
    """Wait until list of object are in signaled state.

    :param object_list: a list of handles
    :type object_list: list[int]
    :param timeout: maximum waiting time in seconds. If 0 then maximum waiting
        time is set to infinity
    :type timeout: int
    :param wait_for_all: if True wait for all object to be signaled. If False
        wait for one object to be signaled
    :type wait_for_all: bool
    :return: index in the object list of the signaled object or None in case
        of timeout
    :rtype: int | None
    :raise: WindowsError
    """
    from e3.os.windows.native_api import NT, Wait
    from ctypes.wintypes import HANDLE

    if timeout == 0:
        timeout = Wait.INFINITE
    else:
        timeout = int(timeout * 1000)

    size = len(object_list)
    handle_array = HANDLE * size
    handles = handle_array(*object_list)

    object_index = NT.WaitForMultipleObjects(size, handles, wait_for_all,
                                             timeout)
    if object_index == Wait.TIMEOUT:
        return None
    elif object_index == Wait.FAILED:  # defensive code
        raise WindowsError("error while waiting for objects")
    elif Wait.ABANDONED <= object_index \
            < Wait.ABANDONED + size:  # defensive code
        return object_index - Wait.ABANDONED
    elif Wait.OBJECT <= object_index < Wait.OBJECT + size:
        return object_index
    else:  # defensive code
        raise WindowsError("unknown error while waiting for objects")
示例#2
0
    def uid(self):
        """Retrieve the ID of the file.

        On NTFS system we are sure that this ID is unique on the given volume

        :return: the uid
        :rtype: int
        ;raise: NTException
        """
        result = FileInfo.Internal()
        status = NT.QueryInformationFile(self.handle, pointer(self.io_status),
                                         pointer(result), sizeof(result),
                                         FileInfo.Internal.class_id)
        if status < 0:  # defensive code
            # we should already have raised an error here when trying
            # to open the file
            raise NTException(status=status,
                              message='cannot find file uid',
                              origin="NTFile.uid")

        return result.index_number
示例#3
0
    def rename(self, filename, replace=False):
        """Move file.

        :param filename: target location
        :type filename: unicode
        :param replace: if True replace the target file if it exists
        :type replace: bool
        :raise: NTException
        """
        target = u"\\??\\%s" % os.path.abspath(filename)
        target = target.encode('utf_16_le')
        s = "?PL%ss" % len(target)
        b = create_string_buffer(struct.calcsize(s))
        b.raw = struct.pack(s, replace, 0, len(target), target)
        status = NT.SetInformationFile(self.handle, pointer(self.io_status), b,
                                       struct.calcsize(s),
                                       FileInfo.Rename.class_id)
        if status < 0:
            raise NTException(status=status,
                              message="move of %s to %s failed" %
                              (self.path, filename),
                              origin="NTFile.rename")
示例#4
0
文件: fs.py 项目: enzbang/e3-core
    def unlink(self):
        """Remove file safely.

        :raise: NTException
        """
        open_options = self.open_options
        is_in_trash = False

        # First we need to check that file is not mark readonly
        try:
            self.read_attributes_internal()
        except NTException as e:
            if e.status == Status.OBJECT_NAME_NOT_FOUND:
                return
            elif e.status == Status.DELETE_PENDING:
                return
            else:
                raise

        if self.is_readonly:
            # Try to remove the readonly flag
            self.basic_info.file_attributes.attr &= ~FileAttribute.READONLY
            self.write_attributes()

        # set our access modes
        desired_access = Access.DELETE
        shared_access = Share.DELETE
        if self.is_dir:
            desired_access |= Access.LIST_DIRECTORY | Access.SYNCHRONIZE
            open_options |= OpenOptions.SYNCHRONOUS_IO_NON_ALERT

        try_counter = 10
        # Open the file for deletion
        while try_counter > 0:
            try:
                self.open(desired_access, shared_access, open_options)
                break
            except NTException as e:
                if e.status == Status.SHARING_VIOLATION:
                    # File is already open elsewhere for a non delete operation
                    # Try a few times to open it with relaxed share settings
                    shared_access = Share.ALL
                elif e.status == Status.DELETE_PENDING:  # defensive code
                    # file is already pending deletion (just after our call
                    # to read_attributes) so consider the deletion
                    # is done and return
                    return
                else:  # defensive code
                    # We don't know what to do here so just fail
                    raise

            # Wait a few ms before attempting again to open the file
            NT.Sleep(5)
            try_counter -= 1

        if try_counter == 0:
            raise NTException(
                status=1,
                message="cannot open file %s for deletion" % self.path,
                origin="NTFile.unlink",
            )

        # From there we assume that the file has been opened
        try:
            if shared_access == Share.ALL:
                # The file is also opened elsewhere for a non delete operation
                # In that case we will try to move it to the trash
                # first check that the directory is empty
                if self.is_dir and not self.is_dir_empty:
                    raise NTException(
                        status=1,
                        message="directory not empty: %s" % self.path,
                        origin="NTFile.unlink",
                    )

                self.move_to_trash()
                is_in_trash = True

            # If the file has been moved away then we try to delete it in the
            # trash but it is not necessary to try as hard as the goal is to
            # just keep the trash space used as low as possible.
            if is_in_trash:
                try_counter = 5
            else:
                try_counter = 20

            while try_counter > 0:
                try:
                    self.dispose()
                    break
                except NTException as e:
                    if e.status == Status.DIRECTORY_NOT_EMPTY:
                        # The directory is not empty but that might be because
                        # of remaining files in PENDING_DELETE status. Our
                        # is_dir_empty method return empty if the directory
                        # contains only files pending for deletion
                        if not self.is_dir_empty:
                            raise NTException(
                                status=e.status,
                                message="dir %s is not empty" % self.path,
                                origin="NTFile.unlink",
                            )
                    elif e.status == Status.CANNOT_DELETE:  # defensive code
                        # At this stage we are sure that the file is not
                        # read_only but it seems that we can get this error
                        # when the file has been mapped to memory.
                        if not is_in_trash:
                            try:
                                self.move_to_trash()
                                is_in_trash = True
                                try_counter = min(try_counter, 5)
                            except NTException:
                                pass
                    else:  # defensive code
                        # Unknown error. If the file has been moved away
                        # consider it success. Otherwise reraise exception
                        if is_in_trash:
                            break
                        raise

                NT.Sleep(5)
                try_counter -= 1

        finally:
            self.close()
示例#5
0
文件: fs.py 项目: enzbang/e3-core
    def iterate_on_dir(self, fun, default_result=None):
        """Iterate on directory.

        :param fun: function called on each entry (. are .. are skipped)
        :param default_result: default return value
        :return: last return value or fun or default_result
        """
        result = default_result
        s_size = struct.calcsize("LLL")
        b_size = 100 * 1024
        b = create_string_buffer(b_size)
        status = NT.QueryDirectoryFile(
            self.handle,
            None,
            None,
            None,
            pointer(self.io_status),
            b,
            b_size,
            FileInfo.Names.class_id,
            False,
            None,
            True,
        )
        if status == Status.NO_MORE_FILES:  # defensive code
            # In theory this case should not occurs at it means that the
            # directory does not even have the . and .. entries. In practice
            # it can occurs (probably because of an intermediate state).
            # In that case behave as if the directory is empty
            return result

        if status < 0:
            raise NTException(
                status=status,
                message="can't read dir %s" % self.path,
                origin="NTFile.iterate_on_dir",
            )

        while status >= 0 and status != Status.NO_MORE_FILES:
            pos = 0
            while True:
                off, _, size = struct.unpack_from("LLL", b.raw, pos)
                name = b.raw[pos + s_size:pos + s_size +
                             size].decode("utf-16-le")
                if name != "." and name != "..":
                    result, should_exit = fun(name, self)
                    if should_exit:
                        return result

                if off == 0:
                    break
                pos += off

            status = NT.QueryDirectoryFile(
                self.handle,
                None,
                None,
                None,
                pointer(self.io_status),
                b,
                b_size,
                FileInfo.Names.class_id,
                False,
                None,
                False,
            )
        return result