@@ -179,10 +179,28 @@ async def stat(self, path: str) -> dict:
179179 "size" : s .st_size ,
180180 "modified" : s .st_mtime ,
181181 "type" : "directory" if os .path .isdir (path ) else "file" ,
182+ "writable" : self ._is_writable_sync (path ),
182183 }
183184
185+ def _is_writable_sync (self , path : str ) -> bool :
186+ if not self .is_path_allowed (path ):
187+ return False
188+ try :
189+ if os .statvfs (path ).f_flag & getattr (os , "ST_RDONLY" , 0 ):
190+ return False
191+ except (AttributeError , OSError ):
192+ pass
193+ try :
194+ return os .access (path , os .W_OK , effective_ids = True )
195+ except TypeError :
196+ return os .access (path , os .W_OK )
197+
198+ async def is_writable (self , path : str ) -> bool :
199+ """Return whether the current process can write to *path*."""
200+ return await asyncio .to_thread (self ._is_writable_sync , path )
201+
184202 async def listdir (self , path : str ) -> list [dict ]:
185- """List directory contents with type, size, and mtime ."""
203+ """List directory contents with type, size, mtime, and writability ."""
186204 self ._check_path (path )
187205 def _list_sync ():
188206 entries = []
@@ -197,6 +215,7 @@ def _list_sync():
197215 "type" : "directory" if os .path .isdir (full ) else "file" ,
198216 "size" : s .st_size ,
199217 "modified" : s .st_mtime ,
218+ "writable" : self ._is_writable_sync (full ),
200219 })
201220 except OSError :
202221 continue
0 commit comments