Skip to content

Commit

Permalink
Custom devoptab wrappers (part 1).
Browse files Browse the repository at this point in the history
This commit implements a devoptab wrapper for Partition FS sections within NCAs, using code from pfs.c/h.

Other changes include:

* codebase: use NX_IGNORE_ARG macro where needed.

* hfs: slight tweaks to some of the static functions.

* pfs: slight tweaks to some of the static functions.
* pfs: use pfsIsValidContext() where needed.

* utils: update utilsInitializeResources() to use __system_argc and __system_argv variables from libnx.

* todo: update text file.
  • Loading branch information
DarkMatterCore committed Dec 20, 2023
1 parent bfdd9e0 commit d402776
Show file tree
Hide file tree
Showing 21 changed files with 1,090 additions and 66 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ BUILD_TIMESTAMP := $(strip $(shell date --utc '+%Y-%m-%d %T UTC'))

TARGET := ${APP_TITLE}
BUILD := build
SOURCES := source source/core source/fatfs
SOURCES := source source/core source/fatfs source/devoptab
DATA := data
ICON := romfs/icon/${APP_TITLE}.jpg
INCLUDES := include include/core include/fatfs
INCLUDES := include include/core include/fatfs include/devoptab
ROMFS := romfs

BOREALIS_PATH := libs/borealis
Expand Down
24 changes: 14 additions & 10 deletions code_templates/nxdt_rw_poc.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "legal_info.h"
#include "cert.h"
#include "usb.h"
#include "nxdt_devoptab.h"

#define BLOCK_SIZE USB_TRANSFER_BUFFER_SIZE
#define WAIT_TIME_LIMIT 30
Expand Down Expand Up @@ -924,9 +925,12 @@ static char path[FS_MAX_PATH] = {0};

int main(int argc, char *argv[])
{
NX_IGNORE_ARG(argc);
NX_IGNORE_ARG(argv);

int ret = EXIT_SUCCESS;

if (!utilsInitializeResources(argc, (const char**)argv))
if (!utilsInitializeResources())
{
ret = EXIT_FAILURE;
goto end;
Expand Down Expand Up @@ -2323,7 +2327,7 @@ static bool resetSettings(void *userdata)

static bool saveGameCardImage(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

u64 gc_size = 0, free_space = 0;

Expand Down Expand Up @@ -2480,7 +2484,7 @@ static bool saveGameCardImage(void *userdata)

static bool saveGameCardHeader(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

GameCardHeader gc_header = {0};
bool success = false;
Expand Down Expand Up @@ -2514,7 +2518,7 @@ static bool saveGameCardHeader(void *userdata)

static bool saveGameCardCardInfo(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

GameCardInfo gc_cardinfo = {0};
bool success = false;
Expand Down Expand Up @@ -2548,7 +2552,7 @@ static bool saveGameCardCardInfo(void *userdata)

static bool saveGameCardCertificate(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

FsGameCardCertificate gc_cert = {0};
bool success = false;
Expand Down Expand Up @@ -2582,7 +2586,7 @@ static bool saveGameCardCertificate(void *userdata)

static bool saveGameCardInitialData(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

GameCardSecurityInformation gc_security_information = {0};
bool success = false;
Expand Down Expand Up @@ -2615,7 +2619,7 @@ static bool saveGameCardInitialData(void *userdata)
/* Instead, take a look at saveGameCardIdSet and saveGameCardUid which is a more standardised format of the Gamecard ID data. */
static bool saveGameCardSpecificData(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

GameCardSecurityInformation gc_security_information = {0};
bool success = false;
Expand Down Expand Up @@ -2643,7 +2647,7 @@ static bool saveGameCardSpecificData(void *userdata)

static bool saveGameCardIdSet(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

FsGameCardIdSet id_set = {0};
bool success = false;
Expand Down Expand Up @@ -2676,7 +2680,7 @@ static bool saveGameCardIdSet(void *userdata)

static bool saveGameCardUid(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

GameCardSecurityInformation gc_security_information = {0};
bool success = false;
Expand Down Expand Up @@ -2870,7 +2874,7 @@ static bool saveGameCardExtractedHfsPartition(HashFileSystemContext *hfs_ctx)

static bool saveConsoleLafwBlob(void *userdata)
{
(void)userdata;
NX_IGNORE_ARG(userdata);

u64 lafw_version = 0;
LotusAsicFirmwareBlob lafw_blob = {0};
Expand Down
5 changes: 4 additions & 1 deletion code_templates/xml_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ static void writeFile(void *buf, size_t buf_size, const char *path)

int main(int argc, char *argv[])
{
NX_IGNORE_ARG(argc);
NX_IGNORE_ARG(argv);

int ret = EXIT_SUCCESS;

if (!utilsInitializeResources(argc, (const char**)argv))
if (!utilsInitializeResources())
{
ret = EXIT_FAILURE;
goto out;
Expand Down
15 changes: 5 additions & 10 deletions include/core/hfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,18 @@ NX_INLINE bool hfsIsValidContext(HashFileSystemContext *ctx)

NX_INLINE u32 hfsGetEntryCount(HashFileSystemContext *ctx)
{
if (!ctx || !ctx->header_size || !ctx->header) return 0;
return ((HashFileSystemHeader*)ctx->header)->entry_count;
return (hfsIsValidContext(ctx) ? ((HashFileSystemHeader*)ctx->header)->entry_count : 0);
}

NX_INLINE HashFileSystemEntry *hfsGetEntryByIndex(HashFileSystemContext *ctx, u32 idx)
{
if (idx >= hfsGetEntryCount(ctx)) return NULL;
return (HashFileSystemEntry*)(ctx->header + sizeof(HashFileSystemHeader) + (idx * sizeof(HashFileSystemEntry)));
return (idx < hfsGetEntryCount(ctx) ? (HashFileSystemEntry*)(ctx->header + sizeof(HashFileSystemHeader) + (idx * sizeof(HashFileSystemEntry))) : NULL);
}

NX_INLINE char *hfsGetNameTable(HashFileSystemContext *ctx)
{
u32 entry_count = hfsGetEntryCount(ctx);
if (!entry_count) return NULL;
return (char*)(ctx->header + sizeof(HashFileSystemHeader) + (entry_count * sizeof(HashFileSystemEntry)));
return (entry_count ? (char*)(ctx->header + sizeof(HashFileSystemHeader) + (entry_count * sizeof(HashFileSystemEntry))) : NULL);
}

NX_INLINE char *hfsGetEntryName(HashFileSystemContext *ctx, HashFileSystemEntry *fs_entry)
Expand All @@ -135,15 +132,13 @@ NX_INLINE char *hfsGetEntryNameByIndex(HashFileSystemContext *ctx, u32 idx)
{
HashFileSystemEntry *fs_entry = hfsGetEntryByIndex(ctx, idx);
char *name_table = hfsGetNameTable(ctx);
if (!fs_entry || !name_table) return NULL;
return (name_table + fs_entry->name_offset);
return ((fs_entry && name_table) ? (name_table + fs_entry->name_offset) : NULL);
}

NX_INLINE HashFileSystemEntry *hfsGetEntryByName(HashFileSystemContext *ctx, const char *name)
{
u32 idx = 0;
if (!hfsGetEntryIndexByName(ctx, name, &idx)) return NULL;
return hfsGetEntryByIndex(ctx, idx);
return (hfsGetEntryIndexByName(ctx, name, &idx) ? hfsGetEntryByIndex(ctx, idx) : NULL);
}

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions include/core/nxdt_includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <dirent.h>
#include <assert.h>
#include <unistd.h>
Expand Down
2 changes: 1 addition & 1 deletion include/core/nxdt_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ typedef struct {

/// Resource initialization.
/// Called at program startup.
bool utilsInitializeResources(const int program_argc, const char **program_argv);
bool utilsInitializeResources(void);

/// Resource deinitialization.
/// Called at program exit.
Expand Down
31 changes: 15 additions & 16 deletions include/core/pfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,23 +112,27 @@ NX_INLINE void pfsFreeContext(PartitionFileSystemContext *ctx)
memset(ctx, 0, sizeof(PartitionFileSystemContext));
}

/// Checks if the provided PartitionFileSystemContext is valid.
NX_INLINE bool pfsIsValidContext(PartitionFileSystemContext *ctx)
{
return (ctx && ncaStorageIsValidContext(&(ctx->storage_ctx)) && ctx->nca_fs_ctx == ctx->storage_ctx.nca_fs_ctx && \
ctx->storage_ctx.base_storage_type == NcaStorageBaseStorageType_Regular && ctx->size && ctx->header_size && ctx->header);
}

NX_INLINE u32 pfsGetEntryCount(PartitionFileSystemContext *ctx)
{
if (!ctx || !ctx->header_size || !ctx->header) return 0;
return ((PartitionFileSystemHeader*)ctx->header)->entry_count;
return (pfsIsValidContext(ctx) ? ((PartitionFileSystemHeader*)ctx->header)->entry_count : 0);
}

NX_INLINE PartitionFileSystemEntry *pfsGetEntryByIndex(PartitionFileSystemContext *ctx, u32 idx)
{
if (idx >= pfsGetEntryCount(ctx)) return NULL;
return (PartitionFileSystemEntry*)(ctx->header + sizeof(PartitionFileSystemHeader) + (idx * sizeof(PartitionFileSystemEntry)));
return (idx < pfsGetEntryCount(ctx) ? (PartitionFileSystemEntry*)(ctx->header + sizeof(PartitionFileSystemHeader) + (idx * sizeof(PartitionFileSystemEntry))) : NULL);
}

NX_INLINE char *pfsGetNameTable(PartitionFileSystemContext *ctx)
{
u32 entry_count = pfsGetEntryCount(ctx);
if (!entry_count) return NULL;
return (char*)(ctx->header + sizeof(PartitionFileSystemHeader) + (entry_count * sizeof(PartitionFileSystemEntry)));
return (entry_count ? (char*)(ctx->header + sizeof(PartitionFileSystemHeader) + (entry_count * sizeof(PartitionFileSystemEntry))) : NULL);
}

NX_INLINE char *pfsGetEntryName(PartitionFileSystemContext *ctx, PartitionFileSystemEntry *fs_entry)
Expand All @@ -142,21 +146,18 @@ NX_INLINE char *pfsGetEntryNameByIndex(PartitionFileSystemContext *ctx, u32 idx)
{
PartitionFileSystemEntry *fs_entry = pfsGetEntryByIndex(ctx, idx);
char *name_table = pfsGetNameTable(ctx);
if (!fs_entry || !name_table) return NULL;
return (name_table + fs_entry->name_offset);
return ((fs_entry && name_table) ? (name_table + fs_entry->name_offset) : NULL);
}

NX_INLINE PartitionFileSystemEntry *pfsGetEntryByName(PartitionFileSystemContext *ctx, const char *name)
{
u32 idx = 0;
if (!pfsGetEntryIndexByName(ctx, name, &idx)) return NULL;
return pfsGetEntryByIndex(ctx, idx);
return (pfsGetEntryIndexByName(ctx, name, &idx) ? pfsGetEntryByIndex(ctx, idx) : NULL);
}

NX_INLINE void pfsWriteEntryPatchToMemoryBuffer(PartitionFileSystemContext *ctx, NcaHierarchicalSha256Patch *patch, void *buf, u64 buf_size, u64 buf_offset)
{
if (!ctx || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || ctx->nca_fs_ctx != ctx->storage_ctx.nca_fs_ctx || \
ctx->storage_ctx.base_storage_type != NcaStorageBaseStorageType_Regular) return;
if (!pfsIsValidContext(ctx)) return;
ncaWriteHierarchicalSha256PatchToMemoryBuffer(ctx->nca_fs_ctx->nca_ctx, patch, buf, buf_size, buf_offset);
}

Expand Down Expand Up @@ -187,15 +188,13 @@ NX_INLINE u32 pfsGetEntryCountFromImageContext(PartitionFileSystemImageContext *

NX_INLINE PartitionFileSystemEntry *pfsGetEntryByIndexFromImageContext(PartitionFileSystemImageContext *ctx, u32 idx)
{
if (idx >= pfsGetEntryCountFromImageContext(ctx)) return NULL;
return &(ctx->entries[idx]);
return (idx < pfsGetEntryCountFromImageContext(ctx) ? &(ctx->entries[idx]) : NULL);
}

NX_INLINE char *pfsGetEntryNameByIndexFromImageContext(PartitionFileSystemImageContext *ctx, u32 idx)
{
PartitionFileSystemEntry *fs_entry = pfsGetEntryByIndexFromImageContext(ctx, idx);
if (!fs_entry || !ctx->name_table) return NULL;
return (ctx->name_table + fs_entry->name_offset);
return ((fs_entry && ctx->name_table) ? (ctx->name_table + fs_entry->name_offset) : NULL);
}

#ifdef __cplusplus
Expand Down
104 changes: 104 additions & 0 deletions include/devoptab/nxdt_devoptab.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* nxdt_devoptab.h
*
* Copyright (c) 2020-2023, DarkMatterCore <[email protected]>.
*
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
*
* nxdumptool is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* nxdumptool is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#ifndef __NXDT_DEVOPTAB_H__
#define __NXDT_DEVOPTAB_H__

#include "pfs.h"
#include "hfs.h"
#include "romfs.h"

#ifdef __cplusplus
extern "C" {
#endif

#define DEVOPTAB_MOUNT_NAME_LENGTH 32 // Including NULL terminator.

#define DEVOPTAB_DECL_ERROR_STATE int _errno = 0
#define DEVOPTAB_DECL_DEV_CTX DevoptabDeviceContext *dev_ctx = (DevoptabDeviceContext*)r->deviceData
#define DEVOPTAB_DECL_FS_CTX(type) type *fs_ctx = (type*)dev_ctx->fs_ctx
#define DEVOPTAB_DECL_FILE_STATE(type) type *file = (type*)fd
#define DEVOPTAB_DECL_DIR_STATE(type) type *dir = (type*)dirState->dirStruct

#define DEVOPTAB_SET_ERROR(x) r->_errno = _errno = (x)
#define DEVOPTAB_IS_ERROR_SET (_errno != 0)

#define DEVOPTAB_EXIT goto end
#define DEVOPTAB_SET_ERROR_AND_EXIT(x) \
do { \
DEVOPTAB_SET_ERROR(x); \
DEVOPTAB_EXIT; \
} while(0)

#define DEVOPTAB_RETURN_INT(x) return (DEVOPTAB_IS_ERROR_SET ? -1 : (x))
#define DEVOPTAB_RETURN_PTR(x) return (DEVOPTAB_IS_ERROR_SET ? NULL : (x))
#define DEVOPTAB_RETURN_BOOL return (DEVOPTAB_IS_ERROR_SET ? false : true)
#define DEVOPTAB_RETURN_UNSUPPORTED_OP r->_errno = ENOSYS; \
return -1;

#define DEVOPTAB_INIT_VARS(type, decl) devoptabControlMutex(true); \
DEVOPTAB_DECL_ERROR_STATE; \
decl

#define DEVOPTAB_INIT_VARS_WITH_FILE_STATE(fs_type, file_type) DEVOPTAB_INIT_VARS(fs_type,); \
DEVOPTAB_DECL_FILE_STATE(file_type)

#define DEVOPTAB_INIT_VARS_WITH_DIR_STATE(fs_type, dir_type) DEVOPTAB_INIT_VARS(fs_type,); \
DEVOPTAB_DECL_DIR_STATE(dir_type)

#define DEVOPTAB_INIT_FS_ACCESS(type) DEVOPTAB_DECL_DEV_CTX; \
DEVOPTAB_DECL_FS_CTX(type)

#define DEVOPTAB_DEINIT_VARS devoptabControlMutex(false)

typedef struct {
bool initialized; ///< Device initialization flag.
char name[DEVOPTAB_MOUNT_NAME_LENGTH]; ///< Mount name string, without a trailing colon (:).
time_t mount_time; ///< Mount time.
devoptab_t device; ///< Devoptab virtual device interface. Provides a way to use libcstd I/O calls on the mounted filesystem.
void *fs_ctx; ///< Pointer to actual type-specific filesystem context (PartitionFileSystemContext, HashFileSystemContext, RomFileSystemContext).
} DevoptabDeviceContext;

/// Mounts a virtual Partition FS device using the provided Partition FS context and a mount name.
bool devoptabMountPartitionFileSystemDevice(PartitionFileSystemContext *pfs_ctx, const char *name);

/// Mounts a virtual Hash FS device using the provided Hash FS context and a mount name.
bool devoptabMountHashFileSystemDevice(HashFileSystemContext *hfs_ctx, const char *name);

/// Mounts a virtual RomFS device using the provided RomFS context and a mount name.
bool devoptabMountRomFileSystemDevice(RomFileSystemContext *romfs_ctx, const char *name);

/// Unmounts a previously mounted virtual device.
void devoptabUnmountDevice(const char *name);

/// Unmounts all previously mounted virtual devices.
void devoptabUnmountAllDevices(void);

/// (Un)locks the devoptab mutex. Used by filesystem-specific devoptab interfaces.
void devoptabControlMutex(bool lock);

#ifdef __cplusplus
}
#endif

#endif /* __NXDT_DEVOPTAB_H__ */
Loading

0 comments on commit d402776

Please sign in to comment.