diff options
Diffstat (limited to 'FICS/gamedb.c')
-rw-r--r-- | FICS/gamedb.c | 257 |
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); } |