Skip to content

Instantly share code, notes, and snippets.

@Jordach
Last active December 29, 2015 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jordach/7711006 to your computer and use it in GitHub Desktop.
Save Jordach/7711006 to your computer and use it in GitHub Desktop.
use gcc clean.c then ./a.out /home/somewhere/.minetest/worlds/world/
/*
* Application to delete empty player files from a minetest world.
* Usage: ./clean /path/to/minetest/world
*
* Criteria for removal of a player file and auth line:
* The player must have nothing in his inventory and mut not have interact.
* This obviously won't work well for servers where interact is granted by
* default, but all you have to do is remove the
* " || strstr(player->privs, "interact")" part for those servers.
*/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define MAX_EMPTY 47
#define NAME_LEN 20
#define HASH_LEN 29
#define PRIVS_LEN 256
#define PF_LINE_LEN 256
typedef struct {
char name[NAME_LEN];
char hash[HASH_LEN];
char privs[PRIVS_LEN];
bool cleared;
} Auth;
int main(int argc, char *argv[]);
Auth *read_auth(char worldpath[], Auth *auth_list);
void read_auth_line(FILE *authf, Auth *auth);
bool check_playerfile(char worldpath[], Auth *player);
void write_auth(char worldpath[], Auth *auth_list);
void cleanup(Auth *auth_list);
int main(int argc, char *argv[]) {
Auth *auth_list;
int i, num_removed = 0;
clock_t start = clock();
if (argc != 2) {
printf("Usage:\n"
" %s <WorldPath>\n",
argv[0]);
exit(1);
}
auth_list = read_auth(argv[1], auth_list);
for (i = 0; auth_list[i].name[0] != '\0'; i++) {
if (check_playerfile(argv[1], &auth_list[i])) {
num_removed++;
}
}
write_auth(argv[1], auth_list);
cleanup(auth_list);
printf("%d player entries deleted in %f seconds\n", num_removed, (float)(clock() - start) / CLOCKS_PER_SEC);
return 0;
}
Auth *read_auth(char worldpath[], Auth *auth_list) {
char filename[FILENAME_MAX];
FILE *authf;
int ch, i, auth_len = 0;
strcpy(filename, worldpath);
strcat(filename, "/auth.txt");
authf = fopen(filename, "r");
if (!authf) {
printf("Error opening %s for reading\n", filename);
exit(1);
}
/* Get the number of lines in the auth file */
while ((ch = getc(authf)) != EOF) {
if (ch == '\n') {
auth_len++;
}
}
printf("%d lines found\n", auth_len);
/* We need to increment the length in case the file doesn't end with
* a newline */
auth_len++;
/* Then get back to the top of the file */
rewind(authf);
/* Allocate our array of structs */
auth_list = (Auth *) calloc(auth_len + 1, sizeof(Auth));
/* Load the auth data into our array */
for (i = 0; !feof(authf); i++) {
if (ferror(authf)) {
perror("Error reading auth file: ");
exit(1);
}
read_auth_line(authf, &auth_list[i]);
}
/* Null out the last item */
auth_list[i].name[0] = '\0';
fclose(authf);
return auth_list;
}
void read_auth_line(FILE *authf, Auth *auth) {
int ch, i = 0;
while ((ch = fgetc(authf)) != ':') {
if (ch == EOF) break;
auth->name[i] = ch;
i++;
}
auth->name[i] = '\0';
i = 0;
while ((ch = fgetc(authf)) != ':') {
if (ch == EOF) break;
auth->hash[i] = ch;
i++;
}
auth->hash[i] = '\0';
i = 0;
while ((ch = fgetc(authf)) != '\n') {
if (ch == EOF) break;
auth->privs[i] = ch;
i++;
}
auth->privs[i] = '\0';
auth->cleared = false;
return;
}
/* Checks if a player file has deviated from the
* default and deletes it if it hasn't.
*/
bool check_playerfile(char worldpath[], Auth *player) {
char filename[FILENAME_MAX];
FILE *playerfile;
char line[PF_LINE_LEN];
int i = 0;
/* Check for null entries and players with interact. Includes basic_privs */
if (player->name[0] == '\0' || strstr(player->privs, "interact")) {
return false;
}
strcpy(filename, worldpath);
strcat(filename, "/players/");
strcat(filename, player->name);
playerfile = fopen(filename, "r");
if (!playerfile) {
return false;
}
/* Count the number of empty inventory slots */
while (fscanf(playerfile, " %s", line) != EOF) {
if (strcmp(line, "Empty") == 0) {
i++;
}
}
fclose(playerfile);
if (i >= MAX_EMPTY) {
remove(filename);
player->cleared = true;
return true;
}
return false;
}
void write_auth(char worldpath[], Auth *auth_list) {
char filename[FILENAME_MAX];
FILE *authf;
int i;
strcpy(filename, worldpath);
strcat(filename, "/auth.txt");
authf = fopen(filename, "w");
if (!authf) {
printf("Unable to save auth data\n");
exit(1);
}
for (i = 0; auth_list[i].name[0] != '\0'; i++) {
if (auth_list[i].cleared) {
continue;
}
fprintf(authf, "%s:%s:%s\n",
auth_list[i].name,
auth_list[i].hash,
auth_list[i].privs);
}
fclose(authf);
return;
}
void cleanup(Auth *auth_list) {
free(auth_list);
return;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment