Beispiel #1
0
def main(mountpoint, label, debug):
    if debug:
        enable_debug_log()

    operations = InMemoryFileSystemOperations(label, container_path)
    fs = FileSystem(
        mountpoint,
        operations,
        sector_size=512,
        sectors_per_allocation_unit=1,
        volume_creation_time=filetime_now(),
        volume_serial_number=0,
        file_info_timeout=1000,
        case_sensitive_search=1,
        case_preserved_names=1,
        unicode_on_disk=1,
        persistent_acls=1,
        post_cleanup_when_modified_only=1,
        um_file_context_is_user_context2=1,
        file_system_name=mountpoint,
        prefix="",
        # security_timeout_valid=1,
        # security_timeout=10000,
    )
    try:
        print('Starting FS')
        fs.start()
        print('FS started, keep it running for 100s')
        time.sleep(10000)

    finally:
        print('Stopping FS')
        fs.stop()
        print('FS stopped')
Beispiel #2
0
def create_memory_file_system(mountpoint,
                              label="memfs",
                              verbose=True,
                              debug=False,
                              testing=False):
    if debug:
        enable_debug_log()

    if verbose:
        logging.basicConfig(stream=sys.stdout, level=logging.INFO)

    # The avast workaround is not necessary with drives
    # Also, it is not compatible with winfsp-tests
    mountpoint = Path(mountpoint)
    is_drive = mountpoint.parent == mountpoint
    reject_irp_prior_to_transact0 = not is_drive and not testing

    operations = InMemoryFileSystemOperations(label)
    fs = FileSystem(
        str(mountpoint),
        operations,
        sector_size=512,
        sectors_per_allocation_unit=1,
        volume_creation_time=filetime_now(),
        volume_serial_number=0,
        file_info_timeout=1000,
        case_sensitive_search=1,
        case_preserved_names=1,
        unicode_on_disk=1,
        persistent_acls=1,
        post_cleanup_when_modified_only=1,
        um_file_context_is_user_context2=1,
        file_system_name=str(mountpoint),
        prefix="",
        debug=debug,
        reject_irp_prior_to_transact0=reject_irp_prior_to_transact0,
        # security_timeout_valid=1,
        # security_timeout=10000,
    )
    return fs
Beispiel #3
0
async def winfsp_mountpoint_runner(
    user_fs: UserFS,
    workspace_fs: WorkspaceFS,
    base_mountpoint_path: PurePath,
    config: dict,
    event_bus: EventBus,
):
    """
    Raises:
        MountpointDriverCrash
    """
    device = workspace_fs.device
    workspace_name = winify_entry_name(workspace_fs.get_workspace_name())
    trio_token = trio.lowlevel.current_trio_token()
    fs_access = ThreadFSAccess(trio_token, workspace_fs, event_bus)

    user_manifest = user_fs.get_user_manifest()
    workspace_ids = [entry.id for entry in user_manifest.workspaces]
    workspace_index = workspace_ids.index(workspace_fs.workspace_id)
    # `base_mountpoint_path` is ignored given we only mount from a drive
    mountpoint_path = await _get_available_drive(workspace_index,
                                                 len(workspace_ids))

    # Prepare event information
    event_kwargs = {
        "mountpoint": mountpoint_path,
        "workspace_id": workspace_fs.workspace_id,
        "timestamp": getattr(workspace_fs, "timestamp", None),
    }

    if config.get("debug", False):
        enable_debug_log()

    # Volume label is limited to 32 WCHAR characters, so force the label to
    # ascii to easily enforce the size.
    volume_label = (unicodedata.normalize(
        "NFKD", f"{workspace_name.capitalize()}").encode(
            "ascii", "ignore")[:32].decode("ascii"))
    volume_serial_number = _generate_volume_serial_number(
        device, workspace_fs.workspace_id)
    operations = WinFSPOperations(fs_access=fs_access,
                                  volume_label=volume_label,
                                  **event_kwargs)
    # See https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getvolumeinformationa  # noqa
    fs = FileSystem(
        mountpoint_path.drive,
        operations,
        sector_size=512,
        sectors_per_allocation_unit=1,
        volume_creation_time=filetime_now(),
        volume_serial_number=volume_serial_number,
        file_info_timeout=1000,
        case_sensitive_search=1,
        case_preserved_names=1,
        unicode_on_disk=1,
        persistent_acls=0,
        reparse_points=0,
        reparse_points_access_check=0,
        named_streams=0,
        read_only_volume=workspace_fs.is_read_only(),
        post_cleanup_when_modified_only=1,
        device_control=0,
        um_file_context_is_user_context2=1,
        file_system_name="Parsec",
        prefix="",
        # The minimum value for IRP timeout is 1 minute (default is 5)
        irp_timeout=60000,
        # security_timeout_valid=1,
        # security_timeout=10000,
    )

    try:
        event_bus.send(CoreEvent.MOUNTPOINT_STARTING, **event_kwargs)

        # Manage drive icon
        drive_letter, *_ = mountpoint_path.drive
        with parsec_drive_icon_context(drive_letter):

            # Run fs start in a thread
            await trio.to_thread.run_sync(fs.start)

            # The system is too sensitive right after starting
            await trio.sleep(0.010)  # 10 ms

            # Make sure the mountpoint is ready
            await _wait_for_winfsp_ready(mountpoint_path)

            # Notify the manager that the mountpoint is ready
            yield mountpoint_path

            # Start recording `sharing.updated` events
            with event_bus.waiter_on(CoreEvent.SHARING_UPDATED) as waiter:

                # Loop over `sharing.updated` event
                while True:

                    # Restart the mountpoint with the right read_only flag if necessary
                    # Don't bother with restarting if the workspace has been revoked
                    # It's the manager's responsibility to unmount the workspace in this case
                    if (workspace_fs.is_read_only() !=
                            fs.volume_params["read_only_volume"]
                            and not workspace_fs.is_revoked()):
                        restart = partial(
                            fs.restart,
                            read_only_volume=workspace_fs.is_read_only())
                        await trio.to_thread.run_sync(restart)

                    # Wait and reset waiter
                    await waiter.wait()
                    waiter.clear()

    except Exception as exc:
        raise MountpointDriverCrash(
            f"WinFSP has crashed on {mountpoint_path}: {exc}") from exc

    finally:
        event_bus.send(CoreEvent.MOUNTPOINT_STOPPING, **event_kwargs)

        # Must run in thread given this call will wait for any winfsp operation
        # to finish so blocking the trio loop can produce a dead lock...
        with trio.CancelScope(shield=True):
            try:
                await trio.to_thread.run_sync(fs.stop)
            # The file system might not be started,
            # if the task gets cancelled before running `fs.start` for instance
            except FileSystemNotStarted:
                pass
Beispiel #4
0
async def winfsp_mountpoint_runner(
    workspace_fs,
    base_mountpoint_path: Path,
    config: dict,
    event_bus,
    *,
    task_status=trio.TASK_STATUS_IGNORED,
):
    """
    Raises:
        MountpointDriverCrash
    """
    device = workspace_fs.device
    workspace_name = winify_entry_name(workspace_fs.get_workspace_name())
    trio_token = trio.hazmat.current_trio_token()
    fs_access = ThreadFSAccess(trio_token, workspace_fs)

    mountpoint_path = await _bootstrap_mountpoint(base_mountpoint_path, workspace_name)

    if config.get("debug", False):
        enable_debug_log()

    # Volume label is limited to 32 WCHAR characters, so force the label to
    # ascii to easily enforce the size.
    volume_label = (
        unicodedata.normalize("NFKD", f"{device.user_id}-{workspace_name}")
        .encode("ascii", "ignore")[:32]
        .decode("ascii")
    )
    volume_serial_number = _generate_volume_serial_number(device, workspace_fs.workspace_id)
    operations = WinFSPOperations(event_bus, volume_label, fs_access)
    # See https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getvolumeinformationa  # noqa
    fs = FileSystem(
        str(mountpoint_path.absolute()),
        operations,
        sector_size=512,
        sectors_per_allocation_unit=1,
        volume_creation_time=filetime_now(),
        volume_serial_number=volume_serial_number,
        file_info_timeout=1000,
        case_sensitive_search=1,
        case_preserved_names=1,
        unicode_on_disk=1,
        persistent_acls=0,
        reparse_points=0,
        reparse_points_access_check=0,
        named_streams=0,
        read_only_volume=0,
        post_cleanup_when_modified_only=1,
        device_control=0,
        um_file_context_is_user_context2=1,
        file_system_name="Parsec",
        prefix="",
        # The minimum value for IRP timeout is 1 minute (default is 5)
        irp_timeout=60000,
        # Work around the avast/winfsp incompatibility
        reject_irp_prior_to_transact0=True,
        # security_timeout_valid=1,
        # security_timeout=10000,
    )
    try:
        event_bus.send("mountpoint.starting", mountpoint=mountpoint_path)

        # Run fs start in a thread, as a cancellable operation
        # This is because fs.start() might get stuck for while in case of an IRP timeout
        await trio.to_thread.run_sync(fs.start, cancellable=True)

        # Because of reject_irp_prior_to_transact0, the mountpoint isn't ready yet
        # We have to add a bit of delay here, the tests would fail otherwise
        # 10 ms is more than enough, although a strict process would be nicer
        # Still, this is only temporary as avast is working on a fix at the moment
        # Another way to address this problem would be to migrate to python 3.8,
        # then use `os.stat` to differentiate between a started and a non-started
        # file syste.
        await trio.sleep(0.01)

        event_bus.send("mountpoint.started", mountpoint=mountpoint_path)
        task_status.started(mountpoint_path)

        await trio.sleep_forever()

    except Exception as exc:
        raise MountpointDriverCrash(f"WinFSP has crashed on {mountpoint_path}: {exc}") from exc

    finally:
        # Must run in thread given this call will wait for any winfsp operation
        # to finish so blocking the trio loop can produce a dead lock...
        with trio.CancelScope(shield=True):
            await trio.to_thread.run_sync(fs.stop)
        event_bus.send("mountpoint.stopped", mountpoint=mountpoint_path)