mirror of
https://github.com/neovim/neovim.git
synced 2026-11-06 05:16:52 +00:00
refactor(shada): get available ".tmp.X" filename #42617
This commit is contained in:
1 parent
33a812f4fd
commit
aeb1e67d0f
2 files changed
+35
-48
No files matched your search
@@ -1137,7 +1137,7 @@ files for different types of files (e.g., C code) and load them based on the
|
||||
file name, using the ":autocmd" command (see |:autocmd|). More information on
|
||||
ShaDa file format is contained in |shada-format| section.
|
||||
|
||||
*E136* *E929* *shada-error-handling*
|
||||
*E136* *shada-error-handling*
|
||||
Some errors make Nvim leave temporary file named `{basename}.tmp.X` (X is
|
||||
any free letter from `a` to `z`) while normally it will create this file,
|
||||
write to it and then rename `{basename}.tmp.X` to `{basename}`. Such errors
|
||||
|
||||
+34
-47
@@ -103,9 +103,9 @@
|
||||
// E577: Illegal register name
|
||||
// E886: Can't rename viminfo file to %s!
|
||||
// E929: Too many viminfo temp files, like %s!
|
||||
// Now only six of them are used:
|
||||
// Now only seven of them are used:
|
||||
// E137: ShaDa file is not writeable (for pre-open checks)
|
||||
// E929: All %s.tmp.X files exist, cannot write ShaDa file!
|
||||
// E138: All %s.tmp.X files exist, cannot write ShaDa file!
|
||||
// RCERR (E576) for critical read errors.
|
||||
// RNERR (E136) for various errors when renaming.
|
||||
// RERR (E575) for various errors inside read ShaDa file.
|
||||
@@ -2693,19 +2693,36 @@ shada_write_exit:
|
||||
|
||||
#undef PACK_KEY
|
||||
|
||||
/// Deletes the oldest of the `{file}.tmp.a…z` files.
|
||||
/// Creates the first available `{fname}.tmp.a…z` file. If all exist (old failed writes), deletes
|
||||
/// the oldest and reuses its name.
|
||||
///
|
||||
/// @param[in,out] tempname Any of these names, set to the removed one.
|
||||
/// @param[out] sd_writer Opened file.
|
||||
/// @param[in] perm Permissions of the new file.
|
||||
///
|
||||
/// @return Whether a file was removed.
|
||||
static bool shada_del_oldest_tmp(char *const tempname)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
/// @return Name of the opened file, or NULL on error.
|
||||
static char *shada_open_tmp(const char *const fname, FileDescriptor *const sd_writer,
|
||||
const int perm)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
char *const tempname = modname(fname, ".tmp.a", false);
|
||||
if (tempname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
const int flags = kFileCreateOnly|kFileNoSymlink;
|
||||
char *const letter = tempname + strlen(tempname) - 1;
|
||||
char oldest = NUL;
|
||||
int64_t oldest_mtime = 0;
|
||||
for (int c = 'a'; c <= 'z'; c++) {
|
||||
*letter = (char)c;
|
||||
const int error = file_open(sd_writer, tempname, flags, perm);
|
||||
if (error == 0) {
|
||||
return tempname;
|
||||
} else if (error != UV_EEXIST && error != UV_ELOOP) {
|
||||
semsg(_(SERR "System error while opening temporary ShaDa file %s for writing: %s"),
|
||||
tempname, os_strerror(error));
|
||||
xfree(tempname);
|
||||
return NULL;
|
||||
}
|
||||
FileInfo info;
|
||||
if (os_fileinfo_link(tempname, &info)
|
||||
&& (oldest == NUL || info.stat.st_mtim.tv_sec < oldest_mtime)) {
|
||||
@@ -2713,11 +2730,15 @@ static bool shada_del_oldest_tmp(char *const tempname)
|
||||
oldest_mtime = info.stat.st_mtim.tv_sec;
|
||||
}
|
||||
}
|
||||
if (oldest == NUL) {
|
||||
return false;
|
||||
if (oldest != NUL) {
|
||||
*letter = oldest;
|
||||
if (os_remove(tempname) == 0 && file_open(sd_writer, tempname, flags, perm) == 0) {
|
||||
return tempname;
|
||||
}
|
||||
}
|
||||
*letter = oldest;
|
||||
return os_remove(tempname) == 0;
|
||||
semsg(_("E138: All %s.tmp.X files exist, cannot write ShaDa file!"), fname);
|
||||
xfree(tempname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Write ShaDa file to a given location
|
||||
@@ -2739,7 +2760,6 @@ int shada_write_file(const char *const file, bool nomerge)
|
||||
FileDescriptor sd_reader;
|
||||
bool did_open_writer = false;
|
||||
bool did_open_reader = false;
|
||||
bool did_remove_tmp = false;
|
||||
|
||||
if (!nomerge) {
|
||||
int error;
|
||||
@@ -2756,11 +2776,6 @@ int shada_write_file(const char *const file, bool nomerge)
|
||||
} else {
|
||||
did_open_reader = true;
|
||||
}
|
||||
tempname = modname(fname, ".tmp.a", false);
|
||||
if (tempname == NULL) {
|
||||
nomerge = true;
|
||||
goto shada_write_file_nomerge;
|
||||
}
|
||||
|
||||
// Save permissions from the original file, with modifications:
|
||||
int perm = (int)os_getperm(fname);
|
||||
@@ -2770,36 +2785,8 @@ int shada_write_file(const char *const file, bool nomerge)
|
||||
// 2: Make sure that user can always read and write the result.
|
||||
// 3: If somebody happened to delete the file after it was opened for
|
||||
// reading use u=rw permissions.
|
||||
shada_write_file_open: {}
|
||||
error = file_open(&sd_writer, tempname, kFileCreateOnly|kFileNoSymlink, perm);
|
||||
if (error) {
|
||||
if (error == UV_EEXIST || error == UV_ELOOP) {
|
||||
// File already exists, try another name
|
||||
char *const wp = tempname + strlen(tempname) - 1;
|
||||
if (*wp == 'z') {
|
||||
// Tried names from .tmp.a to .tmp.z, all failed. Reuse the oldest.
|
||||
if (!did_remove_tmp && shada_del_oldest_tmp(tempname)) {
|
||||
did_remove_tmp = true;
|
||||
goto shada_write_file_open;
|
||||
}
|
||||
semsg(_("E138: All %s.tmp.X files exist, cannot write ShaDa file!"),
|
||||
fname);
|
||||
xfree(fname);
|
||||
xfree(tempname);
|
||||
if (did_open_reader) {
|
||||
close_file(&sd_reader);
|
||||
}
|
||||
return FAIL;
|
||||
}
|
||||
(*wp)++;
|
||||
goto shada_write_file_open;
|
||||
} else {
|
||||
semsg(_(SERR "System error while opening temporary ShaDa file %s "
|
||||
"for writing: %s"), tempname, os_strerror(error));
|
||||
}
|
||||
} else {
|
||||
did_open_writer = true;
|
||||
}
|
||||
tempname = shada_open_tmp(fname, &sd_writer, perm);
|
||||
did_open_writer = tempname != NULL;
|
||||
}
|
||||
if (nomerge) {
|
||||
shada_write_file_nomerge: {}
|
||||
|
||||
Reference in new issue
Block a user