Compare commits

...

3 Commits

Author SHA1 Message Date
Chee Yee df6a068bd3 add support for more compress formats and password protected archive 2024-01-13 19:48:07 -08:00
Chee Yee c1307d4221 fix crash for invalid smb url 2024-01-08 18:06:09 -08:00
Chee Yee 832c60862b display title name instead of id during install 2023-11-16 23:22:57 -08:00
8 changed files with 356 additions and 132 deletions
+6 -1
View File
@@ -70,7 +70,7 @@ add_executable(ezremote_client
add_self(ezremote_client)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.10" 32 0)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.11" 32 0)
target_link_libraries(ezremote_client
c
@@ -93,6 +93,11 @@ target_link_libraries(ezremote_client
minizip
un7zip
unrar
bz2
b2
lzma
lz4
archive
json-c
ssh2
kernel
+4 -1
View File
@@ -28,6 +28,7 @@
#include "web/request.hpp"
#include "web/urn.hpp"
#include "system.h"
#include "sfo.h"
#include "zip_util.h"
namespace Actions
@@ -709,7 +710,9 @@ namespace Actions
else
{
std::string url = INSTALLER::getRemoteUrl(it->path, true);
if (INSTALLER::InstallRemotePkg(url, &header, true) == 0)
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
failed++;
else
success++;
+7
View File
@@ -34,7 +34,14 @@ int SmbClient::Connect(const std::string &url, const std::string &user, const st
sprintf(response, "Failed to init SMB context");
return 0;
}
smb_url = smb2_parse_url(smb2, url.c_str());
if (smb_url == NULL || smb_url->share == NULL || strlen(smb_url->share) == 0)
{
sprintf(response, "Invalid SMB Url");
return 0;
}
if (pass.length() > 0)
smb2_set_password(smb2, pass.c_str());
smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED);
+108 -9
View File
@@ -21,7 +21,9 @@
#include "lang.h"
#include "system.h"
#include "fs.h"
#include "sfo.h"
#include "clients/webdavclient.h"
#include "clients/remote_client.h"
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
@@ -99,6 +101,96 @@ namespace INSTALLER
s_bgft_initialized = false;
}
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header)
{
size_t entry_count = BE32(header->pkg_entry_count);
uint32_t entry_table_offset = BE32(header->pkg_table_offset);
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
void *entry_table_data = malloc(entry_table_size);
int ret = client->GetRange(path, entry_table_data, entry_table_size, entry_table_offset);
if (ret == 0)
{
free(entry_table_data);
return "";
}
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
void* param_sfo_data = nullptr;
uint32_t param_sfo_offset = 0;
uint32_t param_sfo_size = 0;
for (size_t i = 0; i < entry_count; ++i)
{
if (BE32(entries[i].id) == PKG_ENTRY_ID__PARAM_SFO)
{
param_sfo_offset = BE32(entries[i].offset);
param_sfo_size = BE32(entries[i].size);
break;
}
}
free(entry_table_data);
std::string title;
if (param_sfo_offset > 0 && param_sfo_size > 0)
{
param_sfo_data = malloc(param_sfo_size);
int ret = client->GetRange(path, param_sfo_data, param_sfo_size, param_sfo_offset);
if (ret)
{
const char* tmp_title = SFO::GetString((const char*)param_sfo_data, param_sfo_size, "TITLE");
if (tmp_title != nullptr)
title = std::string(tmp_title);
}
free(param_sfo_data);
}
return title;
}
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header)
{
size_t entry_count = BE32(header->pkg_entry_count);
uint32_t entry_table_offset = BE32(header->pkg_table_offset);
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
void *entry_table_data = malloc(entry_table_size);
FILE *fd = FS::OpenRead(path);
FS::Seek(fd, entry_table_offset);
FS::Read(fd, entry_table_data, entry_table_size);
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
void* param_sfo_data = NULL;
uint32_t param_sfo_offset = 0;
uint32_t param_sfo_size = 0;
void *icon0_png_data = NULL;
uint32_t icon0_png_offset = 0;
uint32_t icon0_png_size = 0;
for (size_t i = 0; i < entry_count; ++i)
{
if (BE32(entries[i].id) == PKG_ENTRY_ID__PARAM_SFO)
{
param_sfo_offset = BE32(entries[i].offset);
param_sfo_size = BE32(entries[i].size);
break;
}
}
free(entry_table_data);
std::string title;
if (param_sfo_offset > 0 && param_sfo_size > 0)
{
param_sfo_data = malloc(param_sfo_size);
FS::Seek(fd, param_sfo_offset);
FS::Read(fd, param_sfo_data, param_sfo_size);
const char* tmp_title = SFO::GetString((const char*)param_sfo_data, param_sfo_size, "TITLE");
if (tmp_title != nullptr)
title = std::string(tmp_title);
free(param_sfo_data);
}
return title;
}
std::string getRemoteUrl(const std::string path, bool encodeUrl)
{
if (strlen(remote_settings->username) == 0 && strlen(remote_settings->password) == 0 &&
@@ -145,7 +237,7 @@ namespace INSTALLER
return true;
}
int InstallRemotePkg(const std::string &url, pkg_header *header, bool prompt)
int InstallRemotePkg(const std::string &url, pkg_header *header, std::string title, bool prompt)
{
if (url.empty())
return 0;
@@ -153,6 +245,7 @@ namespace INSTALLER
int ret;
std::string cid = std::string((char *)header->pkg_content_id);
cid = cid.substr(cid.find_first_of("-") + 1, 9);
std::string display_title = title.length() > 0 ? title : cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
@@ -196,7 +289,7 @@ namespace INSTALLER
params.entitlementType = 5;
params.id = (char *)header->pkg_content_id;
params.contentUrl = url.c_str();
params.contentName = cid.c_str();
params.contentName = display_title.c_str();
params.iconPath = "";
params.playgoScenarioId = "0";
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
@@ -215,7 +308,7 @@ namespace INSTALLER
{
if (prompt)
{
sprintf(confirm_message, "%s - %s?", cid.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
@@ -251,7 +344,7 @@ namespace INSTALLER
goto err;
}
Util::Notify("%s queued", cid.c_str());
Util::Notify("%s queued", display_title.c_str());
if (prompt)
{
@@ -299,6 +392,9 @@ namespace INSTALLER
return 0;
}
std::string title = GetLocalPkgTitle(path, &header);
std::string display_title = title.length() > 0 ? title : std::string(titleId);
OrbisBgftTaskProgress progress_info;
OrbisBgftDownloadParamEx download_params;
memset(&download_params, 0, sizeof(download_params));
@@ -306,7 +402,7 @@ namespace INSTALLER
download_params.params.entitlementType = 5;
download_params.params.id = (char *)header.pkg_content_id;
download_params.params.contentUrl = filepath;
download_params.params.contentName = path.c_str();
download_params.params.contentName = display_title.c_str();
;
download_params.params.iconPath = "";
download_params.params.playgoScenarioId = "0";
@@ -331,7 +427,7 @@ namespace INSTALLER
if (ret)
return 0;
Util::Notify("%s queued", path.c_str());
Util::Notify("%s queued", display_title.c_str());
file_transfering = true;
bytes_to_download = 100;
@@ -373,6 +469,9 @@ namespace INSTALLER
return 0;
}
std::string title = GetLocalPkgTitle(path, header);
std::string display_title = title.length() > 0 ? title : std::string(titleId);
OrbisBgftTaskProgress progress_info;
int prog = 0;
OrbisBgftDownloadParamEx download_params;
@@ -381,7 +480,7 @@ namespace INSTALLER
download_params.params.entitlementType = 5;
download_params.params.id = (char *)header->pkg_content_id;
download_params.params.contentUrl = filepath;
download_params.params.contentName = filename.c_str();
download_params.params.contentName = display_title.c_str();
;
download_params.params.iconPath = "";
download_params.params.playgoScenarioId = "0";
@@ -394,7 +493,7 @@ namespace INSTALLER
ret = sceBgftServiceIntDownloadRegisterTaskByStorageEx(&download_params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
sprintf(confirm_message, "%s - %s?", path.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
@@ -429,7 +528,7 @@ namespace INSTALLER
if (!remove_after_install)
{
Util::Notify("%s queued", filename.c_str());
Util::Notify("%s queued", display_title.c_str());
return 1;
}
+5 -1
View File
@@ -1,5 +1,7 @@
#pragma once
#include "clients/remote_client.h"
#define SWAP16(x) \
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
(((uint16_t)(x)&UINT16_C(0xFF00)) >> 8)))
@@ -121,9 +123,11 @@ namespace INSTALLER
bool canInstallRemotePkg(const std::string &url);
std::string getRemoteUrl(const std::string path, bool encodeUrl = false);
int InstallRemotePkg(const std::string &path, pkg_header *header, bool prompt = false);
int InstallRemotePkg(const std::string &path, pkg_header *header, std::string title, bool prompt = false);
int InstallLocalPkg(const std::string &path);
int InstallLocalPkg(const std::string &path, pkg_header *header, bool remove_after_install = false);
bool ExtractLocalPkg(const std::string &path, const std::string sfo_path, const std::string icon_path);
bool ExtractRemotePkg(const std::string &path, const std::string sfo_path, const std::string icon_path);
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header);
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header);
}
+2 -1
View File
@@ -1105,10 +1105,11 @@ namespace HttpServer
BaseClient *baseclient = new BaseClient();
baseclient->Connect(host, "", "");
baseclient->Head(path, &header, sizeof(pkg_header));
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
delete(baseclient);
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header);
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title);
if (rc == 0)
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
+2 -2
View File
@@ -1062,7 +1062,7 @@ namespace Windows
ime_after_update = AfterExtractFolderCallback;
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = true;
file_transfering = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
@@ -2000,7 +2000,7 @@ namespace Windows
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = true;
file_transfering = false;
selected_action = ACTION_NONE;
Actions::ExtractLocalZips();
break;
+222 -117
View File
@@ -9,18 +9,23 @@
#include <minizip/zip.h>
#include <un7zip.h>
#include <unrar.h>
#include <archive.h>
#include <archive_entry.h>
#include "common.h"
#include "fs.h"
#include "ime_dialog.h"
#include "lang.h"
#include "system.h"
#include "windows.h"
#include "zip_util.h"
#define TRANSFER_SIZE (128 * 1024)
#define TRANSFER_SIZE (16 * 1024)
namespace ZipUtil
{
static char filename_extracted[256];
static char password[128];
void callback_7zip(const char *fileName, unsigned long fileSize, unsigned fileNum, unsigned numFiles)
{
@@ -217,153 +222,253 @@ namespace ZipUtil
return 1;
}
CompressFileType getCompressFileType(const std::string &file)
/* duplicate a path name, possibly converting to lower case */
static char *pathdup(const char *path)
{
char buf[8];
char *str;
size_t i, len;
memset(buf, 0, 8);
int ret = FS::Head(file, buf, 8);
if (ret == 0)
return COMPRESS_FILE_TYPE_UNKNOWN;
if (path == NULL || path[0] == '\0')
return (NULL);
if (strncmp(buf, (const char *)MAGIC_7Z_1, 6) == 0)
return COMPRESS_FILE_TYPE_7Z;
else if (strncmp(buf, (const char *)MAGIC_RAR_1, 7) == 0 || strncmp(buf, (const char *)MAGIC_RAR_2, 8) == 0)
return COMPRESS_FILE_TYPE_RAR;
else if (strncmp(buf, (const char *)MAGIC_ZIP_1, 4) == 0 || strncmp(buf, (const char *)MAGIC_ZIP_2, 4) == 0 || strncmp(buf, (const char *)MAGIC_ZIP_3, 4) == 0)
return COMPRESS_FILE_TYPE_ZIP;
len = strlen(path);
while (len && path[len - 1] == '/')
len--;
if ((str = (char*) malloc(len + 1)) == NULL) {
errno = ENOMEM;
}
memcpy(str, path, len);
return COMPRESS_FILE_TYPE_UNKNOWN;
str[len] = '\0';
return (str);
}
int ExtractZip(const DirEntry &file, const std::string &dir)
/* concatenate two path names */
static char *pathcat(const char *prefix, const char *path)
{
file_transfering = true;
unz_global_info global_info;
unz_file_info file_info;
unzFile zipfile = unzOpen(file.path);
std::string dest_dir = std::string(dir);
if (dest_dir[dest_dir.length() - 1] != '/')
{
dest_dir = dest_dir + "/";
}
if (zipfile == NULL)
{
return 0;
}
unzGetGlobalInfo(zipfile, &global_info);
unzGoToFirstFile(zipfile);
uint64_t curr_extracted_bytes = 0;
uint64_t curr_file_bytes = 0;
int num_files = global_info.number_entry;
char fname[512];
char ext_fname[512];
char read_buffer[TRANSFER_SIZE];
char *str;
size_t prelen, len;
for (int zip_idx = 0; zip_idx < num_files; ++zip_idx)
{
if (stop_activity)
break;
unzGetCurrentFileInfo(zipfile, &file_info, fname, 512, NULL, 0, NULL, 0);
sprintf(ext_fname, "%s%s", dest_dir.c_str(), fname);
const size_t filename_length = strlen(ext_fname);
bytes_transfered = 0;
bytes_to_download = file_info.uncompressed_size;
if (ext_fname[filename_length - 1] != '/')
{
snprintf(activity_message, 255, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, fname);
curr_file_bytes = 0;
unzOpenCurrentFile(zipfile);
FS::MkDirs(ext_fname, true);
FILE *f = fopen(ext_fname, "wb");
while (curr_file_bytes < file_info.uncompressed_size)
{
int rbytes = unzReadCurrentFile(zipfile, read_buffer, TRANSFER_SIZE);
if (rbytes > 0)
{
fwrite(read_buffer, 1, rbytes, f);
curr_extracted_bytes += rbytes;
curr_file_bytes += rbytes;
bytes_transfered = curr_file_bytes;
}
}
fclose(f);
unzCloseCurrentFile(zipfile);
}
else
{
FS::MkDirs(ext_fname, true);
}
if ((zip_idx + 1) < num_files)
{
unzGoToNextFile(zipfile);
}
prelen = prefix ? strlen(prefix) + 1 : 0;
len = strlen(path) + 1;
if ((str = (char*) malloc(prelen + len)) == NULL) {
errno = ENOMEM;
}
unzClose(zipfile);
return 1;
if (prefix) {
memcpy(str, prefix, prelen); /* includes zero */
str[prelen - 1] = '/'; /* splat zero */
}
memcpy(str + prelen, path, len); /* includes zero */
return (str);
}
int Extract7Zip(const DirEntry &file, const std::string &dir)
/*
* Extract a directory.
*/
static void extract_dir(struct archive *a, struct archive_entry *e, const std::string &path)
{
file_transfering = false;
FS::MkDirs(dir, true);
sprintf(filename_extracted, "%s", file.name);
int res = Extract7zFileEx(file.path, dir.c_str(), callback_7zip, DEFAULT_IN_BUF_SIZE);
return res == 0;
int mode;
if (path[0] == '\0')
return;
FS::MkDirs(path);
archive_read_data_skip(a);
}
int ExtractRar(const DirEntry &file, const std::string &dir)
/*
* Extract to a file descriptor
*/
static int extract2fd(struct archive *a, const std::string &pathname, int fd)
{
file_transfering = false;
HANDLE hArcData; // Archive Handle
struct RAROpenArchiveDataEx rarOpenArchiveData;
struct RARHeaderDataEx rarHeaderData;
char destPath[256];
ssize_t len;
unsigned char buffer[TRANSFER_SIZE];
memset(&rarOpenArchiveData, 0, sizeof(rarOpenArchiveData));
memset(&rarHeaderData, 0, sizeof(rarHeaderData));
/* loop over file contents and write to fd */
for (int n = 0; ; n++) {
len = archive_read_data(a, buffer, sizeof buffer);
sprintf(destPath, "%s", dir.c_str());
rarOpenArchiveData.ArcName = (char *)file.path;
rarOpenArchiveData.CmtBuf = NULL;
rarOpenArchiveData.CmtBufSize = 0;
rarOpenArchiveData.OpenMode = RAR_OM_EXTRACT;
hArcData = RAROpenArchiveEx(&rarOpenArchiveData);
if (len == 0)
return 1;
if (rarOpenArchiveData.OpenResult != ERAR_SUCCESS)
{
return 0;
}
while (RARReadHeaderEx(hArcData, &rarHeaderData) == ERAR_SUCCESS)
{
sprintf(activity_message, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, rarHeaderData.FileName);
if (RARProcessFile(hArcData, RAR_EXTRACT, destPath, NULL) != ERAR_SUCCESS)
if (len < 0)
{
RARCloseArchive(hArcData);
sprintf(status_message, "error archive_read_data('%s')", pathname.c_str());
return 0;
}
if (write(fd, buffer, len) != len)
{
sprintf(status_message, "error write('%s')", pathname.c_str());
return 0;
}
}
RARCloseArchive(hArcData);
return 1;
}
int Extract(const DirEntry &file, const std::string &dir)
/*
* Extract a regular file.
*/
static void extract_file(struct archive *a, struct archive_entry *e, const std::string &path)
{
CompressFileType fileType = getCompressFileType(file.path);
struct stat sb;
int fd;
const char *linkname;
if (fileType == COMPRESS_FILE_TYPE_ZIP)
return ExtractZip(file, dir);
else if (fileType == COMPRESS_FILE_TYPE_7Z)
return Extract7Zip(file, dir);
else if (fileType == COMPRESS_FILE_TYPE_RAR)
return ExtractRar(file, dir);
/* look for existing file of same name */
recheck:
if (lstat(path.c_str(), &sb) == 0) {
(void)unlink(path.c_str());
}
/* process symlinks */
linkname = archive_entry_symlink(e);
if (linkname != NULL) {
if (symlink(linkname, path.c_str()) != 0)
{
sprintf(status_message, "error symlink('%s')", path.c_str());
return;
}
/* set access and modification time */
return;
}
if ((fd = open(path.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0777)) < 0)
{
sprintf(status_message, "error open('%s')", path.c_str());
return;
}
extract2fd(a, path, fd);
/* set access and modification time */
if (close(fd) != 0)
{
return;
}
}
static void extract(struct archive *a, struct archive_entry *e, const std::string &base_dir)
{
char *pathname, *realpathname;
mode_t filetype;
char *p, *q;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) {
archive_read_data_skip(a);
return;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL) {
archive_read_data_skip(a);
free(pathname);
return;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) {
archive_read_data_skip(a);
free(pathname);
return;
}
realpathname = pathcat(base_dir.c_str(), pathname);
/* ensure that parent directory exists */
FS::MkDirs(realpathname, true);
if (S_ISDIR(filetype))
extract_dir(a, e, realpathname);
else
{
sprintf(status_message, "%s - %s", file.name, lang_strings[STR_UNSUPPORTED_FILE_FORMAT]);
return -1;
snprintf(activity_message, 255, "%s: %s", lang_strings[STR_EXTRACTING], pathname);
extract_file(a, e, realpathname);
}
free(realpathname);
free(pathname);
}
/*
* Callback function for reading passphrase.
* Originally from cpio.c and passphrase.c, libarchive.
*/
static const char *passphrase_callback(struct archive *a, void *_client_data)
{
Dialog::initImeDialog(lang_strings[STR_PASSWORD], password, 127, ORBIS_TYPE_DEFAULT, 560, 200);
int ime_result = Dialog::updateImeDialog();
if (ime_result == IME_DIALOG_RESULT_FINISHED || ime_result == IME_DIALOG_RESULT_CANCELED)
{
if (ime_result == IME_DIALOG_RESULT_FINISHED)
{
snprintf(password, 127, "%s", (char *)Dialog::getImeDialogInputText());
return password;
}
else
{
memset(password, 0, sizeof(password));
}
}
memset(password, 0, sizeof(password));
return password;
}
/*
* Main loop: open the zipfile, iterate over its contents and decide what
* to do with each entry.
*/
int Extract(const DirEntry &file, const std::string &basepath)
{
struct archive *a;
struct archive_entry *e;
int ret;
uintmax_t total_size, file_count, error_count;
if ((a = archive_read_new()) == NULL)
sprintf(status_message, "%s", "archive_read_new failed");
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
archive_read_set_passphrase_callback(a, NULL, &passphrase_callback);
ret = archive_read_open_filename(a, file.path, TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
for (;;) {
if (stop_activity)
break;
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
archive_read_free(a);
return 0;
}
if (ret == ARCHIVE_EOF)
break;
extract(a, e, basepath);
}
archive_read_free(a);
return 1;
}
}