aboutsummaryrefslogtreecommitdiffstats
path: root/FICS/gamedb.c
diff options
context:
space:
mode:
Diffstat (limited to 'FICS/gamedb.c')
-rw-r--r--FICS/gamedb.c257
1 files changed, 178 insertions, 79 deletions
diff --git a/FICS/gamedb.c b/FICS/gamedb.c
index 2e65af0..2656447 100644
--- a/FICS/gamedb.c
+++ b/FICS/gamedb.c
@@ -30,12 +30,27 @@
a crash.
Markus Uhlin 24/07/18 Return value checking
Markus Uhlin 24/08/03 See previous change
+ Markus Uhlin 24/11/23 Added width specifications to
+ multiple fscanf() calls.
+ Markus Uhlin 24/11/23 Fixed bugs in movesToString()
+ Markus Uhlin 24/11/25 Null checks
+ Markus Uhlin 24/12/02 Fixed bugs and ignored function
+ return values.
+ Markus Uhlin 25/03/18 Fixed unchecked return values
+ Markus Uhlin 25/03/25 ReadGameState: fixed truncated
+ stdio return value.
+ Markus Uhlin 25/04/01 Fixed call of risky function
+ Markus Uhlin 25/04/01 ReadV1GameFmt: guard num half
+ moves.
+ Markus Uhlin 25/04/06 Fixed Clang Tidy warnings.
*/
#include "stdinclude.h"
#include "common.h"
#include <err.h>
+#include <errno.h>
+#include <limits.h>
#include "command.h"
#include "config.h"
@@ -85,9 +100,11 @@ PRIVATE char gameString[GAME_STRING_LEN];
PRIVATE int
get_empty_slot(void)
{
- for (int i = 0; i < g_num; i++) {
- if (garray[i].status == GAME_EMPTY)
- return i;
+ if (garray != NULL) {
+ for (int i = 0; i < g_num; i++) {
+ if (garray[i].status == GAME_EMPTY)
+ return i;
+ }
}
g_num++;
@@ -551,7 +568,8 @@ movesToString(int g, int pgn)
char tmp[160] = { '\0' };
int i, col;
int wr, br;
- unsigned int curTime;
+ struct tm *tm_ptr = NULL;
+ time_t curTime;
wr = garray[g].white_rating;
br = garray[g].black_rating;
@@ -567,11 +585,15 @@ movesToString(int g, int pgn)
bstr[garray[g].type],
serv_name,
serv_loc);
- strftime(tmp, sizeof(tmp),
- "[Date \"%Y.%m.%d\"]\n"
- "[Time \"%H:%M:%S\"]\n",
- localtime((time_t *) &curTime));
- mstrlcat(gameString, tmp, sizeof gameString);
+
+ if ((tm_ptr = localtime(&curTime)) != NULL) {
+ strftime(tmp, sizeof(tmp),
+ "[Date \"%Y.%m.%d\"]\n"
+ "[Time \"%H:%M:%S\"]\n",
+ tm_ptr);
+ mstrlcat(gameString, tmp, sizeof gameString);
+ } else
+ warn("%s: localtime", __func__);
msnprintf(tmp, sizeof tmp,
"[Round \"-\"]\n"
@@ -620,6 +642,10 @@ movesToString(int g, int pgn)
mstrlcat(gameString, "\n", sizeof gameString);
} else {
+ /*
+ * !pgn
+ */
+
msnprintf(gameString, sizeof gameString, "\n%s ",
garray[g].white_name);
@@ -641,8 +667,12 @@ movesToString(int g, int pgn)
mstrlcat(gameString, tmp, sizeof gameString);
mstrlcat(gameString, "--- ", sizeof gameString);
- mstrlcat(gameString, (char *) (localtime((time_t *) &curTime)),
- sizeof gameString);
+
+ if ((tm_ptr = localtime(&curTime)) != NULL) {
+ strftime(tmp, sizeof tmp, "%Y.%m.%d %H:%M:%S", tm_ptr);
+ mstrlcat(gameString, tmp, sizeof gameString);
+ } else
+ warn("%s: localtime", __func__);
if (garray[g].rated) {
mstrlcat(gameString, "\nRated ", sizeof gameString);
@@ -864,7 +894,8 @@ WriteMoves(FILE *fp, move_t *m)
/* Are we using from-file or from-rank in 'algString'? */
- i = strlen(m->algString) - 1;
+ if ((i = strlen(m->algString)) > 0)
+ i -= 1;
if (m->algString[i] == '+') {
check = 1;
@@ -904,7 +935,10 @@ ReadMove(FILE *fp, move_t *m)
if (fgets(line, sizeof line, fp) == NULL)
return -1;
- if (sscanf(line, "%d %d %d %d %d %d %d %d %d \"%[^\"]\" \"%[^\"]\" "
+ _Static_assert(ARRAY_SIZE(m->moveString) > 7, "'moveString' too small");
+ _Static_assert(ARRAY_SIZE(m->algString) > 7, "'algString' too small");
+
+ if (sscanf(line, "%d %d %d %d %d %d %d %d %d \"%7[^\"]\" \"%7[^\"]\" "
"%u %u\n",
&m->color,
&m->fromFile, &m->fromRank,
@@ -948,8 +982,8 @@ WriteGameState(FILE *fp, game_state_t *gs)
PRIVATE int
ReadGameState(FILE *fp, game_state_t *gs, int version)
{
- char pieceChar;
int i, j;
+ int pieceChar;
int wkmoved, wqrmoved, wkrmoved, bkmoved, bqrmoved, bkrmoved;
if (version == 0) {
@@ -960,11 +994,12 @@ ReadGameState(FILE *fp, game_state_t *gs, int version)
}
}
} else {
- getc(fp); /* Skip past a newline. */
+ (void) getc(fp); /* Skip past a newline. */
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
- pieceChar = getc(fp);
+ if ((pieceChar = getc(fp)) == EOF)
+ return -1;
gs->board[i][j] = CharToPiece(pieceChar);
}
}
@@ -1033,10 +1068,16 @@ got_attr_value(int g, char *attr, char *value, FILE *fp, char *file)
} else if (!strcmp(attr, "type:")) {
garray[g].type = atoi(value);
} else if (!strcmp(attr, "halfmoves:")) {
- garray[g].numHalfMoves = atoi(value);
-
- if (garray[g].numHalfMoves == 0)
+ if ((garray[g].numHalfMoves = atoi(value)) == 0)
return 0;
+ else if (garray[g].numHalfMoves < 0 ||
+ (size_t)garray[g].numHalfMoves > INT_MAX / sizeof(move_t)) {
+ warnx("%s: num half moves out-of-bounds (%d)", __func__,
+ garray[g].numHalfMoves);
+ return -1;
+ } else {
+ /* null */;
+ }
garray[g].moveListSize = garray[g].numHalfMoves;
garray[g].moveList = reallocarray(NULL, sizeof(move_t),
@@ -1241,8 +1282,10 @@ ReadV1GameFmt(game *g, FILE *fp, const char *file, int version)
_Static_assert(17 < ARRAY_SIZE(g->black_name), "Unexpected array size");
ret[0] = fscanf(fp, "%17s %17s", g->white_name, g->black_name);
- ret[1] = fscanf(fp, "%d %d", &g->white_rating, &g->black_rating);
- ret[2] = fscanf(fp, "%d %d %d %d",
+ ret[1] = fscanf(fp, "%d %d", // NOLINT
+ &g->white_rating,
+ &g->black_rating);
+ ret[2] = fscanf(fp, "%d %d %d %d", // NOLINT
&g->wInitTime,
&g->wIncrement,
&g->bInitTime,
@@ -1285,10 +1328,16 @@ ReadV1GameFmt(game *g, FILE *fp, const char *file, int version)
ret[0] = fscanf(fp, "%d %d %d %d", &g->private, &g->type, &g->rated,
&g->clockStopped);
- ret[1] = fscanf(fp, "%d", &g->numHalfMoves);
+ ret[1] = fscanf(fp, "%d", &g->numHalfMoves); // NOLINT
if (ret[0] != 4 || ret[1] != 1) {
warnx("%s: fscanf error: %s", __func__, file);
return -1;
+ } else if (g->numHalfMoves < 0 || (size_t)g->numHalfMoves >
+ INT_MAX / sizeof(move_t)) {
+ warnx("%s: warning: num half moves out-of-bounds (%d)",
+ __func__,
+ g->numHalfMoves);
+ return -1;
}
if (ReadV1Moves(g, fp) != 0) {
@@ -1311,7 +1360,7 @@ ReadGameAttrs(FILE *fp, char *fname, int g)
{
char *attr, *value;
char line[MAX_GLINE_SIZE] = { '\0' };
- int len;
+ int len = 0;
int version = 0;
if (fgets(line, sizeof line, fp) == NULL) {
@@ -1330,7 +1379,8 @@ ReadGameAttrs(FILE *fp, char *fname, int g)
} else {
do {
if ((len = strlen(line)) <= 1) {
- fgets(line, sizeof line, fp);
+ if (fgets(line, sizeof line, fp) == NULL)
+ break;
continue;
}
@@ -1345,7 +1395,8 @@ ReadGameAttrs(FILE *fp, char *fname, int g)
if (!*value) {
fprintf(stderr, "FICS: Error reading file %s\n",
fname);
- fgets(line, sizeof line, fp);
+ if (fgets(line, sizeof line, fp) == NULL)
+ break;
continue;
}
@@ -1356,7 +1407,8 @@ ReadGameAttrs(FILE *fp, char *fname, int g)
if (!*value) {
fprintf(stderr, "FICS: Error reading file %s\n",
fname);
- fgets(line, sizeof line, fp);
+ if (fgets(line, sizeof line, fp) == NULL)
+ break;
continue;
}
@@ -1365,7 +1417,8 @@ ReadGameAttrs(FILE *fp, char *fname, int g)
if (got_attr_value(g, attr, value, fp, fname))
return -1;
- fgets(line, sizeof line, fp);
+ if (fgets(line, sizeof line, fp) == NULL)
+ break;
} while (!feof(fp));
}
@@ -1549,8 +1602,9 @@ game_save(int g)
/*
* Create link for easier stored game finding
*/
- if (bp->login[0] != wp->login[0])
- link(fname, lname);
+ if (bp->login[0] != wp->login[0] &&
+ link(fname, lname) != 0)
+ warn("%s: link() error", __func__);
return 0;
}
@@ -1594,10 +1648,9 @@ RemoveHistGame(char *file, int maxlines)
char Opponent[MAX_LOGIN_NAME + 1] = { '\0' };
char line[MAX_LINE_SIZE] = { '\0' };
int count = 0;
- long int When, oppWhen;
+ long int When = 0, oppWhen = 0;
_Static_assert(20 < ARRAY_SIZE(Opponent), "Not within bounds");
- When = oppWhen = 0;
if ((fp = fopen(file, "r")) == NULL) {
return;
@@ -1614,12 +1667,8 @@ RemoveHistGame(char *file, int maxlines)
count++;
- while (!feof(fp)) {
- fgets(line, ARRAY_SIZE(line), fp);
-
- if (!feof(fp))
- count++;
- }
+ while (fgets(line, ARRAY_SIZE(line), fp) != NULL)
+ count++;
fclose(fp);
stolower(Opponent);
@@ -1647,22 +1696,37 @@ RemHist(char *who)
msnprintf(fName, sizeof fName, "%s/player_data/%c/%s.%s", stats_dir,
who[0], who, STATS_GAMES);
- fp = fopen(fName, "r");
-
- if (fp != NULL) {
- while (!feof(fp)) {
- fscanf(fp, "%*d %*c %*d %*c %*d %s %*s %*d %*d %*d "
- "%*d %*s %*s %ld", Opp, &When);
+ if ((fp = fopen(fName, "r")) != NULL) {
+ long int iter_no = 0;
+
+ while (!feof(fp) && !ferror(fp)) {
+ const int ret = fscanf(fp, "%*d %*c %*d %*c %*d %19s "
+ "%*s %*d %*d %*d %*d %*s %*s %ld\n", Opp, &When);
+ if (ret != 2) {
+ warnx("%s: fscanf() error (%s:%ld)", __func__,
+ fName, iter_no);
+// iter_no++;
+ break;
+ }
stolower(Opp);
oppWhen = OldestHistGame(Opp);
if (oppWhen > When || oppWhen <= 0L) {
- msnprintf(fName, sizeof fName, "%s/%ld/%ld",
- hist_dir, When % 100, When);
- unlink(fName);
+ char histfile[MAX_FILENAME_SIZE] = { '\0' };
+
+ msnprintf(histfile, sizeof histfile,
+ "%s/%ld/%ld", hist_dir, (When % 100), When);
+ if (unlink(histfile) != 0) {
+ warn("%s: unlink(%s)", __func__,
+ histfile);
+ }
}
+
+ iter_no++;
}
+
+ fclose(fp);
}
}
@@ -1732,11 +1796,10 @@ write_g_out(int g, char *file, int maxlines, int isDraw, char *EndSymbol,
type[3] = '\0';
- fp = fopen(file, "r");
-
- if (fp) {
- while (!feof(fp))
- fgets(tmp, 1024, fp);
+ if ((fp = fopen(file, "r")) != NULL) {
+ while (fgets(tmp, sizeof tmp, fp) != NULL) {
+ /* null */;
+ }
if (sscanf(ptmp, "%d", &count) != 1)
warnx("%s: failed to read 'count'", __func__);
fclose(fp);
@@ -1799,38 +1862,46 @@ write_g_out(int g, char *file, int maxlines, int isDraw, char *EndSymbol,
* Find from_spot in journal list - return 0 if corrupted
*/
PUBLIC int
-journal_get_info(int p, char from_spot, char *WhiteName, int *WhiteRating,
- char *BlackName, int *BlackRating, char *type, int *t, int *i, char *eco,
- char *ending, char *result, char *fname)
+journal_get_info(struct JGI_context *ctx, const char *fname)
{
FILE *fp;
char count;
if ((fp = fopen(fname, "r")) == NULL) {
fprintf(stderr, "Corrupt journal file! %s\n", fname);
- pprintf(p, "The journal file is corrupt! See an admin.\n");
+ pprintf(ctx->p, "The journal file is corrupt! See an admin.\n");
return 0;
}
while (!feof(fp)) {
- if (fscanf(fp, "%c %s %d %s %d %s %d %d %s %s %s\n",
+ _Static_assert(ARRAY_SIZE(ctx->WhiteName) > 20,
+ "'WhiteName' too small");
+ _Static_assert(ARRAY_SIZE(ctx->BlackName) > 20,
+ "'BlackName' too small");
+
+ _Static_assert(ARRAY_SIZE(ctx->type) > 99, "'type' too small");
+ _Static_assert(ARRAY_SIZE(ctx->eco) > 99, "'eco' too small");
+ _Static_assert(ARRAY_SIZE(ctx->ending) > 99, "'ending' too small");
+ _Static_assert(ARRAY_SIZE(ctx->result) > 99, "'result' too small");
+
+ if (fscanf(fp, "%c %20s %d %20s %d %99s %d %d %99s %99s %99s\n",
&count,
- WhiteName, &(*WhiteRating),
- BlackName, &(*BlackRating),
- type,
- &(*t), &(*i),
- eco,
- ending,
- result) != 11) {
+ ctx->WhiteName, &ctx->WhiteRating,
+ ctx->BlackName, &ctx->BlackRating,
+ ctx->type,
+ &ctx->t, &ctx->i,
+ ctx->eco,
+ ctx->ending,
+ ctx->result) != 11) {
fprintf(stderr, "FICS: Error in journal info format. "
"%s\n", fname);
- pprintf(p, "The journal file is corrupt! Error in "
+ pprintf(ctx->p, "The journal file is corrupt! Error in "
"internal format.\n");
fclose(fp);
return 0;
}
- if (tolower(count) == from_spot) {
+ if (tolower(count) == ctx->from_spot) {
fclose(fp);
return 1;
}
@@ -1881,11 +1952,22 @@ addjournalitem(int p, char count2, char *WhiteName2, int WhiteRating2,
ending2,
result2);
fclose(fp2);
- rename(fname2, fname);
+ xrename(__func__, fname2, fname);
return;
} else {
+ _Static_assert(ARRAY_SIZE(WhiteName) > 19,
+ "'WhiteName' too small");
+ _Static_assert(ARRAY_SIZE(BlackName) > 19,
+ "'BlackName' too small");
+
+ _Static_assert(ARRAY_SIZE(type) > 99, "'type' too small");
+ _Static_assert(ARRAY_SIZE(eco) > 99, "'eco' too small");
+ _Static_assert(ARRAY_SIZE(ending) > 99, "'ending' too small");
+ _Static_assert(ARRAY_SIZE(result) > 99, "'result' too small");
+
while (!feof(fp)) {
- if (fscanf(fp, "%c %s %d %s %d %s %d %d %s %s %s\n",
+ if (fscanf(fp, "%c %19s %d %19s %d %99s %d %d %99s "
+ "%99s %99s\n",
&count,
WhiteName, &WhiteRating,
BlackName, &BlackRating,
@@ -1944,7 +2026,7 @@ addjournalitem(int p, char count2, char *WhiteName2, int WhiteRating2,
fclose(fp);
fclose(fp2);
- rename(fname2, fname);
+ xrename(__func__, fname2, fname);
}
PUBLIC int
@@ -1970,8 +2052,16 @@ pjournal(int p, int p1, char *fname)
pprintf(p, " White Rating Black Rating "
"Type ECO End Result\n");
+ _Static_assert(ARRAY_SIZE(WhiteName) > 19, "'WhiteName' too small");
+ _Static_assert(ARRAY_SIZE(BlackName) > 19, "'BlackName' too small");
+
+ _Static_assert(ARRAY_SIZE(type) > 99, "'type' too small");
+ _Static_assert(ARRAY_SIZE(eco) > 99, "'eco' too small");
+ _Static_assert(ARRAY_SIZE(ending) > 99, "'ending' too small");
+ _Static_assert(ARRAY_SIZE(result) > 99, "'result' too small");
+
while (!feof(fp)) {
- if (fscanf(fp, "%c %s %d %s %d %s %d %d %s %s %s\n",
+ if (fscanf(fp, "%c %19s %d %19s %d %99s %d %d %99s %99s %99s\n",
&count,
WhiteName, &WhiteRating,
BlackName, &BlackRating,
@@ -2009,7 +2099,7 @@ pgames(int p, int p1, char *fname)
char OppName[MAX_LOGIN_NAME + 1] = { '\0' };
char eco[100] = { '\0' };
char ending[100] = { '\0' };
- char result[2] = { 0,0 };
+ char result[2] = { 0,0 }; // XXX: right size?
char type[100] = { '\0' };
int MyRating, OppRating;
int count;
@@ -2025,8 +2115,16 @@ pgames(int p, int p1, char *fname)
pprintf(p, " Opponent Type "
"ECO End Date\n");
+ _Static_assert(ARRAY_SIZE(result) > 1, "'result' too small");
+ _Static_assert(ARRAY_SIZE(MyColor) > 1, "'MyColor' too small");
+ _Static_assert(ARRAY_SIZE(OppName) > 19, "'OppName' too small");
+ _Static_assert(ARRAY_SIZE(type) > 99, "'type' too small");
+ _Static_assert(ARRAY_SIZE(eco) > 99, "'eco' too small");
+ _Static_assert(ARRAY_SIZE(ending) > 99, "'ending' too small");
+
while (!feof(fp)) {
- if (fscanf(fp, "%d %s %d %s %d %s %s %d %d %d %d %s %s %ld\n",
+ if (fscanf(fp, "%d %1s %d %1s %d %19s %99s %d %d %d %d %99s "
+ "%99s %ld\n",
&count, result, &MyRating, MyColor,
&OppRating, OppName,
type,
@@ -2057,9 +2155,9 @@ pgames(int p, int p1, char *fname)
PUBLIC void
game_write_complete(int g, int isDraw, char *EndSymbol)
{
- FILE *fp;
+ FILE *fp = NULL;
char fname[MAX_FILENAME_SIZE] = { '\0' };
- int fd;
+ int fd = -1;
int wp = garray[g].white, bp = garray[g].black;
time_t now = time(NULL);
@@ -2068,20 +2166,21 @@ game_write_complete(int g, int isDraw, char *EndSymbol)
hist_dir,
(long int)(now % 100),
(long int)now);
+ errno = 0;
fd = open(fname, (O_WRONLY | O_CREAT | O_EXCL), 0644);
- if (fd == EEXIST)
+ if (fd == -1 && errno == EEXIST)
now++;
- } while (fd == EEXIST);
+ } while (fd == -1 && errno == EEXIST);
if (fd >= 0) {
- fp = fdopen(fd, "w");
- if (fp != NULL)
+ if ((fp = fdopen(fd, "w")) != NULL) {
WriteGameFile(fp, g);
- else {
+ fclose(fp);
+ } else {
fprintf(stderr, "Trouble writing history file %s",
fname);
}
- fclose(fp);
+
close(fd);
}