You can find information about the format from the source.
NB! Swapfiles are “binary” files with for example fixed offsets for various data. For example at byte number N in the file it expect to find specific data. In other words: one can look at, but not modify, unless one know what one are doing. I.e. one can change User but have to be aware of padding bytes etc.
It starts with a block named block0
which holds basic information, see below.
The rest of the file is copies of memory blocks in a tree structure. See description in top of source file.
The base information could easily be extracted. I.e:
$ ./vimswap .foo.swp
b0_id 6230
Version VIM 8.0
User goldilocks
Host HouseOfCorrection
File ~goldilocks/devel/foo
inode 2230823
PID 12066
Pagesize 4096
mtime 1572209814
mtime_h 2019-10-27 21:56:54
by something like:
(char_to_long
(modified), struct block0
and constants copied form source-code.)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef unsigned char char_u;
#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
#define B0_UNAME_SIZE 40
#define B0_HNAME_SIZE 40
struct block0 {
char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
* BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
char_u b0_version[10]; /* Vim version string */
char_u b0_page_size[4];/* number of bytes per page */
char_u b0_mtime[4]; /* last modification time of file */
char_u b0_ino[4]; /* inode of b0_fname */
char_u b0_pid[4]; /* process id of creator (or 0) */
char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
long b0_magic_long; /* check for byte order of long */
int b0_magic_int; /* check for byte order of int */
short b0_magic_short; /* check for byte order of short */
char_u b0_magic_char; /* check for last char */
};
static long char_to_long(char_u *s) {
return s[3] << 24 | s[2] << 16 | s[1] << 8 | s[0];
}
char *t_str(long ts, char res[32]) {
struct tm lt;
lt = *localtime(&ts);
strftime(res, 32, "%F %T", <);
return res;
}
void dump_b0(struct block0 b0) {
int wh = -8;
char res[32];
long mtime = char_to_long(b0.b0_mtime);
/* TAB's added to make for easy shell-parsing */
fprintf(stdout,
"%*s\t%02x%02x\n"
"%*s\t%s\n"
"%*s\t%s\n"
"%*s\t%s\n"
"%*s\t%s\n"
"%*s\t%ld\n"
"%*s\t%ld\n"
"%*s\t%ld\n"
"%*s\t%ld\n"
"%*s\t%s\n"
,
wh, "b0_id", b0.b0_id[0], b0.b0_id[1],
wh, "Version", b0.b0_version,
wh, "User", b0.b0_uname,
wh, "Host", b0.b0_hname,
wh, "File", b0.b0_fname,
wh, "inode", char_to_long(b0.b0_ino),
wh, "PID", char_to_long(b0.b0_pid),
wh, "Pagesize", char_to_long(b0.b0_page_size),
wh, "mtime", mtime,
wh, "mtime_h", t_str(mtime, res)
);
}
int read_block0(char *fn, struct block0 *b0) {
size_t sz_str = sizeof *b0;
size_t b_read;
FILE *fh;
fh = fopen(fn, "rb");
if (fh == NULL) {
fprintf(stderr, "Unable to open `%s'\n", fn);
return 1;
}
b_read = fread(b0, 1, sz_str, fh);
fclose(fh);
return b_read != sz_str;
}
int dump_block0(char *fn) {
struct block0 b0 = {0};
if (read_block0(fn, &b0) != 0)
return 1;
dump_b0(b0);
return 0;
}
int main(int argc, char *argv[])
{
int ec = 0;
if (argc != 2) {
fprintf(stderr, "Usage: %s SWAP_FILE\n", argv[0]);
ec = 1;
} else {
ec = dump_block0(argv[1]);
}
return ec;
}