fileService.ts ×17

Frontier kind: Code frontier

unlabeled · c_374cb6ad47dd

993 tests · 11728 LOC · 44 files · introduces 0 tests · 80 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
19 ranges80 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1881 ranges11728 lines · 44 files · Browse complete extent
All tests (intent)
993 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 80 introduced LOC across 19 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/files/common/fileService.ts 76 introduced LOC · 17 ranges

Open complete file

380
381 async writeFile(resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise<IFileStatWithMetadata> {
382 > const provider = this.throwIfFileSystemIsReadonly(await this.withWriteProvider(resource), resource); fileService.ts
383 > const { providerExtUri } = this.getExtUri(provider);
384 >
385 > let writeFileOptions = options;
386 > if (hasFileAtomicWriteCapability(provider) && !writeFileOptions?.atomic) {
387 const enforcedAtomicWrite = provider.enforceAtomicWriteFile?.(resource);
388 if (enforcedAtomicWrite) {
390 }
391 }
393 > try {
394 >
395 > // validate write (this may already return a peeked-at buffer)
396 > let { stat, buffer: bufferOrReadableOrStreamOrBufferedStream } = await this.validateWriteFile(provider, resource, bufferOrReadableOrStream, writeFileOptions);
397 >
398 > // mkdir recursively as needed
399 > if (!stat) {
400 await this.mkdirp(provider, providerExtUri.dirname(resource));
401 }
403 > // optimization: if the provider has unbuffered write capability and the data
404 > // to write is not a buffer, we consume up to 3 chunks and try to write the data
405 > // unbuffered to reduce the overhead. If the stream or readable has more data
406 > // to provide we continue to write buffered.
407 > if (!bufferOrReadableOrStreamOrBufferedStream) {
408 > bufferOrReadableOrStreamOrBufferedStream = await this.peekBufferForWriting(provider, bufferOrReadableOrStream);
409 > }
410 >
411 > // write file: unbuffered
412 > if (
413 > !hasOpenReadWriteCloseCapability(provider) || // buffered writing is unsupported
414 > (hasReadWriteCapability(provider) && bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer) || // data is a full buffer already
415 (hasReadWriteCapability(provider) && hasFileAtomicWriteCapability(provider) && writeFileOptions?.atomic) // atomic write forces unbuffered write if the provider supports it
416 > ) { fileService.ts
417 > await this.doWriteUnbuffered(provider, resource, writeFileOptions, bufferOrReadableOrStreamOrBufferedStream);
418 > }
419
420 // write file: buffered
422 await this.doWriteBuffered(provider, resource, writeFileOptions, bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer ? bufferToReadable(bufferOrReadableOrStreamOrBufferedStream) : bufferOrReadableOrStreamOrBufferedStream);
423 }
425 > // events
426 > this._onDidRunOperation.fire(new FileOperationEvent(resource, FileOperation.WRITE));
427 > } catch (error) {
428 throw new FileOperationError(localize('err.write', "Unable to write file '{0}' ({1})", this.resourceForError(resource), ensureFileSystemProviderError(error).toString()), toFileOperationResult(error), writeFileOptions);
429 }
431 > return this.resolve(resource, { resolveMetadata: true });
432 > }
433
434
435 private async peekBufferForWriting(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream): Promise<VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream> {
436 > let peekResult: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream; fileService.ts
437 > if (hasReadWriteCapability(provider) && !(bufferOrReadableOrStream instanceof VSBuffer)) {
438 if (isReadableStream(bufferOrReadableOrStream)) {
439 const bufferedStream = await peekStream(bufferOrReadableOrStream, 3);
446 peekResult = peekReadable(bufferOrReadableOrStream, data => VSBuffer.concat(data), 3);
447 }
448 > } else { fileService.ts
449 > peekResult = bufferOrReadableOrStream;
450 > }
451 >
452 > return peekResult;
453 > }
454
455 private async validateWriteFile(provider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, bufferOrReadableOrStream: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: IWriteFileOptions): Promise<{ stat: IStat | undefined; buffer: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream | undefined }> {
457 > // Validate unlock support
458 > const unlock = !!options?.unlock;
459 > if (unlock && !(provider.capabilities & FileSystemProviderCapabilities.FileWriteUnlock)) {
460 throw new Error(localize('writeFailedUnlockUnsupported', "Unable to unlock file '{0}' because provider does not support it.", this.resourceForError(resource)));
461 }
463 > // Validate append support
464 > if (options?.append && !hasFileAppendCapability(provider)) {
465 throw new FileOperationError(localize('err.noAppend', "Filesystem provider for scheme '{0}' does not does not support append", this.resourceForError(resource)), FileOperationResult.FILE_PERMISSION_DENIED);
466 }
468 > // Validate atomic support
469 > const atomic = !!options?.atomic;
470 > if (atomic) {
471 if (!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicWrite)) {
472 throw new Error(localize('writeFailedAtomicUnsupported1', "Unable to atomically write file '{0}' because provider does not support it.", this.resourceForError(resource)));
481 }
482 }
484 > // Validate via file stat meta data
485 > let stat: IStat | undefined = undefined;
486 > try {
487 > stat = await provider.stat(resource);
488 > } catch (error) {
489 return Object.create(null); // file might not exist
490 }
516 let buffer: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream | undefined;
517 if (
518 > typeof options?.mtime === 'number' && typeof options.etag === 'string' && options.etag !== ETAG_DISABLED && fileService.ts
519 > typeof stat.mtime === 'number' && typeof stat.size === 'number' &&
520 > options.mtime < stat.mtime && options.etag !== etag({ mtime: options.mtime /* not using stat.mtime for a reason, see above */, size: stat.size })
521 > ) {
522 buffer = await this.peekBufferForWriting(provider, bufferOrReadableOrStream);
523 if (buffer instanceof VSBuffer && buffer.byteLength === stat.size) {
536
537 return { stat, buffer };
538 > } fileService.ts
539
540 async readFile(resource: URI, options?: IReadFileOptions, token?: CancellationToken): Promise<IFileContent> {
1364
1365 private async doWriteUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options: IWriteFileOptions | undefined, bufferOrReadableOrStreamOrBufferedStream: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream): Promise<void> {
1366 > return this.writeQueue.queueFor(resource, () => this.doWriteUnbufferedQueued(provider, resource, options, bufferOrReadableOrStreamOrBufferedStream), this.getExtUri(provider).providerExtUri); fileService.ts
1367 > }
1368
1369 private async doWriteUnbufferedQueued(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options: IWriteFileOptions | undefined, bufferOrReadableOrStreamOrBufferedStream: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream): Promise<void> {
1370 > let buffer: VSBuffer; fileService.ts
1371 > if (bufferOrReadableOrStreamOrBufferedStream instanceof VSBuffer) {
1372 > buffer = bufferOrReadableOrStreamOrBufferedStream;
1373 > } else if (isReadableStream(bufferOrReadableOrStreamOrBufferedStream)) {
1374 buffer = await streamToBuffer(bufferOrReadableOrStreamOrBufferedStream);
1375 } else if (isReadableBufferedStream(bufferOrReadableOrStreamOrBufferedStream)) {
1378 buffer = readableToBuffer(bufferOrReadableOrStreamOrBufferedStream);
1379 }
1381 > // Write through the provider
1382 > await provider.writeFile(resource, buffer.buffer, { create: true, overwrite: true, unlock: options?.unlock ?? false, atomic: options?.atomic ?? false, append: options?.append ?? false });
1383 > }
1384
1385 private async doPipeBuffered(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise<void> {
src/vs/platform/files/common/files.ts 4 introduced LOC · 2 ranges

Open complete file

781
782 export function hasFileAtomicWriteCapability(provider: IFileSystemProvider): provider is IFileSystemProviderWithFileAtomicWriteCapability {
783 > if (!hasReadWriteCapability(provider)) { files.ts
784 return false; // we require the `FileReadWrite` capability too
785 }
786 > files.ts
787 > return !!(provider.capabilities & FileSystemProviderCapabilities.FileAtomicWrite);
788 > }
789
790 export interface IFileSystemProviderWithFileAtomicDeleteCapability extends IFileSystemProvider {