summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-08-21 20:28:54 +0200
committerBram Moolenaar <Bram@vim.org>2018-08-21 20:28:54 +0200
commit00f123a56585363cd13f062fd3bb123efcfaa664 (patch)
tree7c8fb2556c2b395cb4d6035a1b0299f05073e409
parent8e82c057ffb86cec3210ad8a22ad3f21d52e0953 (diff)
patch 8.1.0313: information about a swap file is unavailablev8.1.0313
Problem: Information about a swap file is unavailable. Solution: Add swapinfo(). (Enzo Ferber)
-rw-r--r--runtime/doc/eval.txt17
-rw-r--r--src/evalfunc.c12
-rw-r--r--src/memline.c43
-rw-r--r--src/proto/memline.pro3
-rw-r--r--src/testdir/test_swap.vim34
-rw-r--r--src/version.c2
6 files changed, 110 insertions, 1 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 821cbbca9b..a9d0dc0151 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2409,6 +2409,7 @@ submatch({nr} [, {list}]) String or List
specific match in ":s" or substitute()
substitute({expr}, {pat}, {sub}, {flags})
String all {pat} in {expr} replaced with {sub}
+swapinfo({fname}) Dict information about swap file {fname}
synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col}
synIDattr({synID}, {what} [, {mode}])
String attribute {what} of syntax ID {synID}
@@ -8001,6 +8002,22 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
|submatch()| returns. Example: >
:echo substitute(s, '%\(\x\x\)', {m -> '0x' . m[1]}, 'g')
+swapinfo({fname}) swapinfo()
+ The result is a dictionary, which holds information about the
+ swapfile {fname}. The available fields are:
+ version VIM version
+ user user name
+ host host name
+ fname original file name
+ pid PID of the VIM process that created the swap
+ file
+ mtime last modification time in seconds
+ inode Optional: INODE number of the file
+ In case of failure an "error" item is added with the reason:
+ Cannot open file: file not found or in accessible
+ Cannot read file: cannot read first block
+ magic number mismatch: info in first block is invalid
+
synID({lnum}, {col}, {trans}) *synID()*
The result is a Number, which is the syntax ID at the position
{lnum} and {col} in the current window.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 5e7c013979..3c64212061 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -398,6 +398,7 @@ static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
static void f_strwidth(typval_T *argvars, typval_T *rettv);
static void f_submatch(typval_T *argvars, typval_T *rettv);
static void f_substitute(typval_T *argvars, typval_T *rettv);
+static void f_swapinfo(typval_T *argvars, typval_T *rettv);
static void f_synID(typval_T *argvars, typval_T *rettv);
static void f_synIDattr(typval_T *argvars, typval_T *rettv);
static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
@@ -859,6 +860,7 @@ static struct fst
{"strwidth", 1, 1, f_strwidth},
{"submatch", 1, 2, f_submatch},
{"substitute", 4, 4, f_substitute},
+ {"swapinfo", 1, 1, f_swapinfo},
{"synID", 3, 3, f_synID},
{"synIDattr", 2, 3, f_synIDattr},
{"synIDtrans", 1, 1, f_synIDtrans},
@@ -12314,6 +12316,16 @@ f_substitute(typval_T *argvars, typval_T *rettv)
}
/*
+ * "swapinfo(swap_filename)" function
+ */
+ static void
+f_swapinfo(typval_T *argvars, typval_T *rettv)
+{
+ if (rettv_dict_alloc(rettv) == OK)
+ get_b0_dict(get_tv_string(argvars), rettv->vval.v_dict);
+}
+
+/*
* "synID(lnum, col, trans)" function
*/
static void
diff --git a/src/memline.c b/src/memline.c
index fbdd8a372c..660e89c111 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -2042,6 +2042,49 @@ static int process_still_running;
#endif
/*
+ * Return information found in swapfile "fname" in dictionary "d".
+ * This is used by the swapinfo() function.
+ */
+ void
+get_b0_dict(char_u *fname, dict_T *d)
+{
+ int fd;
+ struct block0 b0;
+
+ if ((fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0)) >= 0)
+ {
+ if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
+ {
+ if (b0_magic_wrong(&b0))
+ {
+ dict_add_string(d, "error",
+ vim_strsave((char_u *)"magic number mismatch"));
+ }
+ else
+ {
+ /* we have swap information */
+ dict_add_string(d, "version", vim_strsave(b0.b0_version));
+ dict_add_string(d, "user", vim_strsave(b0.b0_uname));
+ dict_add_string(d, "host", vim_strsave(b0.b0_hname));
+ dict_add_string(d, "fname", vim_strsave(b0.b0_fname));
+
+ dict_add_number(d, "pid", char_to_long(b0.b0_pid));
+ dict_add_number(d, "mtime", char_to_long(b0.b0_mtime));
+#ifdef CHECK_INODE
+ dict_add_number(d, "inode", char_to_long(b0.b0_ino));
+#endif
+ }
+ }
+ else
+ dict_add_string(d, "error",
+ vim_strsave((char_u *)"Cannot read file"));
+ close(fd);
+ }
+ else
+ dict_add_string(d, "error", vim_strsave((char_u *)"Cannot open file"));
+}
+
+/*
* Give information about an existing swap file.
* Returns timestamp (0 when unknown).
*/
diff --git a/src/proto/memline.pro b/src/proto/memline.pro
index 727b24cc30..d18ede37b6 100644
--- a/src/proto/memline.pro
+++ b/src/proto/memline.pro
@@ -11,6 +11,8 @@ void ml_close_notmod(void);
void ml_timestamp(buf_T *buf);
void ml_recover(void);
int recover_names(char_u *fname, int list, int nr, char_u **fname_out);
+char_u *make_percent_swname(char_u *dir, char_u *name);
+void get_b0_dict(char_u *fname, dict_T *d);
void ml_sync_all(int check_file, int check_char);
void ml_preserve(buf_T *buf, int message);
char_u *ml_get(linenr_T lnum);
@@ -34,5 +36,4 @@ char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned siz
void ml_decrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size);
long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp);
void goto_byte(long cnt);
-char_u *make_percent_swname (char_u *dir, char_u *name);
/* vim: set ft=c : */
diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim
index da5da2dbbd..b0e2ec9aa5 100644
--- a/src/testdir/test_swap.vim
+++ b/src/testdir/test_swap.vim
@@ -97,3 +97,37 @@ func Test_missing_dir()
set directory&
call delete('Xswapdir', 'rf')
endfunc
+
+func Test_swapinfo()
+ new Xswapinfo
+ call setline(1, ['one', 'two', 'three'])
+ w
+ let fname = trim(execute('swapname'))
+ call assert_match('Xswapinfo', fname)
+ let info = swapinfo(fname)
+ call assert_match('8\.', info.version)
+ call assert_match('\w', info.user)
+ call assert_equal(hostname(), info.host)
+ call assert_match('Xswapinfo', info.fname)
+ call assert_equal(getpid(), info.pid)
+ call assert_match('^\d*$', info.mtime)
+ if has_key(info, 'inode')
+ call assert_match('\d', info.inode)
+ endif
+ bwipe!
+ call delete(fname)
+ call delete('Xswapinfo')
+
+ let info = swapinfo('doesnotexist')
+ call assert_equal('Cannot open file', info.error)
+
+ call writefile(['burp'], 'Xnotaswapfile')
+ let info = swapinfo('Xnotaswapfile')
+ call assert_equal('Cannot read file', info.error)
+ call delete('Xnotaswapfile')
+
+ call writefile([repeat('x', 10000)], 'Xnotaswapfile')
+ let info = swapinfo('Xnotaswapfile')
+ call assert_equal('magic number mismatch', info.error)
+ call delete('Xnotaswapfile')
+endfunc
diff --git a/src/version.c b/src/version.c
index d752d04ff4..d0052fa331 100644
--- a/src/version.c
+++ b/src/version.c
@@ -795,6 +795,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 313,
+/**/
312,
/**/
311,