]> Chaos Git - corbenik/ctrulib.git/commitdiff
Bring FS up to date.
authorSteven Smith <Steveice10@gmail.com>
Thu, 12 Nov 2015 04:27:33 +0000 (20:27 -0800)
committerSteven Smith <Steveice10@gmail.com>
Sun, 15 Nov 2015 01:36:07 +0000 (17:36 -0800)
libctru/include/3ds.h
libctru/include/3ds/services/fs.h
libctru/include/3ds/types.h
libctru/source/ndsp/ndsp.c
libctru/source/romfs_dev.c
libctru/source/sdmc_dev.c
libctru/source/services/fs.c

index 004ad78dbad7269ceb60ee26272d49b8b895668b..44b91d20ea5f62db10f2cae8ae8c1797b5e9e5be 100644 (file)
@@ -49,6 +49,7 @@ extern "C" {
 #include <3ds/services/mvd.h>
 #include <3ds/services/news.h>
 #include <3ds/services/qtm.h>
+#include <3ds/services/srvpm.h>
 #include <3ds/services/y2r.h>
 #include <3ds/services/hb.h>
 
index 0e5bd3d7f1af42dbe62c6b46ee4ec205eb012aed..fc88c25638400599fd71821933099f6d0e86bf4c 100644 (file)
 
 #include <3ds/types.h>
 
-///@name FS Open Flags
-///@{
-/// 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)
-/// @}
-
-///@name FS Create Attributes
-///@{
-/// 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)
-/// @}
-
-///@name FS Flush Flags
-///@{
-/// Don't flush
-#define FS_WRITE_NOFLUSH (0x00000000)
-/// Flush
-#define FS_WRITE_FLUSH   (0x00010001)
-/// @}
-
-/// FS path type.
+/// Open flags.
+enum
+{
+       FS_OPEN_READ   = BIT(0), ///< Open for reading.
+       FS_OPEN_WRITE  = BIT(1), ///< Open for writing.
+       FS_OPEN_CREATE = BIT(2), ///< Create file.
+};
+
+/// Write flags.
+enum
+{
+       FS_WRITE_FLUSH       = BIT(0), ///< Flush.
+       FS_WRITE_UPDATE_TIME = BIT(8), ///< Update file timestamp.
+};
+
+/// Attribute flags.
+enum
+{
+       FS_ATTRIBUTE_READ_ONLY = BIT(0),  ///< Read-only.
+       FS_ATTRIBUTE_ARCHIVE   = BIT(8),  ///< Archive.
+       FS_ATTRIBUTE_HIDDEN    = BIT(16), ///< Hidden.
+       FS_ATTRIBUTE_DIRECTORY = BIT(24), ///< Directory.
+};
+
+/// Media types.
 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 archive IDs.
+       MEDIATYPE_NAND      = 0, ///< NAND.
+       MEDIATYPE_SD        = 1, ///< SD card.
+       MEDIATYPE_GAME_CARD = 2, ///< Game card.
+} FS_MediaType;
+
+/// Archive IDs.
 typedef enum
 {
-       ARCH_ROMFS = 0x3,                       ///< RomFS archive.
-       ARCH_SAVEDATA = 0x4,                    ///< Save data archive.
-       ARCH_EXTDATA = 0x6,                     ///< Ext data archive.
-       ARCH_SHARED_EXTDATA = 0x7,              ///< Shared ext data archive.
-       ARCH_SYSTEM_SAVEDATA = 0x8,             ///< System save data archive.
-       ARCH_SDMC = 0x9,                        ///< SDMC archive.
-       ARCH_SDMC_WRITE_ONLY = 0xA,             ///< Write-only SDMC archive.
-       ARCH_BOSS_EXTDATA = 0x12345678,         ///< BOSS ext data archive.
-       ARCH_CARD_SPIFS = 0x12345679,           ///< Card SPIFS archive.
-       ARCH_NAND_RW = 0x1234567D,              ///< Read-write NAND archive.
-       ARCH_NAND_RO = 0x1234567E,              ///< Read-only NAND archive.
-       ARCH_NAND_RO_WRITE_ACCESS = 0x1234567F, ///< Read-only write access NAND archive.
-} FS_archiveIds;
+       ARCHIVE_ROMFS                    = 0x00000003, ///< RomFS archive.
+       ARCHIVE_SAVEDATA                 = 0x00000004, ///< Save data archive.
+       ARCHIVE_EXTDATA                  = 0x00000006, ///< Ext data archive.
+       ARCHIVE_SHARED_EXTDATA           = 0x00000007, ///< Shared ext data archive.
+       ARCHIVE_SYSTEM_SAVEDATA          = 0x00000008, ///< System save data archive.
+       ARCHIVE_SDMC                     = 0x00000009, ///< SDMC archive.
+       ARCHIVE_SDMC_WRITE_ONLY          = 0x0000000A, ///< Write-only SDMC archive.
+       ARCHIVE_BOSS_EXTDATA             = 0x12345678, ///< BOSS ext data archive.
+       ARCHIVE_CARD_SPIFS               = 0x12345679, ///< Card SPI FS archive.
+       ARCHIVE_EXTDATA_AND_BOSS_EXTDATA = 0x1234567B, ///< Ext data and BOSS ext data archive.
+       ARCHIVE_SYSTEM_SAVEDATA2         = 0x1234567C, ///< System save data archive.
+       ARCHIVE_NAND_RW                  = 0x1234567D, ///< Read-write NAND archive.
+       ARCHIVE_NAND_RO                  = 0x1234567E, ///< Read-only NAND archive.
+       ARCHIVE_NAND_RO_WRITE_ACCESS     = 0x1234567F, ///< Read-only write access NAND archive.
+       ARCHIVE_SAVEDATA_AND_CONTENT     = 0x2345678A, ///< User save data and ExeFS/RomFS archive.
+       ARCHIVE_SAVEDATA_AND_CONTENT2    = 0x2345678E, ///< User save data and ExeFS/RomFS archive (only ExeFS for fs:LDR).
+       ARCHIVE_NAND_CTR_FS              = 0x567890AB, ///< NAND CTR FS archive.
+       ARCHIVE_TWL_PHOTO                = 0x567890AC, ///< TWL PHOTO archive.
+       ARCHIVE_NAND_TWL_FS              = 0x567890AE, ///< NAND TWL FS archive.
+       ARCHIVE_NAND_W_FS                = 0x567890AF, ///< NAND W FS archive.
+       ARCHIVE_GAMECARD_SAVEDATA        = 0x567890B1, ///< Game card save data archive.
+       ARCHIVE_USER_SAVEDATA            = 0x567890B2, ///< User save data archive.
+       ARCHIVE_DEMO_SAVEDATA            = 0x567890B4, ///< Demo save data archive.
+} FS_ArchiveID;
 
-/// FS path.
+/// Path types.
+typedef enum
+{
+       PATH_INVALID = 0, ///< Invalid path.
+       PATH_EMPTY   = 1, ///< Empty path.
+       PATH_BINARY  = 2, ///< Binary path. Meaning is per-archive.
+       PATH_ASCII   = 3, ///< ASCII text path.
+       PATH_UTF16   = 4, ///< UTF-16 text path.
+} FS_PathType;
+
+/// Secure value slot.
+typedef enum
+{
+       SECUREVALUE_SLOT_SD = 0x1000, ///< SD application.
+} FS_SecureValueSlot;
+
+/// Card SPI baud rate.
+typedef enum
+{
+       BAUDRATE_512KHZ = 0, ///< 512KHz.
+       BAUDRATE_1MHZ   = 1, ///< 1MHz.
+       BAUDRATE_2MHZ   = 2, ///< 2MHz.
+       BAUDRATE_4MHZ   = 3, ///< 4MHz.
+       BAUDRATE_8MHZ   = 4, ///< 8MHz.
+       BAUDRATE_16MHZ  = 5, ///< 16MHz.
+} FS_CardSpiBaudRate;
+
+/// Card SPI bus mode.
+typedef enum
+{
+       BUSMODE_1BIT = 0, ///< 1-bit.
+       BUSMODE_4BIT = 1, ///< 4-bit.
+} FS_CardSpiBusMode;
+
+/// Card SPI bus mode.
+typedef enum
+{
+       SPECIALCONTENT_UPDATE    = 1, ///< Update.
+       SPECIALCONTENT_MANUAL    = 2, ///< Manual.
+       SPECIALCONTENT_DLP_CHILD = 3, ///< DLP child.
+} FS_SpecialContentType;
+
+typedef enum
+{
+       CARD_CTR = 0, ///< CTR card.
+       CARD_TWL = 1, ///< TWL card.
+} FS_CardType;
+
+/// FS control actions.
+typedef enum
+{
+       FS_ACTION_UNKNOWN = 0,
+} FS_Action;
+
+/// Archive control actions.
+typedef enum
+{
+       ARCHIVE_ACTION_COMMIT_SAVE_DATA = 0, ///< Commits save data changes. No inputs/outputs.
+       ARCHIVE_ACTION_GET_TIMESTAMP    = 1, ///< Retrieves a file's last-modified timestamp. In: "u16*, UTF-16 Path", Out: "u64, Time Stamp".
+} FS_ArchiveAction;
+
+/// Secure save control actions.
+typedef enum
+{
+       SECURESAVE_ACTION_DELETE = 0, ///< Deletes a save's secure value. In: "u64, ((SecureValueSlot << 32) | (TitleUniqueId << 8) | TitleVariation)", Out: "u8, Value Existed"
+       SECURESAVE_ACTION_FORMAT = 1, ///< Formats a save. No inputs/outputs.
+} FS_SecureSaveAction;
+
+/// File control actions.
+typedef enum
+{
+       FILE_ACTION_UNKNOWN = 0,
+} FS_FileAction;
+
+/// Directory control actions.
+typedef enum
+{
+       DIRECTORY_ACTION_UNKNOWN = 0,
+} FS_DirectoryAction;
+
+/// Directory entry.
 typedef struct
 {
-       FS_pathType type;  ///< FS path type.
-       u32         size;  ///< FS path size.
-       const u8    *data; ///< Pointer to FS path data.
-} FS_path;
+       u16 name[0x106];      ///< UTF-16 directory name.
+       char shortName[0x0A]; ///< File name.
+       char shortExt[0x04];  ///< File extension.
+       u8 valid;             ///< Valid flag. (Always 1)
+       u8 reserved;          ///< Reserved.
+       u32 attributes;       ///< Attributes.
+       u64 fileSize;         ///< File size.
+} FS_DirectoryEntry;
 
-/// FS archive.
+/// Archive resource information.
 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;
+       u32 sectorSize;    ///< Size of each sector, in bytes.
+       u32 clusterSize;   ///< Size of each cluster, in bytes.
+       u32 totalClusters; ///< Total number of clusters.
+       u32 freeClusters;  ///< Number of free clusters.
+} FS_ArchiveResource;
 
-/// Directory entry.
+/// Program information.
+typedef struct
+{
+       u64 programId;              ///< Program ID.
+       FS_MediaType mediaType : 8; ///< Media type.
+       u8 padding[7];              ///< Padding.
+} FS_ProgramInfo;
+
+/// Product information.
+typedef struct
+{
+       char productCode[0x10]; ///< Product code.
+       char companyCode[0x2];  ///< Company code.
+       u16 remasterVersion;    ///< Remaster version.
+} FS_ProductInfo;
+
+/// Integrity verification seed.
 typedef struct
 {
-  // 0x00
-  u16 name[0x106];     ///< UTF-16 encoded name
-  // 0x20C
-  u8  shortName[0x0A]; ///< 8.3 File name
-  // 0x216
-  u8  shortExt[0x04];  ///< 8.3 File extension (set to spaces for directories)
-  // 0x21A
-  u8  unknown2;        ///< ???
-  // 0x21B
-  u8  unknown3;        ///< ???
-  // 0x21C
-  u8  isDirectory;     ///< Directory bit
-  // 0x21D
-  u8  isHidden;        ///< Hidden bit
-  // 0x21E
-  u8  isArchive;       ///< Archive bit
-  // 0x21F
-  u8  isReadOnly;      ///< Read-only bit
-  // 0x220
-  u64 fileSize;        ///< File size
-} FS_dirent;
+       u8 aesCbcMac[0x10];   ///< AES-CBC MAC over a SHA256 hash, which hashes the first 0x110-bytes of the cleartext SEED.
+       u8 movableSed[0x120]; ///< The "nand/private/movable.sed", encrypted with AES-CTR using the above MAC for the counter.
+} FS_IntegrityVerificationSeed;
+
+/// Ext save data information.
+typedef struct PACKED
+{
+       FS_MediaType mediaType : 8; ///< Media type.
+       u8 unknown;                 ///< Unknown.
+       u16 reserved1;              ///< Reserved.
+       u64 saveId;                 ///< Save ID.
+       u32 reserved2;              ///< Reserved.
+} FS_ExtSaveDataInfo;
+
+/// System save data information.
+typedef struct
+{
+       FS_MediaType mediaType : 8; ///< Media type.
+       u8 unknown;                 ///< Unknown.
+       u16 reserved;               ///< Reserved.
+       u32 saveId;                 ///< Save ID.
+} FS_SystemSaveDataInfo;
+
+/// Device move context.
+typedef struct
+{
+       u8 ivs[0x10];              ///< IVs.
+       u8 encryptParameter[0x10]; ///< Encrypt parameter.
+} FS_DeviceMoveContext;
+
+/// 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.
+       u64 handle;      ///< Handle.
+} FS_Archive;
 
 /// Initializes FS.
 Result fsInit(void);
@@ -117,224 +242,789 @@ void fsExit(void);
  * @brief Gets the current FS session handle.
  * @return The current FS session handle.
  */
-Handle *fsGetSessionHandle(void);
+HandlefsGetSessionHandle(void);
 
 /**
- * Creates an FS_path instance.
- * @param type Type of path.
- * @param path Path to use.
- * @return The created FS_path instance.
+ * @brief Performs a control operation on the filesystem.
+ * @param action Action to perform.
+ * @param input Buffer to read input from.
+ * @param inputSize Size of the input.
+ * @param output Buffer to write output to.
+ * @param outputSize Size of the output.
  */
-FS_path fsMakePath(FS_pathType type, const char *path);
+Result FSUSER_Control(FS_Action action, void* input, u32 inputSize, void* output, u32 outputSize);
+
+/// Initializes the FSUSER session.
+Result FSUSER_Initialize(void);
 
 /**
- * @brief Initializes FSUSER.
- * @param handle FS:USER service handle to use.
+ * @brief Opens a file.
+ * @param out Pointer to output the file handle to.
+ * @param archive Archive containing the file.
+ * @param path Path of the file.
+ * @param openFlags Flags to open the file with.
+ * @param attributes Attributes of the file.
  */
-Result FSUSER_Initialize(Handle handle);
+Result FSUSER_OpenFile(Handle* out, FS_Archive archive, FS_Path path, u32 openFlags, u32 attributes);
 
 /**
- * @brief Opens an archive.
- * @param archive Archive to open.
+ * @brief Opens a file directly.
+ * @param out Pointer to output the file handle to.
+ * @param archive Archive containing the file.
+ * @param path Path of the file.
+ * @param openFlags Flags to open the file with.
+ * @param attributes Attributes of the file.
+ */
+Result FSUSER_OpenFileDirectly(Handle* out, FS_Archive archive, FS_Path path, u32 openFlags, u32 attributes);
+
+/**
+ * @brief Deletes a file.
+ * @param archive Archive containing the file.
+ * @param path Path of the file.
+ */
+Result FSUSER_DeleteFile(FS_Archive archive, FS_Path path);
+
+/**
+ * @brief Renames a file.
+ * @param srcArchive Archive containing the source file.
+ * @param srcPath Path of the source file.
+ * @param dstArchive Archive containing the destination file.
+ * @param dstPath Path of the destination file.
+ */
+Result FSUSER_RenameFile(FS_Archive srcArchive, FS_Path srcPath, FS_Archive dstArchive, FS_Path dstPath);
+
+/**
+ * @brief Deletes a directory, failing if it is not empty.
+ * @param archive Archive containing the directory.
+ * @param path Path of the directory.
+ */
+Result FSUSER_DeleteDirectory(FS_Archive archive, FS_Path path);
+
+/**
+ * @brief Deletes a directory, also deleting its contents.
+ * @param archive Archive containing the directory.
+ * @param path Path of the directory.
+ */
+Result FSUSER_DeleteDirectoryRecursively(FS_Archive archive, FS_Path path);
+
+/**
+ * @brief Creates a file.
+ * @param archive Archive containing the file.
+ * @param path Path of the file.
+ * @param attributes Attributes of the file.
+ * @param fileSize Size of the file.
+ */
+Result FSUSER_CreateFile(FS_Archive archive, FS_Path path, u32 attributes, u64 fileSize);
+
+/**
+ * @brief Creates a directory
+ * @param archive Archive containing the directory.
+ * @param path Path of the directory.
+ * @param attributes Attributes of the directory.
  */
-Result FSUSER_OpenArchive(FS_archive* archive);
+Result FSUSER_CreateDirectory(FS_Archive archive, FS_Path path, u32 attributes);
+
+/**
+ * @brief Renames a directory.
+ * @param srcArchive Archive containing the source directory.
+ * @param srcPath Path of the source directory.
+ * @param dstArchive Archive containing the destination directory.
+ * @param dstPath Path of the destination directory.
+ */
+Result FSUSER_RenameDirectory(FS_Archive srcArchive, FS_Path srcPath, FS_Archive dstArchive, FS_Path dstPath);
 
 /**
  * @brief Opens a directory.
  * @param out Pointer to output the directory handle to.
- * @param archive Archive to open the directory from.
- * @param dirLowPath Path of the directory.
+ * @param archive Archive containing the directory.
+ * @param path Path of the directory.
  */
-Result FSUSER_OpenDirectory(Handle* out, FS_archive archive, FS_path dirLowPath);
+Result FSUSER_OpenDirectory(Handle *out, FS_Archive archive, FS_Path path);
 
 /**
- * @brief Opens a file.
- * @param out Pointer to output the file handle to.
- * @param archive Archive to open the file from.
- * @param fileLowPath Path of the file.
- * @param openflags Open flags to use.
- * @param attributes Attributes to use.
+ * @brief Opens an archive.
+ * @param archive Archive to open.
  */
-Result FSUSER_OpenFile(Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes);
+Result FSUSER_OpenArchive(FS_Archive* archive);
 
 /**
- * @brief Opens a file directly.
- * @param out Pointer to output the file handle to.
- * @param archive Archive to open the file from.
- * @param fileLowPath Path of the file.
- * @param openflags Open flags to use.
- * @param attributes Attributes to use.
+ * @brief Performs a control operation on an archive.
+ * @param archive Archive to control.
+ * @param action Action to perform.
+ * @param input Buffer to read input from.
+ * @param inputSize Size of the input.
+ * @param output Buffer to write output to.
+ * @param outputSize Size of the output.
  */
-Result FSUSER_OpenFileDirectly(Handle* out, FS_archive archive, FS_path fileLowPath, u32 openflags, u32 attributes);
+Result FSUSER_ControlArchive(FS_Archive archive, FS_ArchiveAction action, void* input, u32 inputSize, void* output, u32 outputSize);
 
 /**
  * @brief Closes an archive.
  * @param archive Archive to close.
  */
-Result FSUSER_CloseArchive(FS_archive* archive);
+Result FSUSER_CloseArchive(FS_Archive* archive);
 
 /**
- * @brief Creates a file.
- * @param archive Archive to use.
- * @param fileLowPath Path of the file.
- * @param fileSize Initial size of the file.
+ * @brief Gets the number of free bytes within an archive.
+ * @param freeBytes Pointer to output the free bytes to.
+ * @param archive Archive to check.
  */
-Result FSUSER_CreateFile(FS_archive archive, FS_path fileLowPath, u32 fileSize);
+Result FSUSER_GetFreeBytes(u64* freeBytes, FS_Archive archive);
 
 /**
- * @brief Creates a directory.
- * @param archive Archive to use.
- * @param dirLowPath Path of the directory.
+ * @brief Gets the inserted card type.
+ * @param type Pointer to output the card type to.
  */
-Result FSUSER_CreateDirectory(FS_archive archive, FS_path dirLowPath);
+Result FSUSER_GetCardType(FS_CardType* type);
 
 /**
- * @brief Deletes a file.
- * @param archive Archive to use.
- * @param fileLowPath Path of the file.
+ * @brief Gets the SDMC archive resource information.
+ * @param archiveResource Pointer to output the archive resource information to.
+ */
+Result FSUSER_GetSdmcArchiveResource(FS_ArchiveResource* archiveResource);
+
+/**
+ * @brief Gets the NAND archive resource information.
+ * @param archiveResource Pointer to output the archive resource information to.
+ */
+Result FSUSER_GetNandArchiveResource(FS_ArchiveResource* archiveResource);
+
+/**
+ * @brief Gets the last SDMC fatfs error.
+ * @param error Pointer to output the error to.
+ */
+Result FSUSER_GetSdmcFatfsError(u32* error);
+
+/**
+ * @brief Gets whether an SD card is detected.
+ * @param detected Pointer to output the detection status to.
+ */
+Result FSUSER_IsSdmcDetected(bool *detected);
+
+/**
+ * @brief Gets whether the SD card is writable.
+ * @param detected Pointer to output the writable status to.
+ */
+Result FSUSER_IsSdmcWritable(bool *writable);
+
+/**
+ * @brief Gets the SDMC CID.
+ * @param out Pointer to output the CID to.
+ * @param length Length of the CID buffer. (should be 0x10)
+ */
+Result FSUSER_GetSdmcCid(u8* out, u32 length);
+
+/**
+ * @brief Gets the NAND CID.
+ * @param out Pointer to output the CID to.
+ * @param length Length of the CID buffer. (should be 0x10)
+ */
+Result FSUSER_GetNandCid(u8* out, u32 length);
+
+/**
+ * @brief Gets the SDMC speed info.
+ * @param speedInfo Pointer to output the speed info to.
+ */
+Result FSUSER_GetSdmcSpeedInfo(u32 *speedInfo);
+
+/**
+ * @brief Gets the NAND speed info.
+ * @param speedInfo Pointer to output the speed info to.
+ */
+Result FSUSER_GetNandSpeedInfo(u32 *speedInfo);
+
+/**
+ * @brief Gets the SDMC log.
+ * @param out Pointer to output the log to.
+ * @param length Length of the log buffer.
+ */
+Result FSUSER_GetSdmcLog(u8* out, u32 length);
+
+/**
+ * @brief Gets the NAND log.
+ * @param out Pointer to output the log to.
+ * @param length Length of the log buffer.
+ */
+Result FSUSER_GetNandLog(u8* out, u32 length);
+
+/// Clears the SDMC log.
+Result FSUSER_ClearSdmcLog(void);
+
+/// Clears the NAND log.
+Result FSUSER_ClearNandLog(void);
+
+/**
+ * @brief Gets whether a card is inserted.
+ * @param inserted Pointer to output the insertion status to.
+ */
+Result FSUSER_CardSlotIsInserted(bool* inserted);
+
+/**
+ * @brief Powers on the card slot.
+ * @param status Pointer to output the power status to.
+ */
+Result FSUSER_CardSlotPowerOn(bool* status);
+
+/**
+ * @brief Powers off the card slot.
+ * @param status Pointer to output the power status to.
+ */
+Result FSUSER_CardSlotPowerOff(bool* status);
+
+/**
+ * @brief Gets the card's power status.
+ * @param status Pointer to output the power status to.
+ */
+Result FSUSER_CardSlotGetCardIFPowerStatus(bool* status);
+
+/**
+ * @brief Executes a CARDNOR direct command.
+ * @param commandId ID of the command.
  */
-Result FSUSER_DeleteFile(FS_archive archive, FS_path fileLowPath);
+Result FSUSER_CardNorDirectCommand(u8 commandId);
 
 /**
- * @brief Deletes a directory.
+ * @brief Executes a CARDNOR direct command with an address.
+ * @param commandId ID of the command.
+ * @param address Address to provide.
+ */
+Result FSUSER_CardNorDirectCommandWithAddress(u8 commandId, u32 address);
+
+/**
+ * @brief Executes a CARDNOR direct read.
+ * @param commandId ID of the command.
+ * @param size Size of the output buffer.
+ * @param output Output buffer.
+ */
+Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, u8* output);
+
+/**
+ * @brief Executes a CARDNOR direct read with an address.
+ * @param commandId ID of the command.
+ * @param address Address to provide.
+ * @param size Size of the output buffer.
+ * @param output Output buffer.
+ */
+Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, u8* output);
+
+/**
+ * @brief Executes a CARDNOR direct write.
+ * @param commandId ID of the command.
+ * @param size Size of the input buffer.
+ * @param output Input buffer.
+ */
+Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, u8* input);
+
+/**
+ * @brief Executes a CARDNOR direct write with an address.
+ * @param commandId ID of the command.
+ * @param address Address to provide.
+ * @param size Size of the input buffer.
+ * @param input Input buffer.
+ */
+Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, u8* input);
+
+/**
+ * @brief Executes a CARDNOR 4xIO direct read.
+ * @param commandId ID of the command.
+ * @param address Address to provide.
+ * @param size Size of the output buffer.
+ * @param output Output buffer.
+ */
+Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, u8* output);
+
+/**
+ * @brief Executes a CARDNOR direct CPU write without verify.
+ * @param address Address to provide.
+ * @param size Size of the input buffer.
+ * @param output Input buffer.
+ */
+Result FSUSER_CardNorDirectCpuWriteWithoutVerify(u32 address, u32 size, u8* input);
+
+/**
+ * @brief Executes a CARDNOR direct sector erase without verify.
+ * @param address Address to provide.
+ */
+Result FSUSER_CardNorDirectSectorEraseWithoutVerify(u32 address);
+
+/**
+ * @brief Gets a process's product info.
+ * @param info Pointer to output the product info to.
+ * @param processId ID of the process.
+ */
+Result FSUSER_GetProductInfo(FS_ProductInfo* info, u32 processId);
+
+/**
+ * @brief Gets a process's program launch info.
+ * @param info Pointer to output the program launch info to.
+ * @param processId ID of the process.
+ */
+Result FSUSER_GetProgramLaunchInfo(FS_ProgramInfo* info, u32 processId);
+
+/**
+ * @brief Sets the CARDSPI baud rate.
+ * @param baudRate Baud rate to set.
+ */
+Result FSUSER_SetCardSpiBaudRate(FS_CardSpiBaudRate baudRate);
+
+/**
+ * @brief Sets the CARDSPI bus mode.
+ * @param baudRate Bus mode to set.
+ */
+Result FSUSER_SetCardSpiBusMode(FS_CardSpiBusMode busMode);
+
+/// Sends initialization info to ARM9.
+Result FSUSER_SendInitializeInfoTo9(void);
+
+/**
+ * @brief Gets a special content's index.
+ * @param index Pointer to output the index to.
+ * @param mediaType Media type of the special content.
+ * @param programId Program ID owning the special content.
+ * @param type Type of special content.
+ */
+Result FSUSER_GetSpecialContentIndex(u16* index, FS_MediaType mediaType, u64 programId, FS_SpecialContentType type);
+
+/**
+ * @brief Gets the legacy ROM header of a program.
+ * @param mediaType Media type of the program.
+ * @param programId ID of the program.
+ * @param header Pointer to output the legacy ROM header to. (size = 0x3B4)
+ */
+Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, u8* header);
+
+/**
+ * @brief Gets the legacy banner data of a program.
+ * @param mediaType Media type of the program.
+ * @param programId ID of the program.
+ * @param header Pointer to output the legacy banner data to. (size = 0x23C0)
+ */
+Result FSUSER_GetLegacyBannerData(FS_MediaType mediaType, u64 programId, u8* banner);
+
+/**
+ * @brief Checks a process's authority to access a save data archive.
+ * @param access Pointer to output the access status to.
+ * @param mediaType Media type of the save data.
+ * @param saveId ID of the save data.
+ * @param processId ID of the process to check.
+ */
+Result FSUSER_CheckAuthorityToAccessExtSaveData(bool* access, FS_MediaType mediaType, u64 saveId, u32 processId);
+
+/**
+ * @brief Queries the total quota size of a save data archive.
+ * @param quotaSize Pointer to output the quota size to.
+ * @param directories Number of directories.
+ * @param files Number of files.
+ * @param fileSizeCount Number of file sizes to provide.
+ * @param fileSizes File sizes to provide.
+ */
+Result FSUSER_QueryTotalQuotaSize(u64* quotaSize, u32 directories, u32 files, u32 fileSizeCount, u64* fileSizes);
+
+/**
+ * @brief Abnegates an access right.
+ * @param accessRight Access right to abnegate.
+ */
+Result FSUSER_AbnegateAccessRight(u32 accessRight);
+
+/// Deletes the 3DS SDMC root.
+Result FSUSER_DeleteSdmcRoot(void);
+
+/// Deletes all ext save data on the NAND.
+Result FSUSER_DeleteAllExtSaveDataOnNand(void);
+
+/// Initializes the CTR file system.
+Result FSUSER_InitializeCtrFileSystem(void);
+
+/// Creates the FS seed.
+Result FSUSER_CreateSeed(void);
+
+/**
+ * @brief Retrieves archive format info.
+ * @param totalSize Pointer to output the total size to.
+ * @param directories Pointer to output the number of directories to.
+ * @param files Pointer to output the number of files to.
+ * @param duplicateData Pointer to output whether to duplicate data to.
+ * @param archiveId ID of the archive.
+ * @param path Path of the archive.
+ */
+Result FSUSER_GetFormatInfo(u32* totalSize, u32* directories, u32* files, bool* duplicateData, FS_ArchiveID archiveId, FS_Path path);
+
+/**
+ * @brief Gets the legacy ROM header of a program.
+ * @param headerSize Size of the ROM header.
+ * @param mediaType Media type of the program.
+ * @param programId ID of the program.
+ * @param header Pointer to output the legacy ROM header to.
+ */
+Result FSUSER_GetLegacyRomHeader2(u32 headerSize, FS_MediaType mediaType, u64 programId, u8* header);
+
+/**
+ * @brief Gets the CTR SDMC root path.
+ * @param out Pointer to output the root path to.
+ * @param length Length of the output buffer.
+ */
+Result FSUSER_GetSdmcCtrRootPath(u8* out, u32 length);
+
+/**
+ * @brief Gets an archive's resource information.
+ * @param archiveResource Pointer to output the archive resource information to.
+ * @param mediaType Media type to check.
+ */
+Result FSUSER_GetArchiveResource(FS_ArchiveResource* archiveResource, FS_MediaType mediaType);
+
+/**
+ * @brief Exports the integrity verification seed.
+ * @param seed Pointer to output the seed to.
+ */
+Result FSUSER_ExportIntegrityVerificationSeed(FS_IntegrityVerificationSeed* seed);
+
+/**
+ * @brief Imports an integrity verification seed.
+ * @param seed Seed to import.
+ */
+Result FSUSER_ImportIntegrityVerificationSeed(FS_IntegrityVerificationSeed* seed);
+
+/**
+ * @brief Formats save data.
+ * @param archiveId ID of the save data archive.
+ * @param path Path of the save data.
+ * @param blocks Size of the save data in blocks. (512 bytes)
+ * @param directories Number of directories.
+ * @param files Number of files.
+ * @param directoryBuckets Directory hash tree bucket count.
+ * @param fileBuckets File hash tree bucket count.
+ * @param duplicateData Whether to store an internal duplicate of the data.
+ */
+Result FSUSER_FormatSaveData(FS_ArchiveID archiveId, FS_Path path, u32 blocks, u32 directories, u32 files, u32 directoryBuckets, u32 fileBuckets, bool duplicateData);
+
+/**
+ * @brief Gets the legacy sub banner data of a program.
+ * @param bannerSize Size of the banner.
+ * @param mediaType Media type of the program.
+ * @param programId ID of the program.
+ * @param header Pointer to output the legacy sub banner data to.
+ */
+Result FSUSER_GetLegacySubBannerData(u32 bannerSize, FS_MediaType mediaType, u64 programId, u8* banner);
+
+/**
+ * @brief Reads from a special file.
+ * @param bytesRead Pointer to output the number of bytes read to.
+ * @param fileOffset Offset of the file.
+ * @param size Size of the buffer.
+ * @param data Buffer to read to.
+ */
+Result FSUSER_ReadSpecialFile(u32* bytesRead, u64 fileOffset, u32 size, u8* data);
+
+/**
+ * @brief Gets the size of a special file.
+ * @param fileSize Pointer to output the size to.
+ */
+Result FSUSER_GetSpecialFileSize(u64* fileSize);
+
+/**
+ * @brief Creates ext save data.
+ * @param info Info of the save data.
+ * @param directories Number of directories.
+ * @param files Number of files.
+ * @param sizeLimit Size limit of the save data.
+ * @param smdhSize Size of the save data's SMDH data.
+ * @param smdh SMDH data.
+ */
+Result FSUSER_CreateExtSaveData(FS_ExtSaveDataInfo info, u32 directories, u32 files, u64 sizeLimit, u32 smdhSize, u8* smdh);
+
+/**
+ * @brief Deletes ext save data.
+ * @param info Info of the save data.
+ */
+Result FSUSER_DeleteExtSaveData(FS_ExtSaveDataInfo info);
+
+/**
+ * @brief Reads the SMDH icon of ext save data.
+ * @param bytesRead Pointer to output the number of bytes read to.
+ * @param info Info of the save data.
+ * @param smdhSize Size of the save data SMDH.
+ * @param smdh Pointer to output SMDH data to.
+ */
+Result FSUSER_ReadExtSaveDataIcon(u32* bytesRead, FS_ExtSaveDataInfo info, u32 smdhSize, u8* smdh);
+
+/**
+ * @brief Gets an ext data archive's block information.
+ * @param totalBlocks Pointer to output the total blocks to.
+ * @param freeBlocks Pointer to output the free blocks to.
+ * @param blockSize Pointer to output the block size to.
+ * @param info Info of the save data.
+ */
+Result FSUSER_GetExtDataBlockSize(u64* totalBlocks, u64* freeBlocks, u32* blockSize, FS_ExtSaveDataInfo info);
+
+/**
+ * @brief Enumerates ext save data.
+ * @param idsWritten Pointer to output the number of IDs written to.
+ * @param idsSize Size of the IDs buffer.
+ * @param mediaType Media type to enumerate over.
+ * @param idSize Size of each ID element.
+ * @param shared Whether to enumerate shared ext save data.
+ * @param ids Pointer to output IDs to.
+ */
+Result FSUSER_EnumerateExtSaveData(u32* idsWritten, u32 idsSize, FS_MediaType mediaType, u32 idSize, bool shared, u8* ids);
+
+/**
+ * @brief Creates system save data.
+ * @param info Info of the save data.
+ * @param totalSize Total size of the save data.
+ * @param blockSize Block size of the save data. (usually 0x1000)
+ * @param directories Number of directories.
+ * @param files Number of files.
+ * @param directoryBuckets Directory hash tree bucket count.
+ * @param fileBuckets File hash tree bucket count.
+ * @param duplicateData Whether to store an internal duplicate of the data.
+ */
+Result FSUSER_CreateSystemSaveData(FS_SystemSaveDataInfo info, u32 totalSize, u32 blockSize, u32 directories, u32 files, u32 directoryBuckets, u32 fileBuckets, bool duplicateData);
+
+/**
+ * @brief Deletes system save data.
+ * @param info Info of the save data.
+ */
+Result FSUSER_DeleteSystemSaveData(FS_SystemSaveDataInfo info);
+
+/**
+ * @brief Initiates a device move as the source device.
+ * @param context Pointer to output the context to.
+ */
+Result FSUSER_StartDeviceMoveAsSource(FS_DeviceMoveContext* context);
+
+/**
+ * @brief Initiates a device move as the destination device.
+ * @param context Context to use.
+ * @param clear Whether to clear the device's data first.
+ */
+Result FSUSER_StartDeviceMoveAsDestination(FS_DeviceMoveContext context, bool clear);
+
+/**
+ * @brief Sets an archive's priority.
  * @param archive Archive to use.
- * @param dirLowPath Path of the directory.
+ * @param priority Priority to set.
  */
-Result FSUSER_DeleteDirectory(FS_archive archive, FS_path dirLowPath);
+Result FSUSER_SetArchivePriority(FS_Archive archive, u32 priority);
 
 /**
- * @brief Deletes a directory recursively.
+ * @brief Gets an archive's priority.
+ * @param priority Pointer to output the priority to.
  * @param archive Archive to use.
- * @param dirLowPath Path of the directory.
  */
-Result FSUSER_DeleteDirectoryRecursively(FS_archive archive, FS_path dirLowPath);
+Result FSUSER_GetArchivePriority(u32* priority, FS_Archive archive);
 
 /**
- * @brief Renames a file.
- * @param srcArchive Source archive.
- * @param srcFileLowPath Source file.
- * @param destArchive Destination archive.
- * @param destFileLowPath Destination file.
+ * @brief Configures CTRCARD latency emulation.
+ * @param latency Latency to apply, in milliseconds.
+ * @param emulateEndurance Whether to emulate card endurance.
  */
-Result FSUSER_RenameFile(FS_archive srcArchive, FS_path srcFileLowPath, FS_archive destArchive, FS_path destFileLowPath);
+Result FSUSER_SetCtrCardLatencyParameter(u64 latency, bool emulateEndurance);
 
 /**
- * @brief Renames a directory.
- * @param srcArchive Source archive.
- * @param srcDirLowPath Source directory.
- * @param destArchive Destination archive.
- * @param destDirLowPath Destination directory.
+ * @brief Toggles cleaning up invalid save data.
+ * @param Whether to enable cleaning up invalid save data.
  */
-Result FSUSER_RenameDirectory(FS_archive srcArchive, FS_path srcDirLowPath, FS_archive destArchive, FS_path destDirLowPath);
+Result FSUSER_SwitchCleanupInvalidSaveData(bool enable);
 
 /**
- * @brief Gets the SDMC resource info.
- * @param sectorSize Pointer to output the sector size to.
- * @param sectorSize Pointer to output the cluster size to.
- * @param sectorSize Pointer to output the total number of clusters to.
- * @param sectorSize Pointer to output the number of free clusters to.
+ * @brief Enumerates system save data.
+ * @param idsWritten Pointer to output the number of IDs written to.
+ * @param idsSize Size of the IDs buffer.
+ * @param ids Pointer to output IDs to.
  */
-Result FSUSER_GetSdmcArchiveResource(u32 *sectorSize, u32 *clusterSize, u32 *numClusters, u32 *freeClusters);
+Result FSUSER_EnumerateSystemSaveData(u32* idsWritten, u32 idsSize, u64* ids);
 
 /**
- * @brief Gets the NAND resource info.
- * @param sectorSize Pointer to output the sector size to.
- * @param sectorSize Pointer to output the cluster size to.
- * @param sectorSize Pointer to output the total number of clusters to.
- * @param sectorSize Pointer to output the number of free clusters to.
+ * @brief Initializes the FSUSER session with an SDK version.
+ * @param version SDK version to initialize with.
  */
-Result FSUSER_GetNandArchiveResource(u32 *sectorSize, u32 *clusterSize, u32 *numClusters, u32 *freeClusters);
+Result FSUSER_InitializeWithSdkVersion(u32 version);
 
 /**
- * @brief Gets whether an SD card is detected.
- * @param detected Pointer to output the SD detection state to.
+ * @brief Sets the file system priority.
+ * @param priority Priority to set.
  */
-Result FSUSER_IsSdmcDetected(u8 *detected);
+Result FSUSER_SetPriority(u32 priority);
 
 /**
- * @brief Gets whether the SD card is writable.
- * @param detected Pointer to output the SD writable state to.
+ * @brief Gets the file system priority.
+ * @param priority Pointer to output the priority to.
+ */
+Result FSUSER_GetPriority(u32* priority);
+
+/**
+ * @brief Sets the save data secure value.
+ * @param value Secure value to set.
+ * @param slot Slot of the secure value.
+ * @param titleUniqueId Unique ID of the title. (default = 0)
+ * @param titleVariation Variation of the title. (default = 0)
+ */
+Result FSUSER_SetSaveDataSecureValue(u64 value, FS_SecureValueSlot slot, u32 titleUniqueId, u8 titleVariation);
+
+/**
+ * @brief Gets the save data secure value.
+ * @param exists Pointer to output whether the secure value exists to.
+ * @param value Pointer to output the secure value to.
+ * @param slot Slot of the secure value.
+ * @param titleUniqueId Unique ID of the title. (default = 0)
+ * @param titleVariation Variation of the title. (default = 0)
  */
-Result FSUSER_IsSdmcWritable(u8 *writable);
+Result FSUSER_GetSaveDataSecureValue(bool* exists, u64* value, FS_SecureValueSlot slot, u32 titleUniqueId, u8 titleVariation);
+
+/**
+ * @brief Performs a control operation on a secure save.
+ * @param action Action to perform.
+ * @param input Buffer to read input from.
+ * @param inputSize Size of the input.
+ * @param output Buffer to write output to.
+ * @param outputSize Size of the output.
+ */
+Result FSUSER_ControlSecureSave(FS_SecureSaveAction action, void* input, u32 inputSize, void* output, u32 outputSize);
 
 /**
  * @brief Gets the media type of the current application.
- * @param mediatype Pointer to output the media type to.
+ * @param mediaType Pointer to output the media type to.
  */
-Result FSUSER_GetMediaType(u8* mediatype);
+Result FSUSER_GetMediaType(FS_MediaType* mediaType);
 
 /**
- * @brief Closes a file handle.
- * @param handle File handle to close.
+ * @brief Performs a control operation on a file.
+ * @param handle Handle of the file.
+ * @param action Action to perform.
+ * @param input Buffer to read input from.
+ * @param inputSize Size of the input.
+ * @param output Buffer to write output to.
+ * @param outputSize Size of the output.
  */
-Result FSFILE_Close(Handle handle);
+Result FSFILE_Control(Handle handle, FS_FileAction action, void* input, u32 inputSize, void* output, u32 outputSize);
+
+/**
+ * @brief Opens a handle to a sub-section of a file.
+ * @param handle Handle of the file.
+ * @param subFile Pointer to output the sub-file to.
+ * @param offset Offset of the sub-section.
+ * @param size Size of the sub-section.
+ */
+Result FSFILE_OpenSubFile(Handle handle, Handle* subFile, u64 offset, u64 size);
 
 /**
  * @brief Reads from a file.
- * @param handle File handle to use.
+ * @param handle Handle of the file.
  * @param bytesRead Pointer to output the number of bytes read to.
  * @param offset Offset to read from.
  * @param buffer Buffer to read to.
  * @param size Size of the buffer.
  */
-Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, void *buffer, u32 size);
+Result FSFILE_Read(Handle handle, u32* bytesRead, u64 offset, void* buffer, u32 size);
 
 /**
  * @brief Writes to a file.
- * @param handle File handle to use.
- * @param bytesRead Pointer to output the number of bytes written to.
+ * @param handle Handle of the file.
+ * @param bytesWritten Pointer to output the number of bytes written to.
  * @param offset Offset to write to.
  * @param buffer Buffer to write from.
  * @param size Size of the buffer.
- * @param flushFlags Flush flags to apply after writing.
+ * @param flags Flags to use when writing.
  */
-Result FSFILE_Write(Handle handle, u32 *bytesWritten, u64 offset, const void *buffer, u32 size, u32 flushFlags);
+Result FSFILE_Write(Handle handle, u32* bytesWritten, u64 offset, const void* buffer, u32 size, u32 flags);
 
 /**
- * @brief Gets a file's size.
- * @param handle File handle to use.
+ * @brief Gets the size of a file.
+ * @param handle Handle of the file.
  * @param size Pointer to output the size to.
  */
-Result FSFILE_GetSize(Handle handle, u64 *size);
+Result FSFILE_GetSize(Handle handle, u64size);
 
 /**
- * @brief Sets a file's size.
- * @param handle File handle to use.
+ * @brief Sets the size of a file.
+ * @param handle Handle of the file.
  * @param size Size to set.
  */
 Result FSFILE_SetSize(Handle handle, u64 size);
 
 /**
- * @brief Gets a file's attributes.
- * @param handle File handle to use.
+ * @brief Gets the attributes of a file.
+ * @param handle Handle of the file.
  * @param attributes Pointer to output the attributes to.
  */
-Result FSFILE_GetAttributes(Handle handle, u32 *attributes);
+Result FSFILE_GetAttributes(Handle handle, u32attributes);
 
 /**
- * @brief Sets a file's attributes.
- * @param handle File handle to use.
+ * @brief Sets the attributes of a file.
+ * @param handle Handle of the file.
  * @param attributes Attributes to set.
  */
 Result FSFILE_SetAttributes(Handle handle, u32 attributes);
 
 /**
- * @brief Flushes a file to disk.
- * @param handle File handle to flush.
+ * @brief Closes a file.
+ * @param handle Handle of the file.
+ */
+Result FSFILE_Close(Handle handle);
+
+/**
+ * @brief Flushes a file's contents.
+ * @param handle Handle of the file.
  */
 Result FSFILE_Flush(Handle handle);
 
+/**
+ * @brief Sets a file's priority.
+ * @param handle Handle of the file.
+ * @param priority Priority to set.
+ */
+Result FSFILE_SetPriority(Handle handle, u32 priority);
+
+/**
+ * @brief Gets a file's priority.
+ * @param handle Handle of the file.
+ * @param priority Pointer to output the priority to.
+ */
+Result FSFILE_GetPriority(Handle handle, u32* priority);
+
+/**
+ * @brief Opens a duplicate handle to a file.
+ * @param handle Handle of the file.
+ * @param linkFile Pointer to output the link handle to.
+ */
+Result FSFILE_OpenLinkFile(Handle handle, Handle* linkFile);
+
+/**
+ * @brief Performs a control operation on a directory.
+ * @param handle Handle of the directory.
+ * @param action Action to perform.
+ * @param input Buffer to read input from.
+ * @param inputSize Size of the input.
+ * @param output Buffer to write output to.
+ * @param outputSize Size of the output.
+ */
+Result FSDIR_Control(Handle handle, FS_DirectoryAction action, void* input, u32 inputSize, void* output, u32 outputSize);
+
 /**
  * @brief Reads one or more directory entries.
- * @param handle Directory handle to read from.
- * @param entriesRead Pointer to output the current number of read entries to.
- * @param entrycount Number of entries to read.
- * @param buffer Buffer to output directory entries to.
+ * @param handle Handle of the directory.
+ * @param entriesRead Pointer to output the number of entries read to.
+ * @param entryCount Number of entries to read.
+ * @param entryOut Pointer to output directory entries to.
  */
-Result FSDIR_Read(Handle handle, u32 *entriesRead, u32 entrycount, FS_dirent *buffer);
+Result FSDIR_Read(Handle handle, u32* entriesRead, u32 entryCount, FS_DirectoryEntry* entries);
 
 /**
- * @brief Closes a directory handle.
- * @param handle Directory handle to close.
+ * @brief Closes a directory.
+ * @param handle Handle of the directory.
  */
 Result FSDIR_Close(Handle handle);
+
+/**
+ * @brief Sets a directory's priority.
+ * @param handle Handle of the directory.
+ * @param priority Priority to set.
+ */
+Result FSDIR_SetPriority(Handle handle, u32 priority);
+
+/**
+ * @brief Gets a directory's priority.
+ * @param handle Handle of the directory.
+ * @param priority Pointer to output the priority to.
+ */
+Result FSDIR_GetPriority(Handle handle, u32* priority);
index a2bb20e42a5bcf82363459c7da2886514ad287af..6fa2dfec667aec60084e3d26604b9b7aa3085f75 100644 (file)
 /// The maximum value of a u64.
 #define U64_MAX        UINT64_MAX
 
-/// Possible media types.
-typedef enum
-{
-       mediatype_NAND,     ///< NAND
-       mediatype_SDMC,     ///< SDMC
-       mediatype_GAMECARD, ///< Game card
-} mediatypes_enum;
-
 typedef uint8_t u8;   ///<  8-bit unsigned integer
 typedef uint16_t u16; ///< 16-bit unsigned integer
 typedef uint32_t u32; ///< 32-bit unsigned integer
index e5ead038f7646eaae6ccf2cefa2e5ec57079e8ef..11445ba0f618ad91817aeeb7ba24590ea00177fa 100644 (file)
@@ -400,10 +400,10 @@ static bool ndspFindAndLoadComponent(void)
        do
        {
                static const char dsp_filename[] = "/3ds/dspfirm.cdc";
-               FS_archive arch = { ARCH_SDMC, { PATH_EMPTY, 1, (u8*)"" }, 0, 0 };
-               FS_path path = { PATH_CHAR, sizeof(dsp_filename), (u8*)dsp_filename };
+               FS_Archive arch = { ARCHIVE_SDMC, { PATH_EMPTY, 1, (u8*)"" }, 0 };
+               FS_Path path = { PATH_ASCII, sizeof(dsp_filename), (u8*)dsp_filename };
 
-               rc = FSUSER_OpenFileDirectly(&rsrc, arch, path, FS_OPEN_READ, FS_ATTRIBUTE_NONE);
+               rc = FSUSER_OpenFileDirectly(&rsrc, arch, path, FS_OPEN_READ, 0);
                if (R_FAILED(rc)) break;
 
                u64 size = 0;
index 729a8ee364623b0f5c07952ab738342b17c88e7a..1706b7871d21fac061576b0dc2c0ab520fff29c2 100644 (file)
@@ -137,10 +137,10 @@ Result romfsInit(void)
                if (units == (size_t)-1) return 3;
                __utf16path[units] = 0;
 
-               FS_archive arch = { ARCH_SDMC, { PATH_EMPTY, 1, (u8*)"" }, 0, 0 };
-               FS_path path = { PATH_WCHAR, (units+1)*2, (u8*)__utf16path };
+               FS_Archive arch = { ARCHIVE_SDMC, { PATH_EMPTY, 1, (u8*)"" }, 0 };
+               FS_Path path = { PATH_UTF16, (units+1)*2, (u8*)__utf16path };
 
-               Result rc = FSUSER_OpenFileDirectly(&romFS_file, arch, path, FS_OPEN_READ, FS_ATTRIBUTE_NONE);
+               Result rc = FSUSER_OpenFileDirectly(&romFS_file, arch, path, FS_OPEN_READ, 0);
                if (R_FAILED(rc)) return rc;
 
                _3DSX_Header hdr;
@@ -155,10 +155,10 @@ Result romfsInit(void)
                u8 zeros[0xC];
                memset(zeros, 0, sizeof(zeros));
 
-               FS_archive arch = { ARCH_ROMFS, { PATH_EMPTY, 1, (u8*)"" }, 0, 0 };
-               FS_path path = { PATH_BINARY, sizeof(zeros), zeros };
+               FS_Archive arch = { ARCHIVE_ROMFS, { PATH_EMPTY, 1, (u8*)"" }, 0 };
+               FS_Path path = { PATH_BINARY, sizeof(zeros), zeros };
 
-               Result rc = FSUSER_OpenFileDirectly(&romFS_file, arch, path, FS_OPEN_READ, FS_ATTRIBUTE_NONE);
+               Result rc = FSUSER_OpenFileDirectly(&romFS_file, arch, path, FS_OPEN_READ, 0);
                if (R_FAILED(rc)) return rc;
        }
 
index 47037dc6abf491cbd3293f69acbf8c771891ecce..dc8d1242e09f075d291cca653b7c1f68e91c7ac3 100644 (file)
@@ -60,8 +60,8 @@ typedef struct
 /*! Open directory struct */
 typedef struct
 {
-  Handle    fd;         /*! CTRU handle */
-  FS_dirent entry_data; /*! Temporary storage for reading entries */
+  Handle    fd;                 /*! CTRU handle */
+  FS_DirectoryEntry entry_data; /*! Temporary storage for reading entries */
 } sdmc_dir_t;
 
 /*! SDMC devoptab */
@@ -97,9 +97,9 @@ sdmc_devoptab =
 };
 
 /*! SDMC archive handle */
-static FS_archive sdmcArchive =
+static FS_Archive sdmcArchive =
 {
-  .id = ARCH_SDMC,
+  .id = ARCHIVE_SDMC,
   .lowPath =
   {
     .type = PATH_EMPTY,
@@ -178,12 +178,12 @@ sdmc_fixpath(struct _reent *r,
   return __fixedpath;
 }
 
-static const FS_path
+static const FS_Path
 sdmc_utf16path(struct _reent *r,
                const char    *path)
 {
   size_t  units;
-  FS_path fspath;
+  FS_Path fspath;
 
   fspath.data = NULL;
 
@@ -205,7 +205,7 @@ sdmc_utf16path(struct _reent *r,
 
   __utf16path[units] = 0;
 
-  fspath.type = PATH_WCHAR;
+  fspath.type = PATH_UTF16;
   fspath.size = (units+1)*sizeof(uint16_t);
   fspath.data = (const u8*)__utf16path;
 
@@ -316,11 +316,11 @@ sdmc_open(struct _reent *r,
           int           flags,
           int           mode)
 {
-  Handle      fd;
-  Result      rc;
-  u32         sdmc_flags = 0;
-  u32         attributes = FS_ATTRIBUTE_NONE;
-  FS_path     fs_path;
+  Handle        fd;
+  Result        rc;
+  u32           sdmc_flags = 0;
+  u32           attributes = 0;
+  FS_Path       fs_path;
 
   fs_path = sdmc_utf16path(r, path);
   if(fs_path.data == NULL)
@@ -365,7 +365,7 @@ sdmc_open(struct _reent *r,
   /* Test O_EXCL. */
   if((flags & O_CREAT) && (flags & O_EXCL))
   {
-    rc = FSUSER_CreateFile(sdmcArchive, fs_path, 0);
+    rc = FSUSER_CreateFile(sdmcArchive, fs_path, attributes, 0);
     if(R_FAILED(rc))
     {
       r->_errno = sdmc_translate_error(rc);
@@ -662,14 +662,13 @@ sdmc_stat(struct _reent *r,
 {
   Handle  fd;
   Result  rc;
-  FS_path fs_path;
+  FS_Path fs_path;
 
   fs_path = sdmc_utf16path(r, file);
   if(fs_path.data == NULL)
     return -1;
 
-  if(R_SUCCEEDED(rc = FSUSER_OpenFile(&fd, sdmcArchive, fs_path,
-                           FS_OPEN_READ, FS_ATTRIBUTE_NONE)))
+  if(R_SUCCEEDED(rc = FSUSER_OpenFile(&fd, sdmcArchive, fs_path, FS_OPEN_READ, 0)))
   {
     sdmc_file_t tmpfd = { .fd = fd };
     rc = sdmc_fstat(r, (int)&tmpfd, st);
@@ -721,7 +720,7 @@ sdmc_unlink(struct _reent *r,
             const char    *name)
 {
   Result  rc;
-  FS_path fs_path;
+  FS_Path fs_path;
 
   fs_path = sdmc_utf16path(r, name);
   if(fs_path.data == NULL)
@@ -749,7 +748,7 @@ sdmc_chdir(struct _reent *r,
 {
   Handle  fd;
   Result  rc;
-  FS_path fs_path;
+  FS_Path fs_path;
 
   fs_path = sdmc_utf16path(r, name);
   if(fs_path.data == NULL)
@@ -782,7 +781,7 @@ sdmc_rename(struct _reent *r,
             const char    *newName)
 {
   Result  rc;
-  FS_path fs_path_old, fs_path_new;
+  FS_Path fs_path_old, fs_path_new;
   static uint16_t __utf16path_old[PATH_MAX+1];
 
   fs_path_old = sdmc_utf16path(r, oldName);
@@ -823,7 +822,7 @@ sdmc_mkdir(struct _reent *r,
            int           mode)
 {
   Result rc;
-  FS_path fs_path;
+  FS_Path fs_path;
 
   fs_path = sdmc_utf16path(r, path);
   if(fs_path.data == NULL)
@@ -831,7 +830,7 @@ sdmc_mkdir(struct _reent *r,
 
   /* TODO: Use mode to set directory attributes. */
 
-  rc = FSUSER_CreateDirectory(sdmcArchive, fs_path);
+  rc = FSUSER_CreateDirectory(sdmcArchive, fs_path, 0);
   if(R_SUCCEEDED(rc))
     return 0;
 
@@ -855,7 +854,7 @@ sdmc_diropen(struct _reent *r,
 {
   Handle  fd;
   Result  rc;
-  FS_path fs_path;
+  FS_Path fs_path;
 
   fs_path = sdmc_utf16path(r, path);
 
@@ -931,7 +930,7 @@ sdmc_dirnext(struct _reent *r,
 
     /* fill in the stat info */
     filestat->st_ino = 0;
-    if(dir->entry_data.isDirectory)
+    if(dir->entry_data.attributes & FS_ATTRIBUTE_DIRECTORY)
       filestat->st_mode = S_IFDIR;
     else
       filestat->st_mode = S_IFREG;
@@ -999,24 +998,21 @@ sdmc_statvfs(struct _reent  *r,
              struct statvfs *buf)
 {
   Result rc;
-  u32    clusterSize, numClusters, freeClusters;
-  u8    writable = 0;
+  FS_ArchiveResource resource;
+  bool writable = false;
 
-  rc = FSUSER_GetSdmcArchiveResource(NULL,
-                                     &clusterSize,
-                                     &numClusters,
-                                     &freeClusters);
+  rc = FSUSER_GetSdmcArchiveResource(&resource);
 
   if(R_SUCCEEDED(rc))
   {
-    buf->f_bsize   = clusterSize;
-    buf->f_frsize  = clusterSize;
-    buf->f_blocks  = numClusters;
-    buf->f_bfree   = freeClusters;
-    buf->f_bavail  = freeClusters;
+    buf->f_bsize   = resource.clusterSize;
+    buf->f_frsize  = resource.clusterSize;
+    buf->f_blocks  = resource.totalClusters;
+    buf->f_bfree   = resource.freeClusters;
+    buf->f_bavail  = resource.freeClusters;
     buf->f_files   = 0; //??? how to get
-    buf->f_ffree   = freeClusters;
-    buf->f_favail  = freeClusters;
+    buf->f_ffree   = resource.freeClusters;
+    buf->f_favail  = resource.freeClusters;
     buf->f_fsid    = 0; //??? how to get
     buf->f_flag    = ST_NOSUID;
     buf->f_namemax = 0; //??? how to get
@@ -1141,7 +1137,7 @@ sdmc_rmdir(struct _reent *r,
            const char    *name)
 {
   Result  rc;
-  FS_path fs_path;
+  FS_Path fs_path;
 
   fs_path = sdmc_utf16path(r, name);
   if(fs_path.data == NULL)
index 61864091eedca977656ef75a5da52a8e64082b0f..e949b36c7011dc7282b226f6a7b1a4c6fc70e42d 100644 (file)
@@ -20,9 +20,9 @@ Result fsInit(void)
        if (AtomicPostIncrement(&fsuRefCount)) return 0;
 
        ret = srvGetServiceHandle(&fsuHandle, "fs:USER");
-       if (R_SUCCEEDED(ret) && __get_handle_from_list("fs:USER")==0)
+       if (R_SUCCEEDED(ret) && __get_handle_from_list("fs:USER") == 0)
        {
-               ret = FSUSER_Initialize(fsuHandle);
+               ret = FSUSER_Initialize();
                if (R_FAILED(ret)) svcCloseHandle(fsuHandle);
        }
 
@@ -36,17 +36,31 @@ void fsExit(void)
        svcCloseHandle(fsuHandle);
 }
 
-Handle *fsGetSessionHandle(void)
+HandlefsGetSessionHandle(void)
 {
        return &fsuHandle;
 }
 
-FS_path fsMakePath(FS_pathType type, const char *path)
+Result FSUSER_Control(FS_Action action, void* input, u32 inputSize, void* output, u32 outputSize)
 {
-       return (FS_path){type, strlen(path)+1, (const u8*)path};
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x401,3,4); // 0x40100C4
+       cmdbuf[1] = action;
+       cmdbuf[2] = inputSize;
+       cmdbuf[3] = outputSize;
+       cmdbuf[4] = IPC_Desc_Buffer(inputSize, IPC_BUFFER_R);
+       cmdbuf[5] = (u32) input;
+       cmdbuf[6] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W);
+       cmdbuf[7] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
 }
 
-Result FSUSER_Initialize(Handle handle)
+Result FSUSER_Initialize(void)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
@@ -54,25 +68,25 @@ Result FSUSER_Initialize(Handle handle)
        cmdbuf[1] = IPC_Desc_CurProcessHandle();
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
        return cmdbuf[1];
 }
 
-Result FSUSER_OpenFile(Handle *out, FS_archive archive, FS_path fileLowPath, u32 openFlags, u32 attributes)
+Result FSUSER_OpenFile(Handle* out, FS_Archive archive, FS_Path path, u32 openFlags, u32 attributes)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x802,7,2); // 0x80201C2
        cmdbuf[1] = 0;
-       cmdbuf[2] = archive.handleLow;
-       cmdbuf[3] = archive.handleHigh;
-       cmdbuf[4] = fileLowPath.type;
-       cmdbuf[5] = fileLowPath.size;
+       cmdbuf[2] = (u32) archive.handle;
+       cmdbuf[3] = (u32) (archive.handle >> 32);
+       cmdbuf[4] = path.type;
+       cmdbuf[5] = path.size;
        cmdbuf[6] = openFlags;
        cmdbuf[7] = attributes;
-       cmdbuf[8] = IPC_Desc_StaticBuffer(fileLowPath.size,0);
-       cmdbuf[9] = (u32)fileLowPath.data;
+       cmdbuf[8] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[9] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -82,7 +96,7 @@ Result FSUSER_OpenFile(Handle *out, FS_archive archive, FS_path fileLowPath, u32
        return cmdbuf[1];
 }
 
-Result FSUSER_OpenFileDirectly(Handle *out, FS_archive archive, FS_path fileLowPath, u32 openFlags, u32 attributes)
+Result FSUSER_OpenFileDirectly(Handle* out, FS_Archive archive, FS_Path path, u32 openFlags, u32 attributes)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
@@ -91,14 +105,14 @@ Result FSUSER_OpenFileDirectly(Handle *out, FS_archive archive, FS_path fileLowP
        cmdbuf[2] = archive.id;
        cmdbuf[3] = archive.lowPath.type;
        cmdbuf[4] = archive.lowPath.size;
-       cmdbuf[5] = fileLowPath.type;
-       cmdbuf[6] = fileLowPath.size;
+       cmdbuf[5] = path.type;
+       cmdbuf[6] = path.size;
        cmdbuf[7] = openFlags;
        cmdbuf[8] = attributes;
-       cmdbuf[9] = IPC_Desc_StaticBuffer(archive.lowPath.size,2);
-       cmdbuf[10] = (u32)archive.lowPath.data;
-       cmdbuf[11] = IPC_Desc_StaticBuffer(fileLowPath.size,0);
-       cmdbuf[12] = (u32)fileLowPath.data;
+       cmdbuf[9] = IPC_Desc_StaticBuffer(archive.lowPath.size, 2);
+       cmdbuf[10] = (u32) archive.lowPath.data;
+       cmdbuf[11] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[12] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -108,18 +122,18 @@ Result FSUSER_OpenFileDirectly(Handle *out, FS_archive archive, FS_path fileLowP
        return cmdbuf[1];
 }
 
-Result FSUSER_DeleteFile(FS_archive archive, FS_path fileLowPath)
+Result FSUSER_DeleteFile(FS_Archive archive, FS_Path path)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x804,5,2); // 0x8040142
        cmdbuf[1] = 0;
-       cmdbuf[2] = archive.handleLow;
-       cmdbuf[3] = archive.handleHigh;
-       cmdbuf[4] = fileLowPath.type;
-       cmdbuf[5] = fileLowPath.size;
-       cmdbuf[6] = IPC_Desc_StaticBuffer(fileLowPath.size ,0);
-       cmdbuf[7] = (u32)fileLowPath.data;
+       cmdbuf[2] = (u32) archive.handle;
+       cmdbuf[3] = (u32) (archive.handle >> 32);
+       cmdbuf[4] = path.type;
+       cmdbuf[5] = path.size;
+       cmdbuf[6] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[7] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -127,24 +141,24 @@ Result FSUSER_DeleteFile(FS_archive archive, FS_path fileLowPath)
        return cmdbuf[1];
 }
 
-Result FSUSER_RenameFile(FS_archive srcArchive, FS_path srcFileLowPath, FS_archive destArchive, FS_path destFileLowPath)
+Result FSUSER_RenameFile(FS_Archive srcArchive, FS_Path srcPath, FS_Archive dstArchive, FS_Path dstPath)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x805,9,4); // 0x8050244
        cmdbuf[1] = 0;
-       cmdbuf[2] = srcArchive.handleLow;
-       cmdbuf[3] = srcArchive.handleHigh;
-       cmdbuf[4] = srcFileLowPath.type;
-       cmdbuf[5] = srcFileLowPath.size;
-       cmdbuf[6] = destArchive.handleLow;
-       cmdbuf[7] = destArchive.handleHigh;
-       cmdbuf[8] = destFileLowPath.type;
-       cmdbuf[9] = destFileLowPath.size;
-       cmdbuf[10] = IPC_Desc_StaticBuffer(srcFileLowPath.size,1);
-       cmdbuf[11] = (u32)srcFileLowPath.data;
-       cmdbuf[12] = IPC_Desc_StaticBuffer(destFileLowPath.size,2);
-       cmdbuf[13] = (u32)destFileLowPath.data;
+       cmdbuf[2] = (u32) srcArchive.handle;
+       cmdbuf[3] = (u32) (srcArchive.handle >> 32);
+       cmdbuf[4] = srcPath.type;
+       cmdbuf[5] = srcPath.size;
+       cmdbuf[6] = (u32) dstArchive.handle;
+       cmdbuf[7] = (u32) (dstArchive.handle >> 32);
+       cmdbuf[8] = dstPath.type;
+       cmdbuf[9] = dstPath.size;
+       cmdbuf[10] = IPC_Desc_StaticBuffer(srcPath.size, 1);
+       cmdbuf[11] = (u32) srcPath.data;
+       cmdbuf[12] = IPC_Desc_StaticBuffer(dstPath.size, 2);
+       cmdbuf[13] = (u32) dstPath.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -152,18 +166,18 @@ Result FSUSER_RenameFile(FS_archive srcArchive, FS_path srcFileLowPath, FS_archi
        return cmdbuf[1];
 }
 
-Result FSUSER_DeleteDirectory(FS_archive archive, FS_path dirLowPath)
+Result FSUSER_DeleteDirectory(FS_Archive archive, FS_Path path)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x806,5,2); // 0x8060142
        cmdbuf[1] = 0;
-       cmdbuf[2] = archive.handleLow;
-       cmdbuf[3] = archive.handleHigh;
-       cmdbuf[4] = dirLowPath.type;
-       cmdbuf[5] = dirLowPath.size;
-       cmdbuf[6] = IPC_Desc_StaticBuffer(dirLowPath.size,0);
-       cmdbuf[7] = (u32)dirLowPath.data;
+       cmdbuf[2] = (u32) archive.handle;
+       cmdbuf[3] = (u32) (archive.handle >> 32);
+       cmdbuf[4] = path.type;
+       cmdbuf[5] = path.size;
+       cmdbuf[6] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[7] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -171,18 +185,18 @@ Result FSUSER_DeleteDirectory(FS_archive archive, FS_path dirLowPath)
        return cmdbuf[1];
 }
 
-Result FSUSER_DeleteDirectoryRecursively(FS_archive archive, FS_path dirLowPath)
+Result FSUSER_DeleteDirectoryRecursively(FS_Archive archive, FS_Path path)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x807,5,2); // 0x8070142
        cmdbuf[1] = 0;
-       cmdbuf[2] = archive.handleLow;
-       cmdbuf[3] = archive.handleHigh;
-       cmdbuf[4] = dirLowPath.type;
-       cmdbuf[5] = dirLowPath.size;
-       cmdbuf[6] = IPC_Desc_StaticBuffer(dirLowPath.size,0);
-       cmdbuf[7] = (u32)dirLowPath.data;
+       cmdbuf[2] = (u32) archive.handle;
+       cmdbuf[3] = (u32) (archive.handle >> 32);
+       cmdbuf[4] = path.type;
+       cmdbuf[5] = path.size;
+       cmdbuf[6] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[7] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -190,21 +204,21 @@ Result FSUSER_DeleteDirectoryRecursively(FS_archive archive, FS_path dirLowPath)
        return cmdbuf[1];
 }
 
-Result FSUSER_CreateFile(FS_archive archive, FS_path fileLowPath, u32 fileSize)
+Result FSUSER_CreateFile(FS_Archive archive, FS_Path path, u32 attributes, u64 fileSize)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0]  = IPC_MakeHeader(0x808,8,2); // 0x8080202
-       cmdbuf[1]  = 0;
-       cmdbuf[2]  = archive.handleLow;
-       cmdbuf[3]  = archive.handleHigh;
-       cmdbuf[4]  = fileLowPath.type;
-       cmdbuf[5]  = fileLowPath.size;
-       cmdbuf[6]  = 0;
-       cmdbuf[7]  = fileSize;
-       cmdbuf[8]  = 0;
-       cmdbuf[9]  = IPC_Desc_StaticBuffer(fileLowPath.size,0);
-       cmdbuf[10] = (u32)fileLowPath.data;
+       cmdbuf[0] = IPC_MakeHeader(0x808,8,2); // 0x8080202
+       cmdbuf[1] = 0;
+       cmdbuf[2] = (u32) archive.handle;
+       cmdbuf[3] = (u32) (archive.handle >> 32);
+       cmdbuf[4] = path.type;
+       cmdbuf[5] = path.size;
+       cmdbuf[6] = attributes;
+       cmdbuf[7] = (u32) fileSize;
+       cmdbuf[8] = (u32) (fileSize >> 32);
+       cmdbuf[9] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[10] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -212,19 +226,19 @@ Result FSUSER_CreateFile(FS_archive archive, FS_path fileLowPath, u32 fileSize)
        return cmdbuf[1];
 }
 
-Result FSUSER_CreateDirectory(FS_archive archive, FS_path dirLowPath)
+Result FSUSER_CreateDirectory(FS_Archive archive, FS_Path path, u32 attributes)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x809,6,2); // 0x8090182
        cmdbuf[1] = 0;
-       cmdbuf[2] = archive.handleLow;
-       cmdbuf[3] = archive.handleHigh;
-       cmdbuf[4] = dirLowPath.type;
-       cmdbuf[5] = dirLowPath.size;
-       cmdbuf[6] = 0;
-       cmdbuf[7] = IPC_Desc_StaticBuffer(dirLowPath.size,0);
-       cmdbuf[8] = (u32)dirLowPath.data;
+       cmdbuf[2] = (u32) archive.handle;
+       cmdbuf[3] = (u32) (archive.handle >> 32);
+       cmdbuf[4] = path.type;
+       cmdbuf[5] = path.size;
+       cmdbuf[6] = attributes;
+       cmdbuf[7] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[8] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -232,24 +246,24 @@ Result FSUSER_CreateDirectory(FS_archive archive, FS_path dirLowPath)
        return cmdbuf[1];
 }
 
-Result FSUSER_RenameDirectory(FS_archive srcArchive, FS_path srcDirLowPath, FS_archive destArchive, FS_path destDirLowPath)
+Result FSUSER_RenameDirectory(FS_Archive srcArchive, FS_Path srcPath, FS_Archive dstArchive, FS_Path dstPath)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x80A,9,4); // 0x80A0244
        cmdbuf[1] = 0;
-       cmdbuf[2] = srcArchive.handleLow;
-       cmdbuf[3] = srcArchive.handleHigh;
-       cmdbuf[4] = srcDirLowPath.type;
-       cmdbuf[5] = srcDirLowPath.size;
-       cmdbuf[6] = destArchive.handleLow;
-       cmdbuf[7] = destArchive.handleHigh;
-       cmdbuf[8] = destDirLowPath.type;
-       cmdbuf[9] = destDirLowPath.size;
-       cmdbuf[10] = IPC_Desc_StaticBuffer(srcDirLowPath.size,1);
-       cmdbuf[11] = (u32)srcDirLowPath.data;
-       cmdbuf[12] = IPC_Desc_StaticBuffer(destDirLowPath.size,2);
-       cmdbuf[13] = (u32)destDirLowPath.data;
+       cmdbuf[2] = (u32) srcArchive.handle;
+       cmdbuf[3] = (u32) (srcArchive.handle >> 32);
+       cmdbuf[4] = srcPath.type;
+       cmdbuf[5] = srcPath.size;
+       cmdbuf[6] = (u32) dstArchive.handle;
+       cmdbuf[7] = (u32) (dstArchive.handle >> 32);
+       cmdbuf[8] = dstPath.type;
+       cmdbuf[9] = dstPath.size;
+       cmdbuf[10] = IPC_Desc_StaticBuffer(srcPath.size, 1);
+       cmdbuf[11] = (u32) srcPath.data;
+       cmdbuf[12] = IPC_Desc_StaticBuffer(dstPath.size, 2);
+       cmdbuf[13] = (u32) dstPath.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -257,17 +271,17 @@ Result FSUSER_RenameDirectory(FS_archive srcArchive, FS_path srcDirLowPath, FS_a
        return cmdbuf[1];
 }
 
-Result FSUSER_OpenDirectory(Handle *out, FS_archive archive, FS_path dirLowPath)
+Result FSUSER_OpenDirectory(Handle* out, FS_Archive archive, FS_Path path)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x80B,4,2); // 0x80B0102
-       cmdbuf[1] = archive.handleLow;
-       cmdbuf[2] = archive.handleHigh;
-       cmdbuf[3] = dirLowPath.type;
-       cmdbuf[4] = dirLowPath.size;
-       cmdbuf[5] = IPC_Desc_StaticBuffer(dirLowPath.size,0);
-       cmdbuf[6] = (u32)dirLowPath.data;
+       cmdbuf[1] = (u32) archive.handle;
+       cmdbuf[2] = (u32) (archive.handle >> 32);
+       cmdbuf[3] = path.type;
+       cmdbuf[4] = path.size;
+       cmdbuf[5] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[6] = (u32) path.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
@@ -277,7 +291,7 @@ Result FSUSER_OpenDirectory(Handle *out, FS_archive archive, FS_path dirLowPath)
        return cmdbuf[1];
 }
 
-Result FSUSER_OpenArchive(FS_archive *archive)
+Result FSUSER_OpenArchive(FS_Archive* archive)
 {
        if(!archive) return -2;
 
@@ -287,35 +301,85 @@ Result FSUSER_OpenArchive(FS_archive *archive)
        cmdbuf[1] = archive->id;
        cmdbuf[2] = archive->lowPath.type;
        cmdbuf[3] = archive->lowPath.size;
-       cmdbuf[4] = IPC_Desc_StaticBuffer(archive->lowPath.size,0);
-       cmdbuf[5] = (u32)archive->lowPath.data;
+       cmdbuf[4] = IPC_Desc_StaticBuffer(archive->lowPath.size, 0);
+       cmdbuf[5] = (u32) archive->lowPath.data;
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       archive->handleLow  = cmdbuf[2];
-       archive->handleHigh = cmdbuf[3];
+       archive->handle = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_ControlArchive(FS_Archive archive, FS_ArchiveAction action, void* input, u32 inputSize, void* output, u32 outputSize)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x80D,5,4); // 0x80D0144
+       cmdbuf[1] = (u32) archive.handle;
+       cmdbuf[2] = (u32) (archive.handle >> 32);
+       cmdbuf[3] = action;
+       cmdbuf[4] = inputSize;
+       cmdbuf[5] = outputSize;
+       cmdbuf[6] = IPC_Desc_Buffer(inputSize, IPC_BUFFER_R);
+       cmdbuf[7] = (u32) input;
+       cmdbuf[8] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W);
+       cmdbuf[9] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
        return cmdbuf[1];
 }
 
-Result FSUSER_CloseArchive(FS_archive *archive)
+Result FSUSER_CloseArchive(FS_Archive* archive)
 {
        if(!archive) return -2;
 
        u32 *cmdbuf = getThreadCommandBuffer();
 
        cmdbuf[0] = IPC_MakeHeader(0x80E,2,0); // 0x80E0080
-       cmdbuf[1] = archive->handleLow;
-       cmdbuf[2] = archive->handleHigh;
+       cmdbuf[1] = (u32) archive->handle;
+       cmdbuf[2] = (u32) (archive->handle >> 32);
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetFreeBytes(u64* freeBytes, FS_Archive archive)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x812,2,0); // 0x8120080
+       cmdbuf[1] = (u32) archive.handle;
+       cmdbuf[2] = (u32) (archive.handle >> 32);
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(freeBytes) *freeBytes = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetCardType(FS_CardType* type)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x813,0,0); // 0x8130000
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
+       if(type) *type = cmdbuf[2] & 0xFF;
+
        return cmdbuf[1];
 }
 
-Result FSUSER_GetSdmcArchiveResource(u32 *sectorSize, u32 *clusterSize, u32 *numClusters, u32 *freeClusters)
+Result FSUSER_GetSdmcArchiveResource(FS_ArchiveResource* archiveResource)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
@@ -324,15 +388,12 @@ Result FSUSER_GetSdmcArchiveResource(u32 *sectorSize, u32 *clusterSize, u32 *num
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(sectorSize) *sectorSize = cmdbuf[2];
-       if(clusterSize) *clusterSize = cmdbuf[3];
-       if(numClusters) *numClusters = cmdbuf[4];
-       if(freeClusters) *freeClusters = cmdbuf[5];
+       if(archiveResource) memcpy(archiveResource, &cmdbuf[2], sizeof(FS_ArchiveResource));
 
        return cmdbuf[1];
 }
 
-Result FSUSER_GetNandArchiveResource(u32 *sectorSize, u32 *clusterSize, u32 *numClusters, u32 *freeClusters)
+Result FSUSER_GetNandArchiveResource(FS_ArchiveResource* archiveResource)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
@@ -341,43 +402,40 @@ Result FSUSER_GetNandArchiveResource(u32 *sectorSize, u32 *clusterSize, u32 *num
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(sectorSize) *sectorSize = cmdbuf[2];
-       if(clusterSize) *clusterSize = cmdbuf[3];
-       if(numClusters) *numClusters = cmdbuf[4];
-       if(freeClusters) *freeClusters = cmdbuf[5];
+       if(archiveResource) memcpy(archiveResource, &cmdbuf[2], sizeof(FS_ArchiveResource));
 
        return cmdbuf[1];
 }
 
-Result FSUSER_IsSdmcDetected(u8 *detected)
+Result FSUSER_GetSdmcFatfsError(u32* error)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x817,0,0); // 0x8170000
+       cmdbuf[0] = IPC_MakeHeader(0x816,0,0); // 0x8160000
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(detected) *detected = cmdbuf[2] & 0xFF;
+       if(error) *error = cmdbuf[2];
 
        return cmdbuf[1];
 }
 
-Result FSUSER_GetMediaType(u8* mediatype)
+Result FSUSER_IsSdmcDetected(bool *detected)
 {
-       u32cmdbuf = getThreadCommandBuffer();
+       u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x868,0,0); // 0x8680000
+       cmdbuf[0] = IPC_MakeHeader(0x817,0,0); // 0x8170000
 
        Result ret = 0;
        if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(mediatype) *mediatype = cmdbuf[2] & 0xFF;
+       if(detected) *detected = cmdbuf[2] & 0xFF;
 
        return cmdbuf[1];
 }
 
-Result FSUSER_IsSdmcWritable(u8 *writable)
+Result FSUSER_IsSdmcWritable(bool *writable)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
@@ -391,155 +449,1313 @@ Result FSUSER_IsSdmcWritable(u8 *writable)
        return cmdbuf[1];
 }
 
-Result FSFILE_Close(Handle handle)
+Result FSUSER_GetSdmcCid(u8* out, u32 length)
 {
-       u32cmdbuf = getThreadCommandBuffer();
+       u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x808,0,0); // 0x8080000
+       cmdbuf[0] = IPC_MakeHeader(0x819,1,2); // 0x8190042
+       cmdbuf[1] = length;
+       cmdbuf[2] = IPC_Desc_Buffer(length, IPC_BUFFER_W);
+       cmdbuf[3] = (u32) out;
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       ret = cmdbuf[1];
-       if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
+       return cmdbuf[1];
+}
 
-       return ret;
+Result FSUSER_GetNandCid(u8* out, u32 length)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x81A,1,2); // 0x81A0042
+       cmdbuf[1] = length;
+       cmdbuf[2] = IPC_Desc_Buffer(length, IPC_BUFFER_W);
+       cmdbuf[3] = (u32) out;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
 }
 
-Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, void *buffer, u32 size)
+Result FSUSER_GetSdmcSpeedInfo(u32 *speedInfo)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x802,3,2); // 0x80200C2
-       cmdbuf[1] = (u32)offset;
-       cmdbuf[2] = (u32)(offset >> 32);
-       cmdbuf[3] = size;
-       cmdbuf[4] = IPC_Desc_Buffer(size,IPC_BUFFER_W);
-       cmdbuf[5] = (u32)buffer;
+       cmdbuf[0] = IPC_MakeHeader(0x81B,0,0); // 0x81B0000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(bytesRead) *bytesRead = cmdbuf[2];
+       if(speedInfo) *speedInfo = cmdbuf[2];
 
        return cmdbuf[1];
 }
 
-Result FSFILE_Write(Handle handle, u32 *bytesWritten, u64 offset, const void *buffer, u32 size, u32 flushFlags)
+Result FSUSER_GetNandSpeedInfo(u32 *speedInfo)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x803,4,2); // 0x8030102
-       cmdbuf[1] = (u32)offset;
-       cmdbuf[2] = (u32)(offset >> 32);
-       cmdbuf[3] = size;
-       cmdbuf[4] = flushFlags;
-       cmdbuf[5] = IPC_Desc_Buffer(size,IPC_BUFFER_R);
-       cmdbuf[6] = (u32)buffer;
+       cmdbuf[0] = IPC_MakeHeader(0x81C,0,0); // 0x81C0000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(bytesWritten) *bytesWritten = cmdbuf[2];
+       if(speedInfo) *speedInfo = cmdbuf[2];
 
        return cmdbuf[1];
 }
 
-Result FSFILE_GetSize(Handle handle, u64 *size)
+Result FSUSER_GetSdmcLog(u8* out, u32 length)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x804,0,0); // 0x8040000
+       cmdbuf[0] = IPC_MakeHeader(0x81D,1,2); // 0x81D0042
+       cmdbuf[1] = length;
+       cmdbuf[2] = IPC_Desc_Buffer(length, IPC_BUFFER_W);
+       cmdbuf[3] = (u32) out;
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetNandLog(u8* out, u32 length)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x81E,1,2); // 0x81E0042
+       cmdbuf[1] = length;
+       cmdbuf[2] = IPC_Desc_Buffer(length, IPC_BUFFER_W);
+       cmdbuf[3] = (u32) out;
 
-       if(size) *size = (u64)cmdbuf[2] | ((u64)cmdbuf[3] << 32);
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
        return cmdbuf[1];
 }
 
-Result FSFILE_SetSize(Handle handle, u64 size)
+Result FSUSER_ClearSdmcLog(void)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x805,2,0); // 0x8050080
-       cmdbuf[1] = (u32)size;
-       cmdbuf[2] = (u32)(size >> 32);
+       cmdbuf[0] = IPC_MakeHeader(0x81F,0,0); // 0x81F0000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
        return cmdbuf[1];
 }
 
-Result FSFILE_GetAttributes(Handle handle, u32 *attributes)
+Result FSUSER_ClearNandLog(void)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x806,0,0); // 0x8060000
+       cmdbuf[0] = IPC_MakeHeader(0x820,0,0); // 0x8200000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(attributes) *attributes = cmdbuf[2];
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardSlotIsInserted(bool* inserted)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x821,0,0); // 0x8210000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(inserted) *inserted = cmdbuf[2] & 0xFF;
 
        return cmdbuf[1];
 }
 
-Result FSFILE_SetAttributes(Handle handle, u32 attributes)
+Result FSUSER_CardSlotPowerOn(bool* status)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x807,1,0); // 0x8070040
-       cmdbuf[1] = attributes;
+       cmdbuf[0] = IPC_MakeHeader(0x822,0,0); // 0x8220000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(status) *status = cmdbuf[2] & 0xFF;
 
        return cmdbuf[1];
 }
 
-Result FSFILE_Flush(Handle handle)
+Result FSUSER_CardSlotPowerOff(bool* status)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x809,0,0); // 0x8090000
+       cmdbuf[0] = IPC_MakeHeader(0x823,0,0); // 0x8230000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(status) *status = cmdbuf[2] & 0xFF;
 
        return cmdbuf[1];
 }
 
-Result FSDIR_Read(Handle handle, u32 *entriesRead, u32 entryCount, FS_dirent *buffer)
+Result FSUSER_CardSlotGetCardIFPowerStatus(bool* status)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x801,1,2); // 0x8010042
-       cmdbuf[1] = entryCount;
-       cmdbuf[2] = IPC_Desc_Buffer(entryCount*0x228,IPC_BUFFER_W);
-       cmdbuf[3] = (u32)buffer;
+       cmdbuf[0] = IPC_MakeHeader(0x824,0,0); // 0x8240000
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       if(entriesRead) *entriesRead = cmdbuf[2];
+       if(status) *status = cmdbuf[2] & 0xFF;
 
        return cmdbuf[1];
 }
 
-Result FSDIR_Close(Handle handle)
+Result FSUSER_CardNorDirectCommand(u8 commandId)
 {
        u32 *cmdbuf = getThreadCommandBuffer();
 
-       cmdbuf[0] = IPC_MakeHeader(0x802,0,0); // 0x8020000
+       cmdbuf[0] = IPC_MakeHeader(0x825,1,0); // 0x8250040
+       cmdbuf[1] = commandId;
 
        Result ret = 0;
-       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
 
-       ret = cmdbuf[1];
-       if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
+       return cmdbuf[1];
+}
 
-       return ret;
+Result FSUSER_CardNorDirectCommandWithAddress(u8 commandId, u32 address)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x826,2,0); // 0x8260080
+       cmdbuf[1] = commandId;
+       cmdbuf[2] = address;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectRead(u8 commandId, u32 size, u8* output)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x827,2,2); // 0x8270082
+       cmdbuf[1] = commandId;
+       cmdbuf[2] = size;
+       cmdbuf[3] = IPC_Desc_Buffer(size * sizeof(u32), IPC_BUFFER_W);
+       cmdbuf[4] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectReadWithAddress(u8 commandId, u32 address, u32 size, u8* output)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x828,3,2); // 0x82800C2
+       cmdbuf[1] = commandId;
+       cmdbuf[2] = address;
+       cmdbuf[3] = size;
+       cmdbuf[4] = IPC_Desc_Buffer(size * sizeof(u32), IPC_BUFFER_W);
+       cmdbuf[5] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectWrite(u8 commandId, u32 size, u8* input)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x829,2,2); // 0x8290082
+       cmdbuf[1] = commandId;
+       cmdbuf[2] = size;
+       cmdbuf[3] = IPC_Desc_Buffer(size * sizeof(u32), IPC_BUFFER_R);
+       cmdbuf[4] = (u32) input;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectWriteWithAddress(u8 commandId, u32 address, u32 size, u8* input)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x82A,3,2); // 0x82A00C2
+       cmdbuf[1] = commandId;
+       cmdbuf[2] = address;
+       cmdbuf[3] = size;
+       cmdbuf[4] = IPC_Desc_Buffer(size * sizeof(u32), IPC_BUFFER_R);
+       cmdbuf[5] = (u32) input;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectRead_4xIO(u8 commandId, u32 address, u32 size, u8* output)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x82B,3,2); // 0x82B00C2
+       cmdbuf[1] = commandId;
+       cmdbuf[2] = address;
+       cmdbuf[3] = size;
+       cmdbuf[4] = IPC_Desc_Buffer(size * sizeof(u32), IPC_BUFFER_W);
+       cmdbuf[5] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectCpuWriteWithoutVerify(u32 address, u32 size, u8* input)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x82C,2,2); // 0x82C0082
+       cmdbuf[1] = address;
+       cmdbuf[2] = size;
+       cmdbuf[3] = IPC_Desc_Buffer(size * sizeof(u32), IPC_BUFFER_R);
+       cmdbuf[4] = (u32) input;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CardNorDirectSectorEraseWithoutVerify(u32 address)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x82D,1,0); // 0x82D0040
+       cmdbuf[1] = address;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetProductInfo(FS_ProductInfo* info, u32 processId)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x82E,1,0); // 0x82E0040
+       cmdbuf[1] = processId;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(info) memcpy(info, &cmdbuf[2], sizeof(FS_ProductInfo));
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetProgramLaunchInfo(FS_ProgramInfo* info, u32 processId)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x82F,1,0); // 0x82F0040
+       cmdbuf[1] = processId;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(info) memcpy(info, &cmdbuf[2], sizeof(FS_ProgramInfo));
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SetCardSpiBaudRate(FS_CardSpiBaudRate baudRate)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x837,1,0); // 0x8370040
+       cmdbuf[1] = baudRate;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SetCardSpiBusMode(FS_CardSpiBusMode busMode)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x838,1,0); // 0x8380040
+       cmdbuf[1] = busMode;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SendInitializeInfoTo9(void)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x839,0,0); // 0x8390000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetSpecialContentIndex(u16* index, FS_MediaType mediaType, u64 programId, FS_SpecialContentType type)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x83A,4,0); // 0x83A0100
+       cmdbuf[1] = mediaType;
+       cmdbuf[2] = (u32) programId;
+       cmdbuf[3] = (u32) (programId >> 32);
+       cmdbuf[4] = type;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(index) *index = cmdbuf[2] & 0xFFFF;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetLegacyRomHeader(FS_MediaType mediaType, u64 programId, u8* header)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x83B,3,2); // 0x83B00C2
+       cmdbuf[1] = mediaType;
+       cmdbuf[2] = (u32) programId;
+       cmdbuf[3] = (u32) (programId >> 32);
+       cmdbuf[4] = IPC_Desc_Buffer(0x3B4, IPC_BUFFER_W);
+       cmdbuf[5] = (u32) header;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetLegacyBannerData(FS_MediaType mediaType, u64 programId, u8* banner)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x83C,3,2); // 0x83C00C2
+       cmdbuf[1] = mediaType;
+       cmdbuf[2] = (u32) programId;
+       cmdbuf[3] = (u32) (programId >> 32);
+       cmdbuf[4] = IPC_Desc_Buffer(0x23C0, IPC_BUFFER_W);
+       cmdbuf[5] = (u32) banner;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CheckAuthorityToAccessExtSaveData(bool* access, FS_MediaType mediaType, u64 saveId, u32 processId)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x83D,4,0); // 0x83D0100
+       cmdbuf[1] = mediaType;
+       cmdbuf[2] = (u32) saveId;
+       cmdbuf[3] = (u32) (saveId >> 32);
+       cmdbuf[4] = processId;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(access) *access = cmdbuf[2] & 0xFF;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_QueryTotalQuotaSize(u64* quotaSize, u32 directories, u32 files, u32 fileSizeCount, u64* fileSizes)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x83E,3,2); // 0x83E00C2
+       cmdbuf[1] = directories;
+       cmdbuf[2] = files;
+       cmdbuf[3] = fileSizeCount;
+       cmdbuf[4] = IPC_Desc_Buffer(fileSizeCount * 8, IPC_BUFFER_R);
+       cmdbuf[5] = (u32) fileSizes;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(quotaSize) *quotaSize = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_AbnegateAccessRight(u32 accessRight)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x840,1,0); // 0x8400040
+       cmdbuf[1] = accessRight;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_DeleteSdmcRoot(void)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x841,0,0); // 0x8410000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_DeleteAllExtSaveDataOnNand(void)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x842,1,0); // 0x8420040
+       cmdbuf[1] = 0;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_InitializeCtrFileSystem(void)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x843,0,0); // 0x8430000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CreateSeed(void)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x844,0,0); // 0x8440000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetFormatInfo(u32* totalSize, u32* directories, u32* files, bool* duplicateData, FS_ArchiveID archiveId, FS_Path path)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x845,3,2); // 0x84500C2
+       cmdbuf[1] = archiveId;
+       cmdbuf[2] = path.type;
+       cmdbuf[3] = path.size;
+       cmdbuf[4] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[5] = (u32) path.data;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(totalSize) *totalSize = cmdbuf[2];
+       if(directories) *directories = cmdbuf[3];
+       if(files) *files = cmdbuf[4];
+       if(duplicateData) *duplicateData = cmdbuf[5] & 0xFF;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetLegacyRomHeader2(u32 headerSize, FS_MediaType mediaType, u64 programId, u8* header)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x846,4,2); // 0x8460102
+       cmdbuf[1] = headerSize;
+       cmdbuf[2] = mediaType;
+       cmdbuf[3] = (u32) programId;
+       cmdbuf[4] = (u32) (programId >> 32);
+       cmdbuf[5] = IPC_Desc_Buffer(headerSize, IPC_BUFFER_W);
+       cmdbuf[6] = (u32) header;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetSdmcCtrRootPath(u8* out, u32 length)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x848,1,2); // 0x8480042
+       cmdbuf[1] = length;
+       cmdbuf[2] = IPC_Desc_Buffer(length, IPC_BUFFER_W);
+       cmdbuf[3] = (u32) out;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetArchiveResource(FS_ArchiveResource* archiveResource, FS_MediaType mediaType)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x849,1,0); // 0x8490040
+       cmdbuf[1] = mediaType;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(archiveResource) memcpy(archiveResource, &cmdbuf[2], sizeof(FS_ArchiveResource));
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_ExportIntegrityVerificationSeed(FS_IntegrityVerificationSeed* seed)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x84A,0,2); // 0x84A0002
+       cmdbuf[2] = IPC_Desc_Buffer(sizeof(FS_IntegrityVerificationSeed), IPC_BUFFER_W);
+       cmdbuf[3] = (u32) seed;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_ImportIntegrityVerificationSeed(FS_IntegrityVerificationSeed* seed)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x84B,0,2); // 0x84B0002
+       cmdbuf[2] = IPC_Desc_Buffer(sizeof(FS_IntegrityVerificationSeed), IPC_BUFFER_R);
+       cmdbuf[3] = (u32) seed;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_FormatSaveData(FS_ArchiveID archiveId, FS_Path path, u32 blocks, u32 directories, u32 files, u32 directoryBuckets, u32 fileBuckets, bool duplicateData)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x84C,9,2); // 0x84C0242
+       cmdbuf[1] = archiveId;
+       cmdbuf[2] = path.type;
+       cmdbuf[3] = path.size;
+       cmdbuf[4] = blocks;
+       cmdbuf[5] = directories;
+       cmdbuf[6] = files;
+       cmdbuf[7] = directoryBuckets;
+       cmdbuf[8] = fileBuckets;
+       cmdbuf[9] = duplicateData;
+       cmdbuf[10] = IPC_Desc_StaticBuffer(path.size, 0);
+       cmdbuf[11] = (u32) path.data;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetLegacySubBannerData(u32 bannerSize, FS_MediaType mediaType, u64 programId, u8* banner)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x84D,4,2); // 0x84D0102
+       cmdbuf[1] = bannerSize;
+       cmdbuf[2] = mediaType;
+       cmdbuf[3] = (u32) programId;
+       cmdbuf[4] = (u32) (programId >> 32);
+       cmdbuf[5] = IPC_Desc_Buffer(bannerSize, IPC_BUFFER_W);
+       cmdbuf[6] = (u32) banner;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_ReadSpecialFile(u32* bytesRead, u64 fileOffset, u32 size, u8* data)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x84F,4,2); // 0x84F0102
+       cmdbuf[1] = 0;
+       cmdbuf[2] = (u32) fileOffset;
+       cmdbuf[3] = (u32) (fileOffset >> 32);
+       cmdbuf[4] = size;
+       cmdbuf[5] = IPC_Desc_Buffer(size, IPC_BUFFER_W);
+       cmdbuf[6] = (u32) data;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(bytesRead) *bytesRead = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetSpecialFileSize(u64* fileSize)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x850,1,0); // 0x8500040
+       cmdbuf[1] = 0;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(fileSize) *fileSize = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CreateExtSaveData(FS_ExtSaveDataInfo info, u32 directories, u32 files, u64 sizeLimit, u32 smdhSize, u8* smdh)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x851,9,2); // 0x8510242
+       memcpy(&cmdbuf[1], &info, sizeof(FS_ExtSaveDataInfo));
+       cmdbuf[5] = directories;
+       cmdbuf[6] = files;
+       cmdbuf[7] = (u32) sizeLimit;
+       cmdbuf[8] = (u32) (sizeLimit >> 32);
+       cmdbuf[9] = smdhSize;
+       cmdbuf[10] = IPC_Desc_Buffer(smdhSize, IPC_BUFFER_R);
+       cmdbuf[11] = (u32) smdh;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_DeleteExtSaveData(FS_ExtSaveDataInfo info)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x852,4,0); // 0x8520100
+       memcpy(&cmdbuf[1], &info, sizeof(FS_ExtSaveDataInfo));
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_ReadExtSaveDataIcon(u32* bytesRead, FS_ExtSaveDataInfo info, u32 smdhSize, u8* smdh)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x853,5,2); // 0x8530142
+       memcpy(&cmdbuf[1], &info, sizeof(FS_ExtSaveDataInfo));
+       cmdbuf[5] = smdhSize;
+       cmdbuf[6] = IPC_Desc_Buffer(smdhSize, IPC_BUFFER_W);
+       cmdbuf[7] = (u32) smdh;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(bytesRead) *bytesRead = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetExtDataBlockSize(u64* totalBlocks, u64* freeBlocks, u32* blockSize, FS_ExtSaveDataInfo info)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x854,4,0); // 0x8540100
+       memcpy(&cmdbuf[1], &info, sizeof(FS_ExtSaveDataInfo));
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(totalBlocks) *totalBlocks = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
+       if(freeBlocks) *freeBlocks = cmdbuf[4] | ((u64) cmdbuf[5] << 32);
+       if(blockSize) *blockSize = cmdbuf[6];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_EnumerateExtSaveData(u32* idsWritten, u32 idsSize, FS_MediaType mediaType, u32 idSize, bool shared, u8* ids)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x855,4,2); // 0x8550102
+       cmdbuf[1] = idsSize;
+       cmdbuf[2] = mediaType;
+       cmdbuf[3] = idSize;
+       cmdbuf[4] = shared;
+       cmdbuf[5] = IPC_Desc_Buffer(idsSize, IPC_BUFFER_W);
+       cmdbuf[6] = (u32) ids;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(idsWritten) *idsWritten = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_CreateSystemSaveData(FS_SystemSaveDataInfo info, u32 totalSize, u32 blockSize, u32 directories, u32 files, u32 directoryBuckets, u32 fileBuckets, bool duplicateData)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x856,9,0); // 0x8560240
+       memcpy(&cmdbuf[1], &info, sizeof(FS_SystemSaveDataInfo));
+       cmdbuf[3] = totalSize;
+       cmdbuf[4] = blockSize;
+       cmdbuf[5] = directories;
+       cmdbuf[6] = files;
+       cmdbuf[7] = directoryBuckets;
+       cmdbuf[8] = fileBuckets;
+       cmdbuf[9] = duplicateData;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_DeleteSystemSaveData(FS_SystemSaveDataInfo info)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x857,2,0); // 0x8570080
+       memcpy(&cmdbuf[1], &info, sizeof(FS_SystemSaveDataInfo));
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_StartDeviceMoveAsSource(FS_DeviceMoveContext* context)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x858,0,0); // 0x8580000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(context) memcpy(context, &cmdbuf[2], sizeof(FS_DeviceMoveContext));
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_StartDeviceMoveAsDestination(FS_DeviceMoveContext context, bool clear)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x859,9,0); // 0x8590240
+       memcpy(&cmdbuf[1], &context, sizeof(FS_DeviceMoveContext));
+       cmdbuf[9] = clear;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SetArchivePriority(FS_Archive archive, u32 priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x85A,3,0); // 0x85A00C0
+       cmdbuf[1] = (u32) archive.handle;
+       cmdbuf[2] = (u32) (archive.handle >> 32);
+       cmdbuf[3] = priority;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetArchivePriority(u32* priority, FS_Archive archive)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x85B,2,0); // 0x85B0080
+       cmdbuf[1] = (u32) archive.handle;
+       cmdbuf[2] = (u32) (archive.handle >> 32);
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(priority) *priority = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SetCtrCardLatencyParameter(u64 latency, bool emulateEndurance)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x85C,3,0); // 0x85C00C0
+       cmdbuf[1] = (u32) latency;
+       cmdbuf[2] = (u32) (latency >> 32);
+       cmdbuf[3] = emulateEndurance;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SwitchCleanupInvalidSaveData(bool enable)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x85F,1,0); // 0x85F0040
+       cmdbuf[1] = enable;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_EnumerateSystemSaveData(u32* idsWritten, u32 idsSize, u64* ids)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x860,1,2); // 0x8600042
+       cmdbuf[1] = idsSize;
+       cmdbuf[2] = IPC_Desc_Buffer(idsSize, IPC_BUFFER_W);
+       cmdbuf[3] = (u32) ids;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(idsWritten) *idsWritten = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_InitializeWithSdkVersion(u32 version)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x861,1,2); // 0x8610042
+       cmdbuf[1] = version;
+       cmdbuf[2] = IPC_Desc_CurProcessHandle();
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SetPriority(u32 priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x862,1,0); // 0x8620040
+       cmdbuf[1] = priority;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetPriority(u32* priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x863,0,0); // 0x8630000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(priority) *priority = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_SetSaveDataSecureValue(u64 value, FS_SecureValueSlot slot, u32 titleUniqueId, u8 titleVariation)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x865,5,0); // 0x8650140
+       cmdbuf[1] = (u32) value;
+       cmdbuf[2] = (u32) (value >> 32);
+       cmdbuf[3] = slot;
+       cmdbuf[4] = titleUniqueId;
+       cmdbuf[5] = titleVariation;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetSaveDataSecureValue(bool* exists, u64* value, FS_SecureValueSlot slot, u32 titleUniqueId, u8 titleVariation)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x866,3,0); // 0x86600C0
+       cmdbuf[1] = slot;
+       cmdbuf[2] = titleUniqueId;
+       cmdbuf[3] = titleVariation;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(exists) *exists = cmdbuf[2] & 0xFF;
+       if(value) *value = cmdbuf[3] | ((u64) cmdbuf[4] << 32);
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_ControlSecureSave(FS_SecureSaveAction action, void* input, u32 inputSize, void* output, u32 outputSize)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x867,3,4); // 0x86700C4
+       cmdbuf[1] = action;
+       cmdbuf[2] = inputSize;
+       cmdbuf[3] = outputSize;
+       cmdbuf[4] = IPC_Desc_Buffer(inputSize, IPC_BUFFER_R);
+       cmdbuf[5] = (u32) input;
+       cmdbuf[6] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W);
+       cmdbuf[7] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSUSER_GetMediaType(FS_MediaType* mediaType)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x868,0,0); // 0x8680000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(fsuHandle))) return ret;
+
+       if(mediaType) *mediaType = cmdbuf[2] & 0xFF;
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_Control(Handle handle, FS_FileAction action, void* input, u32 inputSize, void* output, u32 outputSize)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x401,3,4); // 0x40100C4
+       cmdbuf[1] = action;
+       cmdbuf[2] = inputSize;
+       cmdbuf[3] = outputSize;
+       cmdbuf[4] = IPC_Desc_Buffer(inputSize, IPC_BUFFER_R);
+       cmdbuf[5] = (u32) input;
+       cmdbuf[6] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W);
+       cmdbuf[7] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_OpenSubFile(Handle handle, Handle* subFile, u64 offset, u64 size)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x801,4,0); // 0x8010100
+       cmdbuf[1] = (u32) offset;
+       cmdbuf[2] = (u32) (offset >> 32);
+       cmdbuf[3] = (u32) size;
+       cmdbuf[4] = (u32) (size >> 32);
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(subFile) *subFile = cmdbuf[3];
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_Read(Handle handle, u32* bytesRead, u64 offset, void* buffer, u32 size)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x802,3,2); // 0x80200C2
+       cmdbuf[1] = (u32) offset;
+       cmdbuf[2] = (u32) (offset >> 32);
+       cmdbuf[3] = size;
+       cmdbuf[4] = IPC_Desc_Buffer(size, IPC_BUFFER_W);
+       cmdbuf[5] = (u32) buffer;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(bytesRead) *bytesRead = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_Write(Handle handle, u32* bytesWritten, u64 offset, const void* buffer, u32 size, u32 flags)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x803,4,2); // 0x8030102
+       cmdbuf[1] = (u32) offset;
+       cmdbuf[2] = (u32) (offset >> 32);
+       cmdbuf[3] = size;
+       cmdbuf[4] = flags;
+       cmdbuf[5] = IPC_Desc_Buffer(size, IPC_BUFFER_R);
+       cmdbuf[6] = (u32) buffer;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(bytesWritten) *bytesWritten = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_GetSize(Handle handle, u64* size)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x804,0,0); // 0x8040000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(size) *size = cmdbuf[2] | ((u64) cmdbuf[3] << 32);
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_SetSize(Handle handle, u64 size)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x805,2,0); // 0x8050080
+       cmdbuf[1] = (u32) size;
+       cmdbuf[2] = (u32) (size >> 32);
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_GetAttributes(Handle handle, u32* attributes)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x806,0,0); // 0x8060000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(attributes) *attributes = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_SetAttributes(Handle handle, u32 attributes)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x807,1,0); // 0x8070040
+       cmdbuf[1] = attributes;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_Close(Handle handle)
+{
+       u32* cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x808,0,0); // 0x8080000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       ret = cmdbuf[1];
+       if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
+
+       return ret;
+}
+
+Result FSFILE_Flush(Handle handle)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x809,0,0); // 0x8090000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_SetPriority(Handle handle, u32 priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x80A,1,0); // 0x80A0040
+       cmdbuf[1] = priority;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_GetPriority(Handle handle, u32* priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x80B,0,0); // 0x80B0000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(priority) *priority = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSFILE_OpenLinkFile(Handle handle, Handle* linkFile)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x80C,0,0); // 0x80C0000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(linkFile) *linkFile = cmdbuf[3];
+
+       return cmdbuf[1];
+}
+
+Result FSDIR_Control(Handle handle, FS_DirectoryAction action, void* input, u32 inputSize, void* output, u32 outputSize)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x401,3,4); // 0x40100C4
+       cmdbuf[1] = action;
+       cmdbuf[2] = inputSize;
+       cmdbuf[3] = outputSize;
+       cmdbuf[4] = IPC_Desc_Buffer(inputSize, IPC_BUFFER_R);
+       cmdbuf[5] = (u32) input;
+       cmdbuf[6] = IPC_Desc_Buffer(outputSize, IPC_BUFFER_W);
+       cmdbuf[7] = (u32) output;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSDIR_Read(Handle handle, u32* entriesRead, u32 entryCount, FS_DirectoryEntry* entries)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x801,1,2); // 0x8010042
+       cmdbuf[1] = entryCount;
+       cmdbuf[2] = IPC_Desc_Buffer(entryCount * sizeof(FS_DirectoryEntry), IPC_BUFFER_W);
+       cmdbuf[3] = (u32) entries;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(entriesRead) *entriesRead = cmdbuf[2];
+
+       return cmdbuf[1];
+}
+
+Result FSDIR_Close(Handle handle)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x802,0,0); // 0x8020000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       ret = cmdbuf[1];
+       if(R_SUCCEEDED(ret)) ret = svcCloseHandle(handle);
+
+       return ret;
+}
+
+Result FSDIR_SetPriority(Handle handle, u32 priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x803,1,0); // 0x8030040
+       cmdbuf[1] = priority;
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       return cmdbuf[1];
+}
+
+Result FSDIR_GetPriority(Handle handle, u32* priority)
+{
+       u32 *cmdbuf = getThreadCommandBuffer();
+
+       cmdbuf[0] = IPC_MakeHeader(0x804,0,0); // 0x8040000
+
+       Result ret = 0;
+       if(R_FAILED(ret = svcSendSyncRequest(handle))) return ret;
+
+       if(priority) *priority = cmdbuf[2];
+
+       return cmdbuf[1];
 }