|
1 | 1 | " Manipulation of UNIX file permissions.
|
2 | 2 | "
|
3 | 3 | " Author: Peter Odding <[email protected]>
|
4 |
| -" Last Change: June 29, 2014 |
| 4 | +" Last Change: June 30, 2014 |
5 | 5 | " URL: http://peterodding.com/code/vim/misc/
|
6 | 6 | "
|
7 | 7 | " Vim's [writefile()][] function cannot set file permissions for newly created
|
|
26 | 26 | " [vim-easytags]: http://peterodding.com/code/vim/easytags/
|
27 | 27 | " [writefile()]: http://vimdoc.sourceforge.net/htmldoc/eval.html#writefile()
|
28 | 28 |
|
| 29 | +function! xolox#misc#perm#update(fname, contents) |
| 30 | + " Atomically update a file's contents while preserving the owner, group and |
| 31 | + " mode. The first argument is the pathname of the file to update (a string). |
| 32 | + " The second argument is the list of lines to be written to the file. Writes |
| 33 | + " the new contents to a temporary file and renames the temporary file into |
| 34 | + " place, thereby preventing readers from reading a partially written file. |
| 35 | + let starttime = xolox#misc#timer#start() |
| 36 | + let temporary_file = printf('%s.tmp', a:fname) |
| 37 | + call xolox#misc#msg#debug("vim-misc %s: Writing new contents of %s to temporary file %s ..", g:xolox#misc#version, a:fname, temporary_file) |
| 38 | + if writefile(a:contents, temporary_file) == 0 |
| 39 | + call xolox#misc#perm#set(temporary_file, xolox#misc#perm#get(a:fname)) |
| 40 | + call xolox#misc#msg#debug("vim-misc %s: Replacing %s with %s ..", g:xolox#misc#version, a:fname, temporary_file) |
| 41 | + if rename(temporary_file, a:fname) == 0 |
| 42 | + call xolox#misc#timer#stop("vim-misc %s: Successfully updated %s using atomic rename in %s.", g:xolox#misc#version, a:fname, starttime) |
| 43 | + return 1 |
| 44 | + endif |
| 45 | + endif |
| 46 | + if filereadable(temporary_file) |
| 47 | + call delete(temporary_file) |
| 48 | + endif |
| 49 | + return 0 |
| 50 | +endfunction |
| 51 | + |
29 | 52 | function! xolox#misc#perm#get(fname)
|
30 |
| - " Get the permissions of the pathname given as the first argument. Returns a |
31 |
| - " string which you can later pass to `xolox#misc#perm#set()`. |
| 53 | + " Get the owner, group and permissions of the pathname given as the first |
| 54 | + " argument. Returns an opaque value which you can later pass to |
| 55 | + " `xolox#misc#perm#set()`. |
32 | 56 | let pathname = xolox#misc#path#absolute(a:fname)
|
33 | 57 | if filereadable(pathname)
|
34 |
| - let command = printf('stat --format %%a %s', shellescape(pathname)) |
| 58 | + let command = printf('stat --format %s %s', '%U:%G:%a', shellescape(pathname)) |
35 | 59 | let result = xolox#misc#os#exec({'command': command})
|
36 | 60 | if result['exit_code'] == 0 && len(result['stdout']) >= 1
|
37 |
| - let permissions_string = '0' . xolox#misc#str#trim(result['stdout'][0]) |
38 |
| - if permissions_string =~ '^[0-7]\+$' |
39 |
| - call xolox#misc#msg#debug("vim-misc %s: Found permissions of %s: %s.", g:xolox#misc#version, pathname, permissions_string) |
40 |
| - return permissions_string |
| 61 | + let tokens = split(result['stdout'][0], ':') |
| 62 | + if len(tokens) == 3 |
| 63 | + let [owner, group, mode] = tokens |
| 64 | + let mode = '0' . mode |
| 65 | + call xolox#misc#msg#debug("vim-misc %s: File %s has owner %s, group %s, mode %s.", g:xolox#misc#version, pathname, owner, group, mode) |
| 66 | + return [owner, group, mode] |
41 | 67 | endif
|
42 | 68 | endif
|
43 | 69 | endif
|
44 |
| - return '' |
| 70 | + return [] |
45 | 71 | endfunction
|
46 | 72 |
|
47 | 73 | function! xolox#misc#perm#set(fname, perms)
|
48 | 74 | " Set the permissions (the second argument) of the pathname given as the
|
49 |
| - " first argument. Expects a permissions string created by |
| 75 | + " first argument. Expects a permissions value created by |
50 | 76 | " `xolox#misc#perm#get()`.
|
51 | 77 | if !empty(a:perms)
|
52 | 78 | let pathname = xolox#misc#path#absolute(a:fname)
|
53 |
| - let command = printf('chmod %s %s', shellescape(a:perms), shellescape(pathname)) |
54 |
| - let result = xolox#misc#os#exec({'command': command}) |
55 |
| - if result['exit_code'] == 0 |
56 |
| - call xolox#misc#msg#debug("vim-misc %s: Successfully set permissions of %s to %s.", g:xolox#misc#version, pathname, a:perms) |
| 79 | + let [owner, group, mode] = a:perms |
| 80 | + if s:run('chown %s:%s %s', owner, group, pathname) && s:run('chmod %s %s', mode, pathname) |
| 81 | + call xolox#misc#msg#debug("vim-misc %s: Successfully set %s owner to %s, group to %s and permissions to %s.", g:xolox#misc#version, pathname, owner, group, mode) |
57 | 82 | return 1
|
58 | 83 | endif
|
59 | 84 | endif
|
60 | 85 | return 0
|
61 | 86 | endfunction
|
| 87 | + |
| 88 | +function! s:run(command, ...) |
| 89 | + let args = map(copy(a:000), 'shellescape(v:val)') |
| 90 | + call insert(args, a:command, 0) |
| 91 | + let result = xolox#misc#os#exec({'command': call('printf', args)}) |
| 92 | + return result['exit_code'] == 0 |
| 93 | +endfunction |
0 commit comments