commit de6a6a402e45970c4b6d65778efc2e990c4a78a4 from: Omar Polo date: Sun Apr 24 10:43:32 2022 UTC generate session/history_file atomically if an i/o error occurs while writing those files, they may end up being corrupted or truncated. Use the approach already used for tofu, write a temp file and rename(2) it to the correct position. commit - f63b8f7342aefba6b3dac50d6790981987c8faa8 commit + de6a6a402e45970c4b6d65778efc2e990c4a78a4 blob - 2309904c0b78c1bf3d1042531cd40b17c2442cbd blob + 055d8061449bdc4efeae2d66f59b07941e8e7941 --- fs.c +++ fs.c @@ -71,8 +71,8 @@ char lockfile_path[PATH_MAX]; char bookmark_file[PATH_MAX]; char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX]; char crashed_file[PATH_MAX]; -char session_file[PATH_MAX]; -char history_file[PATH_MAX]; +char session_file[PATH_MAX], session_file_tmp[PATH_MAX]; +char history_file[PATH_MAX], history_file_tmp[PATH_MAX]; static void __attribute__((__noreturn__)) die(void) @@ -445,8 +445,12 @@ fs_init(void) join_path(known_hosts_tmp, cache_path_base, "/known_hosts.tmp.XXXXXXXXXX", sizeof(known_hosts_tmp)); join_path(session_file, cache_path_base, "/session", + sizeof(session_file)); + join_path(session_file_tmp, cache_path_base, "/session.XXXXXXXXXX", sizeof(session_file)); join_path(history_file, cache_path_base, "/history", + sizeof(history_file)); + join_path(history_file_tmp, cache_path_base, "/history.XXXXXXXXXX", sizeof(history_file)); join_path(crashed_file, cache_path_base, "/crashed", sizeof(crashed_file)); blob - da0257e65eb443f4bdfca3f75baa41cce5e60076 blob + 984e9d4e4252b6a78b374f1536b06960bf7624e5 --- include/fs.h +++ include/fs.h @@ -30,8 +30,8 @@ extern char lockfile_path[PATH_MAX]; extern char bookmark_file[PATH_MAX]; extern char known_hosts_file[PATH_MAX], known_hosts_tmp[PATH_MAX]; extern char crashed_file[PATH_MAX]; -extern char session_file[PATH_MAX]; -extern char history_file[PATH_MAX]; +extern char session_file[PATH_MAX], session_file_tmp[PATH_MAX]; +extern char history_file[PATH_MAX], history_file_tmp[PATH_MAX]; int fs_init(void); int lock_session(void); blob - b5bd2aaf1318f0aded094a8b90bd8a7519ff04d4 blob + 49f267c9fb03d61e18a50c8e530f12bb1893dde6 --- session.c +++ session.c @@ -193,26 +193,51 @@ savetab(FILE *fp, struct tab *tab, int killed) void save_session(void) { - FILE *session, *hist; - struct tab *tab; - size_t i; + FILE *tmp; + struct tab *tab; + size_t i; + int fd, err= 0; + char sfn[PATH_MAX]; if (safe_mode) return; - if ((session = fopen(session_file, "w")) == NULL) + strlcpy(sfn, session_file_tmp, sizeof(sfn)); + if ((fd = mkstemp(sfn)) == -1 || + (tmp = fdopen(fd, "w")) == NULL) { + if (fd != -1) { + unlink(sfn); + close(fd); + } return; + } TAILQ_FOREACH(tab, &tabshead, tabs) - savetab(session, tab, 0); + savetab(tmp, tab, 0); TAILQ_FOREACH(tab, &ktabshead, tabs) - savetab(session, tab, 1); + savetab(tmp, tab, 1); - fclose(session); + err = ferror(tmp); + fclose(tmp); - if ((hist = fopen(history_file, "a")) == NULL) + if (err) { + unlink(sfn); return; + } + if (rename(sfn, session_file)) + return; + + strlcpy(sfn, history_file_tmp, sizeof(sfn)); + if ((fd = mkstemp(sfn)) == -1 || + (tmp = fdopen(fd, "w")) == NULL) { + if (fd != -1) { + unlink(sfn); + close(fd); + } + return; + } + if (history.dirty) { for (i = 0; i < history.len && history.dirty > 0; ++i) { if (!history.items[i].dirty) @@ -220,14 +245,22 @@ save_session(void) history.dirty--; history.items[i].dirty = 0; - fprintf(hist, "%lld %s\n", + fprintf(tmp, "%lld %s\n", (long long)history.items[i].ts, history.items[i].uri); } history.dirty = 0; } - fclose(hist); + err = ferror(tmp); + fclose(tmp); + + if (err) { + unlink(sfn); + return; + } + + rename(sfn, history_file); } void