mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
account: Updated for new-ipc. Renamed the username field in AccountProfileBase to nickname. Fixed various param types, and also removed the output bool from accountGetLastOpenedUser. Added struct AccountUid for proper userIDs, which replaces u128-userIDs. Added accountUidIsValid. Added accountSetServiceType()/AccountServiceType. Improved docs and minor improvements.
env: Updated UserIdStorage handling for using AccountUid.
This commit is contained in:
parent
040b33c457
commit
95f91c431c
@ -6,6 +6,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/acc.h"
|
||||
|
||||
/// Structure representing an entry in the homebrew environment configuration.
|
||||
typedef struct {
|
||||
@ -114,4 +115,4 @@ bool envHasRandomSeed(void);
|
||||
void envGetRandomSeed(u64 out[2]);
|
||||
|
||||
/// Returns a pointer to the user id storage area (if present).
|
||||
u128* envGetUserIdStorage(void);
|
||||
AccountUid* envGetUserIdStorage(void);
|
||||
|
@ -6,37 +6,60 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "sm.h"
|
||||
#include "../sf/service.h"
|
||||
|
||||
#define ACC_USER_LIST_SIZE 8
|
||||
|
||||
typedef enum {
|
||||
AccountServiceType_NotInitialized = 0, ///< Same as ::AccountServiceType_Application during \ref accountInitialize.
|
||||
AccountServiceType_Application = 1, ///< Initializes acc:u0.
|
||||
AccountServiceType_System = 2, ///< Initializes acc:u1.
|
||||
AccountServiceType_Administrator = 3, ///< Initializes acc:su.
|
||||
} AccountServiceType;
|
||||
|
||||
/// Profile
|
||||
typedef struct {
|
||||
Service s;
|
||||
Service s; ///< IProfile
|
||||
} AccountProfile;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 unk_x0;
|
||||
/// Account UserId.
|
||||
typedef struct {
|
||||
u64 uid[2]; ///< UserId. All-zero is invalid / Uid not set. See also \ref accountUidIsValid.
|
||||
} AccountUid;
|
||||
|
||||
/// UserData
|
||||
typedef struct {
|
||||
u32 unk_x0; ///< Unknown.
|
||||
u32 iconID; ///< Icon ID. 0 = Mii, the rest are character icon IDs.
|
||||
u8 iconBackgroundColorID; ///< Profile icon background color ID
|
||||
u8 unk_x9[0x7];
|
||||
u8 unk_x9[0x7]; ///< Unknown.
|
||||
u8 miiID[0x10]; ///< Some ID related to the Mii? All zeros when a character icon is used.
|
||||
u8 unk_x20[0x60]; ///< Usually zeros?
|
||||
} PACKED AccountUserData;
|
||||
} AccountUserData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u128 userID;
|
||||
/// ProfileBase
|
||||
typedef struct {
|
||||
AccountUid userID; ///< \ref AccountUid
|
||||
u64 lastEditTimestamp; ///< POSIX UTC timestamp, for the last account edit.
|
||||
char username[0x20]; ///< UTF-8 Username.
|
||||
} PACKED AccountProfileBase;
|
||||
char nickname[0x20]; ///< UTF-8 Nickname.
|
||||
} AccountProfileBase;
|
||||
|
||||
/**
|
||||
* @brief Sets the \ref AccountServiceType for initialization. Call this function before \ref accountInitialize, if needed.
|
||||
* @note By default ::AccountServiceType_NotInitialized will be used.
|
||||
*/
|
||||
void accountSetServiceType(AccountServiceType serviceType);
|
||||
|
||||
/// Initialize account.
|
||||
Result accountInitialize(void);
|
||||
|
||||
/// Exit account.
|
||||
void accountExit(void);
|
||||
|
||||
/// Gets the Service object for the actual account service session.
|
||||
Service* accountGetServiceSession(void);
|
||||
|
||||
/// Get the total number of user profiles
|
||||
/// Get the total number of user profiles.
|
||||
Result accountGetUserCount(s32* user_count);
|
||||
|
||||
/**
|
||||
@ -45,26 +68,35 @@ Result accountGetUserCount(s32* user_count);
|
||||
* @param max_userIDs Maximum number of user IDs to return.
|
||||
* @param actual_total The actual total number of user IDs found.
|
||||
*/
|
||||
Result accountListAllUsers(u128* userIDs, size_t max_userIDs, size_t *actual_total);
|
||||
Result accountListAllUsers(AccountUid* userIDs, s32 max_userIDs, s32 *actual_total);
|
||||
|
||||
/// Get the userID for the last opened user. The output userID is only valid when the output account_selected==1.
|
||||
Result accountGetLastOpenedUser(u128 *userID, bool *account_selected);
|
||||
/// Get the userID for the last opened user.
|
||||
Result accountGetLastOpenedUser(AccountUid *userID);
|
||||
|
||||
/// Get an AccountProfile for the specified userID.
|
||||
Result accountGetProfile(AccountProfile* out, u128 userID);
|
||||
Result accountGetProfile(AccountProfile* out, const AccountUid *userID);
|
||||
|
||||
/// Close the AccountProfile.
|
||||
void accountProfileClose(AccountProfile* profile);
|
||||
|
||||
/// Get \ref AccountUserData and \ref AccountProfileBase for the specified profile, userdata is optional (can be NULL).
|
||||
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase);
|
||||
|
||||
/// Get the icon image size.
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size);
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, u32* image_size);
|
||||
|
||||
/// Load the JPEG profile icon, valid for both Miis and character icons. The output image_size is the same as the one from \ref accountProfileGetImageSize.
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size);
|
||||
|
||||
void accountProfileClose(AccountProfile* profile);
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, u32* image_size);
|
||||
|
||||
/// Gets the userID which was selected by the profile-selector applet (if any), prior to launching the currently running Application title.
|
||||
/// This gets the cached PreselectedUser loaded during accountInitialize, when PreselectedUser is available.
|
||||
Result accountGetPreselectedUser(u128 *userID);
|
||||
Result accountGetPreselectedUser(AccountUid *userID);
|
||||
|
||||
/**
|
||||
* @brief Checks whether the specified \ref AccountUid is valid/set (non-zero).
|
||||
* @param[in] Uid \ref AccountUid
|
||||
*/
|
||||
NX_CONSTEXPR bool accountUidIsValid(const AccountUid *Uid) {
|
||||
return Uid->uid[0]!=0 || Uid->uid[1]!=0;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "services/sm.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/applet.h"
|
||||
#include "services/acc.h"
|
||||
|
||||
void NORETURN __nx_exit(Result rc, LoaderReturnFn retaddr);
|
||||
|
||||
@ -23,7 +24,7 @@ static char* g_nextLoadArgv = NULL;
|
||||
static Result g_lastLoadResult = 0;
|
||||
static bool g_hasRandomSeed = false;
|
||||
static u64 g_randomSeed[2] = { 0, 0 };
|
||||
static u128* g_userIdStorage = NULL;
|
||||
static AccountUid* g_userIdStorage = NULL;
|
||||
|
||||
extern __attribute__((weak)) u32 __nx_applet_type;
|
||||
|
||||
@ -104,7 +105,7 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr)
|
||||
break;
|
||||
|
||||
case EntryType_UserIdStorage:
|
||||
g_userIdStorage = (u128*)(uintptr_t)ent->Value[0];
|
||||
g_userIdStorage = (AccountUid*)(uintptr_t)ent->Value[0];
|
||||
break;
|
||||
|
||||
case EntryType_HosVersion:
|
||||
@ -222,6 +223,6 @@ void envGetRandomSeed(u64 out[2]) {
|
||||
out[1] = g_randomSeed[1];
|
||||
}
|
||||
|
||||
u128* envGetUserIdStorage(void) {
|
||||
AccountUid* envGetUserIdStorage(void) {
|
||||
return g_userIdStorage;
|
||||
}
|
||||
|
@ -1,37 +1,44 @@
|
||||
#define NX_SERVICE_ASSUME_NON_DOMAIN
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "service_guard.h"
|
||||
#include "services/acc.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/applet.h"
|
||||
#include "runtime/env.h"
|
||||
#include "runtime/hosversion.h"
|
||||
|
||||
static AccountServiceType g_accServiceType = AccountServiceType_NotInitialized;
|
||||
static Service g_accSrv;
|
||||
static u64 g_refCnt;
|
||||
static u128 g_accPreselectedUserID;
|
||||
static AccountUid g_accPreselectedUserID;
|
||||
static bool g_accPreselectedUserInitialized;
|
||||
|
||||
static Result _accountInitializeApplicationInfo(void);
|
||||
|
||||
static Result _accountGetPreselectedUser(u128 *userID);
|
||||
static Result _accountGetPreselectedUser(AccountUid *userID);
|
||||
|
||||
Result accountInitialize(void)
|
||||
{
|
||||
NX_GENERATE_SERVICE_GUARD(account);
|
||||
|
||||
void accountSetServiceType(AccountServiceType serviceType) {
|
||||
g_accServiceType = serviceType;
|
||||
}
|
||||
|
||||
Result _accountInitialize(void) {
|
||||
Result rc=0;
|
||||
Result rc2=0;
|
||||
u128 *userIdEnv = envGetUserIdStorage();
|
||||
AccountUid *userIdEnv = envGetUserIdStorage();
|
||||
|
||||
atomicIncrement64(&g_refCnt);
|
||||
|
||||
if (serviceIsActive(&g_accSrv))
|
||||
return 0;
|
||||
|
||||
rc = smGetService(&g_accSrv, "acc:u1");
|
||||
if (R_FAILED(rc)) {
|
||||
rc = smGetService(&g_accSrv, "acc:u0");
|
||||
if (R_SUCCEEDED(rc)) rc = _accountInitializeApplicationInfo();
|
||||
switch (g_accServiceType) {
|
||||
case AccountServiceType_NotInitialized:
|
||||
case AccountServiceType_Application:
|
||||
g_accServiceType = AccountServiceType_Application;
|
||||
rc = smGetService(&g_accSrv, "acc:u0");
|
||||
if (R_SUCCEEDED(rc)) rc = _accountInitializeApplicationInfo();
|
||||
break;
|
||||
case AccountServiceType_System:
|
||||
rc = smGetService(&g_accSrv, "acc:u1");
|
||||
break;
|
||||
case AccountServiceType_Administrator:
|
||||
rc = smGetService(&g_accSrv, "acc:su");
|
||||
break;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
@ -42,354 +49,128 @@ Result accountInitialize(void)
|
||||
}
|
||||
else if (userIdEnv) {
|
||||
g_accPreselectedUserID = *userIdEnv;
|
||||
if (g_accPreselectedUserID) g_accPreselectedUserInitialized = true;
|
||||
if (accountUidIsValid(&g_accPreselectedUserID)) g_accPreselectedUserInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) accountExit();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void accountExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0)
|
||||
serviceClose(&g_accSrv);
|
||||
void _accountCleanup(void) {
|
||||
serviceClose(&g_accSrv);
|
||||
g_accServiceType = AccountServiceType_NotInitialized;
|
||||
}
|
||||
|
||||
Service* accountGetServiceSession(void) {
|
||||
return &g_accSrv;
|
||||
}
|
||||
|
||||
static Result _accountCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
|
||||
return serviceDispatchOut(srv, cmd_id, *out);
|
||||
}
|
||||
|
||||
static Result _accountInitializeApplicationInfo(void) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 pid_placeholder;
|
||||
} *raw;
|
||||
|
||||
ipcSendPid(&c);
|
||||
|
||||
raw = serviceIpcPrepareHeader(&g_accSrv, &c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = hosversionBefore(6,0,0) ? 100 : 140;
|
||||
raw->pid_placeholder = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp;
|
||||
|
||||
serviceIpcParse(&g_accSrv, &r, sizeof(*resp));
|
||||
resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
u64 pid_placeholder=0;
|
||||
return serviceDispatchIn(&g_accSrv, hosversionBefore(6,0,0) ? 100 : 140, pid_placeholder,
|
||||
.in_send_pid = true,
|
||||
);
|
||||
}
|
||||
|
||||
Result accountGetUserCount(s32* user_count)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 user_count;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*user_count = resp->user_count;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result accountGetUserCount(s32* user_count) {
|
||||
return _accountCmdNoInOutU32(&g_accSrv, (u32*)user_count, 0);
|
||||
}
|
||||
|
||||
static Result _accountListAllUsers(u128* userIDs)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
static Result _accountListAllUsers(AccountUid* userIDs) {
|
||||
return serviceDispatch(&g_accSrv, 2,
|
||||
.buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { userIDs, sizeof(AccountUid)*ACC_USER_LIST_SIZE } },
|
||||
);
|
||||
}
|
||||
|
||||
Result accountListAllUsers(AccountUid* userIDs, s32 max_userIDs, s32 *actual_total) {
|
||||
Result rc=0;
|
||||
|
||||
size_t bufsize = ACC_USER_LIST_SIZE * sizeof(u128);
|
||||
|
||||
ipcAddRecvStatic(&c, userIDs, bufsize, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
|
||||
rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountListAllUsers(u128* userIDs, size_t max_userIDs, size_t *actual_total)
|
||||
{
|
||||
Result rc=0;
|
||||
u128 temp_userIDs[ACC_USER_LIST_SIZE];
|
||||
AccountUid temp_userIDs[ACC_USER_LIST_SIZE];
|
||||
memset(temp_userIDs, 0, sizeof(temp_userIDs));
|
||||
|
||||
rc = _accountListAllUsers(temp_userIDs);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
size_t total_userIDs;
|
||||
for (total_userIDs = 0; total_userIDs < ACC_USER_LIST_SIZE; total_userIDs++) {
|
||||
if (!temp_userIDs[total_userIDs])
|
||||
break;
|
||||
s32 total_userIDs;
|
||||
for (total_userIDs=0; total_userIDs<ACC_USER_LIST_SIZE; total_userIDs++) {
|
||||
if (!accountUidIsValid(&temp_userIDs[total_userIDs])) break;
|
||||
}
|
||||
|
||||
if (max_userIDs > total_userIDs) {
|
||||
max_userIDs = total_userIDs;
|
||||
}
|
||||
|
||||
memcpy(userIDs, temp_userIDs, sizeof(u128) * max_userIDs);
|
||||
memcpy(userIDs, temp_userIDs, sizeof(AccountUid)*max_userIDs);
|
||||
*actual_total = max_userIDs;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountGetLastOpenedUser(u128 *userID, bool *account_selected)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u128 userID;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && userID) {
|
||||
*userID = resp->userID;
|
||||
if (account_selected) {
|
||||
*account_selected = 0;
|
||||
if (*userID != 0) *account_selected = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result accountGetLastOpenedUser(AccountUid *userID) {
|
||||
return serviceDispatchOut(&g_accSrv, 4, *userID);
|
||||
}
|
||||
|
||||
Result accountGetProfile(AccountProfile* out, u128 userID) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u128 userID;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
raw->userID = userID;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_accSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(&out->s, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
Result accountGetProfile(AccountProfile* out, const AccountUid *userID) {
|
||||
return serviceDispatchIn(&g_accSrv, 5, *userID,
|
||||
.out_num_objects = 1,
|
||||
.out_objects = &out->s,
|
||||
);
|
||||
}
|
||||
|
||||
//IProfile implementation
|
||||
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
if (userdata) ipcAddRecvStatic(&c, userdata, sizeof(AccountUserData), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = userdata==NULL ? 1 : 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&profile->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
AccountProfileBase profilebase;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && profilebase) memcpy(profilebase, &resp->profilebase, sizeof(AccountProfileBase));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, size_t* image_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 10;
|
||||
|
||||
Result rc = serviceIpcDispatch(&profile->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 image_size;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*image_size = resp->image_size;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, size_t* image_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buf, len, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 11;
|
||||
|
||||
Result rc = serviceIpcDispatch(&profile->s);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 image_size;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*image_size = resp->image_size;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
// IProfile
|
||||
|
||||
void accountProfileClose(AccountProfile* profile) {
|
||||
serviceClose(&profile->s);
|
||||
}
|
||||
|
||||
static Result _accountGetPreselectedUser(u128 *userID) {
|
||||
static Result _accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
|
||||
return serviceDispatchOut(&profile->s, 0, *profilebase,
|
||||
.buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out },
|
||||
.buffers = { { userdata, sizeof(AccountUserData) } },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _accountProfileGetBase(AccountProfile* profile, AccountProfileBase* profilebase) {
|
||||
return serviceDispatchOut(&profile->s, 1, *profilebase);
|
||||
}
|
||||
|
||||
Result accountProfileGet(AccountProfile* profile, AccountUserData* userdata, AccountProfileBase* profilebase) {
|
||||
Result rc=0;
|
||||
|
||||
if (!serviceIsActive(&profile->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
if (userdata)
|
||||
rc = _accountProfileGet(profile, userdata, profilebase);
|
||||
else
|
||||
rc = _accountProfileGetBase(profile, profilebase);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountProfileGetImageSize(AccountProfile* profile, u32* image_size) {
|
||||
if (!serviceIsActive(&profile->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _accountCmdNoInOutU32(&profile->s, image_size, 10);
|
||||
}
|
||||
|
||||
Result accountProfileLoadImage(AccountProfile* profile, void* buf, size_t len, u32* image_size) {
|
||||
if (!serviceIsActive(&profile->s))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return serviceDispatchOut(&profile->s, 11, *image_size,
|
||||
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||
.buffers = { { buf, len } },
|
||||
);
|
||||
}
|
||||
|
||||
static Result _accountGetPreselectedUser(AccountUid *userID) {
|
||||
Result rc=0;
|
||||
AppletStorage storage;
|
||||
s64 tmpsize=0;
|
||||
@ -398,9 +179,9 @@ static Result _accountGetPreselectedUser(u128 *userID) {
|
||||
u32 magicnum;//These two fields must match fixed values.
|
||||
u8 unk_x4;
|
||||
u8 pad[3];
|
||||
u128 userID;
|
||||
AccountUid userID;
|
||||
u8 unk_x18[0x70];//unused
|
||||
} PACKED storagedata;
|
||||
} storagedata;
|
||||
|
||||
memset(&storagedata, 0, sizeof(storagedata));
|
||||
|
||||
@ -424,7 +205,7 @@ static Result _accountGetPreselectedUser(u128 *userID) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result accountGetPreselectedUser(u128 *userID) {
|
||||
Result accountGetPreselectedUser(AccountUid *userID) {
|
||||
if (!g_accPreselectedUserInitialized) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
*userID = g_accPreselectedUserID;
|
||||
|
Loading…
Reference in New Issue
Block a user