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.
This commit is contained in:
parent
27a57f4cca
commit
27113c22f7
2 changed files with 50 additions and 35 deletions
|
@ -4013,6 +4013,7 @@ android_saf_stat (const char *uri_name, const char *id_name,
|
|||
memset (statb, 0, sizeof *statb);
|
||||
statb->st_size = MAX (0, MIN (TYPE_MAXIMUM (off_t), size));
|
||||
statb->st_mode = mode;
|
||||
statb->st_dev = -4;
|
||||
#ifdef STAT_TIMESPEC
|
||||
STAT_TIMESPEC (statb, st_mtim).tv_sec = mtim / 1000;
|
||||
STAT_TIMESPEC (statb, st_mtim).tv_nsec = (mtim % 1000) * 1000000;
|
||||
|
@ -6169,7 +6170,14 @@ NATIVE_NAME (safPostRequest) (JNIEnv *env, jobject object)
|
|||
JNIEXPORT jboolean JNICALL
|
||||
NATIVE_NAME (ftruncate) (JNIEnv *env, jobject object, jint fd)
|
||||
{
|
||||
return ftruncate (fd, 0) != -1;
|
||||
if (ftruncate (fd, 0) < 0)
|
||||
return false;
|
||||
|
||||
/* Reset the file pointer. */
|
||||
if (lseek (fd, 0, SEEK_SET) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
|
@ -6722,6 +6730,11 @@ android_fstat (int fd, struct stat *statb)
|
|||
parcel_fd = open_parcel_fds;
|
||||
for (; parcel_fd; parcel_fd = parcel_fd->next)
|
||||
{
|
||||
if (parcel_fd->fd == fd)
|
||||
/* Set STATB->st_dev to a negative device number, signifying
|
||||
that it's contained within a content provider. */
|
||||
statb->st_dev = -4;
|
||||
|
||||
if (parcel_fd->fd == fd
|
||||
&& timespec_valid_p (parcel_fd->mtime))
|
||||
{
|
||||
|
|
70
src/fileio.c
70
src/fileio.c
|
@ -5582,42 +5582,44 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename,
|
|||
if (timespec_valid_p (modtime)
|
||||
&& ! (valid_timestamp_file_system && st.st_dev == timestamp_file_system))
|
||||
{
|
||||
int desc1 = emacs_open (fn, O_WRONLY, 0);
|
||||
if (desc1 >= 0)
|
||||
{
|
||||
struct stat st1;
|
||||
if (sys_fstat (desc1, &st1) == 0
|
||||
&& st.st_dev == st1.st_dev && st.st_ino == st1.st_ino)
|
||||
{
|
||||
/* Use the heuristic if it appears to be valid. With neither
|
||||
O_EXCL nor O_TRUNC, if Emacs happened to write nothing to the
|
||||
file, the time stamp won't change. Also, some non-POSIX
|
||||
systems don't update an empty file's time stamp when
|
||||
truncating it. Finally, file systems with 100 ns or worse
|
||||
resolution sometimes seem to have bugs: on a system with ns
|
||||
resolution, checking ns % 100 incorrectly avoids the heuristic
|
||||
1% of the time, but the problem should be temporary as we will
|
||||
try again on the next time stamp. */
|
||||
bool use_heuristic
|
||||
= ((open_flags & (O_EXCL | O_TRUNC)) != 0
|
||||
&& st.st_size != 0
|
||||
&& modtime.tv_nsec % 100 != 0);
|
||||
struct stat st1;
|
||||
|
||||
struct timespec modtime1 = get_stat_mtime (&st1);
|
||||
if (use_heuristic
|
||||
&& timespec_cmp (modtime, modtime1) == 0
|
||||
&& st.st_size == st1.st_size)
|
||||
{
|
||||
timestamp_file_system = st.st_dev;
|
||||
valid_timestamp_file_system = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
st.st_size = st1.st_size;
|
||||
modtime = modtime1;
|
||||
}
|
||||
/* The code below previously tried to open FN O_WRONLY,
|
||||
subsequently calling fstat on the opened file descriptor.
|
||||
This proved inefficient and resulted in FN being truncated
|
||||
under several Android filesystems, and as such has been
|
||||
changed to a call to `stat'. */
|
||||
|
||||
if (emacs_fstatat (AT_FDCWD, fn, &st1, 0) == 0
|
||||
&& st.st_dev == st1.st_dev && st.st_ino == st1.st_ino)
|
||||
{
|
||||
/* Use the heuristic if it appears to be valid. With neither
|
||||
O_EXCL nor O_TRUNC, if Emacs happened to write nothing to the
|
||||
file, the time stamp won't change. Also, some non-POSIX
|
||||
systems don't update an empty file's time stamp when
|
||||
truncating it. Finally, file systems with 100 ns or worse
|
||||
resolution sometimes seem to have bugs: on a system with ns
|
||||
resolution, checking ns % 100 incorrectly avoids the heuristic
|
||||
1% of the time, but the problem should be temporary as we will
|
||||
try again on the next time stamp. */
|
||||
bool use_heuristic
|
||||
= ((open_flags & (O_EXCL | O_TRUNC)) != 0
|
||||
&& st.st_size != 0
|
||||
&& modtime.tv_nsec % 100 != 0);
|
||||
|
||||
struct timespec modtime1 = get_stat_mtime (&st1);
|
||||
if (use_heuristic
|
||||
&& timespec_cmp (modtime, modtime1) == 0
|
||||
&& st.st_size == st1.st_size)
|
||||
{
|
||||
timestamp_file_system = st.st_dev;
|
||||
valid_timestamp_file_system = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
st.st_size = st1.st_size;
|
||||
modtime = modtime1;
|
||||
}
|
||||
emacs_close (desc1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue