diff options
| author | Frank LENORMAND <lenormf@gmail.com> | 2017-04-19 18:47:07 +0300 |
|---|---|---|
| committer | Frank LENORMAND <lenormf@gmail.com> | 2017-04-20 17:13:42 +0300 |
| commit | 51ab59cd3624476832272112ae5814fecef12f69 (patch) | |
| tree | 9d54c258cd188a16ebabecdb5985fccf08262230 /src | |
| parent | 30e6387071b6aee2239d155822091dc834090b7f (diff) | |
src: Implement a `write!` command
This commit allows "forced" writes to a write-protected file, by
attempting to temporarily grant the current user write permissions on
it. After the buffer has been written, the previous permissions are
restored if the file existed, or set to 0644 otherwise.
Diffstat (limited to 'src')
| -rw-r--r-- | src/commands.cc | 16 | ||||
| -rw-r--r-- | src/file.cc | 22 | ||||
| -rw-r--r-- | src/file.hh | 2 |
3 files changed, 36 insertions, 4 deletions
diff --git a/src/commands.cc b/src/commands.cc index 6143179d..355f560d 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -309,6 +309,7 @@ const CommandDesc force_edit_cmd = { edit<true> }; +template<bool force = false> void write_buffer(const ParametersParser& parser, Context& context, const ShellContext&) { Buffer& buffer = context.buffer(); @@ -326,7 +327,7 @@ void write_buffer(const ParametersParser& parser, Context& context, const ShellC buffer.name() : parse_filename(parser[0]); context.hooks().run_hook("BufWritePre", filename, context); - write_buffer_to_file(buffer, filename); + write_buffer_to_file(buffer, filename, force); context.hooks().run_hook("BufWritePost", filename, context); } @@ -342,6 +343,18 @@ const CommandDesc write_cmd = { write_buffer, }; +const CommandDesc force_write_cmd = { + "write!", + "w!", + "write [filename]: write the current buffer to its file " + "or to [filename] if specified, even when the file is write protected", + single_optional_param, + CommandFlags::None, + CommandHelper{}, + filename_completer, + write_buffer<true>, +}; + void write_all_buffers(Context& context) { // Copy buffer list because hooks might be creating/deleting buffers @@ -2102,6 +2115,7 @@ void register_commands() register_command(edit_cmd); register_command(force_edit_cmd); register_command(write_cmd); + register_command(force_write_cmd); register_command(write_all_cmd); register_command(write_all_quit_cmd); register_command(kill_cmd); diff --git a/src/file.cc b/src/file.cc index bf592689..49fa00e5 100644 --- a/src/file.cc +++ b/src/file.cc @@ -278,9 +278,27 @@ void write_buffer_to_fd(Buffer& buffer, int fd) } } -void write_buffer_to_file(Buffer& buffer, StringView filename) +void write_buffer_to_file(Buffer& buffer, StringView filename, bool force) { - int fd = open(filename.zstr(), O_CREAT | O_WRONLY | O_TRUNC, 0644); + struct stat st; + auto zfilename = filename.zstr(); + + if (force) + { + if (::stat(zfilename, &st) == 0) + { + if (::chmod(zfilename, st.st_mode | S_IWUSR) < 0) + throw runtime_error("couldn't change file permissions"); + } + else + force = false; + } + auto restore_mode = on_scope_end([&]{ + if (force and ::chmod(zfilename, st.st_mode) < 0) + throw runtime_error("couldn't restore file permissions"); + }); + + int fd = open(zfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd == -1) throw file_access_error(filename, strerror(errno)); diff --git a/src/file.hh b/src/file.hh index 7cb5f88c..23fbe0a2 100644 --- a/src/file.hh +++ b/src/file.hh @@ -49,7 +49,7 @@ struct MappedFile struct stat st {}; }; -void write_buffer_to_file(Buffer& buffer, StringView filename); +void write_buffer_to_file(Buffer& buffer, StringView filename, bool force = false); void write_buffer_to_fd(Buffer& buffer, int fd); void write_buffer_to_backup_file(Buffer& buffer); |
