Latest libnx changes, install screen elements, error handling, better sigpatches stuff

This commit is contained in:
Huntereb 2019-10-24 21:33:41 -04:00
parent 049004bea4
commit 2fe766af47
43 changed files with 369 additions and 3009 deletions

View File

@ -35,12 +35,12 @@ namespace tin::data
std::unique_ptr<BufferSegment[]> m_bufferSegments;
nx::ncm::ContentStorage* m_contentStorage;
NcmNcaId m_ncaId;
NcmContentId m_ncaId;
public:
static const int NUM_BUFFER_SEGMENTS = 4;
BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmNcaId ncaId, size_t totalDataSize);
BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmContentId ncaId, size_t totalDataSize);
void AppendData(void* source, size_t length);
bool CanAppendData(size_t length);

View File

@ -11,7 +11,7 @@ namespace tin::install::nsp
HTTPNSP(std::string url);
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId) override;
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmContentId placeholderId) override;
virtual void BufferData(void* buf, off_t offset, size_t size) override;
};
}

View File

@ -33,7 +33,7 @@ namespace tin::install
virtual void InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf);
virtual void InstallApplicationRecord();
virtual void InstallTicketCert() = 0;
virtual void InstallNCA(const NcmNcaId &ncaId) = 0;
virtual void InstallNCA(const NcmContentId &ncaId) = 0;
public:
virtual void Prepare();

View File

@ -15,7 +15,7 @@ namespace tin::install::nsp
protected:
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> ReadCNMT() override;
void InstallNCA(const NcmNcaId& ncaId) override;
void InstallNCA(const NcmContentId& ncaId) override;
void InstallTicketCert() override;
public:

View File

@ -14,7 +14,7 @@ namespace tin::install::nsp
protected:
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> ReadCNMT() override;
void InstallNCA(const NcmNcaId& ncaId) override;
void InstallNCA(const NcmContentId& ncaId) override;
void InstallTicketCert() override;
public:

View File

@ -18,7 +18,7 @@ namespace tin::install::nsp
RemoteNSP();
public:
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId) = 0;
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmContentId placeholderId) = 0;
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
virtual void RetrieveHeader();
@ -27,7 +27,7 @@ namespace tin::install::nsp
virtual const PFS0FileEntry* GetFileEntry(unsigned int index);
virtual const PFS0FileEntry* GetFileEntryByName(std::string name);
virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmNcaId& ncaId);
virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId);
virtual const PFS0FileEntry* GetFileEntryByExtension(std::string extension);
virtual const char* GetFileEntryName(const PFS0FileEntry* fileEntry);

View File

@ -1,19 +0,0 @@
#pragma once
#include <string>
#include "install/remote_nsp.hpp"
namespace tin::install::nsp
{
class USBNSP : public RemoteNSP
{
private:
std::string m_nspName;
public:
USBNSP(std::string nspName);
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId) override;
virtual void BufferData(void* buf, off_t offset, size_t size) override;
};
}

View File

@ -3,6 +3,8 @@
namespace inst::ui {
void setInstInfoText(std::string ourText);
void setInstBarPerc(double ourPercent);
void hideInstBar(bool hidden);
void loadMainMenu();
void loadInstallScreen();
}

View File

@ -8,6 +8,7 @@ typedef struct {
Result esInitialize();
void esExit();
Service* esGetServiceSession();
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize); //1
Result esDeleteTicket(const RightsId *rightsIdBuf, size_t bufSize); //3

View File

@ -1,37 +0,0 @@
/**
* @file usb_comms.h
* @brief USB comms.
* @author yellows8
* @author plutoo
* @copyright libnx Authors
*/
#pragma once
#include <switch/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/// Initializes usbComms with the default number of interfaces (1)
Result usbCommsInitialize(void);
/// Initializes usbComms with a specific number of interfaces.
Result usbCommsInitializeEx(u32 num_interfaces);
/// Exits usbComms.
void usbCommsExit(void);
/// Read data with the default interface.
size_t usbCommsRead(void* buffer, size_t size);
/// Write data with the default interface.
size_t usbCommsWrite(const void* buffer, size_t size);
/// Same as usbCommsRead except with the specified interface.
size_t usbCommsReadEx(void* buffer, size_t size, u32 interface);
/// Same as usbCommsWrite except with the specified interface.
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface);
#ifdef __cplusplus
}
#endif

View File

@ -1,265 +0,0 @@
/**
* @file usb.h
* @brief USB (usb:*) service IPC wrapper.
* @author SciresM, yellows8
* @copyright libnx Authors
*/
#pragma once
#include <switch/types.h>
#include <switch/services/sm.h>
#include <switch/kernel/event.h>
#ifdef __cplusplus
extern "C" {
#endif
/// usb:ds Switch-as-device<>host USB comms, see also here: http://switchbrew.org/index.php?title=USB_services
/// Names starting with "libusb" were changed to "usb" to avoid collision with actual libusb if it's ever used.
#define USBDS_DEFAULT_InterfaceNumber 0x4 ///Value for usb_interface_descriptor bInterfaceNumber for automatically allocating the actual bInterfaceNumber.
/// Imported from libusb with changed names.
/* Descriptor sizes per descriptor type */
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_DEVICE_SIZE 0x12
#define USB_DT_SS_ENDPOINT_COMPANION_SIZE 6
/// Imported from libusb, with some adjustments.
struct usb_endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType; /// Must match USB_DT_ENDPOINT.
uint8_t bEndpointAddress; /// Should be one of the usb_endpoint_direction values, the endpoint-number is automatically allocated.
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
};
/// Imported from libusb, with some adjustments.
struct usb_interface_descriptor {
uint8_t bLength;
uint8_t bDescriptorType; /// Must match USB_DT_INTERFACE.
uint8_t bInterfaceNumber; /// See also USBDS_DEFAULT_InterfaceNumber.
uint8_t bAlternateSetting; /// Must match 0.
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface; /// Ignored.
};
/// Imported from libusb, with some adjustments.
struct usb_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType; /// Must match USB_DT_Device.
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
};
/// Imported from libusb, with some adjustments.
struct usb_ss_endpoint_companion_descriptor {
uint8_t bLength;
uint8_t bDescriptorType; /// Must match USB_DT_SS_ENDPOINT_COMPANION.
uint8_t bMaxBurst;
uint8_t bmAttributes;
uint16_t wBytesPerInterval;
};
/// Imported from libusb, with some adjustments.
struct usb_string_descriptor {
uint8_t bLength;
uint8_t bDescriptorType; /// Must match USB_DT_STRING.
uint16_t wData[0x40];
};
typedef struct {
u16 idVendor; /// VID
u16 idProduct; /// PID
u16 bcdDevice;
char Manufacturer[0x20];
char Product[0x20];
char SerialNumber[0x20];
} UsbDsDeviceInfo;
typedef struct {
u32 id; /// urbId from post-buffer cmds
u32 requestedSize;
u32 transferredSize;
u32 urb_status;
} UsbDsReportEntry;
typedef struct {
UsbDsReportEntry report[8];
u32 report_count;
} UsbDsReportData;
typedef struct {
bool initialized;
u32 interface_index;
Service h;
Event SetupEvent;
Event CtrlInCompletionEvent;
Event CtrlOutCompletionEvent;
} UsbDsInterface;
typedef struct {
bool initialized;
Service h;
Event CompletionEvent;
} UsbDsEndpoint;
typedef enum {
UsbComplexId_Default = 0x2
} UsbComplexId;
typedef enum {
UsbDeviceSpeed_Full = 0x2,
UsbDeviceSpeed_High = 0x3,
UsbDeviceSpeed_Super = 0x4,
} UsbDeviceSpeed;
/// Imported from libusb, with changed names.
enum usb_class_code {
USB_CLASS_PER_INTERFACE = 0,
USB_CLASS_AUDIO = 1,
USB_CLASS_COMM = 2,
USB_CLASS_HID = 3,
USB_CLASS_PHYSICAL = 5,
USB_CLASS_PRINTER = 7,
USB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */
USB_CLASS_IMAGE = 6,
USB_CLASS_MASS_STORAGE = 8,
USB_CLASS_HUB = 9,
USB_CLASS_DATA = 10,
USB_CLASS_SMART_CARD = 0x0b,
USB_CLASS_CONTENT_SECURITY = 0x0d,
USB_CLASS_VIDEO = 0x0e,
USB_CLASS_PERSONAL_HEALTHCARE = 0x0f,
USB_CLASS_DIAGNOSTIC_DEVICE = 0xdc,
USB_CLASS_WIRELESS = 0xe0,
USB_CLASS_APPLICATION = 0xfe,
USB_CLASS_VENDOR_SPEC = 0xff
};
/// Imported from libusb, with changed names.
enum usb_descriptor_type {
USB_DT_DEVICE = 0x01,
USB_DT_CONFIG = 0x02,
USB_DT_STRING = 0x03,
USB_DT_INTERFACE = 0x04,
USB_DT_ENDPOINT = 0x05,
USB_DT_BOS = 0x0f,
USB_DT_DEVICE_CAPABILITY = 0x10,
USB_DT_HID = 0x21,
USB_DT_REPORT = 0x22,
USB_DT_PHYSICAL = 0x23,
USB_DT_HUB = 0x29,
USB_DT_SUPERSPEED_HUB = 0x2a,
USB_DT_SS_ENDPOINT_COMPANION = 0x30
};
/// Imported from libusb, with changed names.
enum usb_endpoint_direction {
USB_ENDPOINT_IN = 0x80,
USB_ENDPOINT_OUT = 0x00
};
/// Imported from libusb, with changed names.
enum usb_transfer_type {
USB_TRANSFER_TYPE_CONTROL = 0,
USB_TRANSFER_TYPE_ISOCHRONOUS = 1,
USB_TRANSFER_TYPE_BULK = 2,
USB_TRANSFER_TYPE_INTERRUPT = 3,
USB_TRANSFER_TYPE_BULK_STREAM = 4,
};
/// Imported from libusb, with changed names.
enum usb_iso_sync_type {
USB_ISO_SYNC_TYPE_NONE = 0,
USB_ISO_SYNC_TYPE_ASYNC = 1,
USB_ISO_SYNC_TYPE_ADAPTIVE = 2,
USB_ISO_SYNC_TYPE_SYNC = 3
};
/// Imported from libusb, with changed names.
enum usb_iso_usage_type {
USB_ISO_USAGE_TYPE_DATA = 0,
USB_ISO_USAGE_TYPE_FEEDBACK = 1,
USB_ISO_USAGE_TYPE_IMPLICIT = 2,
};
/// Opens a session with usb:ds.
Result usbDsInitialize(void);
/// Closes the usb:ds session. Any interfaces/endpoints which are left open are automatically closed, since otherwise usb-sysmodule won't fully reset usb:ds to defaults.
void usbDsExit(void);
/// Helpers
Result usbDsWaitReady(u64 timeout);
Result usbDsParseReportData(UsbDsReportData *reportdata, u32 urbId, u32 *requestedSize, u32 *transferredSize);
/// IDsService
// Do not provide API access to these functions, as they're handled by usbDsInitialize().
// Result usbDsBindDevice(UsbComplexId complexId);
// Result usbDsBindClientProcess(Handle prochandle);
Event* usbDsGetStateChangeEvent(void);
Result usbDsGetState(u32* out);
/// Removed in 5.0.0
Result usbDsGetDsInterface(UsbDsInterface** out, struct usb_interface_descriptor* descriptor, const char* interface_name);
Result usbDsSetVidPidBcd(const UsbDsDeviceInfo* deviceinfo);
/// Added in 5.0.0
Result usbDsRegisterInterface(UsbDsInterface** out, u32 intf_num);
Result usbDsClearDeviceData(void);
Result usbDsAddUsbStringDescriptor(u8* out_index, const char* string);
Result usbDsAddUsbLanguageStringDescriptor(u8* out_index, const u16* lang_ids, u16 num_langs);
Result usbDsDeleteUsbStringDescriptor(u8 index);
Result usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed speed, struct usb_device_descriptor* descriptor);
Result usbDsSetBinaryObjectStore(void* bos, size_t bos_size);
Result usbDsEnable(void);
Result usbDsDisable(void);
/// IDsInterface
void usbDsInterface_Close(UsbDsInterface* interface);
Result usbDsInterface_GetSetupPacket(UsbDsInterface* interface, void* buffer, size_t size);
Result usbDsInterface_EnableInterface(UsbDsInterface* interface);
Result usbDsInterface_DisableInterface(UsbDsInterface* interface);
Result usbDsInterface_CtrlInPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32* urbId);
Result usbDsInterface_CtrlOutPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32* urbId);
Result usbDsInterface_GetCtrlInReportData(UsbDsInterface* interface, UsbDsReportData* out);
Result usbDsInterface_GetCtrlOutReportData(UsbDsInterface* interface, UsbDsReportData* out);
Result usbDsInterface_StallCtrl(UsbDsInterface* interface);
/// Removed in 5.0.0
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor);
/// Added in 5.0.0
Result usbDsInterface_RegisterEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, u8 endpoint_address);
Result usbDsInterface_AppendConfigurationData(UsbDsInterface* interface, UsbDeviceSpeed speed, void* buffer, size_t size);
/// IDsEndpoint
void usbDsEndpoint_Close(UsbDsEndpoint* endpoint);
Result usbDsEndpoint_Cancel(UsbDsEndpoint* endpoint);
Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size_t size, u32* urbId);
Result usbDsEndpoint_GetReportData(UsbDsEndpoint* endpoint, UsbDsReportData* out);
Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint);
Result usbDsEndpoint_SetZlt(UsbDsEndpoint* endpoint, bool zlt);
#ifdef __cplusplus
}
#endif

View File

@ -25,12 +25,12 @@ namespace nx::ncm
ContentStorage(FsStorageId storageId);
~ContentStorage();
void CreatePlaceholder(const NcmNcaId &placeholderId, const NcmNcaId &registeredId, size_t size);
void DeletePlaceholder(const NcmNcaId &placeholderId);
void WritePlaceholder(const NcmNcaId &placeholderId, u64 offset, void *buffer, size_t bufSize);
void Register(const NcmNcaId &placeholderId, const NcmNcaId &registeredId);
void Delete(const NcmNcaId &registeredId);
bool Has(const NcmNcaId &registeredId);
std::string GetPath(const NcmNcaId &registeredId);
void CreatePlaceholder(const NcmContentId &placeholderId, const NcmContentId &registeredId, size_t size);
void DeletePlaceholder(const NcmContentId &placeholderId);
void WritePlaceholder(const NcmContentId &placeholderId, u64 offset, void *buffer, size_t bufSize);
void Register(const NcmContentId &placeholderId, const NcmContentId &registeredId);
void Delete(const NcmContentId &registeredId);
bool Has(const NcmContentId &registeredId);
std::string GetPath(const NcmContentId &registeredId);
};
}

3
include/sigInstall.hpp Executable file
View File

@ -0,0 +1,3 @@
namespace sig {
void installSigPatches ();
}

View File

@ -10,6 +10,7 @@ namespace inst::ui {
PU_SMART_CTOR(instPage)
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
TextBlock::Ref pageInfoText;
pu::ui::elm::ProgressBar::Ref installBar;
private:
TextBlock::Ref topText;
};

View File

@ -10,8 +10,8 @@ namespace tin::util
u64 GetRightsIdTid(RightsId rightsId);
u64 GetRightsIdKeyGen(RightsId rightsId);
std::string GetNcaIdString(const NcmNcaId& ncaId);
NcmNcaId GetNcaIdFromString(std::string ncaIdStr);
std::string GetNcaIdString(const NcmContentId& ncaId);
NcmContentId GetNcaIdFromString(std::string ncaIdStr);
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType);
std::string GetBaseTitleName(u64 baseTitleId);

View File

@ -9,4 +9,6 @@ namespace util {
void initApp ();
void deinitApp ();
std::vector<std::filesystem::path> getDirectoryFiles(const std::string & dir, const std::vector<std::string> & extensions);
bool removeDirectory(std::string dir);
bool copyFile(std::string inFile, std::string outFile);
}

View File

@ -9,7 +9,7 @@
namespace tin::data
{
BufferedPlaceholderWriter::BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmNcaId ncaId, size_t totalDataSize) :
BufferedPlaceholderWriter::BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmContentId ncaId, size_t totalDataSize) :
m_totalDataSize(totalDataSize), m_contentStorage(contentStorage), m_ncaId(ncaId)
{
// Though currently the number of segments is fixed, we want them allocated on the heap, not the stack

View File

@ -6,6 +6,7 @@
#include "util/title_util.hpp"
#include "util/error.hpp"
#include "util/debug.h"
#include "nspInstall.hpp"
namespace tin::install::nsp
{
@ -56,7 +57,7 @@ namespace tin::install::nsp
return 0;
}
void HTTPNSP::StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId)
void HTTPNSP::StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmContentId placeholderId)
{
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
std::string ncaFileName = this->GetFileEntryName(fileEntry);
@ -103,6 +104,8 @@ namespace tin::install::nsp
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
printf("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
inst::ui::setInstInfoText("Downloading " + ncaFileName + "...");
inst::ui::setInstBarPerc((double)downloadProgress);
//consoleUpdate(NULL);
}
@ -114,9 +117,11 @@ namespace tin::install::nsp
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
printf("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
inst::ui::setInstInfoText("Installing " + ncaFileName + "...");
inst::ui::setInstBarPerc((double)installProgress);
//consoleUpdate(NULL);
}
thrd_join(curlThread, NULL);
thrd_join(writeThread, NULL);
//consoleUpdate(NULL);

View File

@ -156,7 +156,7 @@ namespace tin::install
}
printf("Post Install Records: \n");
this->DebugPrintInstallData();
//this->DebugPrintInstallData();
}
u64 Install::GetTitleId()

View File

@ -12,6 +12,7 @@
#include "util/title_util.hpp"
#include "util/debug.h"
#include "util/error.hpp"
#include "nspInstall.hpp"
namespace tin::install::nsp
{
@ -55,7 +56,7 @@ namespace tin::install::nsp
//consoleUpdate(NULL);
}
void NSPInstallTask::InstallNCA(const NcmNcaId &ncaId)
void NSPInstallTask::InstallNCA(const NcmContentId &ncaId)
{
std::string ncaName = tin::util::GetNcaIdString(ncaId);
@ -101,8 +102,11 @@ namespace tin::install::nsp
// Clear the buffer before we read anything, just to be sure
progress = (float)fileOff / (float)ncaSize;
if (fileOff % (0x400000 * 3) == 0)
if (fileOff % (0x400000 * 3) == 0) {
printf("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
inst::ui::setInstInfoText("Installing " + ncaName + "...");
inst::ui::setInstBarPerc((double)(progress * 100.0));
}
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;

View File

@ -24,7 +24,7 @@ namespace tin::install::nsp
THROW_FORMAT("Failed to find cnmt file entry!\n");
std::string cnmtNcaName(m_remoteNSP->GetFileEntryName(fileEntry));
NcmNcaId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
NcmContentId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
size_t cnmtNcaSize = fileEntry->fileSize;
nx::ncm::ContentStorage contentStorage(m_destStorageId);
@ -44,7 +44,7 @@ namespace tin::install::nsp
return { tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo };
}
void RemoteNSPInstall::InstallNCA(const NcmNcaId& ncaId)
void RemoteNSPInstall::InstallNCA(const NcmContentId& ncaId)
{
const PFS0FileEntry* fileEntry = m_remoteNSP->GetFileEntryByNcaId(ncaId);
std::string ncaFileName = m_remoteNSP->GetFileEntryName(fileEntry);

View File

@ -76,7 +76,7 @@ namespace tin::install::nsp
return nullptr;
}
const PFS0FileEntry* RemoteNSP::GetFileEntryByNcaId(const NcmNcaId& ncaId)
const PFS0FileEntry* RemoteNSP::GetFileEntryByNcaId(const NcmContentId& ncaId)
{
const PFS0FileEntry* fileEntry = nullptr;
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);

View File

@ -1,149 +0,0 @@
#include "install/usb_nsp.hpp"
#include <switch.h>
#include <algorithm>
#include <malloc.h>
#include <threads.h>
#include "data/byte_buffer.hpp"
#include "data/buffered_placeholder_writer.hpp"
#include "util/usb_util.hpp"
#include "util/error.hpp"
#include "util/debug.h"
namespace tin::install::nsp
{
USBNSP::USBNSP(std::string nspName) :
m_nspName(nspName)
{
}
struct USBFuncArgs
{
std::string nspName;
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
u64 pfs0Offset;
u64 ncaSize;
};
int USBThreadFunc(void* in)
{
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(args->nspName, args->pfs0Offset, args->ncaSize);
u8* buf = (u8*)memalign(0x1000, 0x800000);
u64 sizeRemaining = header.dataSize;
size_t tmpSizeRead = 0;
try
{
while (sizeRemaining)
{
tmpSizeRead = usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000));
//printf("Read bytes\n")
//printBytes(nxlinkout, buf, tmpSizeRead, true);
sizeRemaining -= tmpSizeRead;
while (true)
{
if (args->bufferedPlaceholderWriter->CanAppendData(tmpSizeRead))
break;
}
args->bufferedPlaceholderWriter->AppendData(buf, tmpSizeRead);
}
}
catch (std::exception& e)
{
printf("An error occurred:\n%s\n", e.what());
printf("An error occurred:\n%s", e.what());
}
free(buf);
return 0;
}
int USBPlaceholderWriteFunc(void* in)
{
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete())
{
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
}
return 0;
}
void USBNSP::StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId)
{
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
std::string ncaFileName = this->GetFileEntryName(fileEntry);
printf("Retrieving %s\n", ncaFileName.c_str());
size_t ncaSize = fileEntry->fileSize;
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(&contentStorage, placeholderId, ncaSize);
USBFuncArgs args;
args.nspName = m_nspName;
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
args.ncaSize = ncaSize;
thrd_t usbThread;
thrd_t writeThread;
thrd_create(&usbThread, USBThreadFunc, &args);
thrd_create(&writeThread, USBPlaceholderWriteFunc, &args);
u64 freq = armGetSystemTickFreq();
u64 startTime = armGetSystemTick();
size_t startSizeBuffered = 0;
double speed = 0.0;
while (!bufferedPlaceholderWriter.IsBufferDataComplete())
{
u64 newTime = armGetSystemTick();
if (newTime - startTime >= freq)
{
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
double duration = ((double)(newTime - startTime) / (double)freq);
speed = mbBuffered / duration;
startTime = newTime;
startSizeBuffered = newSizeBuffered;
}
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
printf("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
//consoleUpdate(NULL);
}
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
while (!bufferedPlaceholderWriter.IsPlaceholderComplete())
{
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
printf("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
//consoleUpdate(NULL);
}
thrd_join(usbThread, NULL);
thrd_join(writeThread, NULL);
}
void USBNSP::BufferData(void* buf, off_t offset, size_t size)
{
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(m_nspName, offset, size);
tin::util::USBRead(buf, header.dataSize);
}
}

View File

@ -43,7 +43,6 @@ namespace netInstStuff{
if (m_serverSocket < -1)
{
inst::ui::mainApp->CreateShowDialog("Failed to create a server socket.", "", {"OK"}, true);
THROW_FORMAT("Failed to create a server socket. Error code: %u\n", errno);
}
@ -54,7 +53,6 @@ namespace netInstStuff{
if (bind(m_serverSocket, (struct sockaddr*) &server, sizeof(server)) < 0)
{
inst::ui::mainApp->CreateShowDialog("Failed to bind server socket.", "", {"OK"}, true);
THROW_FORMAT("Failed to bind server socket. Error code: %u\n", errno);
}
@ -63,13 +61,11 @@ namespace netInstStuff{
if (listen(m_serverSocket, 5) < 0)
{
inst::ui::mainApp->CreateShowDialog("Failed to listen on server socket.", "", {"OK"}, true);
THROW_FORMAT("Failed to listen on server socket. Error code: %u\n", errno);
}
}
catch (std::exception& e)
{
inst::ui::mainApp->CreateShowDialog("Failed to initialize server socket!", "", {"OK"}, true);
printf("Failed to initialize server socket!\n");
fprintf(stdout, "%s", e.what());
@ -78,6 +74,7 @@ namespace netInstStuff{
close(m_serverSocket);
m_serverSocket = 0;
}
inst::ui::mainApp->CreateShowDialog("Failed to initialize server socket!", (std::string)e.what(), {"OK"}, true);
}
void OnUnwound()
@ -100,7 +97,7 @@ namespace netInstStuff{
tin::install::nsp::HTTPNSP httpNSP(ourUrl);
printf("%s %s\n", "NSP_INSTALL_FROM", ourUrl.c_str());
// second var is ignoring required version
// second var is ignoring required version --- add config for this
tin::install::nsp::RemoteNSPInstall install(m_destStorageId, true, &httpNSP);
printf("%s\n", "NSP_INSTALL_PREPARING");
@ -127,7 +124,7 @@ namespace netInstStuff{
printf("Failed to install NSP");
printf("%s", e.what());
fprintf(stdout, "%s", e.what());
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", "", {"OK"}, true);
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", (std::string)e.what(), {"OK"}, true);
}
printf("Done");
@ -149,7 +146,6 @@ namespace netInstStuff{
if (m_serverSocket <= 0)
{
inst::ui::mainApp->CreateShowDialog("Server socket failed to initialize.", "", {"OK"}, true);
THROW_FORMAT("Server socket failed to initialize.\n");
}
}
@ -193,7 +189,6 @@ namespace netInstStuff{
if (size > MAX_URL_SIZE * MAX_URLS)
{
inst::ui::mainApp->CreateShowDialog("URL size is too large!", "", {"OK"}, true);
THROW_FORMAT("URL size %x is too large!\n", size);
}
@ -218,7 +213,6 @@ namespace netInstStuff{
}
else if (errno != EAGAIN)
{
inst::ui::mainApp->CreateShowDialog("Failed to open client socket", "", {"OK"}, true);
THROW_FORMAT("Failed to open client socket with code %u\n", errno);
}
}
@ -228,10 +222,10 @@ namespace netInstStuff{
}
catch (std::runtime_error& e)
{
inst::ui::mainApp->CreateShowDialog("Failed to perform remote install!", "", {"OK"}, true);
printf("Failed to perform remote install!\n");
printf("%s", e.what());
fprintf(stdout, "%s", e.what());
inst::ui::mainApp->CreateShowDialog("Failed to perform remote install!", (std::string)e.what(), {"OK"}, true);
return {};
}
}

View File

@ -17,12 +17,20 @@ namespace inst::ui {
mainApp->CallForRender();
}
void setInstBarPerc(double ourPercent){
mainApp->instpage->installBar->SetVisible(true);
mainApp->instpage->installBar->SetProgress(ourPercent);
mainApp->CallForRender();
}
void loadMainMenu(){
mainApp->LoadLayout(mainApp->mainPage);
}
void loadInstallScreen(){
mainApp->instpage->pageInfoText->SetText("");
mainApp->instpage->installBar->SetProgress(0);
mainApp->instpage->installBar->SetVisible(false);
mainApp->LoadLayout(mainApp->instpage);
mainApp->CallForRender();
}
@ -75,7 +83,7 @@ namespace nspInstStuff {
printf("Failed to install NSP");
printf("%s", e.what());
fprintf(stdout, "%s", e.what());
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", "", {"OK"}, true);
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", (std::string)e.what(), {"OK"}, true);
}
}

View File

@ -79,7 +79,7 @@ namespace nx::fs
Result IFileSystem::OpenSdFileSystem()
{
ASSERT_OK(fsMountSdcard(&m_fileSystem), "Failed to mount sd card");
ASSERT_OK(fsOpenSdCardFileSystem(&m_fileSystem), "Failed to mount sd card");
return 0;
}

View File

@ -3,301 +3,109 @@
#include <string.h>
#include <switch.h>
#include <switch/arm/atomics.h>
#include "service_guard.h"
static Service g_esSrv;
static u64 g_esRefCnt;
Result esInitialize() {
atomicIncrement64(&g_esRefCnt);
Result rc = smGetService(&g_esSrv, "es");
return rc;
NX_GENERATE_SERVICE_GUARD(es);
Result _esInitialize() {
return smGetService(&g_esSrv, "es");
}
void esExit() {
if (atomicDecrement64(&g_esRefCnt) == 0) {
serviceClose(&g_esSrv);
}
void _esCleanup() {
serviceClose(&g_esSrv);
}
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize)
{
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, tikBuf, tikSize, BufferType_Normal);
ipcAddSendBuffer(&c, certBuf, certSize, BufferType_Normal);
Service* esGetServiceSession() {
return &g_esSrv;
}
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 1;
Result rc = serviceIpcDispatch(&g_esSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize) {
return serviceDispatch(&g_esSrv, 1,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
},
.buffers = {
{ tikBuf, tikSize },
{ certBuf, certSize },
},
);
}
Result esDeleteTicket(const RightsId *rightsIdBuf, size_t bufSize) {
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, rightsIdBuf, bufSize, BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
Result rc = serviceIpcDispatch(&g_esSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatch(&g_esSrv, 3,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { rightsIdBuf, bufSize }, },
);
}
Result esGetTitleKey(const RightsId *rightsId, u8 *outBuf, size_t bufSize) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
return serviceDispatchIn(&g_esSrv, 8, *rightsId,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { outBuf, bufSize } },
);
}
Result esCountCommonTicket(u32 *numTickets) {
struct {
u64 magic;
u64 cmd_id;
RightsId rights_id;
u32 key_generation;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 8;
raw->key_generation = 0;
memcpy(&raw->rights_id, rightsId, sizeof(RightsId));
Result rc = serviceIpcDispatch(&g_esSrv);
u32 num_tickets;
} out;
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
Result rc = serviceDispatchOut(&g_esSrv, 9, out);
if (R_SUCCEEDED(rc) && numTickets) *numTickets = out.num_tickets;
return rc;
}
Result esCountCommonTicket(u32 *numTickets)
{
IpcCommand c;
ipcInitialize(&c);
Result esCountPersonalizedTicket(u32 *numTickets) {
struct {
u64 magic;
u64 cmd_id;
} *raw;
u32 num_tickets;
} out;
Result rc = serviceDispatchOut(&g_esSrv, 10, out);
if (R_SUCCEEDED(rc) && numTickets) *numTickets = out.num_tickets;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 9;
Result rc = serviceIpcDispatch(&g_esSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 num_tickets;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (numTickets) *numTickets = resp->num_tickets;
}
}
return rc;
}
Result esCountPersonalizedTicket(u32 *numTickets)
{
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(&g_esSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 num_tickets;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (numTickets) *numTickets = resp->num_tickets;
}
}
return rc;
return rc;
}
Result esListCommonTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
} *raw;
u32 num_rights_ids_written;
} out;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
Result rc = serviceIpcDispatch(&g_esSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 num_rights_ids_written;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (numRightsIdsWritten) *numRightsIdsWritten = resp->num_rights_ids_written;
}
}
Result rc = serviceDispatchInOut(&g_esSrv, 11, *numRightsIdsWritten, out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { outBuf, bufSize } },
);
if (R_SUCCEEDED(rc) && numRightsIdsWritten) *numRightsIdsWritten = out.num_rights_ids_written;
return rc;
}
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
struct {
u64 magic;
u64 cmd_id;
} *raw;
u32 num_rights_ids_written;
} out;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 12;
Result rc = serviceIpcDispatch(&g_esSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 num_rights_ids_written;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (numRightsIdsWritten) *numRightsIdsWritten = resp->num_rights_ids_written;
}
}
Result rc = serviceDispatchInOut(&g_esSrv, 12, *numRightsIdsWritten, out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { outBuf, bufSize } },
);
if (R_SUCCEEDED(rc) && numRightsIdsWritten) *numRightsIdsWritten = out.num_rights_ids_written;
return rc;
}
Result esGetCommonTicketData(u64 *unkOut, void *outBuf1, size_t bufSize1, const RightsId* rightsId)
{
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, outBuf1, bufSize1, BufferType_Normal);
Result esGetCommonTicketData(u64 *unkOut, void *outBuf1, size_t bufSize1, const RightsId* rightsId) {
struct {
u64 magic;
u64 cmd_id;
RightsId rights_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 16;
memcpy(&raw->rights_id, rightsId, sizeof(RightsId));
Result rc = serviceIpcDispatch(&g_esSrv);
u64 unk;
} out;
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u64 unk;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (unkOut) *unkOut = resp->unk;
}
}
Result rc = serviceDispatchInOut(&g_esSrv, 16, rightsId, out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { outBuf1, bufSize1 } },
);
return rc;
}

View File

@ -3,677 +3,231 @@
#include <stdio.h>
#include <string.h>
#include <switch.h>
#include <switch/arm/atomics.h>
#include "service_guard.h"
static Service g_nsAppManSrv, g_nsGetterSrv;
static u64 g_nsRefCnt;
static Result _nsGetInterface(Service* srv_out, u64 cmd_id);
static Result _nsextGetSession(Service* srv, Service* srv_out, u32 cmd_id);
Result nsextInitialize(void)
{
NX_GENERATE_SERVICE_GUARD(nsext);
Result _nsextInitialize(void) {
Result rc=0;
atomicIncrement64(&g_nsRefCnt);
if (serviceIsActive(&g_nsGetterSrv) || serviceIsActive(&g_nsAppManSrv))
return 0;
if(!kernelAbove300())
if(hosversionBefore(3,0,0))
return smGetService(&g_nsAppManSrv, "ns:am");
rc = smGetService(&g_nsGetterSrv, "ns:am2");//TODO: Support the other services?(Only useful when ns:am2 isn't accessible)
if (R_FAILED(rc)) return rc;
rc = _nsGetInterface(&g_nsAppManSrv, 7996);
rc = _nsextGetSession(&g_nsGetterSrv, &g_nsAppManSrv, 7996);
if (R_FAILED(rc)) serviceClose(&g_nsGetterSrv);
return rc;
}
void nsextExit(void)
{
if (atomicDecrement64(&g_nsRefCnt) == 0) {
serviceClose(&g_nsAppManSrv);
if(!kernelAbove300()) return;
void _nsextCleanup(void) {
serviceClose(&g_nsAppManSrv);
if(hosversionBefore(3,0,0)) return;
serviceClose(&g_nsGetterSrv);
}
serviceClose(&g_nsGetterSrv);
}
static Result _nsGetInterface(Service* srv_out, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(&g_nsGetterSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
serviceCreate(srv_out, r.Handles[0]);
}
}
return rc;
static Result _nsextGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
return serviceDispatch(srv, cmd_id,
.out_num_objects = 1,
.out_objects = srv_out,
);
}
Result nsPushApplicationRecord(u64 title_id, u8 last_modified_event, ContentStorageRecord *content_records_buf, size_t buf_size)
{
IpcCommand c;
ipcInitialize(&c);
ipcAddSendBuffer(&c, content_records_buf, buf_size, 0);
Result nsPushApplicationRecord(u64 title_id, u8 last_modified_event, ContentStorageRecord *content_records_buf, size_t buf_size) {
struct {
u64 magic;
u64 cmd_id;
u8 last_modified_event;
u8 padding[0x7];
u64 title_id;
} *raw;
} in = { last_modified_event, {0}, title_id };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 16;
raw->last_modified_event = last_modified_event;
raw->title_id = title_id;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 16, in,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { content_records_buf, buf_size } });
}
Result nsCalculateApplicationOccupiedSize(u64 titleID, void *out_buf)
{
IpcCommand c;
ipcInitialize(&c);
Result nsCalculateApplicationOccupiedSize(u64 titleID, void *out_buf) {
struct {
u64 magic;
u64 cmd_id;
u64 titleID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 11;
raw->titleID = titleID;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
} in = { titleID };
struct {
u64 magic;
u64 result;
u8 out[0x80];
} *resp = r.Raw;
struct {
u8 out[0x80];
} out;
rc = resp->result;
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 11, in, out);
if (R_SUCCEEDED(rc) && out_buf) memcpy(out_buf, out.out, 0x80);
if (R_SUCCEEDED(rc)) {
memcpy(out_buf, resp->out, 0x80);
}
}
return rc;
}
Result nsListApplicationRecordContentMeta(u64 offset, u64 titleID, void *out_buf, size_t out_buf_size, u32 *entries_read_out)
{
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, out_buf, out_buf_size, 0);
Result nsListApplicationRecordContentMeta(u64 offset, u64 titleID, void *out_buf, size_t out_buf_size, u32 *entries_read_out) {
struct {
u64 magic;
u64 cmd_id;
u64 offset;
u64 titleID;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 17;
raw->titleID = titleID;
raw->offset = offset;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
} in = { offset, titleID };
struct {
u64 magic;
u64 result;
u32 entries_read;
} *resp = r.Raw;
struct {
u32 entries_read;
} out;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (entries_read_out) *entries_read_out = resp->entries_read;
}
}
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 17, in, out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out_buf, out_buf_size } });
if (R_SUCCEEDED(rc) && entries_read_out) *entries_read_out = out.entries_read;
return rc;
}
Result nsTouchApplication(u64 titleID)
{
IpcCommand c;
ipcInitialize(&c);
Result nsTouchApplication(u64 titleID) {
struct {
u64 magic;
u64 cmd_id;
u64 titleID;
} *raw;
} in = { titleID };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 904;
raw->titleID = titleID;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 entries_read;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 904, in);
}
Result nsDeleteApplicationRecord(u64 titleID)
{
IpcCommand c;
ipcInitialize(&c);
Result nsDeleteApplicationRecord(u64 titleID) {
struct {
u64 magic;
u64 cmd_id;
u64 titleID;
} *raw;
} in = { titleID };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 27;
raw->titleID = titleID;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 entries_read;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 27, in);
}
Result nsLaunchApplication(u64 titleID)
{
IpcCommand c;
ipcInitialize(&c);
Result nsLaunchApplication(u64 titleID) {
struct {
u64 magic;
u64 cmd_id;
u64 titleID;
} *raw;
} in = { titleID };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 19;
raw->titleID = titleID;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 19, in);
}
Result nsPushLaunchVersion(u64 titleID, u32 version)
{
IpcCommand c;
ipcInitialize(&c);
Result nsPushLaunchVersion(u64 titleID, u32 version) {
struct {
u64 magic;
u64 cmd_id;
u64 title_id;
u64 titleID;
u32 version;
u32 padding;
} *raw;
} in = { titleID, version, 0 };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 36;
raw->title_id = titleID;
raw->version = version;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
return serviceDispatchIn(&g_nsAppManSrv, 36, in);
}
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
Result nsCheckApplicationLaunchVersion(u64 titleID) {
struct {
u64 titleID;
} in = { titleID };
return serviceDispatchIn(&g_nsAppManSrv, 38, in);
}
Result nsCountApplicationContentMeta(u64 titleId, u32* countOut) {
struct {
u64 titleId;
} in = { titleId };
struct {
u32 count;
} out;
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 600, in, out);
if (R_SUCCEEDED(rc) && countOut) *countOut = out.count;
return rc;
}
Result nsCheckApplicationLaunchVersion(u64 titleID)
{
IpcCommand c;
ipcInitialize(&c);
Result nsGetContentMetaStorage(const NcmContentMetaKey *record, u8 *storageOut) {
struct {
u64 magic;
u64 cmd_id;
u64 title_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 38;
raw->title_id = titleID;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result nsCountApplicationContentMeta(u64 titleId, u32* countOut)
{
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 title_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 600;
raw->title_id = titleId;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
u32 count;
} *resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (countOut) *countOut = resp->count;
}
}
return rc;
}
Result nsGetContentMetaStorage(const NcmContentMetaKey *record, u8 *out)
{
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
NcmContentMetaKey metaRecord;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 606;
memcpy(&raw->metaRecord, record, sizeof(NcmContentMetaKey));
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
} in = { *record };
struct {
u64 magic;
u64 result;
u8 out;
} *resp = r.Raw;
struct {
u8 out;
} out;
rc = resp->result;
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 606, in, out);
if (R_SUCCEEDED(rc) && storageOut) *storageOut = out.out;
if (R_SUCCEEDED(rc)) {
if (out) *out = resp->out;
}
}
return rc;
}
Result nsBeginInstallApplication(u64 tid, u32 unk, u8 storageId) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 storageId;
u32 unk;
u64 tid;
} *raw;
} in = { storageId, unk, tid };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 26;
raw->storageId = storageId;
raw->unk = unk;
raw->tid = tid;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 26, in);
}
Result nsInvalidateAllApplicationControlCache(void) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 401;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatch(&g_nsAppManSrv, 401);
}
Result nsInvalidateApplicationControlCache(u64 tid) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u64 tid;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 404;
raw->tid = tid;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} in = { tid };
return serviceDispatchIn(&g_nsAppManSrv, 404, in);
}
Result nsCheckApplicationLaunchRights(u64 tid)
{
IpcCommand c;
ipcInitialize(&c);
Result nsCheckApplicationLaunchRights(u64 tid) {
struct {
u64 magic;
u64 cmd_id;
u64 tid;
} *raw;
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 39;
raw->tid = tid;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
} in = { tid };
return serviceDispatchIn(&g_nsAppManSrv, 39, in);
}
Result nsGetApplicationContentPath(u64 tid, u8 type, char *out, size_t buf_size) {
IpcCommand c;
ipcInitialize(&c);
ipcAddRecvBuffer(&c, out, buf_size, 0);
struct {
u64 magic;
u64 cmd_id;
u8 padding[0x7];
u8 type;
u64 tid;
} *raw;
} in = { {0}, type, tid };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 21;
raw->type = type;
raw->tid = tid;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 21, in,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { out, buf_size } }
);
}
Result nsDisableApplicationAutoUpdate(u64 titleID)
{
IpcCommand c;
ipcInitialize(&c);
Result nsDisableApplicationAutoUpdate(u64 titleID) {
struct {
u64 magic;
u64 cmd_id;
u64 title_id;
} *raw;
} in = { titleID };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 903;
raw->title_id = titleID;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 903, in);
}
Result nsWithdrawApplicationUpdateRequest(u64 titleId)
{
IpcCommand c;
ipcInitialize(&c);
Result nsWithdrawApplicationUpdateRequest(u64 titleId) {
struct {
u64 magic;
u64 cmd_id;
u64 title_id;
} *raw;
} in = { titleId };
raw = ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 907;
raw->title_id = titleId;
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
ipcParse(&r);
struct {
u64 magic;
u64 result;
} *resp = r.Raw;
rc = resp->result;
}
return rc;
return serviceDispatchIn(&g_nsAppManSrv, 907, in);
}

52
source/nx/ipc/service_guard.h Executable file
View File

@ -0,0 +1,52 @@
#pragma once
#include <switch.h>
typedef struct ServiceGuard {
Mutex mutex;
u32 refCount;
} ServiceGuard;
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
{
mutexLock(&g->mutex);
return (g->refCount++) == 0;
}
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
{
if (R_FAILED(rc)) {
cleanupFunc();
--g->refCount;
}
mutexUnlock(&g->mutex);
return rc;
}
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
{
mutexLock(&g->mutex);
if (g->refCount && (--g->refCount) == 0)
cleanupFunc();
mutexUnlock(&g->mutex);
}
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
\
static ServiceGuard g_##name##Guard; \
NX_INLINE Result _##name##Initialize _paramdecl; \
static void _##name##Cleanup(void); \
\
Result name##Initialize _paramdecl \
{ \
Result rc = 0; \
if (serviceGuardBeginInit(&g_##name##Guard)) \
rc = _##name##Initialize _parampass; \
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
} \
\
void name##Exit(void) \
{ \
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
}
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())

View File

@ -1,579 +0,0 @@
#include "nx/ipc/usb_new.h"
#include "nx/ipc/usb_comms_new.h"
#include <string.h>
#include <malloc.h>
#include <switch/types.h>
#include <switch/result.h>
#include <switch/kernel/detect.h>
#include <switch/kernel/rwlock.h>
#include <switch/services/fatal.h>
#define TOTAL_INTERFACES 4
typedef struct {
RwLock lock, lock_in, lock_out;
bool initialized;
UsbDsInterface* interface;
UsbDsEndpoint *endpoint_in, *endpoint_out;
u8 *endpoint_in_buffer, *endpoint_out_buffer;
} usbCommsInterface;
static bool g_usbCommsInitialized = false;
static usbCommsInterface g_usbCommsInterfaces[TOTAL_INTERFACES];
static RwLock g_usbCommsLock;
static Result _usbCommsInterfaceInit1x(u32 intf_ind);
static Result _usbCommsInterfaceInit5x(u32 intf_ind);
static Result _usbCommsInterfaceInit(u32 intf_ind);
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize);
Result usbCommsInitializeEx(u32 num_interfaces)
{
Result rc = 0;
rwlockWriteLock(&g_usbCommsLock);
if (g_usbCommsInitialized) {
rc = MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
} else if (num_interfaces > TOTAL_INTERFACES) {
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
} else {
rc = usbDsInitialize();
if (R_SUCCEEDED(rc)) {
if (kernelAbove500()) {
u8 iManufacturer, iProduct, iSerialNumber;
static const u16 supported_langs[1] = {0x0409};
// Send language descriptor
rc = usbDsAddUsbLanguageStringDescriptor(NULL, supported_langs, sizeof(supported_langs)/sizeof(u16));
// Send manufacturer
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iManufacturer, "Switchbrew");
// Send product
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iProduct, "libnx USB comms");
// Send serial number
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iSerialNumber, "SerialNumber");
// Send device descriptors
struct usb_device_descriptor device_descriptor = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0110,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = 0x40,
.idVendor = 0x057e,
.idProduct = 0x3000,
.bcdDevice = 0x0100,
.iManufacturer = iManufacturer,
.iProduct = iProduct,
.iSerialNumber = iSerialNumber,
.bNumConfigurations = 0x01
};
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Full, &device_descriptor);
// High Speed is USB 2.0
device_descriptor.bcdUSB = 0x0200;
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, &device_descriptor);
// Super Speed is USB 3.0
device_descriptor.bcdUSB = 0x0300;
// Upgrade packet size to 512
device_descriptor.bMaxPacketSize0 = 0x09;
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, &device_descriptor);
// Define Binary Object Store
u8 bos[0x16] = {
0x05, // .bLength
USB_DT_BOS, // .bDescriptorType
0x16, 0x00, // .wTotalLength
0x02, // .bNumDeviceCaps
// USB 2.0
0x07, // .bLength
USB_DT_DEVICE_CAPABILITY, // .bDescriptorType
0x02, // .bDevCapabilityType
0x02, 0x00, 0x00, 0x00, // dev_capability_data
// USB 3.0
0x0A, // .bLength
USB_DT_DEVICE_CAPABILITY, // .bDescriptorType
0x03, // .bDevCapabilityType
0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00
};
if (R_SUCCEEDED(rc)) rc = usbDsSetBinaryObjectStore(bos, sizeof(bos));
}
if (R_SUCCEEDED(rc)) {
for (u32 i = 0; i < num_interfaces; i++) {
usbCommsInterface *intf = &g_usbCommsInterfaces[i];
rwlockWriteLock(&intf->lock);
rwlockWriteLock(&intf->lock_in);
rwlockWriteLock(&intf->lock_out);
rc = _usbCommsInterfaceInit(i);
rwlockWriteUnlock(&intf->lock_out);
rwlockWriteUnlock(&intf->lock_in);
rwlockWriteUnlock(&intf->lock);
if (R_FAILED(rc)) {
break;
}
}
}
}
if (R_SUCCEEDED(rc) && kernelAbove500()) {
rc = usbDsEnable();
}
if (R_FAILED(rc)) {
usbCommsExit();
}
}
if (R_SUCCEEDED(rc)) g_usbCommsInitialized = true;
rwlockWriteUnlock(&g_usbCommsLock);
return rc;
}
Result usbCommsInitialize(void)
{
return usbCommsInitializeEx(1);
}
static void _usbCommsInterfaceFree(usbCommsInterface *interface)
{
rwlockWriteLock(&interface->lock);
if (!interface->initialized) {
rwlockWriteUnlock(&interface->lock);
return;
}
rwlockWriteLock(&interface->lock_in);
rwlockWriteLock(&interface->lock_out);
interface->initialized = 0;
interface->endpoint_in = NULL;
interface->endpoint_out = NULL;
interface->interface = NULL;
free(interface->endpoint_in_buffer);
free(interface->endpoint_out_buffer);
interface->endpoint_in_buffer = NULL;
interface->endpoint_out_buffer = NULL;
rwlockWriteUnlock(&interface->lock_out);
rwlockWriteUnlock(&interface->lock_in);
rwlockWriteUnlock(&interface->lock);
}
void usbCommsExit(void)
{
u32 i;
rwlockWriteLock(&g_usbCommsLock);
usbDsExit();
g_usbCommsInitialized = false;
rwlockWriteUnlock(&g_usbCommsLock);
for (i=0; i<TOTAL_INTERFACES; i++)
{
_usbCommsInterfaceFree(&g_usbCommsInterfaces[i]);
}
}
static Result _usbCommsInterfaceInit(u32 intf_ind)
{
if (kernelAbove500()) {
return _usbCommsInterfaceInit5x(intf_ind);
} else {
return _usbCommsInterfaceInit1x(intf_ind);
}
}
static Result _usbCommsInterfaceInit5x(u32 intf_ind)
{
Result rc = 0;
u32 ep_num = intf_ind + 1;
usbCommsInterface *interface = &g_usbCommsInterfaces[intf_ind];
struct usb_interface_descriptor interface_descriptor = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = intf_ind,
.bNumEndpoints = 2,
.bInterfaceClass = 0xFF,
.bInterfaceSubClass = 0xFF,
.bInterfaceProtocol = 0xFF,
};
struct usb_endpoint_descriptor endpoint_descriptor_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_ENDPOINT_IN + ep_num,
.bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 0x40,
};
struct usb_endpoint_descriptor endpoint_descriptor_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_ENDPOINT_OUT + ep_num,
.bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 0x40,
};
struct usb_ss_endpoint_companion_descriptor endpoint_companion = {
.bLength = sizeof(struct usb_ss_endpoint_companion_descriptor),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMPANION,
.bMaxBurst = 0x0F,
.bmAttributes = 0x00,
.wBytesPerInterval = 0x00,
};
interface->initialized = 1;
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
interface->endpoint_in_buffer = memalign(0x1000, 0x1000);
if (interface->endpoint_in_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
if (R_SUCCEEDED(rc)) {
interface->endpoint_out_buffer = memalign(0x1000, 0x1000);
if (interface->endpoint_out_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
if (R_SUCCEEDED(rc)) {
memset(interface->endpoint_in_buffer, 0, 0x1000);
memset(interface->endpoint_out_buffer, 0, 0x1000);
}
if (R_FAILED(rc)) return rc;
rc = usbDsRegisterInterface(&interface->interface, interface_descriptor.bInterfaceNumber);
if (R_FAILED(rc)) return rc;
// Full Speed Config
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &interface_descriptor, USB_DT_INTERFACE_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
if (R_FAILED(rc)) return rc;
// High Speed Config
endpoint_descriptor_in.wMaxPacketSize = 0x200;
endpoint_descriptor_out.wMaxPacketSize = 0x200;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &interface_descriptor, USB_DT_INTERFACE_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
if (R_FAILED(rc)) return rc;
// Super Speed Config
endpoint_descriptor_in.wMaxPacketSize = 0x400;
endpoint_descriptor_out.wMaxPacketSize = 0x400;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &interface_descriptor, USB_DT_INTERFACE_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
if (R_FAILED(rc)) return rc;
//Setup endpoints.
rc = usbDsInterface_RegisterEndpoint(interface->interface, &interface->endpoint_in, endpoint_descriptor_in.bEndpointAddress);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_RegisterEndpoint(interface->interface, &interface->endpoint_out, endpoint_descriptor_out.bEndpointAddress);
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_EnableInterface(interface->interface);
if (R_FAILED(rc)) return rc;
return rc;
}
static Result _usbCommsInterfaceInit1x(u32 intf_ind)
{
Result rc = 0;
u32 ep_num = intf_ind + 1;
usbCommsInterface *interface = &g_usbCommsInterfaces[intf_ind];
struct usb_interface_descriptor interface_descriptor = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = intf_ind,
.bInterfaceClass = 0xFF,
.bInterfaceSubClass = 0xFF,
.bInterfaceProtocol = 0xFF,
};
struct usb_endpoint_descriptor endpoint_descriptor_in = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_ENDPOINT_IN + ep_num,
.bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 0x200,
};
struct usb_endpoint_descriptor endpoint_descriptor_out = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_ENDPOINT_OUT + ep_num,
.bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 0x200,
};
interface->initialized = 1;
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
interface->endpoint_in_buffer = memalign(0x1000, 0x1000);
if (interface->endpoint_in_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
if (R_SUCCEEDED(rc)) {
interface->endpoint_out_buffer = memalign(0x1000, 0x1000);
if (interface->endpoint_out_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
}
if (R_SUCCEEDED(rc)) {
memset(interface->endpoint_in_buffer, 0, 0x1000);
memset(interface->endpoint_out_buffer, 0, 0x1000);
}
if (R_FAILED(rc)) return rc;
//Setup interface.
rc = usbDsGetDsInterface(&interface->interface, &interface_descriptor, "usb");
if (R_FAILED(rc)) return rc;
//Setup endpoints.
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_in, &endpoint_descriptor_in);//device->host
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_out, &endpoint_descriptor_out);//host->device
if (R_FAILED(rc)) return rc;
rc = usbDsInterface_EnableInterface(interface->interface);
if (R_FAILED(rc)) return rc;
return rc;
}
static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t size, size_t *transferredSize)
{
Result rc=0;
u32 urbId=0;
u8 *bufptr = (u8*)buffer;
u8 *transfer_buffer = NULL;
u8 transfer_type=0;
u32 chunksize=0;
u32 tmp_transferredSize = 0;
size_t total_transferredSize=0;
UsbDsReportData reportdata;
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
rc = usbDsWaitReady(U64_MAX);
if (R_FAILED(rc)) return rc;
while(size)
{
if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly.
{
transfer_buffer = interface->endpoint_out_buffer;
memset(interface->endpoint_out_buffer, 0, 0x1000);
chunksize = 0x1000;
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
if (size<chunksize) chunksize = size;
transfer_type = 0;
}
else
{
transfer_buffer = bufptr;
chunksize = size;
transfer_type = 1;
}
//Start a host->device transfer.
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_out, transfer_buffer, chunksize, &urbId);
if (R_FAILED(rc)) return rc;
//Wait for the transfer to finish.
eventWait(&interface->endpoint_out->CompletionEvent, U64_MAX);
eventClear(&interface->endpoint_out->CompletionEvent);
rc = usbDsEndpoint_GetReportData(interface->endpoint_out, &reportdata);
if (R_FAILED(rc)) return rc;
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
if (R_FAILED(rc)) return rc;
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
total_transferredSize+= (size_t)tmp_transferredSize;
if (transfer_type==0) memcpy(bufptr, transfer_buffer, tmp_transferredSize);
bufptr+= tmp_transferredSize;
size-= tmp_transferredSize;
if(tmp_transferredSize < chunksize)break;
}
if (transferredSize) *transferredSize = total_transferredSize;
return rc;
}
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize)
{
Result rc=0;
u32 urbId=0;
u32 chunksize=0;
u8 *bufptr = (u8*)buffer;
u8 *transfer_buffer = NULL;
u32 tmp_transferredSize = 0;
size_t total_transferredSize=0;
UsbDsReportData reportdata;
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
rc = usbDsWaitReady(U64_MAX);
if (R_FAILED(rc)) return rc;
while(size)
{
if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly.
{
transfer_buffer = interface->endpoint_in_buffer;
memset(interface->endpoint_in_buffer, 0, 0x1000);
chunksize = 0x1000;
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
if (size<chunksize) chunksize = size;
memcpy(interface->endpoint_in_buffer, bufptr, chunksize);
}
else
{
transfer_buffer = bufptr;
chunksize = size;
}
//Start a device->host transfer.
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_in, transfer_buffer, chunksize, &urbId);
if(R_FAILED(rc))return rc;
//Wait for the transfer to finish.
eventWait(&interface->endpoint_in->CompletionEvent, U64_MAX);
eventClear(&interface->endpoint_in->CompletionEvent);
rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
if (R_FAILED(rc)) return rc;
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
if (R_FAILED(rc)) return rc;
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
total_transferredSize+= (size_t)tmp_transferredSize;
bufptr+= tmp_transferredSize;
size-= tmp_transferredSize;
if (tmp_transferredSize < chunksize) break;
}
if (transferredSize) *transferredSize = total_transferredSize;
return rc;
}
size_t usbCommsReadEx(void* buffer, size_t size, u32 interface)
{
size_t transferredSize=0;
u32 state=0;
Result rc, rc2;
usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
bool initialized;
if (interface>=TOTAL_INTERFACES) return 0;
rwlockReadLock(&inter->lock);
initialized = inter->initialized;
rwlockReadUnlock(&inter->lock);
if (!initialized) return 0;
rwlockWriteLock(&inter->lock_out);
rc = _usbCommsRead(inter, buffer, size, &transferredSize);
rwlockWriteUnlock(&inter->lock_out);
if (R_FAILED(rc)) {
rc2 = usbDsGetState(&state);
if (R_SUCCEEDED(rc2)) {
if (state!=5) {
rwlockWriteLock(&inter->lock_out);
rc = _usbCommsRead(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
rwlockWriteUnlock(&inter->lock_out);
}
}
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsRead));
}
return transferredSize;
}
size_t usbCommsRead(void* buffer, size_t size)
{
return usbCommsReadEx(buffer, size, 0);
}
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface)
{
size_t transferredSize=0;
u32 state=0;
Result rc, rc2;
usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
bool initialized;
if (interface>=TOTAL_INTERFACES) return 0;
rwlockReadLock(&inter->lock);
initialized = inter->initialized;
rwlockReadUnlock(&inter->lock);
if (!initialized) return 0;
rwlockWriteLock(&inter->lock_in);
rc = _usbCommsWrite(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize);
rwlockWriteUnlock(&inter->lock_in);
if (R_FAILED(rc)) {
rc2 = usbDsGetState(&state);
if (R_SUCCEEDED(rc2)) {
if (state!=5) {
rwlockWriteLock(&inter->lock_in);
rc = _usbCommsWrite(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
rwlockWriteUnlock(&inter->lock_in);
}
}
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsWrite));
}
return transferredSize;
}
size_t usbCommsWrite(const void* buffer, size_t size)
{
return usbCommsWriteEx(buffer, size, 0);
}

File diff suppressed because it is too large Load Diff

View File

@ -13,39 +13,39 @@ namespace nx::ncm
serviceClose(&m_contentStorage.s);
}
void ContentStorage::CreatePlaceholder(const NcmNcaId &placeholderId, const NcmNcaId &registeredId, size_t size)
void ContentStorage::CreatePlaceholder(const NcmContentId &placeholderId, const NcmContentId &registeredId, size_t size)
{
ASSERT_OK(ncmContentStorageCreatePlaceHolder(&m_contentStorage, &placeholderId, &registeredId, size), "Failed to create placeholder");
}
void ContentStorage::DeletePlaceholder(const NcmNcaId &placeholderId)
void ContentStorage::DeletePlaceholder(const NcmContentId &placeholderId)
{
ASSERT_OK(ncmContentStorageDeletePlaceHolder(&m_contentStorage, &placeholderId), "Failed to delete placeholder");
}
void ContentStorage::WritePlaceholder(const NcmNcaId &placeholderId, u64 offset, void *buffer, size_t bufSize)
void ContentStorage::WritePlaceholder(const NcmContentId &placeholderId, u64 offset, void *buffer, size_t bufSize)
{
ASSERT_OK(ncmContentStorageWritePlaceHolder(&m_contentStorage, &placeholderId, offset, buffer, bufSize), "Failed to write to placeholder");
}
void ContentStorage::Register(const NcmNcaId &placeholderId, const NcmNcaId &registeredId)
void ContentStorage::Register(const NcmContentId &placeholderId, const NcmContentId &registeredId)
{
ASSERT_OK(ncmContentStorageRegister(&m_contentStorage, &registeredId, &placeholderId), "Failed to register placeholder NCA");
}
void ContentStorage::Delete(const NcmNcaId &registeredId)
void ContentStorage::Delete(const NcmContentId &registeredId)
{
ASSERT_OK(ncmContentStorageDelete(&m_contentStorage, &registeredId), "Failed to delete registered NCA");
}
bool ContentStorage::Has(const NcmNcaId &registeredId)
bool ContentStorage::Has(const NcmContentId &registeredId)
{
bool hasNCA = false;
ASSERT_OK(ncmContentStorageHas(&m_contentStorage, &hasNCA, &registeredId), "Failed to check if NCA is present");
return hasNCA;
}
std::string ContentStorage::GetPath(const NcmNcaId &registeredId)
std::string ContentStorage::GetPath(const NcmContentId &registeredId)
{
char pathBuf[FS_MAX_PATH] = {0};
ASSERT_OK(ncmContentStorageGetPath(&m_contentStorage, pathBuf, FS_MAX_PATH, &registeredId), "Failed to get installed NCA path");

40
source/sigInstall.cpp Executable file
View File

@ -0,0 +1,40 @@
#include "ui/MainApplication.hpp"
#include "util/curl.hpp"
#include "util/util.hpp"
#include "util/unzip.hpp"
namespace inst::ui {
extern MainApplication *mainApp;
}
namespace sig {
void installSigPatches () {
int ourResult = inst::ui::mainApp->CreateShowDialog("Install signature patches?", "Signature patches are required for installing and playing NSP contents!", {"Install", "Uninstall", "Cancel"}, true);
if (ourResult == 0) {
if (!util::copyFile("sdmc:/bootloader/patches.ini", "sdmc:/bootloader/patches.ini.old")) {
if (inst::ui::mainApp->CreateShowDialog("Could not back up old Hekate patches.ini! Install anyway?", "", {"Yes", "No"}, false)) return;
}
std::string ourPath = appVariables::appDir + "patches.zip";
bool didDownload = curlStuff::downloadFile("http://github.com/Joonie86/hekate/releases/download/5.0.0J/Kosmos_patches_10_09_2019.zip", ourPath.c_str());
bool didExtract = false;
if (didDownload) didExtract = zipStuff::extractFile(ourPath, "sdmc:/");
else {
inst::ui::mainApp->CreateShowDialog("Could not download signature patches!", "Check your internet connection and try again", {"OK"}, true);
return;
}
std::filesystem::remove(ourPath);
if (didExtract) inst::ui::mainApp->CreateShowDialog("Install complete!", "Restart your console to apply!", {"OK"}, true);
else {
inst::ui::mainApp->CreateShowDialog("Could not extract files!", "", {"OK"}, true);
return;
}
return;
} else if (ourResult == 1) {
if (!util::copyFile( "sdmc:/bootloader/patches.ini.old", "sdmc:/bootloader/patches.ini")) {
if (inst::ui::mainApp->CreateShowDialog("Unable to restore original Hekate patches.ini! Continue uninstalling?", "", {"Yes", "No"}, false)) return;
} else std::filesystem::remove("sdmc:/bootloader/patches.ini.old");
if (util::removeDirectory("sdmc:/atmosphere/exefs_patches/es_patches")) inst::ui::mainApp->CreateShowDialog("Uninstall complete", "Restart your console to apply", {"OK"}, true);
else inst::ui::mainApp->CreateShowDialog("Unable to remove signature patches", "Files may have been renamed or deleted", {"OK"}, true);
} else return;
}
}

View File

@ -1,8 +1,6 @@
#include <filesystem>
#include "ui/MainApplication.hpp"
#include "ui/mainPage.hpp"
#include "ui/instPage.hpp"
#include "util.hpp"
#define COLOR(hex) pu::ui::Color::FromHex(hex)
@ -13,10 +11,13 @@ namespace inst::ui {
this->SetBackgroundColor(COLOR("#670000FF"));
this->topText = TextBlock::New(10, 2, "Awoo Installer", 35);
this->topText->SetColor(COLOR("#FFFFFFFF"));
this->pageInfoText = TextBlock::New(10, 45, "", 35);
this->pageInfoText = TextBlock::New(10, 180, "", 35);
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
this->installBar = pu::ui::elm::ProgressBar::New(340, 360, 600, 48, 100.0f);
this->installBar->SetColor(COLOR("#222222FF"));
this->Add(this->topText);
this->Add(this->pageInfoText);
this->Add(this->installBar);
}
void instPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {

View File

@ -1,9 +1,8 @@
#include <filesystem>
#include "ui/MainApplication.hpp"
#include "ui/mainPage.hpp"
#include "curl.hpp"
#include "util.hpp"
#include "unzip.hpp"
#include "util/util.hpp"
#include "sigInstall.hpp"
#include "netInstall.hpp"
#define COLOR(hex) pu::ui::Color::FromHex(hex)
@ -18,16 +17,12 @@ namespace inst::ui {
this->optionMenu = pu::ui::elm::Menu::New(0, 160, 1280, COLOR("#FFFFFF00"), 80, (560 / 80));
this->optionMenu->SetOnFocusColor(COLOR("#00000033"));
this->installMenuItem = pu::ui::elm::MenuItem::New("Install NSP");
//this->installMenuItem->AddOnClick(std::bind(&MainPage::installMenuItem_Click, this));
this->installMenuItem->SetColor(COLOR("#FFFFFFFF"));
this->netInstallMenuItem = pu::ui::elm::MenuItem::New("Install NSP Over LAN");
//this->netInstallMenuItem->AddOnClick(std::bind(&MainPage::netInstallMenuItem_Click, this));
this->netInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
this->sigPatchesMenuItem = pu::ui::elm::MenuItem::New("Install Signature Patches");
//this->sigPatchesMenuItem->AddOnClick(std::bind(&MainPage::sigPatchesMenuItem_Click, this));
this->sigPatchesMenuItem = pu::ui::elm::MenuItem::New("Manage Signature Patches");
this->sigPatchesMenuItem->SetColor(COLOR("#FFFFFFFF"));
this->exitMenuItem = pu::ui::elm::MenuItem::New("Exit");
//this->exitMenuItem->AddOnClick(std::bind(&MainPage::exitMenuItem_Click, this));
this->exitMenuItem->SetColor(COLOR("#FFFFFFFF"));
this->Add(this->topText);
this->optionMenu->AddItem(this->installMenuItem);
@ -50,21 +45,7 @@ namespace inst::ui {
}
void MainPage::sigPatchesMenuItem_Click() {
std::string ourPath = appVariables::appDir + "patches.zip";
bool didDownload = curlStuff::downloadFile("http://github.com/Joonie86/hekate/releases/download/5.0.0J/Kosmos_patches_10_09_2019.zip", ourPath.c_str());
bool didExtract = false;
if (didDownload) didExtract = zipStuff::extractFile(ourPath, "sdmc:/");
else {
mainApp->CreateShowDialog("Could not download signature patches!", "", {"OK"}, true);
return;
}
std::filesystem::remove(ourPath);
if (didExtract) mainApp->CreateShowDialog("Install complete! Restart your console to apply!", "", {"OK"}, true);
else {
mainApp->CreateShowDialog("Could not extract files!", "", {"OK"}, true);
return;
}
return;
sig::installSigPatches();
}
void MainPage::exitMenuItem_Click() {

View File

@ -2,7 +2,7 @@
#include "ui/MainApplication.hpp"
#include "ui/mainPage.hpp"
#include "ui/netInstPage.hpp"
#include "util.hpp"
#include "util/util.hpp"
#include "netInstall.hpp"
#define COLOR(hex) pu::ui::Color::FromHex(hex)

View File

@ -3,7 +3,7 @@
#include "ui/mainPage.hpp"
#include "ui/nspInstPage.hpp"
#include "nspInstall.hpp"
#include "util.hpp"
#include "util/util.hpp"
#define COLOR(hex) pu::ui::Color::FromHex(hex)

View File

@ -1,4 +1,4 @@
#include "curl.hpp"
#include "util/curl.hpp"
#include <curl/curl.h>
#include <string>

View File

@ -15,7 +15,7 @@ namespace tin::util
return __bswap64(*(u64 *)(rightsId.c + 8));
}
std::string GetNcaIdString(const NcmNcaId& ncaId)
std::string GetNcaIdString(const NcmContentId& ncaId)
{
char ncaIdStr[FS_MAX_PATH] = {0};
u64 ncaIdLower = __bswap64(*(u64 *)ncaId.c);
@ -24,9 +24,9 @@ namespace tin::util
return std::string(ncaIdStr);
}
NcmNcaId GetNcaIdFromString(std::string ncaIdStr)
NcmContentId GetNcaIdFromString(std::string ncaIdStr)
{
NcmNcaId ncaId = {0};
NcmContentId ncaId = {0};
char lowerU64[17] = {0};
char upperU64[17] = {0};
memcpy(lowerU64, ncaIdStr.c_str(), 16);

View File

@ -1,8 +1,10 @@
#include <filesystem>
#include <vector>
#include <algorithm>
#include <fstream>
#include <unistd.h>
#include "switch.h"
#include "util.hpp"
#include "util/util.hpp"
#include "nx/ipc/tin_ipc.h"
namespace util {
@ -48,4 +50,32 @@ namespace util {
std::reverse(files.begin(), files.end());
return files;
}
bool removeDirectory(std::string dir) {
try {
for(auto & p: std::filesystem::recursive_directory_iterator(dir))
{
if (std::filesystem::is_regular_file(p))
{
std::filesystem::remove(p);
}
}
rmdir(dir.c_str());
return true;
}
catch (std::filesystem::filesystem_error & e) {
return false;
}
}
bool copyFile(std::string inFile, std::string outFile) {
char ch;
std::ifstream f1(inFile);
std::ofstream f2(outFile);
if(!f1 || !f2) return false;
while(f1 && f1.get(ch)) f2.put(ch);
return true;
}
}