Compare commits

...

5 Commits

Author SHA1 Message Date
Chee Yee 267551c979 add ability to install pkg inside compress files 2024-02-03 18:58:42 -08:00
Chee Yee b761596fe3 set extract folder to current local directory on multi select 2024-01-31 02:16:54 -08:00
Chee Yee 99568b9990 update logic for selecting default extract folder 2024-01-31 02:13:32 -08:00
Chee Yee 414a8a4b50 add ability to extract files from remote server 2024-01-31 01:47:51 -08:00
Chee Yee 628312360c clear multi selection after uploading files 2024-01-24 23:19:55 -08:00
22 changed files with 1035 additions and 89 deletions
+2 -1
View File
@@ -66,11 +66,12 @@ add_executable(ezremote_client
source/textures.cpp
source/windows.cpp
source/zip_util.cpp
source/split_file.cpp
)
add_self(ezremote_client)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.13" 32 0)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.14" 32 0)
target_link_libraries(ezremote_client
c
+2 -1
View File
@@ -156,4 +156,5 @@ STR_CANT_EXTRACT_URL_MSG=Couldn't extract download url
STR_FAIL_INSTALL_FROM_URL_MSG=Failed to install from URL
STR_INVALID_URL=InValid URL
STR_ALLDEBRID_API_KEY_MISSING_MSG=To use this function, an API Key needs to be configured in the ezRemote Client settings
STR_LANGUAGE=Language
STR_LANGUAGE=Language
STR_TEMP_DIRECTORY=Temp Directory
+129 -2
View File
@@ -465,6 +465,7 @@ namespace Actions
}
activity_inprogess = false;
file_transfering = false;
multi_selected_local_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_REMOTE_FILES;
return NULL;
@@ -722,6 +723,30 @@ namespace Actions
skipped++;
}
}
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") ||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz"))
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path, true);
if (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int res = pthread_create(&install_data->thread, NULL, ExtractArchivePkg, install_data);
INSTALLER::InstallArchivePkg(entry->filename, install_data);
success++;
}
else
skipped++;
}
else
skipped++;
}
@@ -751,6 +776,41 @@ namespace Actions
}
}
void *ExtractArchivePkg(void *argp)
{
ssize_t len;
char buffer[ARCHIVE_TRANSFER_SIZE];
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) argp;
SplitFile *sp = install_data->split_file;
/* loop over file contents and write to fd */
sp->Open();
while (!install_data->stop_write_thread)
{
len = archive_read_data(install_data->archive_entry->archive, buffer, sizeof buffer);
if (len == 0)
break;
if (len < 0)
{
sprintf(status_message, "error archive_read_data('%s')", install_data->archive_entry->filename.c_str());
break;
}
if (sp->Write(buffer, len) != len)
{
sprintf(status_message, "error write('%s')", install_data->archive_entry->filename.c_str());
break;;
}
}
sp->Close();
return NULL;
}
void *InstallLocalPkgsThread(void *argp)
{
int failed = 0;
@@ -774,7 +834,7 @@ namespace Actions
{
std::string path = std::string(it->path);
path = Util::ToLower(path);
if (path.size() > 4 && path.substr(path.size() - 4) == ".pkg")
if (Util::EndsWith(path,".pkg"))
{
pkg_header header;
memset(&header, 0, sizeof(header));
@@ -805,6 +865,30 @@ namespace Actions
skipped++;
}
}
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") || Util::EndsWith(path,".7z") ||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz") || Util::EndsWith(path,".tar.bz2") )
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path);
if (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int res = pthread_create(&install_data->thread, NULL, ExtractArchivePkg, install_data);
INSTALLER::InstallArchivePkg(entry->filename, install_data);
success++;
}
else
skipped++;
}
else
skipped++;
}
@@ -876,6 +960,49 @@ namespace Actions
}
}
void *ExtractRemoteZipThread(void *argp)
{
FS::MkDirs(extract_zip_folder);
std::vector<DirEntry> files;
if (multi_selected_remote_files.size() > 0)
std::copy(multi_selected_remote_files.begin(), multi_selected_remote_files.end(), std::back_inserter(files));
else
files.push_back(selected_remote_file);
for (std::vector<DirEntry>::iterator it = files.begin(); it != files.end(); ++it)
{
if (stop_activity)
break;
if (!it->isDir)
{
int ret = ZipUtil::Extract(*it, extract_zip_folder, true);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAILED_TO_EXTRACT], it->name);
sceKernelUsleep(100000);
}
}
}
activity_inprogess = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_LOCAL_FILES;
return NULL;
}
void ExtractRemoteZips()
{
sprintf(status_message, "%s", "");
int res = pthread_create(&bk_activity_thid, NULL, ExtractRemoteZipThread, NULL);
if (res != 0)
{
file_transfering = false;
activity_inprogess = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
}
}
void *MakeZipThread(void *argp)
{
zipFile zf = zipOpen64(zip_file_path, APPEND_STATUS_CREATE);
@@ -1586,7 +1713,7 @@ namespace Actions
OrbisTick tick;
sceRtcGetCurrentClockLocalTime(&now);
sceRtcGetTick(&now, &tick);
sprintf(local_file, "%s/%lu.pkg", DATA_PATH, tick.mytick);
sprintf(local_file, "%s/%lu.pkg", temp_folder, tick.mytick);
sprintf(activity_message, "%s %s to %s", lang_strings[STR_DOWNLOADING], filename.c_str(), local_file);
remoteclient->Size(filename, &bytes_to_download);
+5 -1
View File
@@ -56,7 +56,8 @@ enum ACTIONS
ACTION_VIEW_LOCAL_IMAGE,
ACTION_VIEW_REMOTE_IMAGE,
ACTION_VIEW_LOCAL_PKG,
ACTION_VIEW_REMOTE_PKG
ACTION_VIEW_REMOTE_PKG,
ACTION_EXTRACT_REMOTE_ZIP,
};
enum OverWriteType
@@ -103,6 +104,8 @@ namespace Actions
void *KeepAliveThread(void *argp);
void *ExtractZipThread(void *argp);
void ExtractLocalZips();
void *ExtractRemoteZipThread(void *argp);
void ExtractRemoteZips();
void *MakeZipThread(void *argp);
void MakeLocalZip();
void *MoveLocalFilesThread(void *argp);
@@ -116,6 +119,7 @@ namespace Actions
int DownloadAndInstallPkg(const std::string &filename, pkg_header *header);
void CreateLocalFile(char *filename);
void CreateRemoteFile(char *filename);
void *ExtractArchivePkg(void *argp);
}
#endif
+2 -1
View File
@@ -20,7 +20,8 @@ enum RemoteActions
REMOTE_ACTION_INSTALL = 256,
REMOTE_ACTION_EDIT = 512,
REMOTE_ACTION_NEW_FILE = 1024,
REMOTE_ACTION_ALL = 2047
REMOTE_ACTION_EXTRACT = 2048,
REMOTE_ACTION_ALL = 4095
};
enum ClientType
+20
View File
@@ -39,6 +39,7 @@ int max_edit_file_size;
GoogleAppInfo gg_app;
bool show_hidden_files;
char alldebrid_api_key[32];
char temp_folder[256];
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
@@ -187,6 +188,14 @@ namespace CONFIG
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
// alldebrid api key
char tmp_api_key[512];
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, ""));
@@ -388,6 +397,7 @@ namespace CONFIG
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions);
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
WriteString(CONFIG_GLOBAL, CONFIG_LANGUAGE, language);
@@ -397,6 +407,16 @@ namespace CONFIG
WriteIniFile(CONFIG_INI_FILE);
CloseIniFile();
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
if (!FS::FolderExists(compressed_file_path))
{
FS::MkDirs(compressed_file_path);
}
}
void SaveLocalDirecotry(const std::string &path)
+3
View File
@@ -17,6 +17,7 @@
#define TMP_EDITOR_FILE DATA_PATH "/tmp_editor.txt"
#define TMP_SFO_PATH DATA_PATH "/tmp_pkg.sfo"
#define TMP_ICON_PATH DATA_PATH "/tmp_icon.png"
#define TMP_FOLDER_PATH DATA_PATH "/tmp"
#define CONFIG_GLOBAL "Global"
@@ -70,6 +71,7 @@
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
#define CONFIG_LOCAL_DIRECTORY "local_directory"
#define CONFIG_TMP_FOLDER_PATH "temp_folder"
#define CONFIG_LANGUAGE "language"
@@ -139,6 +141,7 @@ extern unsigned char cipher_iv[16];
extern GoogleAppInfo gg_app;
extern bool show_hidden_files;
extern char alldebrid_api_key[32];
extern char temp_folder[256];
namespace CONFIG
{
+2 -12
View File
@@ -2,7 +2,6 @@
#include <string>
#include <vector>
#include <map>
#include "openssl/md5.h"
#include "filehost.h"
#include "1fichier.h"
@@ -12,7 +11,6 @@
#include "filehost/mediafire.h"
#include "filehost/pixeldrain.h"
#include "config.h"
#include "base64.h"
#include "util.h"
#define GDRIVE_REGEX "https:\\/\\/drive\\.google\\.com\\/(.*)"
@@ -22,17 +20,9 @@
static std::map<std::string, std::string> cache_downloal_urls;
std::string FileHost::Hash()
std::string FileHost::GetUrl()
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)this->url.c_str(), this->url.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
return url;
}
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
+1 -1
View File
@@ -11,8 +11,8 @@ public:
virtual ~FileHost(){};
virtual bool IsValidUrl() = 0;
virtual std::string GetDownloadUrl() = 0;
std::string GetUrl();
std::string Hash();
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false);
static std::string GetCachedDownloadUrl(std::string &hash);
static void AddCacheDownloadUrl(std::string &hash, std::string &url);
+162
View File
@@ -31,6 +31,8 @@ static OrbisBgftInitParams s_bgft_init_params;
static bool s_bgft_initialized = false;
static std::map<std::string, ArchivePkgInstallData *> archive_pkg_install_data_list;
namespace INSTALLER
{
int Init(void)
@@ -699,4 +701,164 @@ namespace INSTALLER
return true;
}
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash)
{
return archive_pkg_install_data_list[hash];
}
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data)
{
std::pair<std::string, ArchivePkgInstallData*> pair = std::make_pair(hash, pkg_data);
archive_pkg_install_data_list.erase(hash);
archive_pkg_install_data_list.insert(pair);
}
void RemoveArchivePkgInstallData(const std::string &hash)
{
archive_pkg_install_data_list.erase(hash);
}
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data)
{
pkg_header header;
pkg_data->split_file->Read((char*)&header, sizeof(pkg_header), 0);
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 = cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
uint32_t content_type = BE32(header.pkg_content_type);
uint32_t flags = BE32(header.pkg_content_flags);
bool is_patch = false;
bool completed = false;
switch (content_type)
{
case PKG_CONTENT_TYPE_GD:
package_type = "PS4GD";
break;
case PKG_CONTENT_TYPE_AC:
package_type = "PS4AC";
break;
case PKG_CONTENT_TYPE_AL:
package_type = "PS4AL";
break;
case PKG_CONTENT_TYPE_DP:
package_type = "PS4DP";
break;
default:
package_type = NULL;
return 0;
break;
}
if (flags & PKG_CONTENT_FLAGS_FIRST_PATCH ||
flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH ||
flags & PKG_CONTENT_FLAGS_DELTA_PATCH ||
flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
{
is_patch = true;
}
std::string hash = Util::UrlHash(path);
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
AddArchivePkgInstallData(hash, pkg_data);
OrbisBgftTaskProgress progress_info;
OrbisBgftDownloadParam params;
memset(&params, 0, sizeof(params));
{
params.userId = user_id;
params.entitlementType = 5;
params.id = (char *)header.pkg_content_id;
params.contentUrl = full_url.c_str();
params.contentName = display_title.c_str();
params.iconPath = "";
params.playgoScenarioId = "0";
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
params.packageType = package_type;
params.packageSubType = "";
params.packageSize = BE64(header.pkg_size);
}
retry:
int task_id = -1;
if (!is_patch)
ret = sceBgftServiceIntDownloadRegisterTask(&params, &task_id);
else
ret = sceBgftServiceIntDebugDownloadRegisterPkg(&params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
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;
while (confirm_state == CONFIRM_WAIT)
{
sceKernelUsleep(100000);
}
activity_inprogess = true;
selected_action = action_to_take;
if (confirm_state == CONFIRM_YES)
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
ret = 0;
goto finish;
}
goto retry;
}
}
else if (ret > 0)
{
ret = 0;
goto finish;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
ret = 0;
goto finish;
}
Util::Notify("%s queued", display_title.c_str());
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (!completed)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
{
ret = 0;
goto finish;
}
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
}
sceSystemServicePowerTick();
}
ret = 1;
finish:
pkg_data->stop_write_thread = true;
pthread_join(pkg_data->thread, NULL);
delete(pkg_data->split_file);
free(pkg_data->archive_entry);
free(pkg_data);
RemoveArchivePkgInstallData(hash);
return ret;
}
}
+17
View File
@@ -1,6 +1,9 @@
#pragma once
#include "clients/remote_client.h"
#include "zip_util.h"
#include "split_file.h"
#include "pthread.h"
#define SWAP16(x) \
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
@@ -46,6 +49,8 @@
#define PKG_ENTRY_ID__PARAM_SFO 0x1000
#define PKG_ENTRY_ID__ICON0_PNG 0x1200
#define INSTALL_ARCHIVE_PKG_SPLIT_SIZE 10485760
typedef struct
{
uint32_t pkg_magic; // 0x000 - 0x7F434E54
@@ -116,6 +121,14 @@ enum pkg_content_type
PKG_CONTENT_TYPE_DP = 0x1E, /* pkg_ps4_delta_patch */
};
struct ArchivePkgInstallData
{
SplitFile *split_file;
ArchiveEntry *archive_entry;
pthread_t thread;
bool stop_write_thread;
};
namespace INSTALLER
{
int Init(void);
@@ -130,4 +143,8 @@ namespace INSTALLER
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);
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash);
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data);
void RemoveArchivePkgInstallData(const std::string &hash);
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data);
}
+1
View File
@@ -169,6 +169,7 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"InValid URL", // STR_INVALID_URL
"To use this function, an API Key needs to be configured in the ezRemote Client settings", // STR_ALLDEBRID_API_KEY_MISSING_MSG
"Language", // STR_LANGUAGE
"Temp Directory", // STR_TEMP_DIRECTORY
};
bool needs_extended_font = false;
+3 -2
View File
@@ -162,7 +162,8 @@
FUNC(STR_FAIL_INSTALL_FROM_URL_MSG) \
FUNC(STR_INVALID_URL) \
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG) \
FUNC(STR_LANGUAGE)
FUNC(STR_LANGUAGE) \
FUNC(STR_TEMP_DIRECTORY)
#define GET_VALUE(x) x,
#define GET_STRING(x) #x,
@@ -172,7 +173,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 159
#define LANG_STRINGS_NUM 160
#define LANG_ID_SIZE 64
#define LANG_STR_SIZE 384
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
-1
View File
@@ -11,7 +11,6 @@
#include <orbis/Pad.h>
#include <orbis/AudioOut.h>
#include <orbis/Net.h>
// #include <dbglogger.h>
#include "imgui.h"
#include "SDL2/SDL.h"
+60 -1
View File
@@ -15,6 +15,7 @@
#include "lang.h"
#include "system.h"
#include "zip_util.h"
#include "util.h"
#include "installer.h"
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
@@ -1048,6 +1049,64 @@ namespace HttpServer
}
});
svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res)
{
RemoteClient *tmp_client;
RemoteSettings *tmp_settings;
std::string hash = req.matches[1];
ArchivePkgInstallData *pkg_data = INSTALLER::GetArchivePkgInstallData(hash);
if (req.method == "HEAD")
{
res.status = 204;
res.set_header("Content-Length", std::to_string(pkg_data->archive_entry->filesize));
res.set_header("Accept-Ranges", "bytes");
return;
}
if (req.ranges.empty())
{
res.status = 200;
res.set_content_provider(
131072, "application/octet-stream",
[pkg_data](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(131072);
size_t bytes_read = pkg_data->split_file->Read(buf, 131072, offset);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
else
{
res.status = 206;
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 65536ul - req.ranges[0].first;
res.set_header("Content-Length", std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-65535/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
range_len, "application/octet-stream",
[pkg_data, range, range_len](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(range_len);
size_t bytes_read = pkg_data->split_file->Read(buf, range_len, range.first);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
});
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
{
std::string url;
@@ -1085,7 +1144,7 @@ namespace HttpServer
return;
}
std::string hash = filehost->Hash();
std::string hash = Util::UrlHash(filehost->GetUrl());
std::string download_url = filehost->GetDownloadUrl();
if (download_url.empty())
{
+221
View File
@@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdio.h>
#include <string>
#include "common.h"
#include "split_file.h"
SplitFile::SplitFile(const std::string &path, size_t block_size)
{
this->block_size = block_size;
this->path = path;
this->complete = false;
sem_init(&this->block_ready, 0, 0);
}
SplitFile::~SplitFile()
{
for (int i = 0; i < this->file_blocks.size(); i++)
{
if (this->file_blocks[i] != nullptr && this->file_blocks[i]->status != BLOCK_STATUS_DELETED)
{
if (this->file_blocks[i]->fd != nullptr)
{
fclose(this->file_blocks[i]->fd);
}
remove(this->file_blocks[i]->block_file.c_str());
free(this->file_blocks[i]);
}
}
sem_destroy(&this->block_ready);
};
int SplitFile::Open()
{
this->block_in_progress = NewBlock();
this->block_in_progress->fd = fopen(block_in_progress->block_file.c_str(), "w");
return (block_in_progress->fd == nullptr);
}
size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
{
int first_block_num, block_num;
size_t block_offset;
size_t remaining;
size_t bytes_read;
size_t total_bytes_read;
FileBlock *block;
FILE *fd;
char *p;
first_block_num= offset / this->block_size;
block_num = first_block_num;
block_offset = offset % this->block_size;
while ((block_num >= this->file_blocks.size() && !this->complete) ||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
if (block->status == BLOCK_STATUS_DELETED)
{
return -1;
}
if (block_offset > block->size - 1 && this->complete)
{
// requested offset is pass the end of split file
return 0;
}
remaining = buf_size;
bool eof = false;
total_bytes_read = 0;
p = buf;
while (remaining > 0 && !eof)
{
fd = block->fd;
if (fd == nullptr)
{
fd = fopen(block->block_file.c_str(), "rb");
block->fd = fd;
}
fseek(fd, block_offset, SEEK_SET);
bytes_read = fread(p, 1, remaining, fd);
if (bytes_read == remaining)
{
p += bytes_read;
total_bytes_read += bytes_read;
}
else
{
if (feof(fd))
{
p += bytes_read;
total_bytes_read += bytes_read;
if (block->is_last)
{
eof = true;
continue;
}
}
else
return -1;
}
remaining -= bytes_read;
if (remaining == 0)
continue;
block_num++;
block_offset = 0;
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
}
// delete blocks before the first read offset block. Assumuption, that reads are always
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
for (int j=0; j < first_block_num - 2; j++)
{
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
{
if (this->file_blocks[j]->fd != nullptr)
{
fclose(this->file_blocks[j]->fd);
this->file_blocks[j]->fd = nullptr;
}
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
remove(this->file_blocks[j]->block_file.c_str());
}
}
return total_bytes_read;
}
size_t SplitFile::Write(char *buf, size_t buf_size)
{
size_t bytes_written;
size_t block_space_remaining;
size_t bytes_to_write;
char *p = buf;
size_t total_bytes_written = 0;
size_t remaining_to_write = buf_size;
while (remaining_to_write > 0)
{
block_space_remaining = this->block_size - block_in_progress->size;
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
bytes_written = fwrite(p, 1, bytes_to_write, block_in_progress->fd);
block_in_progress->size += bytes_written;
total_bytes_written += bytes_written;
remaining_to_write -= bytes_written;
block_space_remaining -= bytes_written;
p += bytes_written;
// error if bytes_to_write != bytes_written
if (bytes_written != bytes_to_write)
{
break;
}
if (block_space_remaining == 0)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
block_in_progress->status = BLOCK_STATUS_CREATED;
this->file_blocks.push_back(block_in_progress);
sem_post(&this->block_ready);
block_in_progress = NewBlock();
}
}
return total_bytes_written;
}
int SplitFile::Close()
{
if (block_in_progress->fd != nullptr)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
}
block_in_progress->status = BLOCK_STATUS_CREATED;
block_in_progress->is_last = true;
this->file_blocks.push_back(block_in_progress);
this->complete = true;
sem_post(&this->block_ready);
return 0;
}
FileBlock *SplitFile::NewBlock()
{
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
memset(block, 0, sizeof(FileBlock));
block->is_last = false;
block->size = 0;
block->block_file = this->path + "." + std::to_string(this->file_blocks.size());
block->fd = fopen(block->block_file.c_str(), "w");
return block;
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef SPLIT_FILE_H
#define SPLIT_FILE_H
#include <string>
#include <vector>
#include <mutex>
#include <pthread.h>
enum FileBlockStatus
{
BLOCK_STATUS_NOT_EXISTS,
BLOCK_STATUS_CREATED,
BLOCK_STATUS_DELETED
};
typedef struct
{
std::string block_file;
size_t size;
FILE* fd;
bool is_last;
FileBlockStatus status;
} FileBlock;
class SplitFile
{
public:
SplitFile(const std::string& path, size_t block_size);
~SplitFile();
size_t Read(char* buf, size_t buf_size, size_t offset);
size_t Write(char* buf, size_t buf_size);
int Open();
int Close();
private:
std::vector<FileBlock*> file_blocks;
size_t write_offset;
size_t block_size;
std::string path;
int write_error;
bool complete;
FileBlock *block_in_progress;
sem_t block_ready;
FileBlock *NewBlock();
};
#endif
+22
View File
@@ -6,6 +6,8 @@
#include <algorithm>
#include <stdarg.h>
#include <orbis/libkernel.h>
#include "base64.h"
#include "openssl/md5.h"
#include "lang.h"
namespace Util
@@ -47,6 +49,13 @@ namespace Util
return s;
}
static inline bool EndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static inline std::vector<std::string> Split(const std::string &str, const std::string &delimiter)
{
std::string text = std::string(str);
@@ -66,6 +75,19 @@ namespace Util
return tokens;
}
static inline std::string UrlHash(const std::string &text)
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)text.c_str(), text.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
}
static inline void Notify(const char *fmt, ...)
{
OrbisNotificationRequest request;
+79 -27
View File
@@ -243,20 +243,33 @@ namespace Windows
{
std::string zipfolder;
std::vector<DirEntry> files;
bool local_browser_selected = saved_selected_browser & LOCAL_BROWSER;
bool remote_browser_selected = saved_selected_browser & REMOTE_BROWSER;
if (multi_selected_local_files.size() > 0)
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
if (local_browser_selected)
{
if (multi_selected_local_files.size() > 0)
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
else
files.push_back(selected_local_file);
}
else
files.push_back(selected_local_file);
{
if (multi_selected_remote_files.size() > 0)
std::copy(multi_selected_remote_files.begin(), multi_selected_remote_files.end(), std::back_inserter(files));
else
files.push_back(selected_remote_file);
}
if (strncmp(files.begin()->directory, "/data", 5) != 0 &&
strncmp(files.begin()->directory, "/mnt/usb", 8) != 0)
if (strncmp(local_directory, "/data", 5) != 0 &&
strncmp(local_directory, "/mnt/usb", 8) != 0 &&
strncmp(local_directory, "/user/data", 10) != 0)
{
zipfolder = "/data";
}
else if (files.size() > 1)
{
zipfolder = files.begin()->directory;
zipfolder = local_directory;
}
else
{
@@ -1049,26 +1062,29 @@ namespace Windows
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Extract##settings");
if (ImGui::Selectable(lang_strings[STR_EXTRACT], false, getSelectableFlag(REMOTE_ACTION_EXTRACT) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
ResetImeCallbacks();
sprintf(extract_zip_folder, "%s", getExtractFolder().c_str());
ime_single_field = extract_zip_folder;
ime_field_size = 255;
ime_callback = SingleValueImeCallback;
if (local_browser_selected)
ime_after_update = AfterExtractFolderCallback;
else
ime_after_update = AfterExtractRemoteFolderCallback;
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
if (local_browser_selected)
{
ImGui::PushID("Extract##settings");
if (ImGui::Selectable(lang_strings[STR_EXTRACT], false, getSelectableFlag(REMOTE_ACTION_NONE) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
ResetImeCallbacks();
sprintf(extract_zip_folder, "%s", getExtractFolder().c_str());
ime_single_field = extract_zip_folder;
ime_field_size = 255;
ime_callback = SingleValueImeCallback;
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 = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Compress##settings");
if (ImGui::Selectable(lang_strings[STR_COMPRESS], false, getSelectableFlag(REMOTE_ACTION_NONE) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
@@ -1608,6 +1624,10 @@ namespace Windows
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 650), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
char id[192];
ImVec2 field_size;
float width;
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
@@ -1646,6 +1666,26 @@ namespace Windows
ImGui::Checkbox("##show_hidden_files", &show_hidden_files);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_TEMP_DIRECTORY]);
ImGui::SameLine();
field_size = ImGui::CalcTextSize(lang_strings[STR_TEMP_DIRECTORY]);
width = field_size.x + 45;
sprintf(id, "%s##temp_direcotry", temp_folder);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = temp_folder;
ime_field_size = 512;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_COMPRESSED_FILE_PATH], temp_folder, 255, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
// Web Server settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_WEB_SERVER]);
ImGui::Separator();
@@ -1656,15 +1696,13 @@ namespace Windows
ImGui::Checkbox("##web_server_enabled", &web_server_enabled);
ImGui::Separator();
ImVec2 field_size;
field_size = ImGui::CalcTextSize(lang_strings[STR_PORT]);
float width = field_size.x + 45;
width = field_size.x + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_PORT]);
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
char id[192];
sprintf(id, "%s##http_server_port", txt_http_server_port);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
if (ImGui::Button(id, ImVec2(835-width, 0)))
@@ -2027,6 +2065,15 @@ namespace Windows
selected_action = ACTION_NONE;
Actions::ExtractLocalZips();
break;
case ACTION_EXTRACT_REMOTE_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = false;
selected_action = ACTION_NONE;
Actions::ExtractRemoteZips();
break;
case ACTION_CREATE_LOCAL_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
@@ -2406,6 +2453,11 @@ namespace Windows
selected_action = ACTION_EXTRACT_LOCAL_ZIP;
}
void AfterExtractRemoteFolderCallback(int ime_result)
{
selected_action = ACTION_EXTRACT_REMOTE_ZIP;
}
void AfterZipFileCallback(int ime_result)
{
selected_action = ACTION_CREATE_LOCAL_ZIP;
+1
View File
@@ -206,6 +206,7 @@ namespace Windows
void AfterPackageUrlCallback(int ime_result);
void AfterFavoriteUrlCallback(int ime_result);
void AfterExtractFolderCallback(int ime_result);
void AfterExtractRemoteFolderCallback(int ime_result);
void AfterZipFileCallback(int ime_result);
void AferServerChangeCallback(int ime_result);
void AfterHttpPortChangeCallback(int ime_result);
+231 -38
View File
@@ -12,16 +12,17 @@
#include <archive.h>
#include <archive_entry.h>
#include "clients/remote_client.h"
#include "config.h"
#include "common.h"
#include "fs.h"
#include "ime_dialog.h"
#include "lang.h"
#include "system.h"
#include "windows.h"
#include "util.h"
#include "zip_util.h"
#define TRANSFER_SIZE (16 * 1024)
namespace ZipUtil
{
static char filename_extracted[256];
@@ -95,12 +96,12 @@ namespace ZipUtil
}
// Add file to zip
void *buf = memalign(4096, TRANSFER_SIZE);
void *buf = memalign(4096, ARCHIVE_TRANSFER_SIZE);
uint64_t seek = 0;
while (1)
{
int read = FS::Read(fd, buf, TRANSFER_SIZE);
int read = FS::Read(fd, buf, ARCHIVE_TRANSFER_SIZE);
if (read < 0)
{
free(buf);
@@ -234,7 +235,8 @@ namespace ZipUtil
len = strlen(path);
while (len && path[len - 1] == '/')
len--;
if ((str = (char*) malloc(len + 1)) == NULL) {
if ((str = (char *)malloc(len + 1)) == NULL)
{
errno = ENOMEM;
}
memcpy(str, path, len);
@@ -252,21 +254,23 @@ namespace ZipUtil
prelen = prefix ? strlen(prefix) + 1 : 0;
len = strlen(path) + 1;
if ((str = (char*) malloc(prelen + len)) == NULL) {
if ((str = (char *)malloc(prelen + len)) == NULL)
{
errno = ENOMEM;
}
if (prefix) {
memcpy(str, prefix, prelen); /* includes zero */
str[prelen - 1] = '/'; /* splat zero */
if (prefix)
{
memcpy(str, prefix, prelen); /* includes zero */
str[prelen - 1] = '/'; /* splat zero */
}
memcpy(str + prelen, path, len); /* includes zero */
memcpy(str + prelen, path, len); /* includes zero */
return (str);
}
/*
* Extract a directory.
*/
* Extract a directory.
*/
static void extract_dir(struct archive *a, struct archive_entry *e, const std::string &path)
{
int mode;
@@ -279,15 +283,16 @@ namespace ZipUtil
}
/*
* Extract to a file descriptor
*/
* Extract to a file descriptor
*/
static int extract2fd(struct archive *a, const std::string &pathname, int fd)
{
ssize_t len;
unsigned char buffer[TRANSFER_SIZE];
unsigned char buffer[ARCHIVE_TRANSFER_SIZE];
/* loop over file contents and write to fd */
for (int n = 0; ; n++) {
for (int n = 0;; n++)
{
len = archive_read_data(a, buffer, sizeof buffer);
if (len == 0)
@@ -310,8 +315,8 @@ namespace ZipUtil
}
/*
* Extract a regular file.
*/
* Extract a regular file.
*/
static void extract_file(struct archive *a, struct archive_entry *e, const std::string &path)
{
struct stat sb;
@@ -320,13 +325,15 @@ namespace ZipUtil
/* look for existing file of same name */
recheck:
if (lstat(path.c_str(), &sb) == 0) {
if (lstat(path.c_str(), &sb) == 0)
{
(void)unlink(path.c_str());
}
/* process symlinks */
linkname = archive_entry_symlink(e);
if (linkname != NULL) {
if (linkname != NULL)
{
if (symlink(linkname, path.c_str()) != 0)
{
sprintf(status_message, "error symlink('%s')", path.c_str());
@@ -337,7 +344,7 @@ namespace ZipUtil
return;
}
if ((fd = open(path.c_str(), O_RDWR|O_CREAT|O_TRUNC, 0777)) < 0)
if ((fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0777)) < 0)
{
sprintf(status_message, "error open('%s')", path.c_str());
return;
@@ -356,9 +363,9 @@ namespace ZipUtil
{
char *pathname, *realpathname;
mode_t filetype;
char *p, *q;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) {
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
return;
}
@@ -367,14 +374,16 @@ namespace ZipUtil
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL) {
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)) {
if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype))
{
archive_read_data_skip(a);
free(pathname);
return;
@@ -398,9 +407,9 @@ namespace ZipUtil
}
/*
* Callback function for reading passphrase.
* Originally from cpio.c and passphrase.c, libarchive.
*/
* 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);
@@ -422,14 +431,58 @@ namespace ZipUtil
return password;
}
static RemoteArchiveData *OpenRemoteArchive(const std::string &file)
{
RemoteArchiveData *data;
data = (RemoteArchiveData *)malloc(sizeof(RemoteArchiveData));
memset(data, 0, sizeof(RemoteArchiveData));
data->offset = 0;
remoteclient->Size(file, &data->size);
data->client = remoteclient;
data->path = file;
return data;
}
static ssize_t ReadRemoteArchive(struct archive *a, void *client_data, const void **buff)
{
ssize_t to_read;
int ret;
RemoteArchiveData *data;
data = (RemoteArchiveData *)client_data;
*buff = data->buf;
to_read = data->size - data->offset;
if (to_read == 0)
return 0;
to_read = MIN(to_read, ARCHIVE_TRANSFER_SIZE);
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
if (ret == 0)
return -1;
data->offset = data->offset + to_read;
return to_read;
}
static int CloseRemoteArchive(struct archive *a, void *client_data)
{
if (client_data != nullptr)
free(client_data);
return 0;
}
/*
* 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)
* 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, bool is_remote)
{
struct archive *a;
struct archive_entry *e;
RemoteArchiveData *client_data = nullptr;
int ret;
uintmax_t total_size, file_count, error_count;
@@ -440,14 +493,38 @@ namespace ZipUtil
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)
if (!is_remote)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
ret = archive_read_open_filename(a, file.path, ARCHIVE_TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
}
else
{
client_data = OpenRemoteArchive(file.path);
if (client_data == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
if (ret < ARCHIVE_OK)
{
if (client_data != nullptr)
{
free(client_data);
}
sprintf(status_message, "%s", "archive_read_open failed");
return 0;
}
}
for (;;) {
for (;;)
{
if (stop_activity)
break;
@@ -462,7 +539,7 @@ namespace ZipUtil
if (ret == ARCHIVE_EOF)
break;
extract(a, e, basepath);
}
@@ -471,4 +548,120 @@ namespace ZipUtil
return 1;
}
ArchiveEntry *GetPackageEntry(const std::string &zip_file, bool is_remote)
{
struct archive *a;
struct archive_entry *e;
RemoteArchiveData *client_data = nullptr;
char *pathname;
mode_t filetype;
ArchiveEntry *pkg_entry = nullptr;
int ret;
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);
if (!is_remote)
{
ret = archive_read_open_filename(a, zip_file.c_str(), ARCHIVE_TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
}
else
{
client_data = OpenRemoteArchive(zip_file);
if (client_data == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
if (ret < ARCHIVE_OK)
{
if (client_data != nullptr)
{
free(client_data);
}
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
}
for (;;)
{
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
if (client_data != nullptr)
{
free(client_data);
}
archive_read_free(a);
return nullptr;
}
if (ret == ARCHIVE_EOF)
break;
char *p, *q;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
continue;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL)
{
archive_read_data_skip(a);
free(pathname);
continue;
;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISREG(filetype))
{
archive_read_data_skip(a);
free(pathname);
continue;
}
if (Util::EndsWith(Util::ToLower(pathname), ".pkg"))
{
pkg_entry = (ArchiveEntry *)malloc(sizeof(ArchiveEntry));
memset(pkg_entry, 0, sizeof(ArchiveEntry));
pkg_entry->archive = a;
pkg_entry->entry = e;
pkg_entry->client_data = client_data;
pkg_entry->filename = pathname;
pkg_entry->filesize = archive_entry_size(e);
free(pathname);
return pkg_entry;
}
free(pathname);
}
archive_read_free(a);
return nullptr;
}
}
+24 -1
View File
@@ -5,9 +5,13 @@
#include <stdlib.h>
#include <minizip/unzip.h>
#include <minizip/zip.h>
#include <archive.h>
#include <archive_entry.h>
#include "common.h"
#include "fs.h"
#define ARCHIVE_TRANSFER_SIZE (512 * 1024)
static uint8_t MAGIC_ZIP_1[4] = {0x50, 0x4B, 0x03, 0x04};
static uint8_t MAGIC_ZIP_2[4] = {0x50, 0x4B, 0x05, 0x06};
static uint8_t MAGIC_ZIP_3[4] = {0x50, 0x4B, 0x07, 0x08};
@@ -24,9 +28,28 @@ enum CompressFileType {
COMPRESS_FILE_TYPE_UNKNOWN
};
struct RemoteArchiveData
{
std::string path;
ssize_t size;
ssize_t offset;
uint8_t buf[ARCHIVE_TRANSFER_SIZE];
RemoteClient *client;
};
struct ArchiveEntry
{
struct archive *archive;
struct archive_entry *entry;
std::string filename;
size_t filesize;
RemoteArchiveData *client_data;
};
namespace ZipUtil
{
int ZipAddPath(zipFile zf, const std::string &path, int filename_start, int level);
int Extract(const DirEntry &file, const std::string &dir);
int Extract(const DirEntry &file, const std::string &dir, bool is_remote = false);
ArchiveEntry *GetPackageEntry(const std::string &zip_file, bool is_remote = false);
}
#endif