diff options
| author | Paul Eggert | 2025-07-12 14:31:18 -0700 |
|---|---|---|
| committer | Paul Eggert | 2025-07-13 21:09:39 -0700 |
| commit | aee9b598312e282700c4eedf02b174b908479ce7 (patch) | |
| tree | 87c8cd0c1d8c34944f17624007856b4d82251c28 /src | |
| parent | 56091b6d5cccecf320796bd62e36adc64f45b614 (diff) | |
| download | emacs-aee9b598312e282700c4eedf02b174b908479ce7.tar.gz emacs-aee9b598312e282700c4eedf02b174b908479ce7.zip | |
insert-file-contents file end EOF fixes
* src/fileio.c (Finsert_file_contents):
When counting bytes at file end, don’t trust lseek to seek
to the end of the file. Instead, read a bit after lseeking,
to make sure we get to the end, give up if we don’t get to EOF.
This works around problems on /proc filesystems
where lseek pretends the file is empty.
Update file_size_hint when reaching EOF.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/src/fileio.c b/src/fileio.c index 3c371dea98d..b7b4320d73e 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -4488,13 +4488,39 @@ by calling `format-decode', which see. */) | |||
| 4488 | /* Count how many chars at the end of the file | 4488 | /* Count how many chars at the end of the file |
| 4489 | match the text at the end of the buffer. But, if we have | 4489 | match the text at the end of the buffer. But, if we have |
| 4490 | already found that decoding is necessary, don't waste time. */ | 4490 | already found that decoding is necessary, don't waste time. */ |
| 4491 | |||
| 4492 | off_t endpos; | ||
| 4493 | if (!giveup_match_end) | ||
| 4494 | { | ||
| 4495 | endpos = end_offset; | ||
| 4496 | if (endpos == TYPE_MAXIMUM (off_t)) | ||
| 4497 | { | ||
| 4498 | endpos = emacs_fd_lseek (fd, 0, SEEK_END); | ||
| 4499 | giveup_match_end = endpos < 0; | ||
| 4500 | if (giveup_match_end) | ||
| 4501 | seekable = false; | ||
| 4502 | else | ||
| 4503 | { | ||
| 4504 | /* Check that read reports EOF soon, to catch platforms | ||
| 4505 | where SEEK_END can report wildly small offsets. */ | ||
| 4506 | ptrdiff_t n = emacs_fd_read (fd, read_buf, sizeof read_buf); | ||
| 4507 | if (n < 0) | ||
| 4508 | report_file_error ("Read error", orig_filename); | ||
| 4509 | endpos += n; | ||
| 4510 | giveup_match_end = 0 < n; | ||
| 4511 | if (!giveup_match_end) | ||
| 4512 | file_size_hint = endpos; | ||
| 4513 | } | ||
| 4514 | } | ||
| 4515 | } | ||
| 4516 | |||
| 4491 | while (!giveup_match_end) | 4517 | while (!giveup_match_end) |
| 4492 | { | 4518 | { |
| 4493 | int total_read, nread, bufpos, trial; | 4519 | int total_read, nread, bufpos, trial; |
| 4494 | off_t curpos; | 4520 | off_t curpos; |
| 4495 | 4521 | ||
| 4496 | /* At what file position are we now scanning? */ | 4522 | /* At what file position are we now scanning? */ |
| 4497 | curpos = end_offset - (ZV_BYTE - same_at_end); | 4523 | curpos = endpos - (ZV_BYTE - same_at_end); |
| 4498 | /* If the entire file matches the buffer tail, stop the scan. */ | 4524 | /* If the entire file matches the buffer tail, stop the scan. */ |
| 4499 | if (curpos == 0) | 4525 | if (curpos == 0) |
| 4500 | break; | 4526 | break; |
| @@ -4511,7 +4537,10 @@ by calling `format-decode', which see. */) | |||
| 4511 | if (nread < 0) | 4537 | if (nread < 0) |
| 4512 | report_file_error ("Read error", orig_filename); | 4538 | report_file_error ("Read error", orig_filename); |
| 4513 | else if (nread == 0) | 4539 | else if (nread == 0) |
| 4514 | break; | 4540 | { |
| 4541 | file_size_hint = curpos - trial + total_read; | ||
| 4542 | break; | ||
| 4543 | } | ||
| 4515 | total_read += nread; | 4544 | total_read += nread; |
| 4516 | } | 4545 | } |
| 4517 | 4546 | ||
| @@ -4567,15 +4596,14 @@ by calling `format-decode', which see. */) | |||
| 4567 | /* Don't try to reuse the same piece of text twice. */ | 4596 | /* Don't try to reuse the same piece of text twice. */ |
| 4568 | overlap = (same_at_start - BEGV_BYTE | 4597 | overlap = (same_at_start - BEGV_BYTE |
| 4569 | - (same_at_end - ZV_BYTE | 4598 | - (same_at_end - ZV_BYTE |
| 4570 | + (end_offset < TYPE_MAXIMUM (off_t) | 4599 | + endpos)); |
| 4571 | ? end_offset : file_size_hint))); | ||
| 4572 | if (overlap > 0) | 4600 | if (overlap > 0) |
| 4573 | same_at_end += overlap; | 4601 | same_at_end += overlap; |
| 4574 | same_at_end_charpos = BYTE_TO_CHAR (same_at_end); | 4602 | same_at_end_charpos = BYTE_TO_CHAR (same_at_end); |
| 4575 | 4603 | ||
| 4576 | /* Arrange to read only the nonmatching middle part of the file. */ | 4604 | /* Arrange to read only the nonmatching middle part of the file. */ |
| 4577 | beg_offset += same_at_start - BEGV_BYTE; | 4605 | beg_offset += same_at_start - BEGV_BYTE; |
| 4578 | end_offset -= ZV_BYTE - same_at_end; | 4606 | end_offset = endpos - (ZV_BYTE - same_at_end); |
| 4579 | 4607 | ||
| 4580 | if (!NILP (visit) && BEG == BEGV && Z == ZV) | 4608 | if (!NILP (visit) && BEG == BEGV && Z == ZV) |
| 4581 | /* This binding is to avoid ask-user-about-supersession-threat | 4609 | /* This binding is to avoid ask-user-about-supersession-threat |