Open save file once in uiLoad() and keep it open until uiSave()
Opening the same file *path* twice is a TOCTOU, although not a critical one: worst case we load from one file and save to another - the impact depends on how and when catgirl is started the next anyway. More importantly, keeping the file handle open at runtime allows us to drop all filesystem related promises for `-s/save' on OpenBSD. uiLoad() now opens "r+", meaning "Open for reading and writing." up front so uiSave() can write to it. In the case of a nonexistent save file, it now opens with "w" meaning "Open for writing. The file is created if it does not exist.", i.e. the same write/create semantics as "w" except uiLoad() no longer truncates. existing files. uiSave() now truncates the save file to avoid appending in general.master
parent
8e591c96f8
commit
cdd4ccf16f
2
chat.c
2
chat.c
|
@ -83,7 +83,7 @@ struct Self self = { .color = Default };
|
||||||
|
|
||||||
static const char *save;
|
static const char *save;
|
||||||
static void exitSave(void) {
|
static void exitSave(void) {
|
||||||
int error = uiSave(save);
|
int error = uiSave();
|
||||||
if (error) {
|
if (error) {
|
||||||
warn("%s", save);
|
warn("%s", save);
|
||||||
_exit(EX_IOERR);
|
_exit(EX_IOERR);
|
||||||
|
|
2
chat.h
2
chat.h
|
@ -312,7 +312,7 @@ void uiFormat(
|
||||||
uint id, enum Heat heat, const time_t *time, const char *format, ...
|
uint id, enum Heat heat, const time_t *time, const char *format, ...
|
||||||
) __attribute__((format(printf, 4, 5)));
|
) __attribute__((format(printf, 4, 5)));
|
||||||
void uiLoad(const char *name);
|
void uiLoad(const char *name);
|
||||||
int uiSave(const char *name);
|
int uiSave(void);
|
||||||
|
|
||||||
enum { BufferCap = 1024 };
|
enum { BufferCap = 1024 };
|
||||||
struct Buffer;
|
struct Buffer;
|
||||||
|
|
12
ui.c
12
ui.c
|
@ -1128,11 +1128,12 @@ static int writeString(FILE *file, const char *str) {
|
||||||
return (fwrite(str, strlen(str) + 1, 1, file) ? 0 : -1);
|
return (fwrite(str, strlen(str) + 1, 1, file) ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int uiSave(const char *name) {
|
static FILE *saveFile;
|
||||||
FILE *saveFile = dataOpen(name, "w");
|
|
||||||
if (!saveFile) return -1;
|
|
||||||
|
|
||||||
|
int uiSave(void) {
|
||||||
int error = 0
|
int error = 0
|
||||||
|
|| ftruncate(fileno(saveFile), 0)
|
||||||
|
|| fseek(saveFile, 0, SEEK_SET)
|
||||||
|| writeTime(saveFile, Signatures[7])
|
|| writeTime(saveFile, Signatures[7])
|
||||||
|| writeTime(saveFile, self.pos);
|
|| writeTime(saveFile, self.pos);
|
||||||
if (error) return error;
|
if (error) return error;
|
||||||
|
@ -1179,12 +1180,11 @@ static ssize_t readString(FILE *file, char **buf, size_t *cap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiLoad(const char *name) {
|
void uiLoad(const char *name) {
|
||||||
FILE *saveFile = dataOpen(name, "r");
|
saveFile = dataOpen(name, "r+");
|
||||||
if (!saveFile) {
|
if (!saveFile) {
|
||||||
if (errno != ENOENT) exit(EX_NOINPUT);
|
if (errno != ENOENT) exit(EX_NOINPUT);
|
||||||
saveFile = dataOpen(name, "w");
|
saveFile = dataOpen(name, "w");
|
||||||
if (!saveFile) exit(EX_CANTCREAT);
|
if (!saveFile) exit(EX_CANTCREAT);
|
||||||
fclose(saveFile);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1192,7 +1192,6 @@ void uiLoad(const char *name) {
|
||||||
fread(&signature, sizeof(signature), 1, saveFile);
|
fread(&signature, sizeof(signature), 1, saveFile);
|
||||||
if (ferror(saveFile)) err(EX_IOERR, "fread");
|
if (ferror(saveFile)) err(EX_IOERR, "fread");
|
||||||
if (feof(saveFile)) {
|
if (feof(saveFile)) {
|
||||||
fclose(saveFile);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
size_t version = signatureVersion(signature);
|
size_t version = signatureVersion(signature);
|
||||||
|
@ -1225,5 +1224,4 @@ void uiLoad(const char *name) {
|
||||||
urlLoad(saveFile, version);
|
urlLoad(saveFile, version);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
fclose(saveFile);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue