Singe now checks the validity of games before unpacking them.
This commit is contained in:
parent
de6d5f1fe5
commit
fd1a2951ff
3 changed files with 160 additions and 55 deletions
210
src/main.c
210
src/main.c
|
@ -853,17 +853,26 @@ void unpackData(char *name) {
|
|||
|
||||
void unpackGames(void) {
|
||||
struct dirent *de;
|
||||
DIR *dir = opendir(".");
|
||||
DIR *dir = opendir(".");
|
||||
struct archive *a;
|
||||
struct archive *ext;
|
||||
struct archive_entry *entry;
|
||||
int flags;
|
||||
int r;
|
||||
int count = 0;
|
||||
int x;
|
||||
int count = 0;
|
||||
bool ok;
|
||||
bool hasGamesDat;
|
||||
const void *buff;
|
||||
size_t size;
|
||||
la_int64_t offset;
|
||||
char *e;
|
||||
char *gamesDat = NULL;
|
||||
char *extension;
|
||||
char *filename;
|
||||
char *toplevel = NULL;
|
||||
char *badFilenames[] = { "Framework.singe", 0 };
|
||||
char *badExtensions[] = { "exe", "sh", "bat", "cmd", "index", 0 };
|
||||
|
||||
if (dir == NULL) utilDie("Could not open the current directory.");
|
||||
|
||||
|
@ -872,70 +881,161 @@ void unpackGames(void) {
|
|||
if (utilStricmp(utilGetFileExtension(de->d_name), "game") == 0) {
|
||||
showHeader();
|
||||
count++;
|
||||
utilSay(">>> Unpacking Game: %s", de->d_name);
|
||||
ok = true;
|
||||
hasGamesDat = false;
|
||||
|
||||
// https://github.com/libarchive/libarchive/wiki/Examples#user-content-A_Complete_Extractor
|
||||
ok = true;
|
||||
flags = ARCHIVE_EXTRACT_TIME;
|
||||
flags |= ARCHIVE_EXTRACT_PERM;
|
||||
flags |= ARCHIVE_EXTRACT_ACL;
|
||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||
// Look through archive for things I've told people NOT to ship!
|
||||
// https://github.com/libarchive/libarchive/wiki/Examples#user-content-List_contents_of_Archive_stored_in_File
|
||||
a = archive_read_new();
|
||||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
ext = archive_write_disk_new();
|
||||
archive_write_disk_set_options(ext, flags);
|
||||
archive_write_disk_set_standard_lookup(ext);
|
||||
if ((r = archive_read_open_filename(a, de->d_name, 10240))) ok = false;
|
||||
while (ok) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF) break;
|
||||
if (r < ARCHIVE_OK) utilSay("%s", archive_error_string(a));
|
||||
if (r < ARCHIVE_WARN) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
r = archive_write_header(ext, entry);
|
||||
if (r < ARCHIVE_OK) {
|
||||
utilSay("%s", archive_error_string(ext));
|
||||
} else {
|
||||
if (archive_entry_size(entry) > 0) {
|
||||
for (;;) {
|
||||
r = archive_read_data_block(a, &buff, &size, &offset);
|
||||
if (r == ARCHIVE_EOF) {
|
||||
r = ARCHIVE_OK;
|
||||
break;
|
||||
}
|
||||
if (r < ARCHIVE_OK) break;
|
||||
r = archive_write_data_block(ext, buff, size, offset);
|
||||
if (r < ARCHIVE_OK) {
|
||||
utilSay("%s", archive_error_string(ext));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r < ARCHIVE_OK) utilSay("%s", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN) {
|
||||
archive_read_support_format_all(a);
|
||||
r = archive_read_open_filename(a, de->d_name, 10240);
|
||||
if (r != ARCHIVE_OK) {
|
||||
utilSay("!!! Cannot read game: %s", de->d_name);
|
||||
ok = false;
|
||||
} else {
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && ok) {
|
||||
e = (char *)archive_entry_pathname(entry);
|
||||
filename = utilGetLastPathComponent(e);
|
||||
extension = utilGetFileExtension(e);
|
||||
|
||||
// Do we have a top level folder name yet?
|
||||
if (toplevel == NULL) {
|
||||
// No. Is this a folder?
|
||||
if (strstr(e, "/") == NULL) {
|
||||
// No. BAD! No files in the root!
|
||||
ok = false;
|
||||
break;
|
||||
utilSay("!!! Game has files in root: %s", de->d_name);
|
||||
} else {
|
||||
// Remember this folder.
|
||||
toplevel = strdup(e);
|
||||
gamesDat = utilCreateString("%sgames.dat", toplevel);
|
||||
}
|
||||
} else {
|
||||
// Yes, we have a top level. Is this entry inside it?
|
||||
if (!utilStartsWith(e, toplevel)) {
|
||||
// No. BAD! Everything has to be in the top level.
|
||||
ok = false;
|
||||
if (strstr(e, "/") == NULL) {
|
||||
utilSay("!!! Game has files in root: %s", de->d_name);
|
||||
} else {
|
||||
utilSay("!!! Game has multiple top level directories: %s", de->d_name);
|
||||
}
|
||||
utilSay("[%s] %s", toplevel, e);
|
||||
} else {
|
||||
// Is this a forbidden file?
|
||||
x = 0;
|
||||
while (badFilenames[x] != NULL && ok) {
|
||||
if (utilStricmp(filename, badFilenames[x]) == 0) {
|
||||
ok = false;
|
||||
utilSay("!!! Game has %s: %s", badFilenames[x], de->d_name);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
// Is this a forbidden extension?
|
||||
x = 0;
|
||||
while (badExtensions[x] != NULL && ok) {
|
||||
if (utilStricmp(extension, badExtensions[x]) == 0) {
|
||||
ok = false;
|
||||
utilSay("!!! Game has %s file: %s", badExtensions[x], de->d_name);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
// No extension, starts with 'singe' - could be unix binary.
|
||||
if (ok && strlen(extension) == 0 && utilStartsWith(filename, "singe")) {
|
||||
ok = false;
|
||||
utilSay("!!! Game has singe file: %s", de->d_name);
|
||||
}
|
||||
// Is this games.dat?
|
||||
if (ok && !hasGamesDat && utilStricmp(e, gamesDat) == 0) hasGamesDat = true;
|
||||
}
|
||||
}
|
||||
//utilSay("%s [%s] %s", filename, extension, e);
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
r = archive_write_finish_entry(ext);
|
||||
if (r < ARCHIVE_OK) utilSay("%s", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN) {
|
||||
r = archive_read_free(a);
|
||||
if (toplevel != NULL) {
|
||||
free(toplevel);
|
||||
toplevel = NULL;
|
||||
}
|
||||
if (gamesDat != NULL) {
|
||||
free(gamesDat);
|
||||
gamesDat = NULL;
|
||||
}
|
||||
|
||||
// Did we get a games.dat?
|
||||
if (ok && !hasGamesDat) {
|
||||
ok = false;
|
||||
break;
|
||||
utilSay("!!! Game has no games.dat: %s", de->d_name);
|
||||
}
|
||||
}
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
archive_write_close(ext);
|
||||
archive_write_free(ext);
|
||||
|
||||
if (ok) unlink(de->d_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Unpack it!
|
||||
if (ok) {
|
||||
utilSay(">>> Unpacking Game: %s", de->d_name);
|
||||
// https://github.com/libarchive/libarchive/wiki/Examples#user-content-A_Complete_Extractor
|
||||
flags = ARCHIVE_EXTRACT_TIME;
|
||||
flags |= ARCHIVE_EXTRACT_PERM;
|
||||
flags |= ARCHIVE_EXTRACT_ACL;
|
||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||
a = archive_read_new();
|
||||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
ext = archive_write_disk_new();
|
||||
archive_write_disk_set_options(ext, flags);
|
||||
archive_write_disk_set_standard_lookup(ext);
|
||||
if ((r = archive_read_open_filename(a, de->d_name, 10240))) ok = false;
|
||||
while (ok) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF) break;
|
||||
if (r < ARCHIVE_OK) utilSay("%s", archive_error_string(a));
|
||||
if (r < ARCHIVE_WARN) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
r = archive_write_header(ext, entry);
|
||||
if (r < ARCHIVE_OK) {
|
||||
utilSay("%s", archive_error_string(ext));
|
||||
} else {
|
||||
if (archive_entry_size(entry) > 0) {
|
||||
for (;;) {
|
||||
r = archive_read_data_block(a, &buff, &size, &offset);
|
||||
if (r == ARCHIVE_EOF) {
|
||||
r = ARCHIVE_OK;
|
||||
break;
|
||||
}
|
||||
if (r < ARCHIVE_OK) break;
|
||||
r = archive_write_data_block(ext, buff, size, offset);
|
||||
if (r < ARCHIVE_OK) {
|
||||
utilSay("%s", archive_error_string(ext));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r < ARCHIVE_OK) utilSay("%s", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
r = archive_write_finish_entry(ext);
|
||||
if (r < ARCHIVE_OK) utilSay("%s", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
archive_write_close(ext);
|
||||
archive_write_free(ext);
|
||||
|
||||
if (ok) unlink(de->d_name);
|
||||
|
||||
} // if ok
|
||||
} // if extension is game
|
||||
} // if it's a file
|
||||
} // while files
|
||||
|
||||
if (count > 0) utilSay("");
|
||||
|
||||
|
|
|
@ -442,6 +442,10 @@ void utilSay(char *fmt, ...) {
|
|||
}
|
||||
|
||||
|
||||
bool utilStartsWith(char *string, char *start) {
|
||||
return strncmp(start, string, strlen(start)) == 0;
|
||||
}
|
||||
|
||||
|
||||
int utilStricmp(char *a, char *b) {
|
||||
for (;; a++, b++) {
|
||||
|
|
|
@ -53,6 +53,7 @@ char *utilReadFile(char *filename, size_t *bytes);
|
|||
char *utilReadLine(char *haystack, size_t length, char **offset);
|
||||
void utilRedirectConsole(void);
|
||||
void utilSay(char *fmt, ...);
|
||||
bool utilStartsWith(char *string, char *start);
|
||||
int utilStricmp(char *a, char *b);
|
||||
char *utilStrndup( const char *s1, size_t n);
|
||||
void utilTrace(char *fmt, ...);
|
||||
|
|
Loading…
Add table
Reference in a new issue