@@ -2,6 +2,7 @@ import fs from "fs"
22import os from "os"
33import path from "path"
44import {
5+ FileSystemCreateFolderResponse ,
56 FileSystemEntry ,
67 FileSystemListResponse ,
78 FileSystemListingMetadata ,
@@ -56,6 +57,30 @@ export class FileSystemBrowser {
5657 return this . listRestrictedWithMetadata ( targetPath , includeFiles )
5758 }
5859
60+ createFolder ( parentPath : string | undefined , folderName : string ) : FileSystemCreateFolderResponse {
61+ const name = this . normalizeFolderName ( folderName )
62+
63+ if ( this . unrestricted ) {
64+ const resolvedParent = this . resolveUnrestrictedPath ( parentPath )
65+ if ( this . isWindows && resolvedParent === WINDOWS_DRIVES_ROOT ) {
66+ throw new Error ( "Cannot create folders at drive root" )
67+ }
68+ this . assertDirectoryExists ( resolvedParent )
69+ const absolutePath = this . resolveAbsoluteChild ( resolvedParent , name )
70+ fs . mkdirSync ( absolutePath )
71+ return { path : absolutePath , absolutePath }
72+ }
73+
74+ const normalizedParent = this . normalizeRelativePath ( parentPath )
75+ const parentAbsolute = this . toRestrictedAbsolute ( normalizedParent )
76+ this . assertDirectoryExists ( parentAbsolute )
77+
78+ const relativePath = this . buildRelativePath ( normalizedParent , name )
79+ const absolutePath = this . toRestrictedAbsolute ( relativePath )
80+ fs . mkdirSync ( absolutePath )
81+ return { path : relativePath , absolutePath }
82+ }
83+
5984 readFile ( relativePath : string ) : string {
6085 if ( this . unrestricted ) {
6186 throw new Error ( "readFile is not available in unrestricted mode" )
@@ -157,6 +182,41 @@ export class FileSystemBrowser {
157182 return { entries, metadata }
158183 }
159184
185+ private normalizeFolderName ( input : string ) : string {
186+ const name = input . trim ( )
187+ if ( ! name ) {
188+ throw new Error ( "Folder name is required" )
189+ }
190+
191+ if ( name === "." || name === ".." ) {
192+ throw new Error ( "Invalid folder name" )
193+ }
194+
195+ if ( name . startsWith ( "~" ) ) {
196+ throw new Error ( "Invalid folder name" )
197+ }
198+
199+ if ( name . includes ( "/" ) || name . includes ( "\\" ) ) {
200+ throw new Error ( "Folder name must not include path separators" )
201+ }
202+
203+ if ( name . includes ( "\u0000" ) ) {
204+ throw new Error ( "Invalid folder name" )
205+ }
206+
207+ return name
208+ }
209+
210+ private assertDirectoryExists ( directory : string ) {
211+ if ( ! fs . existsSync ( directory ) ) {
212+ throw new Error ( `Directory does not exist: ${ directory } ` )
213+ }
214+ const stats = fs . statSync ( directory )
215+ if ( ! stats . isDirectory ( ) ) {
216+ throw new Error ( `Path is not a directory: ${ directory } ` )
217+ }
218+ }
219+
160220 private readDirectoryEntries ( directory : string , options : DirectoryReadOptions ) : FileSystemEntry [ ] {
161221 const dirents = fs . readdirSync ( directory , { withFileTypes : true } )
162222 const results : FileSystemEntry [ ] = [ ]
0 commit comments