From d5c39263d843af66eebd7f355b57a918bdc26292 Mon Sep 17 00:00:00 2001 From: mtheall Date: Thu, 21 Aug 2014 21:47:25 -0500 Subject: [PATCH] Add more filesystem service commands. --- libctru/include/3ds/FS.h | 183 +++++- libctru/source/services/fs.c | 1194 ++++++++++++++++++++++++++++------ 2 files changed, 1144 insertions(+), 233 deletions(-) diff --git a/libctru/include/3ds/FS.h b/libctru/include/3ds/FS.h index 8fcef07..b3e2a6a 100644 --- a/libctru/include/3ds/FS.h +++ b/libctru/include/3ds/FS.h @@ -1,39 +1,146 @@ +#pragma once #ifndef FS_H #define FS_H -#define FS_OPEN_READ (1<<0) -#define FS_OPEN_WRITE (1<<1) -#define FS_OPEN_CREATE (1<<2) +/*! @file FS.h + * + * Filesystem Services + */ -#define FS_ATTRIBUTE_NONE (0x00000000) -#define FS_ATTRIBUTE_READONLY (0x00000001) -#define FS_ATTRIBUTE_ARCHIVE (0x00000100) -#define FS_ATTRIBUTE_HIDDEN (0x00010000) -#define FS_ATTRIBUTE_DIRECTORY (0x01000000) +#include +#include <3ds/types.h> -typedef enum{ - PATH_INVALID = 0, // Specifies an invalid path. - PATH_EMPTY = 1, // Specifies an empty path. - PATH_BINARY = 2, // Specifies a binary path, which is non-text based. - PATH_CHAR = 3, // Specifies a text based path with a 8-bit byte per character. - PATH_WCHAR = 4, // Specifies a text based path with a 16-bit short per character. -}FS_pathType; - -typedef struct{ - FS_pathType type; - u32 size; - u8* data; -}FS_path; - -typedef struct{ - u32 id; - FS_path lowPath; - Handle handleLow, handleHigh; -}FS_archive; - -static inline FS_path FS_makePath(FS_pathType type, char* path) +#ifdef __cplusplus +extern "C" { - return (FS_path){type, strlen(path)+1, (u8*)path}; +#endif + +/*! @defgroup fs_open_flags FS Open Flags + * + * @sa FSUSER_OpenFile + * @sa FSUSER_OpenFileDirectly + * + * @{ + */ + +/*! Open file for read. */ +#define FS_OPEN_READ (1<<0) +/*! Open file for write. */ +#define FS_OPEN_WRITE (1<<1) +/*! Create file if it doesn't exist. */ +#define FS_OPEN_CREATE (1<<2) +/* @} */ + +/*! @defgroup fs_create_attributes FS Create Attributes + * + * @sa FSUSER_OpenFile + * @sa FSUSER_OpenFileDirectly + * + * @{ + */ + +/*! No attributes. */ +#define FS_ATTRIBUTE_NONE (0x00000000) +/*! Create with read-only attribute. */ +#define FS_ATTRIBUTE_READONLY (0x00000001) +/*! Create with archive attribute. */ +#define FS_ATTRIBUTE_ARCHIVE (0x00000100) +/*! Create with hidden attribute. */ +#define FS_ATTRIBUTE_HIDDEN (0x00010000) +/*! Create with directory attribute. */ +#define FS_ATTRIBUTE_DIRECTORY (0x01000000) +/*! @} */ + +/*! @defgroup fs_write_flush_flags FS Flush Flags + * + * @sa FSFILE_Write + * + * @{ + */ + +/*! Don't flush */ +#define FS_WRITE_NOFLUSH (0x00000000) +/*! Flush */ +#define FS_WRITE_FLUSH (0x00010001) + +/* @} */ + +/*! FS path type */ +typedef enum +{ + PATH_INVALID = 0, //!< Specifies an invalid path. + PATH_EMPTY = 1, //!< Specifies an empty path. + PATH_BINARY = 2, //!< Specifies a binary path, which is non-text based. + PATH_CHAR = 3, //!< Specifies a text based path with a 8-bit byte per character. + PATH_WCHAR = 4, //!< Specifies a text based path with a 16-bit short per character. +} FS_pathType; + +/*! FS path */ +typedef struct +{ + FS_pathType type; //!< FS path type. + u32 size; //!< FS path size. + const u8 *data; //!< Pointer to FS path data. +} FS_path; + +/*! FS archive */ +typedef struct +{ + u32 id; //!< Archive ID. + FS_path lowPath; //!< FS path. + Handle handleLow; //!< High word of handle. + Handle handleHigh; //!< Low word of handle. +} FS_archive; + +/*! Directory entry */ +typedef struct +{ + // 0x00 + u16 name[0x106]; //!< UTF-16 encoded name + // 0x20C + u8 shortName[0x09]; //!< 8.3 file name + // 0x215 + u8 unknown1; //!< ??? + // 0x216 + u8 shortExt[0x04]; //!< 8.3 file extension (set to spaces for directories) + // 0x21A + u8 unknown2; //!< ??? + // 0x21B + u8 unknown3; //!< ??? + // 0x21C + u8 isDirectory; //!< 0x00 for files, 0x01 for directories + // 0x21D + u8 unknown4; //!< ??? + // 0x21E + u8 isFile; //!< 0x01 for files, 0x00 for directories + // 0x21F + u8 unknown5; //!< ??? + // 0x220 + u8 unknown6; //!< ??? + // 0x221 + u8 unknown7; //!< ??? + // 0x222 + u8 unknown8; //!< ??? + // 0x223 + u8 unknown9; //!< ??? + // 0x224 + u8 padding[0x04]; //!< ??? +} FS_dirent; + +/*! Create an FS_path from a type and data pointer. + * + * @param[in] type Path type. + * @param[in] path Pointer to path data. + * + * @returns FS_path + * + * @sa FS_pathType + */ +static inline FS_path +FS_makePath(FS_pathType type, + const char *path) +{ + return (FS_path){type, strlen(path)+1, (const u8*)path}; } Result fsInit(void); @@ -45,14 +152,24 @@ Result FSUSER_OpenDirectory(Handle* handle, Handle* out, FS_archive archive, FS_ Result FSUSER_OpenFile(Handle* handle, Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes); Result FSUSER_OpenFileDirectly(Handle* handle, Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes); Result FSUSER_CloseArchive(Handle* handle, FS_archive* archive); +Result FSUSER_CreateDirectory(Handle* handle, FS_archive archive, FS_path dirLowPath); +Result FSUSER_DeleteFile(Handle *handle, FS_archive archive, FS_path fileLowPath); +Result FSUSER_DeleteDirectory(Handle *handle, FS_archive archive, FS_path dirLowPath); Result FSFILE_Close(Handle handle); -Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, u32 *buffer, u32 size); -Result FSFILE_Write(Handle handle, u32 *bytesWritten, u64 offset, u32 *buffer, u32 size, u32 flushFlags); +Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, void *buffer, u32 size); +Result FSFILE_Write(Handle handle, u32 *bytesWritten, u64 offset, const void *buffer, u32 size, u32 flushFlags); Result FSFILE_GetSize(Handle handle, u64 *size); Result FSFILE_SetSize(Handle handle, u64 size); +Result FSFILE_GetAttributes(Handle handle, u32 *attributes); +Result FSFILE_SetAttributes(Handle handle, u32 attributes); +Result FSFILE_Flush(Handle handle); -Result FSDIR_Read(Handle handle, u32 *entriesRead, u32 entrycount, u16 *buffer); +Result FSDIR_Read(Handle handle, u32 *entriesRead, u32 entrycount, FS_dirent *buffer); Result FSDIR_Close(Handle handle); +#ifdef __cplusplus +} +#endif + #endif diff --git a/libctru/source/services/fs.c b/libctru/source/services/fs.c index 08e3719..566cc43 100644 --- a/libctru/source/services/fs.c +++ b/libctru/source/services/fs.c @@ -4,248 +4,1042 @@ #include <3ds/srv.h> #include <3ds/svc.h> -Handle fsuHandle; +/*! @internal + * + * @file fs.c + * + * Filesystem Services + */ -Result fsInit(void) +/*! FSUSER handle */ +static Handle fsuHandle; + +/*! Initialize FS service + * + * @returns error + */ +Result +fsInit(void) { return srvGetServiceHandle(&fsuHandle, "fs:USER"); } -Result fsExit(void) +/*! Deinitialize FS service + * + * @returns error + */ +Result +fsExit(void) { return svcCloseHandle(fsuHandle); } -Result FSUSER_Initialize(Handle* handle) +/*! Initialize FS service handle + * + * If @a handle is NULL, this initializes @ref fsuHandle. + * + * @param[in] handle fs:USER service handle + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08010002] + * 1 | 0x20 (ProcessID header) + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSUSER_Initialize(Handle* handle) { - if(!handle)handle=&fsuHandle; - u32* cmdbuf=getThreadCommandBuffer(); - cmdbuf[0]=0x08010002; //request header code - cmdbuf[1]=32; - - Result ret=0; - if((ret=svcSendSyncRequest(*handle)))return ret; - - return cmdbuf[1]; -} + if(!handle) + handle = &fsuHandle; -Result FSUSER_OpenFile(Handle* handle, Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes) //archive needs to have been opened -{ - if(!handle)handle=&fsuHandle; - u32* cmdbuf=getThreadCommandBuffer(); + u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0]=0x080201C2; - cmdbuf[1]=0; - cmdbuf[2]=archive.handleLow; - cmdbuf[3]=archive.handleHigh; - cmdbuf[4]=fileLowPath.type; - cmdbuf[5]=fileLowPath.size; - cmdbuf[6]=openflags; - cmdbuf[7]=attributes; - cmdbuf[8]=(fileLowPath.size<<14)|2; - cmdbuf[9]=(u32)fileLowPath.data; - - Result ret=0; - if((ret=svcSendSyncRequest(*handle)))return ret; - - if(out)*out=cmdbuf[3]; - - return cmdbuf[1]; -} + cmdbuf[0] = 0x08010002; + cmdbuf[1] = 0x20; -Result FSUSER_OpenFileDirectly(Handle* handle, Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes) //no need to have archive opened -{ - if(!handle)handle=&fsuHandle; - u32* cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x08030204; - cmdbuf[1]=0; - cmdbuf[2]=archive.id; - cmdbuf[3]=archive.lowPath.type; - cmdbuf[4]=archive.lowPath.size; - cmdbuf[5]=fileLowPath.type; - cmdbuf[6]=fileLowPath.size; - cmdbuf[7]=openflags; - cmdbuf[8]=attributes; - cmdbuf[9]=(archive.lowPath.size<<14)|0x802; - cmdbuf[10]=(u32)archive.lowPath.data; - cmdbuf[11]=(fileLowPath.size<<14)|2; - cmdbuf[12]=(u32)fileLowPath.data; - - Result ret=0; - if((ret=svcSendSyncRequest(*handle)))return ret; - - if(out)*out=cmdbuf[3]; - - return cmdbuf[1]; -} - -Result FSUSER_OpenArchive(Handle* handle, FS_archive* archive) -{ - if(!archive)return -2; - if(!handle)handle=&fsuHandle; - u32* cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x080C00C2; - cmdbuf[1]=archive->id; - cmdbuf[2]=archive->lowPath.type; - cmdbuf[3]=archive->lowPath.size; - cmdbuf[4]=(archive->lowPath.size<<14)|0x2; - cmdbuf[5]=(u32)archive->lowPath.data; - - Result ret=0; - if((ret=svcSendSyncRequest(*handle)))return ret; - - archive->handleLow=cmdbuf[2]; - archive->handleHigh=cmdbuf[3]; - - return cmdbuf[1]; -} - -Result FSUSER_OpenDirectory(Handle* handle, Handle* out, FS_archive archive, FS_path dirLowPath) -{ - if(!handle)handle=&fsuHandle; - u32* cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x080B0102; - cmdbuf[1]=archive.handleLow; - cmdbuf[2]=archive.handleHigh; - cmdbuf[3]=dirLowPath.type; - cmdbuf[4]=dirLowPath.size; - cmdbuf[5]=(dirLowPath.size<<14)|0x2; - cmdbuf[6]=(u32)dirLowPath.data; - - Result ret=0; - if((ret=svcSendSyncRequest(*handle)))return ret; - - if(out)*out=cmdbuf[3]; - - return cmdbuf[1]; -} - -Result FSUSER_CloseArchive(Handle* handle, FS_archive* archive) -{ - if(!archive)return -2; - if(!handle)handle=&fsuHandle; - u32* cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x080E0080; - cmdbuf[1]=archive->handleLow; - cmdbuf[2]=archive->handleLow; - - Result ret=0; - if((ret=svcSendSyncRequest(*handle)))return ret; - - return cmdbuf[1]; -} - -Result FSFILE_Close(Handle handle) -{ - u32* cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x08080000; - - Result ret=0; - if((ret=svcSendSyncRequest(handle)))return ret; + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; return cmdbuf[1]; } -Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, u32 *buffer, u32 size) +/*! Open a file + * + * @param[in] handle fs:USER handle + * @param[out] out Output handle + * @param[in] archive Open archive + * @param[in] fileLowPath File path + * @param[in] openFlags Open flags + * @param[in] attributes Create attributes + * + * @note This requires @a archive to have been opened + * + * @returns error + * + * @sa fs_open_flags + * @sa fs_create_attributes + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x080201C2] + * 1 | Transaction (usually 0) + * 2 | archive.handleLow + * 3 | archive.handleHigh + * 4 | fileLowPath.type + * 5 | fileLowPath.size + * 6 | openFlags + * 7 | attributes + * 8 | (fileLowPath.size << 14) \| 0x2 + * 9 | fileLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | ??? + * 3 | File handle + */ +Result +FSUSER_OpenFile(Handle *handle, + Handle *out, + FS_archive archive, + FS_path fileLowPath, + u32 openFlags, + u32 attributes) { - u32 *cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x080200C2; - cmdbuf[1]=(u32)offset; - cmdbuf[2]=(u32)(offset>>32); - cmdbuf[3]=size; - cmdbuf[4]=(size<<4)|12; - cmdbuf[5]=(u32)buffer; - - Result ret=0; - if((ret=svcSendSyncRequest(handle)))return ret; + if(!handle) + handle = &fsuHandle; - if(bytesRead)*bytesRead=cmdbuf[2]; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x080201C2; + cmdbuf[1] = 0; + cmdbuf[2] = archive.handleLow; + cmdbuf[3] = archive.handleHigh; + cmdbuf[4] = fileLowPath.type; + cmdbuf[5] = fileLowPath.size; + cmdbuf[6] = openFlags; + cmdbuf[7] = attributes; + cmdbuf[8] = (fileLowPath.size << 14) | 0x2; + cmdbuf[9] = (u32)fileLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + if(out) + *out = cmdbuf[3]; return cmdbuf[1]; } -//WARNING : using wrong flushFlags CAN corrupt the archive you're writing to. -//another warning : data should *not* be in RO memory -Result FSFILE_Write(Handle handle, u32 *bytesWritten, u64 offset, u32 *data, u32 size, u32 flushFlags) +/*! Open a file + * + * @param[in] handle fs:USER handle + * @param[out] out Output handle + * @param[in] archive Open archive + * @param[in] fileLowPath File path + * @param[in] openFlags Open flags + * @param[in] attributes Create attributes + * + * @note This does not require @a archive to have been opened + * + * @returns error + * + * @sa fs_open_flags + * @sa fs_create_attributes + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08030204] + * 1 | Transaction (usually 0) + * 2 | archive.id + * 3 | archive.lowPath.type + * 4 | archive.lowPath.Size + * 5 | fileLowPath.type + * 6 | fileLowPath.size + * 7 | openFlags + * 8 | attributes + * 9 | (archive.lowPath.size << 14 \| 0x802 + * 10 | archive.lowPath.data + * 11 | (fileLowPath.size << 14) \| 0x2 + * 12 | fileLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | ??? + * 3 | File handle + */ +Result +FSUSER_OpenFileDirectly(Handle *handle, + Handle *out, + FS_archive archive, + FS_path fileLowPath, + u32 openFlags, + u32 attributes) { - u32 *cmdbuf=getThreadCommandBuffer(); + if(!handle) + handle = &fsuHandle; - cmdbuf[0]=0x08030102; - cmdbuf[1]=(u32)offset; - cmdbuf[2]=(u32)(offset>>32); - cmdbuf[3]=size; - cmdbuf[4]=flushFlags; - cmdbuf[5]=(size<<4)|10; - cmdbuf[6]=(u32)data; + u32 *cmdbuf = getThreadCommandBuffer(); - Result ret=0; - if((ret=svcSendSyncRequest(handle)))return ret; + cmdbuf[ 0] = 0x08030204; + cmdbuf[ 1] = 0; + cmdbuf[ 2] = archive.id; + cmdbuf[ 3] = archive.lowPath.type; + cmdbuf[ 4] = archive.lowPath.size; + cmdbuf[ 5] = fileLowPath.type; + cmdbuf[ 6] = fileLowPath.size; + cmdbuf[ 7] = openFlags; + cmdbuf[ 8] = attributes; + cmdbuf[ 9] = (archive.lowPath.size << 14) | 0x802; + cmdbuf[10] = (u32)archive.lowPath.data; + cmdbuf[11] = (fileLowPath.size << 14) | 0x2; + cmdbuf[12] = (u32)fileLowPath.data; - if(bytesWritten)*bytesWritten=cmdbuf[2]; + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + if(out) + *out = cmdbuf[3]; return cmdbuf[1]; } -Result FSFILE_GetSize(Handle handle, u64 *size) +/*! Delete a file + * + * @param[in] handle fs:USER handle + * @param[in] archive Open archive + * @param[in] fileLowPath File path + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08040142] + * 1 | 0 + * 2 | archive.handleLow + * 3 | archive.handleHigh + * 4 | fileLowPath.type + * 5 | fileLowPath.size + * 6 | (fileLowPath.size << 14) \| 0x2 + * 7 | fileLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSUSER_DeleteFile(Handle *handle, + FS_archive archive, + FS_path fileLowPath) { - u32 *cmdbuf=getThreadCommandBuffer(); - + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08040142; + cmdbuf[1] = 0; + cmdbuf[2] = archive.handleLow; + cmdbuf[3] = archive.handleHigh; + cmdbuf[4] = fileLowPath.type; + cmdbuf[5] = fileLowPath.size; + cmdbuf[6] = (fileLowPath.size << 14) | 0x2; + cmdbuf[7] = (u32)fileLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + return cmdbuf[1]; +} + +/* stub */ +Result +FSUSER_RenameFile(void) +{ + return -1; +} + +/*! Delete a directory + * + * @param[in] handle fs:USER handle + * @param[in] archive Open archive + * @param[in] dirLowPath Directory path + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08060142] + * 1 | 0 + * 2 | archive.handleLow + * 3 | archive.handleHigh + * 4 | dirLowPath.type + * 5 | dirLowPath.size + * 6 | (dirLowPath.size << 14) \| 0x2 + * 7 | dirLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSUSER_DeleteDirectory(Handle *handle, + FS_archive archive, + FS_path dirLowPath) +{ + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08060142; + cmdbuf[1] = 0; + cmdbuf[2] = archive.handleLow; + cmdbuf[3] = archive.handleHigh; + cmdbuf[4] = dirLowPath.type; + cmdbuf[5] = dirLowPath.size; + cmdbuf[6] = (dirLowPath.size << 14) | 0x2; + cmdbuf[7] = (u32)dirLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + return cmdbuf[1]; +} + +/* stub */ +Result +FSUSER_DeleteDirectoryRecursively(void) +{ + return -1; +} + +/* stub */ +Result +FSUSER_CreateFile(void) +{ + return -1; +} + +/*! Create a directory + * + * @param[in] handle fs:USER handle + * @param[in] archive Open archive + * @param[in] dirLowPath Directory path to create + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08090182] + * 1 | 0 + * 2 | archive.handleLow + * 3 | archive.handleHigh + * 4 | dirLowPath.type + * 5 | dirLowPath.size + * 6 | 0 + * 7 | (dirLowPath.size << 14) \| 0x2 + * 8 | dirLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSUSER_CreateDirectory(Handle *handle, + FS_archive archive, + FS_path dirLowPath) +{ + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08090182; + cmdbuf[1] = 0; + cmdbuf[2] = archive.handleLow; + cmdbuf[3] = archive.handleHigh; + cmdbuf[4] = dirLowPath.type; + cmdbuf[5] = dirLowPath.size; + cmdbuf[6] = 0; + cmdbuf[7] = (dirLowPath.size << 14) | 0x2; + cmdbuf[8] = (u32)dirLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + return cmdbuf[1]; +} + +/* stub */ +Result +FSUSER_RenameDirectory(void) +{ + return -1; +} + +/*! Open a directory + * + * @param[in] handle fs:USER handle + * @param[out] out Output handle + * @param[in] archive Open archive + * @param[in] dirLowPath Directory path + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x080B0102] + * 1 | archive.handleLow + * 2 | archive.handleHigh + * 3 | dirLowPath.type + * 4 | dirLowPath.size + * 5 | (dirLowPath.size << 14) \| 0x2 + * 6 | dirLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | Directory handle + */ +Result +FSUSER_OpenDirectory(Handle *handle, + Handle *out, + FS_archive archive, + FS_path dirLowPath) +{ + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x080B0102; + cmdbuf[1] = archive.handleLow; + cmdbuf[2] = archive.handleHigh; + cmdbuf[3] = dirLowPath.type; + cmdbuf[4] = dirLowPath.size; + cmdbuf[5] = (dirLowPath.size << 14) | 0x2; + cmdbuf[6] = (u32)dirLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + if(out) + *out = cmdbuf[3]; + + return cmdbuf[1]; +} + +/*! Open an archive + * + * @param[in] handle fs:USER handle + * @param[in,out] archive Archive to open + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x080C00C2] + * 1 | archive->id + * 2 | archive->lowPath.type + * 3 | archive->lowPath.size + * 4 | (archive->lowPath.size << 14) \| 0x2 + * 5 | archive->lowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | archive->handleLow + * 3 | archive->handleHigh + */ +Result +FSUSER_OpenArchive(Handle *handle, + FS_archive *archive) +{ + if(!archive) + return -2; + + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x080C00C2; + cmdbuf[1] = archive->id; + cmdbuf[2] = archive->lowPath.type; + cmdbuf[3] = archive->lowPath.size; + cmdbuf[4] = (archive->lowPath.size << 14) | 0x2; + cmdbuf[5] = (u32)archive->lowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + archive->handleLow = cmdbuf[2]; + archive->handleHigh = cmdbuf[3]; + + return cmdbuf[1]; +} + + +/*! Close an open archive + * + * @param[in] handle fs:USER handle + * @param[in,out] archive Archive to close + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x080B0102] + * 1 | archive->handleLow + * 2 | archive->handleHigh + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSUSER_CloseArchive(Handle *handle, + FS_archive *archive) +{ + if(!archive) + return -2; + + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x080E0080; + cmdbuf[1] = archive->handleLow; + cmdbuf[2] = archive->handleHigh; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + return cmdbuf[1]; +} + +/*! Close an open file + * + * @param[in] handle Open file handle + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08080000] + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSFILE_Close(Handle handle) +{ + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08080000; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + return cmdbuf[1]; +} + +/*! Read data from an open file + * + * @param[in] handle Open file handle + * @param[out] bytesRead Number of bytes read + * @param[in] offset File offset to read from + * @param[out] buffer Buffer to read into + * @param[in] size Number of bytes to read + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x080200C2] + * 1 | offset (low word) + * 2 | offset (high word) + * 3 | size + * 4 | (size << 4) \| 0xC + * 5 | buffer + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | Number of bytes read + */ +Result +FSFILE_Read(Handle handle, + u32 *bytesRead, + u64 offset, + void *buffer, + u32 size) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x080200C2; + cmdbuf[1] = (u32)offset; + cmdbuf[2] = (u32)(offset >> 32); + cmdbuf[3] = size; + cmdbuf[4] = (size << 4) | 0xC; + cmdbuf[5] = (u32)buffer; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + if(bytesRead) + *bytesRead = cmdbuf[2]; + + return cmdbuf[1]; +} + +/*! Write data to an open file + * + * @param[in] handle Open file handle + * @param[out] bytesWritten Number of bytes read + * @param[in] offset File offset to write to + * @param[in] buffer Buffer to write from + * @param[in] size Number of bytes to write + * @param[in] flushFlags Flush flags + * + * @returns error + * + * @sa fs_write_flush_flags + * + * @warning + * Using invalid flushFlags can corrupt the archive you're writing to. + * + * @warning + * Data should not be in read-only memory. + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08030102] + * 1 | offset (low word) + * 2 | offset (high word) + * 3 | size + * 4 | flushFlags + * 5 | (size << 4) \| 0xA + * 6 | buffer + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | Number of bytes written + */ +Result +FSFILE_Write(Handle handle, + u32 *bytesWritten, + u64 offset, + const void *buffer, + u32 size, + u32 flushFlags) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08030102; + cmdbuf[1] = (u32)offset; + cmdbuf[2] = (u32)(offset >> 32); + cmdbuf[3] = size; + cmdbuf[4] = flushFlags; + cmdbuf[5] = (size << 4) | 0xA; + cmdbuf[6] = (u32)buffer; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + if(bytesWritten) + *bytesWritten = cmdbuf[2]; + + return cmdbuf[1]; +} + +/*! Get the size of an open file + * + * @param[in] handle Open file handle + * @param[out] size Output size + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08040000] + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | File size (lower word) + * 3 | File size (upper word) + */ +Result +FSFILE_GetSize(Handle handle, + u64 *size) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x08040000; - - Result ret=0; - if((ret=svcSendSyncRequest(handle)))return ret; - - if(size)*size = *((u64*)&cmdbuf[2]); - - return cmdbuf[1]; -} -Result FSFILE_SetSize(Handle handle, u64 size) -{ - u32 *cmdbuf = getThreadCommandBuffer(); + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; - cmdbuf[0] = 0x08050080; - cmdbuf[1] = (u32)size; - cmdbuf[2] = (u32)(size >> 32); - - Result ret = 0; - if ((ret = svcSendSyncRequest(handle)))return ret; - - - return cmdbuf[1]; -} - -Result FSDIR_Read(Handle handle, u32 *entriesRead, u32 entrycount, u16 *buffer) -{ - u32 *cmdbuf=getThreadCommandBuffer(); - - cmdbuf[0]=0x08010042; - cmdbuf[1]=entrycount; - cmdbuf[2]=((entrycount*0x228)<<4)|0xC; - cmdbuf[3]=(u32)buffer; - - Result ret=0; - if((ret=svcSendSyncRequest(handle)))return ret; - - if(entriesRead)*entriesRead=cmdbuf[2]; + if(size) + *size = (u64)cmdbuf[2] | ((u64)cmdbuf[3] << 32); return cmdbuf[1]; } -Result FSDIR_Close(Handle handle) +/*! Set the size of an open file + * + * @param[in] handle Open file handle + * @param[in] size Size to set + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08050080] + * 1 | size (lower word) + * 2 | size (upper word) + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSFILE_SetSize(Handle handle, + u64 size) { - u32* cmdbuf=getThreadCommandBuffer(); + u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0]=0x08020000; + cmdbuf[0] = 0x08050080; + cmdbuf[1] = (u32)size; + cmdbuf[2] = (u32)(size >> 32); + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; - Result ret=0; - if((ret=svcSendSyncRequest(handle)))return ret; + + return cmdbuf[1]; +} + +/*! Get attributes for an open file + * + * @param[in] handle Open file handle + * @param[out] attributes Output attributes + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08060000] + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | Attributes + */ +Result +FSFILE_GetAttributes(Handle handle, + u32 *attributes) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08060000; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + if(attributes) + *attributes = cmdbuf[2]; + + return cmdbuf[1]; +} + +/*! Set attributes for an open file + * + * @param[in] handle Open file handle + * @param[in] attributes Attributes to set + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08070040] + * 1 | Attributes + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSFILE_SetAttributes(Handle handle, + u32 attributes) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08070040; + cmdbuf[1] = attributes; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + return cmdbuf[1]; +} + +/*! Flush an open file + * + * @param[in] handle Open file handle + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08090000] + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSFILE_Flush(Handle handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08090000; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + return cmdbuf[1]; +} + +/*! Read a directory entry from an open directory + * + * @param[in] handle Open directory handle + * @param[out] entriesRead Output number of entries read + * @param[in] entryCount Number of entries to read + * @param[out] buffer Output buffer + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08010042] + * 1 | entryCount + * 2 | ((entrycount*0x228) << 4) \| 0xC + * 3 | buffer + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + * 2 | Number of entries read + */ +Result +FSDIR_Read(Handle handle, + u32 *entriesRead, + u32 entryCount, + FS_dirent *buffer) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08010042; + cmdbuf[1] = entryCount; + cmdbuf[2] = ((entryCount*0x228) << 4) | 0xC; + cmdbuf[3] = (u32)buffer; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; + + if(entriesRead) + *entriesRead = cmdbuf[2]; + + return cmdbuf[1]; +} + +/*! Close an open directory + * + * @param[in] handle Open directory handle + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08020000] + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ +Result +FSDIR_Close(Handle handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08020000; + + Result ret = 0; + if((ret = svcSendSyncRequest(handle))) + return ret; return cmdbuf[1]; }