fileService.ts ×15

Frontier kind: Code frontier

unlabeled · c_81a23f9bda33

11 tests · 19214 LOC · 61 files · introduces 0 tests · 173 LOC · 3 files

Introduces — evidence that enters the hierarchy at this concept

Code
37 ranges173 lines · 3 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
2264 ranges19214 lines · 61 files · Browse complete extent
All tests (intent)
11 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.

3 files ranked by introduced lines: 173 introduced LOC across 37 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/files/common/fileService.ts 80 introduced LOC · 15 ranges

Open complete file

807 // copy
808 const mode = await this.doMoveCopy(sourceProvider, source, targetProvider, target, 'copy', !!overwrite);
810 > // resolve and send events
811 > const fileStat = await this.resolve(target, { resolveMetadata: true });
812 this._onDidRunOperation.fire(new FileOperationEvent(source, mode === 'copy' ? FileOperation.COPY : FileOperation.MOVE, fileStat));
813
843 else {
844 const sourceFile = await this.resolve(source);
845 > if (sourceFile.isDirectory) { fileService.ts
846 > await this.doCopyFolder(sourceProvider, sourceFile, targetProvider, target);
847 > } else {
848 await this.doCopyFile(sourceProvider, source, targetProvider, target);
849 }
850 }
852 > return mode;
853 > }
854
855 // move source => target
874
875 private async doCopyFile(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI): Promise<void> {
877 > // copy: source (buffered) => target (buffered)
878 > if (hasOpenReadWriteCloseCapability(sourceProvider) && hasOpenReadWriteCloseCapability(targetProvider)) {
879 > return this.doPipeBuffered(sourceProvider, source, targetProvider, target);
880 > }
881
882 // copy: source (buffered) => target (unbuffered)
883 > if (hasOpenReadWriteCloseCapability(sourceProvider) && hasReadWriteCapability(targetProvider)) { fileService.ts
884 return this.doPipeBufferedToUnbuffered(sourceProvider, source, targetProvider, target);
885 }
886
887 // copy: source (unbuffered) => target (buffered)
888 > if (hasReadWriteCapability(sourceProvider) && hasOpenReadWriteCloseCapability(targetProvider)) { fileService.ts
889 return this.doPipeUnbufferedToBuffered(sourceProvider, source, targetProvider, target);
890 }
891
892 // copy: source (unbuffered) => target (unbuffered)
893 > if (hasReadWriteCapability(sourceProvider) && hasReadWriteCapability(targetProvider)) { fileService.ts
894 return this.doPipeUnbuffered(sourceProvider, source, targetProvider, target);
895 }
896 > } fileService.ts
897
898 private async doCopyFolder(sourceProvider: IFileSystemProvider, sourceFolder: IFileStat, targetProvider: IFileSystemProvider, targetFolder: URI): Promise<void> {
900 > // create folder in target
901 > await targetProvider.mkdir(targetFolder);
902 >
903 > // create children in target
904 > if (Array.isArray(sourceFolder.children)) {
905 > await Promises.settled(sourceFolder.children.map(async sourceChild => {
906 > const targetChild = this.getExtUri(targetProvider).providerExtUri.joinPath(targetFolder, sourceChild.name);
907 > if (sourceChild.isDirectory) {
908 return this.doCopyFolder(sourceProvider, await this.resolve(sourceChild.resource), targetProvider, targetChild);
909 > } else { fileService.ts
910 > return this.doCopyFile(sourceProvider, sourceChild.resource, targetProvider, targetChild);
911 > }
912 > }));
913 > }
914 > }
915
916 private async doValidateMoveCopy(sourceProvider: IFileSystemProvider, source: URI, targetProvider: IFileSystemProvider, target: URI, mode: 'move' | 'copy', overwrite?: boolean): Promise<{ exists: boolean; isSameResourceWithDifferentPathCase: boolean }> {
1354
1355 private async doWriteBuffer(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, handle: number, buffer: VSBuffer, length: number, posInFile: number, posInBuffer: number): Promise<void> {
1356 > let totalBytesWritten = 0; fileService.ts
1357 > while (totalBytesWritten < length) {
1358 >
1359 > // Write through the provider
1360 > const bytesWritten = await provider.write(handle, posInFile + totalBytesWritten, buffer.buffer, posInBuffer + totalBytesWritten, length - totalBytesWritten);
1361 > totalBytesWritten += bytesWritten;
1362 > }
1363 > }
1364
1365 private async doWriteUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, options: IWriteFileOptions | undefined, bufferOrReadableOrStreamOrBufferedStream: VSBuffer | VSBufferReadable | VSBufferReadableStream | VSBufferReadableBufferedStream): Promise<void> {
1384
1385 private async doPipeBuffered(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise<void> {
1386 > return this.writeQueue.queueFor(target, () => this.doPipeBufferedQueued(sourceProvider, source, targetProvider, target), this.getExtUri(targetProvider).providerExtUri); fileService.ts
1387 > }
1388
1389 private async doPipeBufferedQueued(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise<void> {
1390 > let sourceHandle: number | undefined = undefined; fileService.ts
1391 > let targetHandle: number | undefined = undefined;
1392 >
1393 > try {
1394 >
1395 > // Open handles
1396 > sourceHandle = await sourceProvider.open(source, { create: false });
1397 > targetHandle = await targetProvider.open(target, { create: true, unlock: false });
1398 >
1399 > const buffer = VSBuffer.alloc(this.BUFFER_SIZE);
1400 >
1401 > let posInFile = 0;
1402 > let posInBuffer = 0;
1403 > let bytesRead = 0;
1404 > do {
1405 > // read from source (sourceHandle) at current position (posInFile) into buffer (buffer) at
1406 > // buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength).
1407 > bytesRead = await sourceProvider.read(sourceHandle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer);
1408 >
1409 > // write into target (targetHandle) at current position (posInFile) from buffer (buffer) at
1410 > // buffer position (posInBuffer) all bytes we read (bytesRead).
1411 > await this.doWriteBuffer(targetProvider, targetHandle, buffer, bytesRead, posInFile, posInBuffer);
1412 >
1413 > posInFile += bytesRead;
1414 > posInBuffer += bytesRead;
1415 >
1416 > // when buffer full, fill it again from the beginning
1417 > if (posInBuffer === buffer.byteLength) {
1418 posInBuffer = 0;
1419 }
1420 > } while (bytesRead > 0); fileService.ts
1421 > } catch (error) {
1422 throw ensureFileSystemProviderError(error);
1423 > } finally { fileService.ts
1424 > await Promises.settled([
1425 > typeof sourceHandle === 'number' ? sourceProvider.close(sourceHandle) : Promise.resolve(),
1426 > typeof targetHandle === 'number' ? targetProvider.close(targetHandle) : Promise.resolve(),
1427 > ]);
1428 > }
1429 > }
1430
1431 private async doPipeUnbuffered(sourceProvider: IFileSystemProviderWithFileReadWriteCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability, target: URI): Promise<void> {
src/vs/platform/files/common/inMemoryFilesystemProvider.ts 60 introduced LOC · 10 ranges

Open complete file

148 // file open/read/write/close
149 open(resource: URI, opts: IFileOpenOptions): Promise<number> {
150 > let file = this._lookup(resource, true); inMemoryFilesystemProvider.ts
151 > const write = isFileOpenForWriteOptions(opts);
152 > const append = write && !!opts.append;
153 >
154 > if (!file) {
155 > if (!write) {
156 throw createFileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound);
157 }
158 > // Create the file if opening for write inMemoryFilesystemProvider.ts
159 > const basename = resources.basename(resource);
160 > const parent = this._lookupParentDirectory(resource);
161 > file = new File(basename);
162 > file.data = new Uint8Array(0);
163 > parent.entries.set(basename, file);
164 > this._fireSoon({ type: FileChangeType.ADDED, resource });
165 > } else if (file instanceof Directory) {
166 throw createFileSystemProviderError('file is directory', FileSystemProviderErrorCode.FileIsADirectory);
167 }
169 > if (!file.data) {
170 file.data = new Uint8Array(0);
171 }
173 > const fd = this.memoryFdCounter++;
174 > this.fdMemory.set(fd, { file, resource, write, append });
175 > return Promise.resolve(fd);
176 > }
177
178 close(fd: number): Promise<void> {
179 > const fdData = this.fdMemory.get(fd); inMemoryFilesystemProvider.ts
180 > if (fdData?.write) {
181 > // Update file metadata on close
182 > fdData.file.mtime = Date.now();
183 > fdData.file.size = fdData.file.data?.byteLength ?? 0;
184 > this._fireSoon({ type: FileChangeType.UPDATED, resource: fdData.resource });
185 > }
186 > this.fdMemory.delete(fd);
187 > return Promise.resolve();
188 > }
189
190 read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
191 > const fdData = this.fdMemory.get(fd); inMemoryFilesystemProvider.ts
192 > if (!fdData) {
193 throw createFileSystemProviderError(`No file with that descriptor open`, FileSystemProviderErrorCode.Unavailable);
194 }
196 > if (!fdData.file.data) {
197 return Promise.resolve(0);
198 }
200 > const toWrite = VSBuffer.wrap(fdData.file.data).slice(pos, pos + length);
201 > data.set(toWrite.buffer, offset);
202 > return Promise.resolve(toWrite.byteLength);
203 > }
204
205 write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
206 > const fdData = this.fdMemory.get(fd); inMemoryFilesystemProvider.ts
207 > if (!fdData) {
208 throw createFileSystemProviderError(`No file with that descriptor open`, FileSystemProviderErrorCode.Unavailable);
209 }
211 > const toWrite = VSBuffer.wrap(data).slice(offset, offset + length);
212 > fdData.file.data ??= new Uint8Array(0);
213 >
214 > // In append mode, always write at the end
215 > const writePos = fdData.append ? fdData.file.data.byteLength : pos;
216 >
217 > // Grow the buffer if needed
218 > const endPos = writePos + toWrite.byteLength;
219 > if (endPos > fdData.file.data.byteLength) {
220 > const newData = new Uint8Array(endPos);
221 > newData.set(fdData.file.data, 0);
222 > fdData.file.data = newData;
223 > }
224 >
225 > fdData.file.data.set(toWrite.buffer, writePos);
226 > return Promise.resolve(toWrite.byteLength);
227 > }
228
229 // --- manage files/folders
src/vs/platform/agentHost/node/agentPluginManager.ts 33 introduced LOC · 12 ranges

Open complete file

89 try {
90 const pluginDir = await this._syncPlugin(clientId, ref);
91 > const customization: PluginCustomization = { ...ref, load: { kind: CustomizationLoadStatus.Loaded } }; agentPluginManager.ts
92 > progress?.(customization);
93 return { customization, pluginDir };
94 } catch (err) {
129
130 await this._fileService.copy(pluginUri, destDir, true);
132 > this._removeEntry(ref.uri, ref.nonce);
133 this._lru.push({ uri: ref.uri, nonce: ref.nonce ?? '' });
134
136 // in the LRU for a later attempt.
137 await this._cleanupStaleNoncesFor(ref.uri);
138 > await this._evictIfNeeded(); agentPluginManager.ts
139 > await this._persistCache();
140 >
141 > return destDir;
142 }
143
165
166 private _findEntry(uri: string, nonce: string | undefined): ICacheEntry | undefined {
167 > const n = nonce ?? ''; agentPluginManager.ts
168 > return this._lru.find(entry => entry.uri === uri && entry.nonce === n);
169 > }
170
171 private _removeEntry(uri: string, nonce: string | undefined): void {
172 > const entry = this._findEntry(uri, nonce); agentPluginManager.ts
173 > if (entry) {
174 this._removeEntryRef(entry);
175 }
177
178 private _removeEntryRef(entry: ICacheEntry): void {
215 */
216 private async _cleanupStaleNoncesFor(uri: string): Promise<void> {
217 > const entries = this._lru.filter(entry => entry.uri === uri); agentPluginManager.ts
218 > // `entries` preserves LRU order; the last is the current revision.
219 > const stale = entries.slice(0, -1);
220 > for (const entry of stale) {
221 this._logService.info(`[AgentPluginManager] Evicting stale nonce for plugin: ${uri}`);
222 if (await this._tryDeleteDir(this._dirFor(entry.uri, entry.nonce))) {
224 }
225 }
227
228 private async _evictIfNeeded(): Promise<void> {
229 > // Pop from the head until we're at-or-below the cap. Entries whose agentPluginManager.ts
230 > // directory can't be deleted (still locked by a running session)
231 > // are kept in the LRU so they can be retried on a later eviction
232 > // pass; the cap may be exceeded temporarily in that case.
233 > let i = 0;
234 > while (this._lru.length > this._maxPlugins && i < this._lru.length) {
235 const candidate = this._lru[i];
236 this._logService.info(`[AgentPluginManager] Evicting plugin: ${candidate.uri}`);
245 }
246 }
248
249 // ---- cache persistence --------------------------------------------------
281
282 private async _persistCache(): Promise<void> {
283 > try { agentPluginManager.ts
284 > // Write entries in LRU order (oldest first)
285 > const entries: ICacheEntry[] = this._lru.map(entry => ({ uri: entry.uri, nonce: entry.nonce }));
286 > await this._fileService.createFolder(this._basePath);
287 > await this._fileService.writeFile(this._cachePath, VSBuffer.fromString(JSON.stringify(entries)));
288 > } catch (err) {
289 this._logService.warn('[AgentPluginManager] Failed to persist cache to disk', err);
290 }
292 }