Path: blob/main/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { localize } from '../../../../nls.js';6import { Event } from '../../../../base/common/event.js';7import { isLinux } from '../../../../base/common/platform.js';8import { FileSystemProviderCapabilities, IFileDeleteOptions, IStat, FileType, IFileReadStreamOptions, IFileWriteOptions, IFileOpenOptions, IFileOverwriteOptions, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadStreamCapability, IFileSystemProviderWithFileFolderCopyCapability, IFileSystemProviderWithFileAtomicReadCapability, IFileAtomicReadOptions, IFileSystemProviderWithFileCloneCapability, IFileChange } from '../../../../platform/files/common/files.js';9import { AbstractDiskFileSystemProvider } from '../../../../platform/files/common/diskFileSystemProvider.js';10import { IMainProcessService } from '../../../../platform/ipc/common/mainProcessService.js';11import { CancellationToken } from '../../../../base/common/cancellation.js';12import { ReadableStreamEvents } from '../../../../base/common/stream.js';13import { URI } from '../../../../base/common/uri.js';14import { DiskFileSystemProviderClient, LOCAL_FILE_SYSTEM_CHANNEL_NAME } from '../../../../platform/files/common/diskFileSystemProviderClient.js';15import { ILogMessage, AbstractUniversalWatcherClient } from '../../../../platform/files/common/watcher.js';16import { UniversalWatcherClient } from './watcherClient.js';17import { ILoggerService, ILogService } from '../../../../platform/log/common/log.js';18import { IUtilityProcessWorkerWorkbenchService } from '../../utilityProcess/electron-browser/utilityProcessWorkerWorkbenchService.js';19import { LogService } from '../../../../platform/log/common/logService.js';2021/**22* A sandbox ready disk file system provider that delegates almost all calls23* to the main process via `DiskFileSystemProviderServer` except for recursive24* file watching that is done via shared process workers due to CPU intensity.25*/26export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider implements27IFileSystemProviderWithFileReadWriteCapability,28IFileSystemProviderWithOpenReadWriteCloseCapability,29IFileSystemProviderWithFileReadStreamCapability,30IFileSystemProviderWithFileFolderCopyCapability,31IFileSystemProviderWithFileAtomicReadCapability,32IFileSystemProviderWithFileCloneCapability {3334private readonly provider: DiskFileSystemProviderClient;3536constructor(37mainProcessService: IMainProcessService,38private readonly utilityProcessWorkerWorkbenchService: IUtilityProcessWorkerWorkbenchService,39logService: ILogService,40private readonly loggerService: ILoggerService41) {42super(logService, { watcher: { forceUniversal: true /* send all requests to universal watcher process */ } });4344this.provider = this._register(new DiskFileSystemProviderClient(mainProcessService.getChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME), { pathCaseSensitive: isLinux, trash: true }));4546this.registerListeners();47}4849private registerListeners(): void {5051// Forward events from the embedded provider52this._register(this.provider.onDidChangeFile(changes => this._onDidChangeFile.fire(changes)));53this._register(this.provider.onDidWatchError(error => this._onDidWatchError.fire(error)));54}5556//#region File Capabilities5758get onDidChangeCapabilities(): Event<void> { return this.provider.onDidChangeCapabilities; }5960get capabilities(): FileSystemProviderCapabilities { return this.provider.capabilities; }6162//#endregion6364//#region File Metadata Resolving6566stat(resource: URI): Promise<IStat> {67return this.provider.stat(resource);68}6970realpath(resource: URI): Promise<string> {71return this.provider.realpath(resource);72}7374readdir(resource: URI): Promise<[string, FileType][]> {75return this.provider.readdir(resource);76}7778//#endregion7980//#region File Reading/Writing8182readFile(resource: URI, opts?: IFileAtomicReadOptions): Promise<Uint8Array> {83return this.provider.readFile(resource, opts);84}8586readFileStream(resource: URI, opts: IFileReadStreamOptions, token: CancellationToken): ReadableStreamEvents<Uint8Array> {87return this.provider.readFileStream(resource, opts, token);88}8990writeFile(resource: URI, content: Uint8Array, opts: IFileWriteOptions): Promise<void> {91return this.provider.writeFile(resource, content, opts);92}9394open(resource: URI, opts: IFileOpenOptions): Promise<number> {95return this.provider.open(resource, opts);96}9798close(fd: number): Promise<void> {99return this.provider.close(fd);100}101102read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {103return this.provider.read(fd, pos, data, offset, length);104}105106write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {107return this.provider.write(fd, pos, data, offset, length);108}109110//#endregion111112//#region Move/Copy/Delete/Create Folder113114mkdir(resource: URI): Promise<void> {115return this.provider.mkdir(resource);116}117118delete(resource: URI, opts: IFileDeleteOptions): Promise<void> {119return this.provider.delete(resource, opts);120}121122rename(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void> {123return this.provider.rename(from, to, opts);124}125126copy(from: URI, to: URI, opts: IFileOverwriteOptions): Promise<void> {127return this.provider.copy(from, to, opts);128}129130//#endregion131132//#region Clone File133134cloneFile(from: URI, to: URI): Promise<void> {135return this.provider.cloneFile(from, to);136}137138//#endregion139140//#region File Watching141142protected createUniversalWatcher(143onChange: (changes: IFileChange[]) => void,144onLogMessage: (msg: ILogMessage) => void,145verboseLogging: boolean146): AbstractUniversalWatcherClient {147return new UniversalWatcherClient(changes => onChange(changes), msg => onLogMessage(msg), verboseLogging, this.utilityProcessWorkerWorkbenchService);148}149150protected createNonRecursiveWatcher(): never {151throw new Error('Method not implemented in sandbox.'); // we never expect this to be called given we set `forceUniversal: true`152}153154private _watcherLogService: ILogService | undefined = undefined;155private get watcherLogService(): ILogService {156if (!this._watcherLogService) {157this._watcherLogService = new LogService(this.loggerService.createLogger('fileWatcher', { name: localize('fileWatcher', "File Watcher") }));158}159160return this._watcherLogService;161}162163protected override logWatcherMessage(msg: ILogMessage): void {164this.watcherLogService[msg.type](msg.message);165166if (msg.type !== 'trace' && msg.type !== 'debug') {167super.logWatcherMessage(msg); // allow non-verbose log messages in window log168}169}170171//#endregion172}173174175