diff options
| author | Paul Eggert | 2012-10-12 17:52:01 -0700 |
|---|---|---|
| committer | Paul Eggert | 2012-10-12 17:52:01 -0700 |
| commit | d6453ce49724b0a3bd24922ff0ad02f391d6e517 (patch) | |
| tree | 655b2ca5f792dc2058ad731a4c1bb5af89163b28 /src | |
| parent | 06485aa8215af39f9f5f999933aa39d349a2bdf9 (diff) | |
| download | emacs-d6453ce49724b0a3bd24922ff0ad02f391d6e517.tar.gz emacs-d6453ce49724b0a3bd24922ff0ad02f391d6e517.zip | |
Fix some stat-related races.
* fileio.c (Fwrite_region): Avoid race condition if a file is
removed or renamed by some other process immediately after Emacs
writes it but before Emacs stats it. Do not assume that stat (or
fstat) succeeds.
* image.c (slurp_file): Resolve the file name with fopen + fstat
rather than stat + fopen.
(pbm_read_file) [0]: Remove unused code with stat race.
* process.c (allocate_pty) [HAVE_PTYS && !PTY_ITERATION && !PTY_OPEN]:
Remove ineffective code with stat race.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 13 | ||||
| -rw-r--r-- | src/fileio.c | 16 | ||||
| -rw-r--r-- | src/image.c | 44 | ||||
| -rw-r--r-- | src/process.c | 17 |
4 files changed, 27 insertions, 63 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d753221b996..6c03ef0ba0a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | 2012-10-13 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Fix some stat-related races. | ||
| 4 | * fileio.c (Fwrite_region): Avoid race condition if a file is | ||
| 5 | removed or renamed by some other process immediately after Emacs | ||
| 6 | writes it but before Emacs stats it. Do not assume that stat (or | ||
| 7 | fstat) succeeds. | ||
| 8 | * image.c (slurp_file): Resolve the file name with fopen + fstat | ||
| 9 | rather than stat + fopen. | ||
| 10 | (pbm_read_file) [0]: Remove unused code with stat race. | ||
| 11 | * process.c (allocate_pty) [HAVE_PTYS && !PTY_ITERATION && !PTY_OPEN]: | ||
| 12 | Remove ineffective code with stat race. | ||
| 13 | |||
| 1 | 2012-10-12 Stefan Monnier <monnier@iro.umontreal.ca> | 14 | 2012-10-12 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 15 | ||
| 3 | * doc.c (get_doc_string): Don't signal an error if the file is missing. | 16 | * doc.c (get_doc_string): Don't signal an error if the file is missing. |
diff --git a/src/fileio.c b/src/fileio.c index 5de5bc2b021..460eaf1e0b0 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -4545,6 +4545,7 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4545 | int save_errno = 0; | 4545 | int save_errno = 0; |
| 4546 | const char *fn; | 4546 | const char *fn; |
| 4547 | struct stat st; | 4547 | struct stat st; |
| 4548 | EMACS_TIME modtime; | ||
| 4548 | ptrdiff_t count = SPECPDL_INDEX (); | 4549 | ptrdiff_t count = SPECPDL_INDEX (); |
| 4549 | int count1; | 4550 | int count1; |
| 4550 | Lisp_Object handler; | 4551 | Lisp_Object handler; |
| @@ -4757,12 +4758,19 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4757 | } | 4758 | } |
| 4758 | #endif | 4759 | #endif |
| 4759 | 4760 | ||
| 4761 | modtime = invalid_emacs_time (); | ||
| 4762 | if (visiting) | ||
| 4763 | { | ||
| 4764 | if (fstat (desc, &st) == 0) | ||
| 4765 | modtime = get_stat_mtime (&st); | ||
| 4766 | else | ||
| 4767 | ok = 0, save_errno = errno; | ||
| 4768 | } | ||
| 4769 | |||
| 4760 | /* NFS can report a write failure now. */ | 4770 | /* NFS can report a write failure now. */ |
| 4761 | if (emacs_close (desc) < 0) | 4771 | if (emacs_close (desc) < 0) |
| 4762 | ok = 0, save_errno = errno; | 4772 | ok = 0, save_errno = errno; |
| 4763 | 4773 | ||
| 4764 | stat (fn, &st); | ||
| 4765 | |||
| 4766 | /* Discard the unwind protect for close_file_unwind. */ | 4774 | /* Discard the unwind protect for close_file_unwind. */ |
| 4767 | specpdl_ptr = specpdl + count1; | 4775 | specpdl_ptr = specpdl + count1; |
| 4768 | 4776 | ||
| @@ -4790,9 +4798,9 @@ This calls `write-region-annotate-functions' at the start, and | |||
| 4790 | /* Do this before reporting IO error | 4798 | /* Do this before reporting IO error |
| 4791 | to avoid a "file has changed on disk" warning on | 4799 | to avoid a "file has changed on disk" warning on |
| 4792 | next attempt to save. */ | 4800 | next attempt to save. */ |
| 4793 | if (visiting) | 4801 | if (EMACS_TIME_VALID_P (modtime)) |
| 4794 | { | 4802 | { |
| 4795 | current_buffer->modtime = get_stat_mtime (&st); | 4803 | current_buffer->modtime = modtime; |
| 4796 | current_buffer->modtime_size = st.st_size; | 4804 | current_buffer->modtime_size = st.st_size; |
| 4797 | } | 4805 | } |
| 4798 | 4806 | ||
diff --git a/src/image.c b/src/image.c index 9b41cf74993..d52c3a29a27 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -2140,12 +2140,11 @@ x_find_image_file (Lisp_Object file) | |||
| 2140 | static unsigned char * | 2140 | static unsigned char * |
| 2141 | slurp_file (char *file, ptrdiff_t *size) | 2141 | slurp_file (char *file, ptrdiff_t *size) |
| 2142 | { | 2142 | { |
| 2143 | FILE *fp = NULL; | 2143 | FILE *fp = fopen (file, "rb"); |
| 2144 | unsigned char *buf = NULL; | 2144 | unsigned char *buf = NULL; |
| 2145 | struct stat st; | 2145 | struct stat st; |
| 2146 | 2146 | ||
| 2147 | if (stat (file, &st) == 0 | 2147 | if (fp && fstat (fileno (fp), &st) == 0 |
| 2148 | && (fp = fopen (file, "rb")) != NULL | ||
| 2149 | && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX) | 2148 | && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX) |
| 2150 | && (buf = xmalloc (st.st_size), | 2149 | && (buf = xmalloc (st.st_size), |
| 2151 | fread (buf, 1, st.st_size, fp) == st.st_size)) | 2150 | fread (buf, 1, st.st_size, fp) == st.st_size)) |
| @@ -5004,45 +5003,6 @@ pbm_scan_number (unsigned char **s, unsigned char *end) | |||
| 5004 | } | 5003 | } |
| 5005 | 5004 | ||
| 5006 | 5005 | ||
| 5007 | #ifdef HAVE_NTGUI | ||
| 5008 | #if 0 /* Unused. ++kfs */ | ||
| 5009 | |||
| 5010 | /* Read FILE into memory. Value is a pointer to a buffer allocated | ||
| 5011 | with xmalloc holding FILE's contents. Value is null if an error | ||
| 5012 | occurred. *SIZE is set to the size of the file. */ | ||
| 5013 | |||
| 5014 | static char * | ||
| 5015 | pbm_read_file (Lisp_Object file, int *size) | ||
| 5016 | { | ||
| 5017 | FILE *fp = NULL; | ||
| 5018 | char *buf = NULL; | ||
| 5019 | struct stat st; | ||
| 5020 | |||
| 5021 | if (stat (SDATA (file), &st) == 0 | ||
| 5022 | && (fp = fopen (SDATA (file), "rb")) != NULL | ||
| 5023 | && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX) | ||
| 5024 | && (buf = xmalloc (st.st_size), | ||
| 5025 | fread (buf, 1, st.st_size, fp) == st.st_size)) | ||
| 5026 | { | ||
| 5027 | *size = st.st_size; | ||
| 5028 | fclose (fp); | ||
| 5029 | } | ||
| 5030 | else | ||
| 5031 | { | ||
| 5032 | if (fp) | ||
| 5033 | fclose (fp); | ||
| 5034 | if (buf) | ||
| 5035 | { | ||
| 5036 | xfree (buf); | ||
| 5037 | buf = NULL; | ||
| 5038 | } | ||
| 5039 | } | ||
| 5040 | |||
| 5041 | return buf; | ||
| 5042 | } | ||
| 5043 | #endif | ||
| 5044 | #endif /* HAVE_NTGUI */ | ||
| 5045 | |||
| 5046 | /* Load PBM image IMG for use on frame F. */ | 5006 | /* Load PBM image IMG for use on frame F. */ |
| 5047 | 5007 | ||
| 5048 | static bool | 5008 | static bool |
diff --git a/src/process.c b/src/process.c index 2cbce9d28ea..d45a2c6e8e0 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -646,23 +646,6 @@ allocate_pty (void) | |||
| 646 | PTY_OPEN; | 646 | PTY_OPEN; |
| 647 | #else /* no PTY_OPEN */ | 647 | #else /* no PTY_OPEN */ |
| 648 | { | 648 | { |
| 649 | { /* Some systems name their pseudoterminals so that there are gaps in | ||
| 650 | the usual sequence - for example, on HP9000/S700 systems, there | ||
| 651 | are no pseudoterminals with names ending in 'f'. So we wait for | ||
| 652 | three failures in a row before deciding that we've reached the | ||
| 653 | end of the ptys. */ | ||
| 654 | int failed_count = 0; | ||
| 655 | struct stat stb; | ||
| 656 | |||
| 657 | if (stat (pty_name, &stb) < 0) | ||
| 658 | { | ||
| 659 | failed_count++; | ||
| 660 | if (failed_count >= 3) | ||
| 661 | return -1; | ||
| 662 | } | ||
| 663 | else | ||
| 664 | failed_count = 0; | ||
| 665 | } | ||
| 666 | # ifdef O_NONBLOCK | 649 | # ifdef O_NONBLOCK |
| 667 | fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0); | 650 | fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0); |
| 668 | # else | 651 | # else |