Skip to content

Commit

Permalink
Refactor the VFS interface
Browse files Browse the repository at this point in the history
  • Loading branch information
JesseTG committed Mar 19, 2024
1 parent 4105272 commit f290239
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 29 deletions.
24 changes: 14 additions & 10 deletions src/libretro/api/vfs/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
class StandardFileHandle(FileHandle):
def __init__(self, path: VfsPath, mode: VfsFileAccess, hints: VfsFileAccessHint):
super().__init__(path, mode, hints)
self._file: FileIO | None = None
if not path:
raise ValueError("Expected a non-empty path")

Expand Down Expand Up @@ -89,6 +90,7 @@ def truncate(self, length: int) -> int:

class StandardDirectoryHandle(DirectoryHandle):
def __init__(self, path: VfsPath, include_hidden: bool):
super().__init__(path, include_hidden)
self._dirent = os.scandir(path)

def __del__(self):
Expand Down Expand Up @@ -120,7 +122,6 @@ def open(self, path: bytes, mode: VfsFileAccess, hints: VfsFileAccessHint) -> Fi
handle = StandardFileHandle(path, mode, hints)
return handle
except OSError as e:
# TODO: Log error
return None

def remove(self, path: bytes) -> bool:
Expand All @@ -132,19 +133,22 @@ def rename(self, old_path: bytes, new_path: bytes) -> bool:
return True

def stat(self, path: bytes) -> tuple[VfsStat, int] | None:
filestat = os.stat(path)
flags = VfsStat(0)
try:
filestat = os.stat(path)
flags = VfsStat(0)

if stat.S_ISREG(filestat.st_mode):
flags |= VfsStat.IS_VALID
if stat.S_ISREG(filestat.st_mode):
flags |= VfsStat.IS_VALID

if stat.S_ISDIR(filestat.st_mode):
flags |= VfsStat.IS_DIRECTORY
if stat.S_ISDIR(filestat.st_mode):
flags |= VfsStat.IS_DIRECTORY

if stat.S_ISCHR(filestat.st_mode):
flags |= VfsStat.IS_CHARACTER_SPECIAL
if stat.S_ISCHR(filestat.st_mode):
flags |= VfsStat.IS_CHARACTER_SPECIAL

return flags, filestat.st_size
return flags, filestat.st_size
except FileNotFoundError:
return VfsStat(0), 0

def mkdir(self, path: bytes) -> VfsMkdirResult:
try:
Expand Down
2 changes: 1 addition & 1 deletion src/libretro/api/vfs/defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def open_flag(self) -> str:
retro_vfs_rename_t = CFUNCTYPE(c_int, c_char_p, c_char_p)
retro_vfs_stat_t = CFUNCTYPE(c_int, c_char_p, POINTER(c_int32))
retro_vfs_mkdir_t = CFUNCTYPE(c_int, c_char_p)
retro_vfs_opendir_t = CFUNCTYPE(UNCHECKED(POINTER(retro_vfs_dir_handle)), c_char_p, c_bool)
retro_vfs_opendir_t = CFUNCTYPE(c_void_p, c_char_p, c_bool)
retro_vfs_readdir_t = CFUNCTYPE(c_bool, POINTER(retro_vfs_dir_handle))
retro_vfs_dirent_get_name_t = CFUNCTYPE(c_char_p, POINTER(retro_vfs_dir_handle))
retro_vfs_dirent_is_dir_t = CFUNCTYPE(c_bool, POINTER(retro_vfs_dir_handle))
Expand Down
39 changes: 22 additions & 17 deletions src/libretro/api/vfs/interface.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ctypes
from abc import abstractmethod
from ctypes import *
from logging import Logger
Expand Down Expand Up @@ -52,7 +53,7 @@ class DirEntry(NamedTuple):
class DirectoryHandle(Protocol):
@abstractmethod
def __init__(self, dir: bytes, include_hidden: bool):
self._as_parameter_ = c_void_p(id(self))
self._as_parameter_ = id(self)
self._current_dirent: DirEntry | None = None

@abstractmethod
Expand Down Expand Up @@ -168,7 +169,7 @@ def __get_path(self, stream: POINTER(retro_vfs_file_handle)) -> bytes | None:
case _ as result:
raise TypeError(f"Expected path to return a bytes, got: {type(result).__name__}")

def __open(self, path: bytes, mode: int, hints: int) -> POINTER(retro_vfs_file_handle) | None:
def __open(self, path: bytes, mode: int, hints: int) -> c_void_p | None:
if not path:
return None

Expand All @@ -186,7 +187,7 @@ def __open(self, path: bytes, mode: int, hints: int) -> POINTER(retro_vfs_file_h
address = id(file)
self.__file_handles[address] = file

return POINTER(retro_vfs_file_handle).from_address(address)
return address

def __close(self, stream: POINTER(retro_vfs_file_handle)) -> int:
if not stream:
Expand Down Expand Up @@ -284,9 +285,9 @@ def __read(self, stream: POINTER(retro_vfs_file_handle), buffer: c_void_p, lengt
if not buffer:
return -1

assert isinstance(buffer, c_void_p)
assert isinstance(length, int)
assert length >= 0
#assert isinstance(buffer, c_void_p), f"Expected a c_void_p, got: {type(buffer).__name__}"
assert isinstance(length, int), f"Expected an int, got: {type(length).__name__}"
assert length >= 0, f"Expected length to be non-negative, got: {length}"

if length == 0:
return 0
Expand All @@ -297,7 +298,7 @@ def __read(self, stream: POINTER(retro_vfs_file_handle), buffer: c_void_p, lengt
if not handle:
return -1

assert isinstance(handle, FileHandle)
assert isinstance(handle, FileHandle), f"Expected a FileHandle, got: {type(handle).__name__}"

memview = memoryview_at(buffer, length)
bytes_read = handle.read(memview)
Expand All @@ -309,14 +310,14 @@ def __read(self, stream: POINTER(retro_vfs_file_handle), buffer: c_void_p, lengt
# TODO: Log the exception
return -1

def __write(self, stream: POINTER(retro_vfs_file_handle), buffer: c_void_p, length: int) -> int:
def __write(self, stream: POINTER(retro_vfs_file_handle), buffer: int, length: int) -> int:
if not stream:
return -1

if not buffer:
return -1

assert isinstance(buffer, c_void_p)
assert isinstance(buffer, int)
assert isinstance(length, int)
assert length >= 0

Expand Down Expand Up @@ -412,7 +413,7 @@ def __stat(self, path: bytes, size: POINTER(c_int32)) -> int:

match self.stat(path):
case (VfsStat() | int() as flags), int(filesize):
if size:
if size and flags:
# size is allowed to be null!
size[0] = filesize

Expand Down Expand Up @@ -442,24 +443,28 @@ def __mkdir(self, path: bytes) -> int:
# TODO: Log an error here
return VfsMkdirResult.ERROR

def __opendir(self, path: bytes, include_hidden: bool) -> POINTER(retro_vfs_dir_handle) | None:
def __opendir(self, path: bytes, include_hidden: bool) -> c_void_p | None:
if not path:
return None

assert isinstance(path, bytes)
assert isinstance(include_hidden, bool)

dir = self.opendir(path, include_hidden)
if not dir:
return None
try:
dir = self.opendir(path, include_hidden)
if not dir:
return None

if not isinstance(dir, DirectoryHandle):
raise TypeError(f"Expected opendir to return a DirectoryHandle, got: {type(dir).__name__}")
if not isinstance(dir, DirectoryHandle):
raise TypeError(f"Expected opendir to return a DirectoryHandle, got: {type(dir).__name__}")
except:
# TODO: Log the exception
return None

address = id(dir)
self.__dir_handles[address] = dir

return POINTER(retro_vfs_dir_handle).from_address(address)
return address

def __readdir(self, dir: POINTER(retro_vfs_dir_handle)) -> bool:
if not dir:
Expand Down
1 change: 0 additions & 1 deletion src/libretro/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,6 @@ def default_session(
case _:
raise TypeError(f"Expected vfs to be a FileSystemInterface or None, not {type(vfs).__name__}")

logger = logging.getLogger('libretro')
return Session(
core=core,
audio=audio or ArrayAudioState(),
Expand Down

0 comments on commit f290239

Please sign in to comment.