about summary refs log tree commit diff stats
path: root/src/lua.c
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-12-16 21:27:45 -0800
committerKartik K. Agaram <vc@akkartik.com>2021-12-16 21:27:45 -0800
commit18f9f4e4f447625c0a3653f5e28845e43d005e11 (patch)
treeddd15dbf55251b92b685b132ad1a0e286ea8218d /src/lua.c
parent2a6786fee53bc9be7fe9f0bccc6ae651c0db36b5 (diff)
downloadteliva-18f9f4e4f447625c0a3653f5e28845e43d005e11.tar.gz
protect against data loss in some rare situations
Examples:
  - you try to write file but disk is full
  - you have two Teliva files being edited at the same time

Both are situations where it's impossible to avoid some data loss.
However, we should now at least have some valid state of the .tlv file
saved to disk where we'd previously end up with a zero-size file or
garbage.
Diffstat (limited to 'src/lua.c')
-rw-r--r--src/lua.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/src/lua.c b/src/lua.c
index 97b449e..6e879c0 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -346,25 +346,45 @@ static int handle_image (lua_State *L, char **argv, int n) {
 #define CURRENT_DEFINITION_LEN 256
 char Current_definition[CURRENT_DEFINITION_LEN+1] = {0};
 
+extern int mkstemp(char *template);
+extern FILE *fdopen(int fd, const char *mode);
 void save_editor_state (int rowoff, int coloff, int cy, int cx) {
   if (strlen(Current_definition) == 0) return;
-  FILE *out = fopen("teliva_editor_state", "w");
+  char outfilename[] = "teliva_editor_state_XXXXXX";
+  int outfd = mkstemp(outfilename);
+  if (outfd == -1) {
+    endwin();
+    perror("error in creating temporary file");
+    abort();
+  }
+  FILE *out = fdopen(outfd, "w");
+  assert(out != NULL);
   fprintf(out, "__teliva_editor_state = {\n");
   fprintf(out, "  image = \"%s\", definition = \"%s\",\n", Image_name, Current_definition);
   fprintf(out, "  rowoff = %d, coloff = %d,\n", rowoff, coloff);
   fprintf(out, "  cy = %d, cx = %d,\n", cy, cx);
   fprintf(out, "}\n");
   fclose(out);
+  rename(outfilename, "teliva_editor_state");
 }
 
 void save_to_current_definition_and_editor_buffer (lua_State *L, const char *definition) {
   int oldtop = lua_gettop(L);
   strncpy(Current_definition, definition, CURRENT_DEFINITION_LEN);
   int status = look_up_definition(L, Current_definition);
-  FILE *out = fopen("teliva_editor_buffer", "w");
+  char outfilename[] = "teliva_editor_buffer_XXXXXX";
+  int outfd = mkstemp(outfilename);
+  if (outfd == -1) {
+    endwin();
+    perror("error in creating temporary file");
+    abort();
+  }
+  FILE *out = fdopen(outfd, "w");
+  assert(out != NULL);
   if (status)
     fprintf(out, "%s", lua_tostring(L, -1));
   fclose(out);
+  rename(outfilename, "teliva_editor_buffer");
   lua_settop(L, oldtop);
 }
 
@@ -610,10 +630,19 @@ void save_note_to_editor_buffer (lua_State *L, int cursor) {
   lua_rawgeti(L, -1, cursor);
   lua_getfield(L, -1, "__teliva_note");
   const char *contents = lua_tostring(L, -1);
-  FILE *out = fopen("teliva_editor_buffer", "w");
+  char outfilename[] = "teliva_editor_buffer_XXXXXX";
+  int outfd = mkstemp(outfilename);
+  if (outfd == -1) {
+    endwin();
+    perror("error in creating temporary file");
+    abort();
+  }
+  FILE *out = fdopen(outfd, "w");
+  assert(out != NULL);
   if (contents != NULL)
     fprintf(out, "%s", contents);
   fclose(out);
+  rename(outfilename, "teliva_editor_buffer");
   lua_pop(L, 3);  /* contents, table at cursor, teliva_program */
 }