mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-27 05:40:21 +00:00
7f2d1134d9
A new menu feature "Refresh license database" is now available from the top context menu. Its action is to parse all the .rif files under ux0:licence/app and ux0:licence/addcont, and import them to the ux0:licence/license.db SQLite database (which gets created it it doesn't already exists). Used in conjunction with the new App/DLC refresh feature, this allows Vita users to restore their content straight from PKG downloads, and let VitaShell do the job of also restoring the relevant license from the DB backup. This also fixes a small typo in LANGUAGE_CONTAINER_SIZE and adds a .editorconfig, to ensure that the indentation settings of VitaShell are followed by modern code editors.
171 lines
4.8 KiB
C
171 lines
4.8 KiB
C
/*
|
|
PS Vita override for R/W SQLite functionality
|
|
Copyright (C) 2017 VitaSmith
|
|
Based on original work (C) 2015 xyzz
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
Note: We must override part of the default SQlite VFS for full SQLite
|
|
DB access because the native Vita one, called "psp2", only allows read
|
|
operations (which Sony probably did to avoid exploit propagation from
|
|
potential SQLite vulnerabilities).
|
|
Short of using the VFS overrides below, any attempt to create a new DB
|
|
or write to an existing one will result in SQLITE_CANTOPEN...
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <psp2/io/fcntl.h>
|
|
#include <psp2/sqlite.h>
|
|
|
|
#include "sqlite3.h"
|
|
|
|
//#define VERBOSE 1
|
|
#if VERBOSE
|
|
extern int psvDebugScreenPrintf(const char *format, ...);
|
|
#define LOG psvDebugScreenPrintf
|
|
#else
|
|
#define LOG(...)
|
|
#endif
|
|
|
|
#define IS_ERROR(x) ((unsigned)x & 0x80000000)
|
|
|
|
static sqlite3_io_methods* rw_methods = NULL;
|
|
static sqlite3_vfs *rw_vfs = NULL;
|
|
|
|
// The file structure used by Sony
|
|
typedef struct {
|
|
sqlite3_file file;
|
|
int* fd;
|
|
} vfs_file;
|
|
|
|
static int vita_xWrite(sqlite3_file *file, const void *buf, int count, sqlite_int64 offset)
|
|
{
|
|
vfs_file *p = (vfs_file*)file;
|
|
int seek = sceIoLseek(*p->fd, offset, SCE_SEEK_SET);
|
|
LOG("seek %x %x => %x\n", *p->fd, offset, seek);
|
|
if (seek != offset)
|
|
return SQLITE_IOERR_WRITE;
|
|
int write = sceIoWrite(*p->fd, buf, count);
|
|
LOG("write %x %x %x => %x\n", *p->fd, buf, count);
|
|
if (write != count) {
|
|
LOG("write error %08x\n", write);
|
|
return SQLITE_IOERR_WRITE;
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int vita_xOpen(sqlite3_vfs *vfs, const char *name, sqlite3_file *file, int flags, int *out_flags)
|
|
{
|
|
sqlite3_vfs* org_vfs = (sqlite3_vfs*)vfs->pAppData;
|
|
|
|
LOG("open %s: flags = %08x, ", name, flags);
|
|
// Default xOpen() does not create files => do that ourselves
|
|
// TODO: handle SQLITE_OPEN_EXCLUSIVE
|
|
if (flags & SQLITE_OPEN_CREATE) {
|
|
SceUID fd = sceIoOpen(name, SCE_O_RDONLY, 0777);
|
|
if (IS_ERROR(fd))
|
|
fd = sceIoOpen(name, SCE_O_WRONLY | SCE_O_CREAT, 0777);
|
|
if (!IS_ERROR(fd))
|
|
sceIoClose(fd);
|
|
}
|
|
|
|
// Call the original xOpen()
|
|
int r = org_vfs->xOpen(org_vfs, name, file, flags, out_flags);
|
|
vfs_file *p = (vfs_file*)file;
|
|
LOG("fd = %08x, r = %d\n", (p == NULL) ? 0 : *p->fd, r);
|
|
|
|
// Default xOpen() also forces read-only on SQLITE_OPEN_READWRITE files
|
|
if ((file->pMethods != NULL) && (flags & SQLITE_OPEN_READWRITE)) {
|
|
if (!IS_ERROR(*p->fd)) {
|
|
// Reopen the file with write access
|
|
sceIoClose(*p->fd);
|
|
*p->fd = sceIoOpen(name, SCE_O_RDWR, 0777);
|
|
LOG("override fd = %08x\n", *p->fd);
|
|
if (IS_ERROR(*p->fd))
|
|
return SQLITE_IOERR_WRITE;
|
|
}
|
|
// Need to override xWrite() as well
|
|
if (rw_methods == NULL) {
|
|
rw_methods = malloc(sizeof(sqlite3_io_methods));
|
|
if (rw_methods != NULL) {
|
|
memcpy(rw_methods, file->pMethods, sizeof(sqlite3_io_methods));
|
|
rw_methods->xWrite = vita_xWrite;
|
|
}
|
|
}
|
|
if (rw_methods != NULL)
|
|
file->pMethods = rw_methods;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
int vita_xDelete(sqlite3_vfs *vfs, const char *name, int syncDir)
|
|
{
|
|
int ret = sceIoRemove(name);
|
|
LOG("delete %s: 0x%08x\n", name, ret);
|
|
if (IS_ERROR(ret))
|
|
return SQLITE_IOERR_DELETE;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
int sqlite_init()
|
|
{
|
|
int rc;
|
|
|
|
if (rw_vfs != NULL)
|
|
return SQLITE_OK;
|
|
|
|
SceSqliteMallocMethods mf = {
|
|
(void* (*) (int)) malloc,
|
|
(void* (*) (void*, int)) realloc,
|
|
free
|
|
};
|
|
sceSqliteConfigMallocMethods(&mf);
|
|
|
|
rw_vfs = malloc(sizeof(sqlite3_vfs));
|
|
sqlite3_vfs *vfs = sqlite3_vfs_find(NULL);
|
|
if ((vfs != NULL) && (rw_vfs != NULL)) {
|
|
// Override xOpen() and xDelete()
|
|
memcpy(rw_vfs, vfs, sizeof(sqlite3_vfs));
|
|
rw_vfs->zName = "psp2_rw";
|
|
rw_vfs->xOpen = vita_xOpen;
|
|
rw_vfs->xDelete = vita_xDelete;
|
|
// Keep a copy of the original vfs pointer
|
|
rw_vfs->pAppData = vfs;
|
|
rc = sqlite3_vfs_register(rw_vfs, 1);
|
|
if (rc != SQLITE_OK) {
|
|
LOG("sqlite_init: could not register vfs: %d\n", rc);
|
|
return rc;
|
|
}
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
int sqlite_exit()
|
|
{
|
|
int rc = SQLITE_OK;
|
|
free(rw_methods);
|
|
rw_methods = NULL;
|
|
if (rw_vfs != NULL) {
|
|
rc = sqlite3_vfs_unregister(rw_vfs);
|
|
if (rc != SQLITE_OK)
|
|
LOG("sqlite_exit: error unregistering vfs: %d\n", rc);
|
|
free(rw_vfs);
|
|
rw_vfs = NULL;
|
|
}
|
|
return rc;
|
|
}
|