xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit b93a3800f8f3bada478d523ef53a11598c6f5916

Fixed races on writing vifminfo file
This updating of vifminfo file is done in three steps:
1) copy vifminfo
2) update its copy
3) replace original file with its modified copy

Thanks to Christoph (informationen)
Author: xaizek
Author date (UTC): 2013-01-05 21:07
Committer name: xaizek
Committer date (UTC): 2013-01-06 17:30
Parent(s): c3f3b740431e55ecf2f255c8086faf2e711c0c89
Signing key:
Tree: 4f81d6058a3f002911ac57ce39cdd2ec0475fa8e
File Lines added Lines deleted
ChangeLog 2 0
src/cfg/info.c 81 5
src/cfg/info.h 1 0
File ChangeLog changed (mode: 100644) (index b5de421cc..524ff3e77)
38 38
39 39 Fixed silent ignoring issues on running executables on Windows. Fixed silent ignoring issues on running executables on Windows.
40 40
41 Fixed races on writing vifminfo file.
42
41 43 0.7.4 to 0.7.4a 0.7.4 to 0.7.4a
42 44
43 45 Don't redraw statbar until end of :restart command. Don't redraw statbar until end of :restart command.
File src/cfg/info.c changed (mode: 100644) (index 114cd50a5..115345428)
26 26 #include "../utils/fs_limits.h" #include "../utils/fs_limits.h"
27 27 #include "../utils/str.h" #include "../utils/str.h"
28 28 #include "../utils/string_array.h" #include "../utils/string_array.h"
29 #include "../utils/utils.h"
29 30 #include "../bookmarks.h" #include "../bookmarks.h"
30 31 #include "../commands.h" #include "../commands.h"
31 32 #include "../dir_stack.h" #include "../dir_stack.h"
 
... ... static void get_sort_info(FileView *view, const char line[]);
46 47 static void inc_history(char ***hist, int *num, int *len); static void inc_history(char ***hist, int *num, int *len);
47 48 static void get_history(FileView *view, int reread, const char *dir, static void get_history(FileView *view, int reread, const char *dir,
48 49 const char *file, int pos); const char *file, int pos);
50 static int copy_file(const char src[], const char dst[]);
51 static int copy_file_internal(FILE *const src, FILE *const dst);
52 static void update_info_file(const char filename[]);
49 53 static void prepare_line(char *line); static void prepare_line(char *line);
50 54 static const char * escape_spaces(const char *str); static const char * escape_spaces(const char *str);
51 55 static void put_sort_info(FILE *fp, char leading_char, const FileView *view); static void put_sort_info(FILE *fp, char leading_char, const FileView *view);
 
... ... get_history(FileView *view, int reread, const char *dir, const char *file,
359 363
360 364 void void
361 365 write_info_file(void) write_info_file(void)
366 {
367 char info_file[PATH_MAX];
368 char tmp_file[PATH_MAX];
369
370 (void)snprintf(info_file, sizeof(info_file), "%s/vifminfo", cfg.config_dir);
371 (void)snprintf(tmp_file, sizeof(tmp_file), "%s_%u", info_file, get_pid());
372
373 if(access(info_file, R_OK) != 0 || copy_file(info_file, tmp_file) == 0)
374 {
375 update_info_file(tmp_file);
376
377 if(rename(tmp_file, info_file) != 0)
378 {
379 (void)unlink(tmp_file);
380 }
381 }
382 }
383
384 /* Copies the src file to the dst location. Returns zero on success. */
385 static int
386 copy_file(const char src[], const char dst[])
387 {
388 FILE *const src_fp = fopen(src, "rb");
389 FILE *const dst_fp = fopen(dst, "wb");
390 int result;
391
392 result = copy_file_internal(src_fp, dst_fp);
393
394 if(dst_fp != NULL)
395 {
396 (void)fclose(dst_fp);
397 }
398 if(src_fp != NULL)
399 {
400 (void)fclose(src_fp);
401 }
402
403 if(result != 0)
404 {
405 (void)unlink(dst);
406 }
407
408 return result;
409 }
410
411 /* Internal sub-function of the copy_file() function. Returns zero on
412 * success. */
413 static int
414 copy_file_internal(FILE *const src, FILE *const dst)
415 {
416 char buffer[4*1024];
417 size_t nread;
418
419 if(src == NULL || dst == NULL)
420 {
421 return 1;
422 }
423
424 while((nread = fread(&buffer[0], 1, sizeof(buffer), src)))
425 {
426 if(fwrite(&buffer[0], 1, nread, dst) != nread)
427 {
428 break;
429 }
430 }
431
432 return nread > 0;
433 }
434
435 /* Reads contents of the filename file as an info file and updates it with the
436 * state of current instance. */
437 static void
438 update_info_file(const char filename[])
362 439 { {
363 440 /* TODO: refactor this function write_info_file() */ /* TODO: refactor this function write_info_file() */
364 441
365 442 FILE *fp; FILE *fp;
366 char info_file[PATH_MAX];
367 443 char ** list; char ** list;
368 444 int nlist = -1; int nlist = -1;
369 445 char **ft = NULL, **fx = NULL , **fv = NULL, **cmds = NULL, **marks = NULL; char **ft = NULL, **fx = NULL , **fv = NULL, **cmds = NULL, **marks = NULL;
 
... ... write_info_file(void)
378 454 if(cfg.vifm_info == 0) if(cfg.vifm_info == 0)
379 455 return; return;
380 456
381 snprintf(info_file, sizeof(info_file), "%s/vifminfo", cfg.config_dir);
382
383 457 list = list_udf(); list = list_udf();
384 458 while(list[++nlist] != NULL); while(list[++nlist] != NULL);
385 459
386 if((fp = fopen(info_file, "r")) != NULL)
460 if((fp = fopen(filename, "r")) != NULL)
387 461 { {
388 462 char line[MAX_LEN], line2[MAX_LEN], line3[MAX_LEN]; char line[MAX_LEN], line2[MAX_LEN], line3[MAX_LEN];
389 463 while(fgets(line, sizeof(line), fp) == line) while(fgets(line, sizeof(line), fp) == line)
 
... ... write_info_file(void)
569 643 fclose(fp); fclose(fp);
570 644 } }
571 645
572 if((fp = fopen(info_file, "w")) == NULL)
646 if((fp = fopen(filename, "w")) == NULL)
647 {
573 648 return; return;
649 }
574 650
575 651 fprintf(fp, "# You can edit this file by hand, but it's recommended not to do that.\n"); fprintf(fp, "# You can edit this file by hand, but it's recommended not to do that.\n");
576 652
File src/cfg/info.h changed (mode: 100644) (index 677c78390..e7ed488d6)
21 21 #define __INFO_H__ #define __INFO_H__
22 22
23 23 void read_info_file(int reread); void read_info_file(int reread);
24 /* Writes vifminfo file updating it with state of the current instance. */
24 25 void write_info_file(void); void write_info_file(void);
25 26
26 27 #endif #endif
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master