about summary refs log tree commit diff stats
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
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.
-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 */
 }