+#pragma once
#ifndef FS_H
#define FS_H
-#define FS_OPEN_READ (1<<0)
-#define FS_OPEN_WRITE (1<<1)
+/*! @file FS.h
+ *
+ * Filesystem Services
+ */
+
+#include <string.h>
+#include <3ds/types.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#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)
+/* @} */
-#define FS_ATTRIBUTE_NONE (0x00000000)
-#define FS_ATTRIBUTE_READONLY (0x00000001)
-#define FS_ATTRIBUTE_ARCHIVE (0x00000100)
-#define FS_ATTRIBUTE_HIDDEN (0x00010000)
+/*! @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)
-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)
+/* @} */
+
+/*! FS path type */
+typedef enum
{
- return (FS_path){type, strlen(path)+1, (u8*)path};
+ 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);
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
#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)
-{
- 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];
-}
+/*! 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;
+ cmdbuf[1] = 0x20;
+
+ Result ret = 0;
+ if((ret = svcSendSyncRequest(*handle)))
+ return ret;
-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();
-
- 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];
}
-Result FSUSER_OpenFileDirectly(Handle* handle, Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes) //no need to have archive opened
+/*! 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)
{
- if(!handle)handle=&fsuHandle;
- u32* cmdbuf=getThreadCommandBuffer();
+ if(!handle)
+ handle = &fsuHandle;
+
+ 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];
- 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)
+/*! 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)
{
- if(!archive)return -2;
- if(!handle)handle=&fsuHandle;
- u32* cmdbuf=getThreadCommandBuffer();
+ 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) | 0x2;
+ cmdbuf[12] = (u32)fileLowPath.data;
+
+ Result ret = 0;
+ if((ret = svcSendSyncRequest(*handle)))
+ return ret;
+
+ if(out)
+ *out = cmdbuf[3];
- 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)
+/*! 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)
{
- if(!handle)handle=&fsuHandle;
- 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;
- 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)
+/* 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(!archive)return -2;
- if(!handle)handle=&fsuHandle;
- u32* cmdbuf=getThreadCommandBuffer();
+ 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;
- 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)
+/* stub */
+Result
+FSUSER_DeleteDirectoryRecursively(void)
{
- u32* cmdbuf=getThreadCommandBuffer();
+ return -1;
+}
- cmdbuf[0]=0x08080000;
+/* stub */
+Result
+FSUSER_CreateFile(void)
+{
+ return -1;
+}
- Result ret=0;
- if((ret=svcSendSyncRequest(handle)))return ret;
+/*! 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];
}
-Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, u32 *buffer, u32 size)
+/*! 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)
{
- 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(!archive)
+ return -2;
+
+ if(!handle)
+ handle = &fsuHandle;
+
+ u32 *cmdbuf = getThreadCommandBuffer();
- if(bytesRead)*bytesRead=cmdbuf[2];
+ 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];
}
-//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)
+
+/*! 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)
{
- u32 *cmdbuf=getThreadCommandBuffer();
+ if(!archive)
+ return -2;
- 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;
+ if(!handle)
+ handle = &fsuHandle;
- Result ret=0;
- if((ret=svcSendSyncRequest(handle)))return ret;
+ u32 *cmdbuf = getThreadCommandBuffer();
- if(bytesWritten)*bytesWritten=cmdbuf[2];
+ cmdbuf[0] = 0x080E0080;
+ cmdbuf[1] = archive->handleLow;
+ cmdbuf[2] = archive->handleHigh;
+
+ Result ret = 0;
+ if((ret = svcSendSyncRequest(*handle)))
+ return ret;
return cmdbuf[1];
}
-Result FSFILE_GetSize(Handle handle, u64 *size)
+/*! 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();
-
+ 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]);
-
+
+ Result ret = 0;
+ if((ret = svcSendSyncRequest(handle)))
+ return ret;
+
+ if(size)
+ *size = (u64)cmdbuf[2] | ((u64)cmdbuf[3] << 32);
+
+ return cmdbuf[1];
+}
+
+/*! 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();
+
+ cmdbuf[0] = 0x08050080;
+ cmdbuf[1] = (u32)size;
+ cmdbuf[2] = (u32)(size >> 32);
+
+ 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];
}
-Result FSFILE_SetSize(Handle handle, u64 size)
+/*! 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();
+ u32 *cmdbuf = getThreadCommandBuffer();
+
+ cmdbuf[0] = 0x08070040;
+ cmdbuf[1] = attributes;
- 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];
+}
+
+/*! 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];
+ return cmdbuf[1];
}
-Result FSDIR_Read(Handle handle, u32 *entriesRead, u32 entrycount, u16 *buffer)
+/*! 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();
+ u32 *cmdbuf = getThreadCommandBuffer();
- cmdbuf[0]=0x08010042;
- cmdbuf[1]=entrycount;
- cmdbuf[2]=((entrycount*0x228)<<4)|0xC;
- cmdbuf[3]=(u32)buffer;
+ 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;
+ Result ret = 0;
+ if((ret = svcSendSyncRequest(handle)))
+ return ret;
- if(entriesRead)*entriesRead=cmdbuf[2];
+ if(entriesRead)
+ *entriesRead = cmdbuf[2];
return cmdbuf[1];
}
-Result FSDIR_Close(Handle handle)
+/*! 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();
+ u32 *cmdbuf = getThreadCommandBuffer();
- cmdbuf[0]=0x08020000;
+ cmdbuf[0] = 0x08020000;
- Result ret=0;
- if((ret=svcSendSyncRequest(handle)))return ret;
+ Result ret = 0;
+ if((ret = svcSendSyncRequest(handle)))
+ return ret;
return cmdbuf[1];
}