aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-08-08 16:02:49 +0800
committerPo Lu2023-08-08 16:02:49 +0800
commit27113c22f77b7a409c33b956a1a8d8be2d5bc673 (patch)
tree663e42ad962f3383873213e6923e842da47e3d7f /src
parent27a57f4cca55fd64a61eb8952b6422712f27b0af (diff)
downloademacs-27113c22f77b7a409c33b956a1a8d8be2d5bc673.tar.gz
emacs-27113c22f77b7a409c33b956a1a8d8be2d5bc673.zip
Minor improvements to write-region heuristic
* src/androidvfs.c (android_saf_stat): Set STATB->st_dev. (android_fstat): Likewise. (NATIVE_NAME): Seek to start of file after truncation. * src/fileio.c (write_region): Use stat instead of open+fstat to obtain updated mtime.
Diffstat (limited to 'src')
-rw-r--r--src/androidvfs.c15
-rw-r--r--src/fileio.c68
2 files changed, 49 insertions, 34 deletions
diff --git a/src/androidvfs.c b/src/androidvfs.c
index 93927ccc86b..8e742f8b26f 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -4013,6 +4013,7 @@ android_saf_stat (const char *uri_name, const char *id_name,
4013 memset (statb, 0, sizeof *statb); 4013 memset (statb, 0, sizeof *statb);
4014 statb->st_size = MAX (0, MIN (TYPE_MAXIMUM (off_t), size)); 4014 statb->st_size = MAX (0, MIN (TYPE_MAXIMUM (off_t), size));
4015 statb->st_mode = mode; 4015 statb->st_mode = mode;
4016 statb->st_dev = -4;
4016#ifdef STAT_TIMESPEC 4017#ifdef STAT_TIMESPEC
4017 STAT_TIMESPEC (statb, st_mtim).tv_sec = mtim / 1000; 4018 STAT_TIMESPEC (statb, st_mtim).tv_sec = mtim / 1000;
4018 STAT_TIMESPEC (statb, st_mtim).tv_nsec = (mtim % 1000) * 1000000; 4019 STAT_TIMESPEC (statb, st_mtim).tv_nsec = (mtim % 1000) * 1000000;
@@ -6169,7 +6170,14 @@ NATIVE_NAME (safPostRequest) (JNIEnv *env, jobject object)
6169JNIEXPORT jboolean JNICALL 6170JNIEXPORT jboolean JNICALL
6170NATIVE_NAME (ftruncate) (JNIEnv *env, jobject object, jint fd) 6171NATIVE_NAME (ftruncate) (JNIEnv *env, jobject object, jint fd)
6171{ 6172{
6172 return ftruncate (fd, 0) != -1; 6173 if (ftruncate (fd, 0) < 0)
6174 return false;
6175
6176 /* Reset the file pointer. */
6177 if (lseek (fd, 0, SEEK_SET) < 0)
6178 return false;
6179
6180 return true;
6173} 6181}
6174 6182
6175#ifdef __clang__ 6183#ifdef __clang__
@@ -6722,6 +6730,11 @@ android_fstat (int fd, struct stat *statb)
6722 parcel_fd = open_parcel_fds; 6730 parcel_fd = open_parcel_fds;
6723 for (; parcel_fd; parcel_fd = parcel_fd->next) 6731 for (; parcel_fd; parcel_fd = parcel_fd->next)
6724 { 6732 {
6733 if (parcel_fd->fd == fd)
6734 /* Set STATB->st_dev to a negative device number, signifying
6735 that it's contained within a content provider. */
6736 statb->st_dev = -4;
6737
6725 if (parcel_fd->fd == fd 6738 if (parcel_fd->fd == fd
6726 && timespec_valid_p (parcel_fd->mtime)) 6739 && timespec_valid_p (parcel_fd->mtime))
6727 { 6740 {
diff --git a/src/fileio.c b/src/fileio.c
index 26b7e193f0a..5d01e10f0ef 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -5582,42 +5582,44 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
5582 if (timespec_valid_p (modtime) 5582 if (timespec_valid_p (modtime)
5583 && ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system)) 5583 && ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system))
5584 { 5584 {
5585 int desc1 = emacs_open (fn, O_WRONLY, 0); 5585 struct stat st1;
5586 if (desc1 >= 0) 5586
5587 /* The code below previously tried to open FN O_WRONLY,
5588 subsequently calling fstat on the opened file descriptor.
5589 This proved inefficient and resulted in FN being truncated
5590 under several Android filesystems, and as such has been
5591 changed to a call to `stat'. */
5592
5593 if (emacs_fstatat (AT_FDCWD, fn, &st1, 0) == 0
5594 && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino)
5587 { 5595 {
5588 struct stat st1; 5596 /* Use the heuristic if it appears to be valid. With neither
5589 if (sys_fstat (desc1, &st1) == 0 5597 O_EXCL nor O_TRUNC, if Emacs happened to write nothing to the
5590 && st.st_dev == st1.st_dev && st.st_ino == st1.st_ino) 5598 file, the time stamp won't change. Also, some non-POSIX
5599 systems don't update an empty file's time stamp when
5600 truncating it. Finally, file systems with 100 ns or worse
5601 resolution sometimes seem to have bugs: on a system with ns
5602 resolution, checking ns % 100 incorrectly avoids the heuristic
5603 1% of the time, but the problem should be temporary as we will
5604 try again on the next time stamp. */
5605 bool use_heuristic
5606 = ((open_flags & (O_EXCL | O_TRUNC)) != 0
5607 && st.st_size != 0
5608 && modtime.tv_nsec % 100 != 0);
5609
5610 struct timespec modtime1 = get_stat_mtime (&st1);
5611 if (use_heuristic
5612 && timespec_cmp (modtime, modtime1) == 0
5613 && st.st_size == st1.st_size)
5591 { 5614 {
5592 /* Use the heuristic if it appears to be valid. With neither 5615 timestamp_file_system = st.st_dev;
5593 O_EXCL nor O_TRUNC, if Emacs happened to write nothing to the 5616 valid_timestamp_file_system = 1;
5594 file, the time stamp won't change. Also, some non-POSIX 5617 }
5595 systems don't update an empty file's time stamp when 5618 else
5596 truncating it. Finally, file systems with 100 ns or worse 5619 {
5597 resolution sometimes seem to have bugs: on a system with ns 5620 st.st_size = st1.st_size;
5598 resolution, checking ns % 100 incorrectly avoids the heuristic 5621 modtime = modtime1;
5599 1% of the time, but the problem should be temporary as we will
5600 try again on the next time stamp. */
5601 bool use_heuristic
5602 = ((open_flags & (O_EXCL | O_TRUNC)) != 0
5603 && st.st_size != 0
5604 && modtime.tv_nsec % 100 != 0);
5605
5606 struct timespec modtime1 = get_stat_mtime (&st1);
5607 if (use_heuristic
5608 && timespec_cmp (modtime, modtime1) == 0
5609 && st.st_size == st1.st_size)
5610 {
5611 timestamp_file_system = st.st_dev;
5612 valid_timestamp_file_system = 1;
5613 }
5614 else
5615 {
5616 st.st_size = st1.st_size;
5617 modtime = modtime1;
5618 }
5619 } 5622 }
5620 emacs_close (desc1);
5621 } 5623 }
5622 } 5624 }
5623 5625