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')
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
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
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)