shada: First write temporary file and only then check any permissions

It is not logical that on UNIX permissions can prevent even writing temporary
file, while on other OS it will first write temporary file and then fail during
rename.
This commit is contained in:
ZyX 2015-08-23 18:10:40 +03:00
parent 6de5900c50
commit e1dc9ed464
2 changed files with 33 additions and 46 deletions

View File

@ -1121,10 +1121,7 @@ include:
Such errors are listed at |shada-critical-contents-errors|.
- If writing to the temporary file failed: e.g. because of the insufficient
space left.
- If renaming file failed: e.g. because of insufficient permissions. On Unix
permissions are checked before trying to create even the temporary file, so
permission error can only happen if permissions were changed after starting
to edit the temporary file and before renaming it.
- If renaming file failed: e.g. because of insufficient permissions.
- If target ShaDa file has different from the Neovim instance's owners (user
and group) and changing them failed. Unix-specific, applies only when
Neovim was launched from root.

View File

@ -2903,11 +2903,6 @@ int shada_write_file(const char *const file, bool nomerge)
.error = NULL,
};
ShaDaReadDef sd_reader;
#ifdef UNIX
bool do_fchown = false;
uv_uid_t old_uid = (uv_uid_t) -1;
uv_gid_t old_gid = (uv_gid_t) -1;
#endif
intptr_t fd;
@ -2916,31 +2911,6 @@ int shada_write_file(const char *const file, bool nomerge)
nomerge = true;
goto shada_write_file_nomerge;
}
#ifdef UNIX
// For Unix we check the owner of the file. It's not very nice to
// overwrite a users viminfo file after a "su root", with a
// viminfo file that the user can't read.
FileInfo old_info;
if (os_fileinfo((char *)fname, &old_info)) {
if (getuid() == ROOT_UID) {
if (old_info.stat.st_uid != ROOT_UID
|| old_info.stat.st_gid != getgid()) {
do_fchown = true;
old_uid = (uv_uid_t) old_info.stat.st_uid;
old_gid = (uv_gid_t) old_info.stat.st_gid;
}
} else if (!(old_info.stat.st_uid == getuid()
? (old_info.stat.st_mode & 0200)
: (old_info.stat.st_gid == getgid()
? (old_info.stat.st_mode & 0020)
: (old_info.stat.st_mode & 0002)))) {
EMSG2(_("E137: ShaDa file is not writable: %s"), fname);
sd_reader.close(&sd_reader);
xfree(fname);
return FAIL;
}
}
#endif
tempname = modname(fname, ".tmp.a", false);
if (tempname == NULL) {
nomerge = true;
@ -3024,27 +2994,47 @@ shada_write_file_nomerge: {}
const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge
? NULL
: &sd_reader));
#ifdef UNIX
if (!do_fchown) {
#endif
sd_writer.close(&sd_writer);
#ifdef UNIX
}
#ifndef UNIX
sd_writer.close(&sd_writer);
#endif
if (!nomerge) {
sd_reader.close(&sd_reader);
bool did_remove = false;
if (sw_ret == kSDWriteSuccessfull) {
#ifdef UNIX
if (do_fchown) {
const int fchown_ret = os_fchown((int) fd, old_uid, old_gid);
sd_writer.close(&sd_writer);
if (fchown_ret != 0) {
EMSG3(_(RNERR "Failed setting uid and gid for file %s: %s"),
tempname, os_strerror(fchown_ret));
bool closed = false;
// For Unix we check the owner of the file. It's not very nice to
// overwrite a users viminfo file after a "su root", with a
// viminfo file that the user can't read.
FileInfo old_info;
if (os_fileinfo((char *)fname, &old_info)) {
if (getuid() == ROOT_UID) {
if (old_info.stat.st_uid != ROOT_UID
|| old_info.stat.st_gid != getgid()) {
const uv_uid_t old_uid = (uv_uid_t) old_info.stat.st_uid;
const uv_gid_t old_gid = (uv_gid_t) old_info.stat.st_gid;
const int fchown_ret = os_fchown((int) fd, old_uid, old_gid);
sd_writer.close(&sd_writer);
if (fchown_ret != 0) {
EMSG3(_(RNERR "Failed setting uid and gid for file %s: %s"),
tempname, os_strerror(fchown_ret));
goto shada_write_file_did_not_remove;
}
closed = true;
}
} else if (!(old_info.stat.st_uid == getuid()
? (old_info.stat.st_mode & 0200)
: (old_info.stat.st_gid == getgid()
? (old_info.stat.st_mode & 0020)
: (old_info.stat.st_mode & 0002)))) {
EMSG2(_("E137: ShaDa file is not writable: %s"), fname);
sd_writer.close(&sd_writer);
goto shada_write_file_did_not_remove;
}
}
if (!closed) {
sd_writer.close(&sd_writer);
}
#endif
if (vim_rename(tempname, fname) == -1) {
EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"),