package vfs import "core:c" import sce "../common" import sceKernel "../Kernel" import sceIo "../Io" SceVfsType :: enum sce.UInt32 { FS = 0x00000000, DEVFS = 0x00000010, } SceVfsInfo :: struct { vfs_ops: ^SceVfsOpTable, vfs_name: cstring, vfs_name_len: sce.Size, ref_count : sce.UInt32, type: SceVfsType, default_vops: ^SceVopTable, vfs_data: rawptr, next: ^SceVfsInfo, } #assert(size_of(SceVfsInfo) == 0x20) SceVfsPath :: struct { name: cstring, name_length: sce.Size, path: cstring, } #assert(size_of(SceVfsPath) == 0xC) SceVfsMountData :: struct { assign_name: cstring, fs_name: cstring, blockdev_name: cstring, blockdev_name_no_part: cstring, mnt_id: sce.UInt32, } #assert(size_of(SceVfsMountData) == 0x14) SceVfsFsType :: enum sce.UInt8 { FS = 0x01, PFS = 0x03, HOSTFS = 0x04, BLKDEV = 0x10, CHRDEV = 0x20, } SceVfsMountType :: enum { PFS = 0x00000001, FSROOT = 0x00000002, DEVFS = 0x00000003, STACKFS = 0x00000005, HOSTFS = 0x00000006, } SCE_VFS_MOUNT_FLAG_TYPE_MASK :: 0x00000006 SCE_VFS_MOUNT_FLAG_RDONLY :: 0x00001000 SCE_VFS_MOUNT_FLAG_NOBUF :: 0x00002000 SCE_VFS_MOUNT_FLAG_NUMBERED :: 0x00004000 SCE_VFS_MOUNT_FLAG_REMOTE :: 0x00008000 SCE_VFS_MOUNT_FLAG_INTERNAL :: 0x00010000 SCE_VFS_MOUNT_FLAG_EXTERNAL :: 0x00020000 SCE_VFS_MOUNT_FLAG_WRITE_CACHE :: 0x00040000 SCE_VFS_MOUNT_FLAG_NO_RECLAIM :: 0x00100000 // Opaque FdLock :: struct{} Fumount :: struct{} BuffCache :: struct{} Flock :: struct{} DebugPath :: struct{} Ncache :: struct{} SceVfsMount :: struct { fast_mutex: sceKernel.SceKernelFastMutex, mnt_vnode: ^SceVfsVnode, allocator: sce.UID, state: sce.UInt32, fs_type: SceVfsFsType, //!< One of SCE_VFS_FS_TYPE_* opt: sce.UInt16, mnt_flags: sce.UInt32, //!< ORed together SCE_VFS_MOUNT_FLAG_* flags vnode_list: ^SceVfsVnode, vnode_num: sce.UInt32, mnt_vfs_inf: ^SceVfsInfo, mnt_ref_count: sce.UInt32, opened_entry_num: sce.UInt32, available_entry_num: sce.UInt32, pid: sce.UID, mnted_on_list: ^SceVfsMount, mnted_on_list_prev: ^SceVfsMount, mnt_list_next: ^SceVfsMount, mnt_data: ^SceVfsMountData, path: [64]byte, default_io_cache_size: sce.UInt32, data: rawptr, //!< VFS Implementation defined mount point data. fd_lock: ^FdLock, fumount: ^Fumount, opaque: [4]sce.UInt32, // Backing storage for pFdLock opaque2: [4]sce.UInt32, // Backing storage for pFumount padding: [16]sce.UInt8, } #assert(size_of(SceVfsMount) == 0x100) SCE_VNODE_TYPE_REG :: (0x00000001) //!< Regular file SCE_VNODE_TYPE_DIR :: (0x00000002) //!< Regular directory SCE_VNODE_TYPE_CHR :: (0x00000010) //!< Character file SCE_VNODE_TYPE_ROOT :: (0x00001000) //!< Root vnode SCE_VNODE_TYPE_DEV :: (0x00002000) //!< Device vnode SCE_VNODE_TYPE_MOUNTED :: (0x00004000) //!< Vnode used as a backing for a mountpoint SCE_VNODE_TYPE_CHRDEV :: (SCE_VNODE_TYPE_DEV | SCE_VNODE_TYPE_CHR) SCE_VNODE_TYPE_ROOTDIR :: (SCE_VNODE_TYPE_ROOT | SCE_VNODE_TYPE_DIR) //!< Root directory SCE_VNODE_TYPE_ROOTDIR_DEVFS :: (0x10000 | 0x20) //!< Root directory on devfs mountpoints SCE_VNODE_STATE_ACTIVE :: (0x00000001) //!< Vnode is active and valid for all operations SCE_VNODE_STATE_INACTIVE :: (0x00000100) //!< Vnode is inactive and may be pending deletion or otherwise. SCE_VNODE_STATE_UNMOUNTED :: (0x00000200) SCE_VNODE_STATE_DELETED :: (0x00000400) SCE_VNODE_STATE_RECLAIMED :: (0x00002000) SCE_VNODE_STATE_NEW :: (0x00008000) SceVfsVnode :: struct { vdlock: struct { waiter: sce.UInt32, owner_id: sce.UID, recursive_count: sce.UInt32, wait_id: sce.UID, wait_pattern: sce.UInt32, }, padding: [44]sce.UInt8, core: struct { ops: ^SceVopTable, node_inf: sce.UInt32, //!< Field for private VFS vnode info node_data: rawptr, //!< Pointer for private VFS data mnt: ^SceVfsMount, dd: ^SceVfsVnode, //!< Parent vnode next: ^SceVfsVnode, ref_count: sce.UInt32, bc: ^BuffCache, fid: [2]sce.UInt32, flock: ^Flock, allocator: sce.UID, ncache: ^Ncache, state: sce.UInt32, //!< One of SCE_VNODE_STATE_* type: sce.UInt32, //!< ORed together SCE_VNODE_TYPE_* flags vop_tbl: ^SceVopTable, //!< Internal use only size: sce.UInt64, acl_data: [2]sce.UInt32, //!< Typically holds st_attr in acl_data[0] fd_list: ^SceVfsFile, fd_num: sce.UInt32, link_to: ^SceVfsVnode, linked_num: sce.UInt32, unused: [48]sce.UInt8, mnt_opt: sce.UInt32, unk_0xd4: sce.UInt32, }, padding2: [40]sce.UInt8, } #assert(size_of(SceVfsVnode) == 0x100) SCE_VFS_FILE_STATE_OPEN :: (0x00000001) //!< File is open SCE_VFS_FILE_STATE_CLOSED :: (0x00000200) //!< File is closed SCE_VFS_FILE_STATE_UNK :: (0x00000800) //!< Unknown status SCE_VFS_FILE_STATE_DUMMY :: (0x00010000) //!< Dummy file /** * VFS File * * The file structure is contained within the SceUIDVfsFileObject structure, and represents file handles in the VFS. */ SceVfsFile :: struct { is_dir: sce.UInt32, flags: sce.UInt32, position: sce.Off, state: sce.UInt32, pid: sce.UID, vp: ^SceVfsVnode, next: ^SceVfsFile, fd: sce.UInt32, //!< File descriptor provided and used by VFS implementation flock_busy_count: sce.UInt16, is_locked: sce.UInt8, has_flock_ent: sce.UInt8, fd_lock: ^FdLock, idata: sce.UInt32, debug_path: ^DebugPath, ioSchedData: [3]sce.UInt32, } #assert(size_of(SceVfsFile) == 0x40) /** * @name VFS Operation Arguments and Callback Table */ /** @{ */ SceVfsOpMountArgs :: struct { mnt: ^SceVfsMount, dev_file_path: ^SceVfsPath, //!< Path to the device file. } #assert(size_of(SceVfsOpMountArgs) == 0x8) SceVfsOpUmountArgs :: struct { mnt: ^SceVfsMount, flags: c.int, } #assert(size_of(SceVfsOpUmountArgs) == 0x8) SceVfsOpSetRootArgs :: struct { mnt: ^SceVfsMount, unk: c.int, vp: ^SceVfsVnode, } #assert(size_of(SceVfsOpSetRootArgs) == 0xC) SceVfsOpGetRootArgs :: struct { mnt: ^SceVfsMount, unk: c.int, vpp: ^^SceVfsVnode, } #assert(size_of(SceVfsOpGetRootArgs) == 0xC) SceVfsOpSyncArgs :: struct { mnt: ^SceVfsMount, flags: c.int, } #assert(size_of(SceVfsOpSyncArgs) == 0x8) SceVfsOpInitArgs :: struct { vfs_inf: ^SceVfsInfo, } #assert(size_of(SceVfsOpInitArgs) == 0x4) SceVfsOpFiniArgs :: struct { vfs_inf: ^SceVfsInfo, } #assert(size_of(SceVfsOpFiniArgs) == 0x4) SceVfsOpDevctlArg :: struct { mnt: ^SceVfsMount, dev: cstring, cmd: c.uint, arg: rawptr, arg_len: sce.Size, buf: rawptr, buf_len: sce.Size, } #assert(size_of(SceVfsOpDevctlArg) == 0x1C) SceVfsOpDecodePathElemArgs :: struct { mnt: ^SceVfsMount, path: cstring, path2: ^cstring, // path + something path3: ^cstring, // path3 + *decodeLen buf: [^]byte, buf_len: sce.Size, decode_len: ^sce.Size, // out } #assert(size_of(SceVfsOpDecodePathElemArgs) == 0x1C) SceVfsOpTable :: struct { vfs_mount: #type proc "c" (argp: ^SceVfsOpMountArgs) -> c.int, vfs_umount: #type proc "c" (argp: ^SceVfsOpUmountArgs) -> c.int, vfs_set_root: #type proc "c" (argp: ^SceVfsOpSetRootArgs) -> c.int, vfs_get_root: #type proc "c" (argp: ^SceVfsOpGetRootArgs) -> c.int, reserved: [2]rawptr, // Unused vfs_sync: #type proc "c" (argp: ^SceVfsOpSyncArgs) -> c.int, reserved2: rawptr, // Unused vfs_init: #type proc "c" (argp: ^SceVfsOpInitArgs) -> c.int, vfs_fini: #type proc "c" (argp: ^SceVfsOpFiniArgs) -> c.int, reserved3: rawptr, // Unused vfs_devctl: #type proc "c" (arg: ^SceVfsOpDevctlArg) -> c.int, vfs_decode_path_elem: #type proc "c" (argp: ^SceVfsOpDecodePathElemArgs) -> c.int, } #assert(size_of(SceVfsOpTable) == 0x34) /** @} */ /** * @name VFS Vnode Operation Arguments and Callback Table */ /** @{ */ SceVopOpenArgs :: struct { vp: ^SceVfsVnode, path: ^SceVfsPath, flags: c.int, file: ^SceVfsFile, } #assert(size_of(SceVopOpenArgs) == 0x10) SceVopCreateArgs :: struct { dvp: ^SceVfsVnode, vpp: ^^SceVfsVnode, path: ^SceVfsPath, flags: c.int, mode: c.int, } #assert(size_of(SceVopCreateArgs) == 0x14) SceVopCloseArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, } #assert(size_of(SceVopCloseArgs) == 0x8) SceVopLookupArgs :: struct { dvp: ^SceVfsVnode, vpp: ^^SceVfsVnode, path: ^SceVfsPath, flags: sce.UInt32, } #assert(size_of(SceVopLookupArgs) == 0x10) SceVopReadArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, buf: rawptr, nbyte: sce.Size, } #assert(size_of(SceVopReadArgs) == 0x10) SceVopWriteArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, buf: rawptr, nbyte: sce.Size, } #assert(size_of(SceVopWriteArgs) == 0x10) SceVopLseekArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, offset: sce.Off, whence: c.int, } #assert(size_of(SceVopLseekArgs) == 0x18) SceVopIoctlArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, cmd: c.int, in_data: rawptr, in_len: sce.Size, out_data: rawptr, out_len: sce.Size, } #assert(size_of(SceVopIoctlArgs) == 0x1C) SceVopRemoveArgs :: struct { dvp: ^SceVfsVnode, vp: ^SceVfsVnode, path: ^SceVfsPath, flags: sce.UInt32, } #assert(size_of(SceVopRemoveArgs) == 0x10) SceVopMkdirArgs :: struct { dvp: ^SceVfsVnode, vpp: ^^SceVfsVnode, path: ^SceVfsPath, mode: c.int, } #assert(size_of(SceVopMkdirArgs) == 0x10) SceVopRmdirArgs :: struct { dvp: ^SceVfsVnode, vp: ^SceVfsVnode, path: ^SceVfsPath, } #assert(size_of(SceVopRmdirArgs) == 0xC) SceVopDopenArgs :: struct { vp: ^SceVfsVnode, path: ^SceVfsPath, file: ^SceVfsFile, } #assert(size_of(SceVopDopenArgs) == 0xC) SceVopDcloseArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, } #assert(size_of(SceVopDcloseArgs) == 0x8) SceVopDreadArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, dir: ^sceIo.SceIoDirent, } #assert(size_of(SceVopDreadArgs) == 0xC) SceVopGetstatArgs :: struct { vp: ^SceVfsVnode, path: ^SceVfsPath, stat: ^sceIo.SceIoStat, } #assert(size_of(SceVopGetstatArgs) == 0xC) SceVopChstatArgs :: struct { vp: ^SceVfsVnode, path: ^SceVfsPath, stat: ^sceIo.SceIoStat, bit: c.int, } #assert(size_of(SceVopChstatArgs) == 0x10) SceVopFchstatArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, stat: ^sceIo.SceIoStat, bit: sce.UInt32, } #assert(size_of(SceVopFchstatArgs) == 0x10) SceVopFgetstatArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, stat: ^sceIo.SceIoStat, } #assert(size_of(SceVopFgetstatArgs) == 0xC) SceVopInactiveArgs :: struct { vp: ^SceVfsVnode, } #assert(size_of(SceVopInactiveArgs) == 0x4) SceVopLinkArgs :: struct { fvp: ^SceVfsVnode, tvp: ^SceVfsVnode, } #assert(size_of(SceVopLinkArgs) == 0x8) SceVopUnlinkArgs :: struct { fvp: ^SceVfsVnode, tvp: ^SceVfsVnode, } #assert(size_of(SceVopUnlinkArgs) == 0x8) SceVopSyncArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, flags: c.int, } #assert(size_of(SceVopSyncArgs) == 0xC) SceVopRenameArgs :: struct { odvp: ^SceVfsVnode, ovp: ^SceVfsVnode, old_path: ^SceVfsPath, ndvp: ^SceVfsVnode, nvpp: ^^SceVfsVnode, new_path: ^SceVfsPath, } #assert(size_of(SceVopRenameArgs) == 0x18) SceVopPreadArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, buf: rawptr, nbyte: sce.Size, offset: sce.Off, } #assert(size_of(SceVopPreadArgs) == 0x18) SceVopPwriteArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, buf: rawptr, nbyte: sce.Size, offset: sce.Off, } #assert(size_of(SceVopPwriteArgs) == 0x18) SceVopWhiteoutArgs :: struct { dvp: ^SceVfsVnode, vp: ^SceVfsVnode, old_path: ^SceVfsPath, new_path: ^SceVfsPath, } #assert(size_of(SceVopWhiteoutArgs) == 0x10) SceVopCleanupArgs :: struct { vp: ^SceVfsVnode, file: ^SceVfsFile, } #assert(size_of(SceVopCleanupArgs) == 0x8) SceVopZerofillArgs :: struct { vp: ^SceVfsVnode, unk: sce.UInt64, unk1: sce.UInt64, unk2: sce.UInt64, } #assert(size_of(SceVopZerofillArgs) == 0x20) SceVopTable :: struct { vop_open: #type proc "c" (argp: ^SceVopOpenArgs) -> c.int, vop_create: #type proc "c" (argp: ^SceVopCreateArgs) -> c.int, vop_close: #type proc "c" (argp: ^SceVopCloseArgs) -> c.int, vop_lookup: #type proc "c" (argp: ^SceVopLookupArgs) -> c.int, vop_read: #type proc "c" (argp: ^SceVopReadArgs) -> sce.SSize, vop_write: #type proc "c" (argp: ^SceVopWriteArgs) -> sce.SSize, vop_lseek: #type proc "c" (argp: ^SceVopLseekArgs) -> sce.Off, vop_ioctl: #type proc "c" (argp: ^SceVopIoctlArgs) -> c.int, vop_remove: #type proc "c" (argp: ^SceVopRemoveArgs) -> c.int, vop_mkdir: #type proc "c" (argp: ^SceVopMkdirArgs) -> c.int, vop_rmdir: #type proc "c" (argp: ^SceVopRmdirArgs) -> c.int, vop_dopen: #type proc "c" (argp: ^SceVopDopenArgs) -> c.int, vop_dclose: #type proc "c" (argp: ^SceVopDcloseArgs) -> c.int, vop_dread: #type proc "c" (argp: ^SceVopDreadArgs) -> c.int, vop_getstat: #type proc "c" (argp: ^SceVopGetstatArgs) -> c.int, vop_chstat: #type proc "c" (argp: ^SceVopChstatArgs) -> c.int, vop_rename: #type proc "c" (argp: ^SceVopRenameArgs) -> c.int, reserved: rawptr, // Unused vop_pread: #type proc "c" (argp: ^SceVopPreadArgs) -> sce.SSize, vop_pwrite: #type proc "c" (argp: ^SceVopPwriteArgs) -> sce.SSize, vop_inactive: #type proc "c" (argp: ^SceVopInactiveArgs) -> c.int, vop_link: #type proc "c" (argp: ^SceVopLinkArgs) -> c.int, vop_unlink: #type proc "c" (argp: ^SceVopUnlinkArgs) -> c.int, vop_sync: #type proc "c" (argp: ^SceVopSyncArgs) -> c.int, vop_fgetstat: #type proc "c" (argp: ^SceVopFgetstatArgs) -> c.int, vop_fchstat: #type proc "c" (argp: ^SceVopFchstatArgs) -> c.int, vop_whiteout: #type proc "c" (argp: ^SceVopWhiteoutArgs) -> c.int, vop_cleanup: #type proc "c" (argp: ^SceVopCleanupArgs) -> c.int, vop_verofill: #type proc "c" (argp: ^SceVopZerofillArgs) -> c.int, } #assert(size_of(SceVopTable) == 0x74) /** @} */ /** * @name VFS Core API */ /** @{ */ /** * Parameters for vfsMount and vfsMountForPFS */ SceVfsMountParam :: struct { root_path: cstring, //!< This is the internal root path of the mountpoint. (example: /ux/exfat for ux0:) blockdev_name: cstring, //!< Overrides blockdevName in misc->blockdevName fs_type: sce.UInt8, //!< One of SCE_VFS_FS_TYPE_* opt: sce.UInt16, //!< Used to identify the IO Scheduler queue to use for the mountpoint mnt_flags: sce.UInt32, //!< ORed together SCE_VFS_MOUNT_FLAG_* flags vfs_name: cstring, //!< Name of the VFS to use for the mountpoint data: rawptr, //!< To be passed to the created mountpoint misc: ^SceVfsMountData, vops: ^SceVopTable, //!< Overrides defaultVops in the VFS Info for the root vnode of the VFS } #assert(size_of(SceVfsMountParam) == 0x20) SCE_VFS_UMOUNT_FLAG_FORCE :: (0x1) //!< Force unmount /** * Parameters for vfsUmount and vfsUmountForPFS */ SceVfsUmountParam :: struct { assign_name: cstring, //!< Assigned name of the mountpoint to unmount flag: c.int, //!< One of SCE_VFS_UMOUNT_FLAG_* } #assert(size_of(SceVfsUmountParam) == 8)