mirror of
https://github.com/vim/vim.git
synced 2025-09-26 04:04:07 -04:00
Crypt the swapfile.
This commit is contained in:
599
src/memline.c
599
src/memline.c
@@ -65,10 +65,12 @@ typedef struct pointer_block PTR_BL; /* contents of a pointer block */
|
||||
typedef struct data_block DATA_BL; /* contents of a data block */
|
||||
typedef struct pointer_entry PTR_EN; /* block/line-count pair */
|
||||
|
||||
#define DATA_ID (('d' << 8) + 'a') /* data block id */
|
||||
#define PTR_ID (('p' << 8) + 't') /* pointer block id */
|
||||
#define BLOCK0_ID0 'b' /* block 0 id 0 */
|
||||
#define BLOCK0_ID1 '0' /* block 0 id 1 */
|
||||
#define DATA_ID (('d' << 8) + 'a') /* data block id */
|
||||
#define PTR_ID (('p' << 8) + 't') /* pointer block id */
|
||||
#define BLOCK0_ID0 'b' /* block 0 id 0 */
|
||||
#define BLOCK0_ID1 '0' /* block 0 id 1 */
|
||||
#define BLOCK0_ID1_C0 'c' /* block 0 id 1 'cm' 0 */
|
||||
#define BLOCK0_ID1_C1 'C' /* block 0 id 1 'cm' 1 */
|
||||
|
||||
/*
|
||||
* pointer to a block, used in a pointer block
|
||||
@@ -128,7 +130,8 @@ struct data_block
|
||||
#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */
|
||||
|
||||
#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
|
||||
#define B0_FNAME_SIZE 898
|
||||
#define B0_FNAME_SIZE_NOCRYPT 898 /* 2 bytes used for other things */
|
||||
#define B0_FNAME_SIZE_CRYPT 890 /* 10 bytes used for other things */
|
||||
#define B0_UNAME_SIZE 40
|
||||
#define B0_HNAME_SIZE 40
|
||||
/*
|
||||
@@ -155,7 +158,8 @@ struct data_block
|
||||
*/
|
||||
struct block0
|
||||
{
|
||||
char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
|
||||
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 */
|
||||
@@ -177,12 +181,18 @@ struct block0
|
||||
* when there is room, for very long file names it's omitted.
|
||||
*/
|
||||
#define B0_DIRTY 0x55
|
||||
#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG-1]
|
||||
#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG - 1]
|
||||
|
||||
/*
|
||||
* The b0_flags field is new in Vim 7.0.
|
||||
*/
|
||||
#define b0_flags b0_fname[B0_FNAME_SIZE_ORG-2]
|
||||
#define b0_flags b0_fname[B0_FNAME_SIZE_ORG - 2]
|
||||
|
||||
/*
|
||||
* Crypt seed goes here, 8 bytes. New in Vim 7.3.
|
||||
* Without encryption these bytes may be used for 'fenc'.
|
||||
*/
|
||||
#define b0_seed b0_fname[B0_FNAME_SIZE_ORG - 2 - MF_SEED_LEN]
|
||||
|
||||
/* The lowest two bits contain the fileformat. Zero means it's not set
|
||||
* (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or
|
||||
@@ -216,7 +226,18 @@ static linenr_T lowest_marked = 0;
|
||||
#define ML_FLUSH 0x02 /* flush locked block */
|
||||
#define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */
|
||||
|
||||
static void ml_upd_block0 __ARGS((buf_T *buf, int set_fname));
|
||||
/* argument for ml_upd_block0() */
|
||||
typedef enum {
|
||||
UB_FNAME = 0 /* update timestamp and filename */
|
||||
, UB_SAME_DIR /* update the B0_SAME_DIR flag */
|
||||
, UB_CRYPT /* update crypt key */
|
||||
} upd_block0_T;
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
static void ml_set_b0_crypt __ARGS((buf_T *buf, ZERO_BL *b0p));
|
||||
#endif
|
||||
static int ml_check_b0_id __ARGS((ZERO_BL *b0p));
|
||||
static void ml_upd_block0 __ARGS((buf_T *buf, upd_block0_T what));
|
||||
static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));
|
||||
static void set_b0_dir_flag __ARGS((ZERO_BL *b0p, buf_T *buf));
|
||||
#ifdef FEAT_MBYTE
|
||||
@@ -242,6 +263,9 @@ static long char_to_long __ARGS((char_u *));
|
||||
#if defined(UNIX) || defined(WIN3264)
|
||||
static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
static void ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
|
||||
#endif
|
||||
#ifdef FEAT_BYTEOFF
|
||||
static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
|
||||
#endif
|
||||
@@ -264,7 +288,7 @@ ml_open(buf)
|
||||
/*
|
||||
* init fields in memline struct
|
||||
*/
|
||||
buf->b_ml.ml_stack_size = 0; /* no stack yet */
|
||||
buf->b_ml.ml_stack_size = 0; /* no stack yet */
|
||||
buf->b_ml.ml_stack = NULL; /* no stack yet */
|
||||
buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
|
||||
buf->b_ml.ml_locked = NULL; /* no cached block */
|
||||
@@ -289,6 +313,9 @@ ml_open(buf)
|
||||
goto error;
|
||||
|
||||
buf->b_ml.ml_mfp = mfp;
|
||||
#ifdef FEAT_CRYPT
|
||||
mfp->mf_buffer = buf;
|
||||
#endif
|
||||
buf->b_ml.ml_flags = ML_EMPTY;
|
||||
buf->b_ml.ml_line_count = 1;
|
||||
#ifdef FEAT_LINEBREAK
|
||||
@@ -336,12 +363,16 @@ ml_open(buf)
|
||||
mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
|
||||
b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
|
||||
long_to_char(mch_get_pid(), b0p->b0_pid);
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key != NUL)
|
||||
ml_set_b0_crypt(buf, b0p);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Always sync block number 0 to disk, so we can check the file name in
|
||||
* the swap file in findswapname(). Don't do this for help files though
|
||||
* and spell buffer though.
|
||||
* the swap file in findswapname(). Don't do this for a help files or
|
||||
* a spell buffer though.
|
||||
* Only works when there's a swapfile, otherwise it's done when the file
|
||||
* is created.
|
||||
*/
|
||||
@@ -397,6 +428,165 @@ error:
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
#if defined(FEAT_CRYPT) || defined(PROTO)
|
||||
/*
|
||||
* Prepare encryption for "buf" with block 0 "b0p".
|
||||
*/
|
||||
static void
|
||||
ml_set_b0_crypt(buf, b0p)
|
||||
buf_T *buf;
|
||||
ZERO_BL *b0p;
|
||||
{
|
||||
if (*buf->b_p_key == NUL)
|
||||
b0p->b0_id[1] = BLOCK0_ID1;
|
||||
else
|
||||
{
|
||||
if (buf->b_p_cm == 0)
|
||||
b0p->b0_id[1] = BLOCK0_ID1_C0;
|
||||
else
|
||||
{
|
||||
b0p->b0_id[1] = BLOCK0_ID1_C1;
|
||||
/* Generate a seed and store it in block 0 and in the memfile. */
|
||||
sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
|
||||
mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after the crypt key or 'cryptmethod' was changed for "buf".
|
||||
* Will apply this to the swapfile.
|
||||
* "old_key" is the previous key. It is equal to buf->b_p_key when
|
||||
* 'cryptmethod' is changed.
|
||||
* "old_cm" is the previous 'cryptmethod'. It is equal to buf->b_p_cm when
|
||||
* 'key' is changed.
|
||||
*/
|
||||
void
|
||||
ml_set_crypt_key(buf, old_key, old_cm)
|
||||
buf_T *buf;
|
||||
char_u *old_key;
|
||||
int old_cm;
|
||||
{
|
||||
memfile_T *mfp = buf->b_ml.ml_mfp;
|
||||
bhdr_T *hp;
|
||||
int page_count;
|
||||
int idx;
|
||||
long error;
|
||||
infoptr_T *ip;
|
||||
PTR_BL *pp;
|
||||
DATA_BL *dp;
|
||||
blocknr_T bnum;
|
||||
int top;
|
||||
|
||||
if (mfp == NULL || mfp->mf_fd < 0)
|
||||
return; /* no memfile yet, nothing to do */
|
||||
|
||||
/* Set the key, method and seed to be used for reading, these must be the
|
||||
* old values. */
|
||||
mfp->mf_old_key = old_key;
|
||||
mfp->mf_old_cm = old_cm;
|
||||
if (old_cm > 0)
|
||||
mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
|
||||
|
||||
/* Update block 0 with the crypt flag and may set a new seed. */
|
||||
ml_upd_block0(buf, UB_CRYPT);
|
||||
|
||||
if (mfp->mf_infile_count > 2)
|
||||
{
|
||||
/*
|
||||
* Need to read back all data blocks from disk, decrypt them with the
|
||||
* old key/method and mark them to be written. The algorithm is
|
||||
* similar to what happens in ml_recover(), but we skip negative block
|
||||
* numbers.
|
||||
*/
|
||||
ml_flush_line(buf); /* flush buffered line */
|
||||
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
|
||||
|
||||
hp = NULL;
|
||||
bnum = 1; /* start with block 1 */
|
||||
page_count = 1; /* which is 1 page */
|
||||
idx = 0; /* start with first index in block 1 */
|
||||
error = 0;
|
||||
buf->b_ml.ml_stack_top = 0;
|
||||
buf->b_ml.ml_stack = NULL;
|
||||
buf->b_ml.ml_stack_size = 0; /* no stack yet */
|
||||
|
||||
for ( ; !got_int; line_breakcheck())
|
||||
{
|
||||
if (hp != NULL)
|
||||
mf_put(mfp, hp, FALSE, FALSE); /* release previous block */
|
||||
|
||||
/* get the block (pointer or data) */
|
||||
if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
|
||||
{
|
||||
if (bnum == 1)
|
||||
break;
|
||||
++error;
|
||||
}
|
||||
else
|
||||
{
|
||||
pp = (PTR_BL *)(hp->bh_data);
|
||||
if (pp->pb_id == PTR_ID) /* it is a pointer block */
|
||||
{
|
||||
if (pp->pb_count == 0)
|
||||
{
|
||||
/* empty block? */
|
||||
++error;
|
||||
}
|
||||
else if (idx < (int)pp->pb_count) /* go a block deeper */
|
||||
{
|
||||
if (pp->pb_pointer[idx].pe_bnum < 0)
|
||||
{
|
||||
/* Skip data block with negative block number. */
|
||||
++idx; /* get same block again for next index */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* going one block deeper in the tree, new entry in
|
||||
* stack */
|
||||
if ((top = ml_add_stack(buf)) < 0)
|
||||
{
|
||||
++error;
|
||||
break; /* out of memory */
|
||||
}
|
||||
ip = &(buf->b_ml.ml_stack[top]);
|
||||
ip->ip_bnum = bnum;
|
||||
ip->ip_index = idx;
|
||||
|
||||
bnum = pp->pb_pointer[idx].pe_bnum;
|
||||
page_count = pp->pb_pointer[idx].pe_page_count;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else /* not a pointer block */
|
||||
{
|
||||
dp = (DATA_BL *)(hp->bh_data);
|
||||
if (dp->db_id != DATA_ID) /* block id wrong */
|
||||
++error;
|
||||
else
|
||||
{
|
||||
/* It is a data block, need to write it back to disk. */
|
||||
mf_put(mfp, hp, TRUE, FALSE);
|
||||
hp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buf->b_ml.ml_stack_top == 0) /* finished */
|
||||
break;
|
||||
|
||||
/* go one block up in the tree */
|
||||
ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
|
||||
bnum = ip->ip_bnum;
|
||||
idx = ip->ip_index + 1; /* go to next index */
|
||||
page_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
mfp->mf_old_key = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ml_setname() is called when the file name of "buf" has been changed.
|
||||
* It may rename the swap file.
|
||||
@@ -475,7 +665,7 @@ ml_setname(buf)
|
||||
#else
|
||||
mf_set_ffname(mfp);
|
||||
#endif
|
||||
ml_upd_block0(buf, FALSE);
|
||||
ml_upd_block0(buf, UB_SAME_DIR);
|
||||
break;
|
||||
}
|
||||
vim_free(fname); /* this fname didn't work, try another */
|
||||
@@ -569,7 +759,7 @@ ml_open_file(buf)
|
||||
*/
|
||||
mf_fullname(mfp);
|
||||
#endif
|
||||
ml_upd_block0(buf, FALSE);
|
||||
ml_upd_block0(buf, UB_SAME_DIR);
|
||||
|
||||
/* Flush block zero, so others can read it */
|
||||
if (mf_sync(mfp, MFS_ZERO) == OK)
|
||||
@@ -680,16 +870,32 @@ ml_close_notmod()
|
||||
ml_timestamp(buf)
|
||||
buf_T *buf;
|
||||
{
|
||||
ml_upd_block0(buf, TRUE);
|
||||
ml_upd_block0(buf, UB_FNAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return FAIL when the ID of "b0p" is wrong.
|
||||
*/
|
||||
static int
|
||||
ml_check_b0_id(b0p)
|
||||
ZERO_BL *b0p;
|
||||
{
|
||||
if (b0p->b0_id[0] != BLOCK0_ID0
|
||||
|| (b0p->b0_id[1] != BLOCK0_ID1
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C0
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C1)
|
||||
)
|
||||
return FAIL;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the timestamp or the B0_SAME_DIR flag of the .swp file.
|
||||
*/
|
||||
static void
|
||||
ml_upd_block0(buf, set_fname)
|
||||
ml_upd_block0(buf, what)
|
||||
buf_T *buf;
|
||||
int set_fname;
|
||||
upd_block0_T what;
|
||||
{
|
||||
memfile_T *mfp;
|
||||
bhdr_T *hp;
|
||||
@@ -699,13 +905,17 @@ ml_upd_block0(buf, set_fname)
|
||||
if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
|
||||
return;
|
||||
b0p = (ZERO_BL *)(hp->bh_data);
|
||||
if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
|
||||
if (ml_check_b0_id(b0p) == FAIL)
|
||||
EMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
|
||||
else
|
||||
{
|
||||
if (set_fname)
|
||||
if (what == UB_FNAME)
|
||||
set_b0_fname(b0p, buf);
|
||||
else
|
||||
#ifdef FEAT_CRYPT
|
||||
else if (what == UB_CRYPT)
|
||||
ml_set_b0_crypt(buf, b0p);
|
||||
#endif
|
||||
else /* what == UB_SAME_DIR */
|
||||
set_b0_dir_flag(b0p, buf);
|
||||
}
|
||||
mf_put(mfp, hp, TRUE, FALSE);
|
||||
@@ -731,7 +941,7 @@ set_b0_fname(b0p, buf)
|
||||
/* Systems that cannot translate "~user" back into a path: copy the
|
||||
* file name unmodified. Do use slashes instead of backslashes for
|
||||
* portability. */
|
||||
vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE - 1);
|
||||
vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
|
||||
# ifdef BACKSLASH_IN_FILENAME
|
||||
forward_slash(b0p->b0_fname);
|
||||
# endif
|
||||
@@ -746,14 +956,16 @@ set_b0_fname(b0p, buf)
|
||||
* First replace home dir path with "~/" with home_replace().
|
||||
* Then insert the user name to get "~user/".
|
||||
*/
|
||||
home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE, TRUE);
|
||||
home_replace(NULL, buf->b_ffname, b0p->b0_fname,
|
||||
B0_FNAME_SIZE_CRYPT, TRUE);
|
||||
if (b0p->b0_fname[0] == '~')
|
||||
{
|
||||
flen = STRLEN(b0p->b0_fname);
|
||||
/* If there is no user name or it is too long, don't use "~/" */
|
||||
if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
|
||||
|| (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
|
||||
vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE - 1);
|
||||
|| (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
|
||||
vim_strncpy(b0p->b0_fname, buf->b_ffname,
|
||||
B0_FNAME_SIZE_CRYPT - 1);
|
||||
else
|
||||
{
|
||||
mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
|
||||
@@ -816,15 +1028,24 @@ add_b0_fenc(b0p, buf)
|
||||
buf_T *buf;
|
||||
{
|
||||
int n;
|
||||
int size = B0_FNAME_SIZE_NOCRYPT;
|
||||
|
||||
# ifdef FEAT_CRYPT
|
||||
/* Without encryption use the same offset as in Vim 7.2 to be compatible.
|
||||
* With encryption it's OK to move elsewhere, the swap file is not
|
||||
* compatible anyway. */
|
||||
if (*buf->b_p_key != NUL)
|
||||
size = B0_FNAME_SIZE_CRYPT;
|
||||
# endif
|
||||
|
||||
n = (int)STRLEN(buf->b_p_fenc);
|
||||
if (STRLEN(b0p->b0_fname) + n + 1 > B0_FNAME_SIZE)
|
||||
if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
|
||||
b0p->b0_flags &= ~B0_HAS_FENC;
|
||||
else
|
||||
{
|
||||
mch_memmove((char *)b0p->b0_fname + B0_FNAME_SIZE - n,
|
||||
mch_memmove((char *)b0p->b0_fname + size - n,
|
||||
(char *)buf->b_p_fenc, (size_t)n);
|
||||
*(b0p->b0_fname + B0_FNAME_SIZE - n - 1) = NUL;
|
||||
*(b0p->b0_fname + size - n - 1) = NUL;
|
||||
b0p->b0_flags |= B0_HAS_FENC;
|
||||
}
|
||||
}
|
||||
@@ -832,7 +1053,7 @@ add_b0_fenc(b0p, buf)
|
||||
|
||||
|
||||
/*
|
||||
* try to recover curbuf from the .swp file
|
||||
* Try to recover curbuf from the .swp file.
|
||||
*/
|
||||
void
|
||||
ml_recover()
|
||||
@@ -840,10 +1061,14 @@ ml_recover()
|
||||
buf_T *buf = NULL;
|
||||
memfile_T *mfp = NULL;
|
||||
char_u *fname;
|
||||
char_u *fname_used = NULL;
|
||||
bhdr_T *hp = NULL;
|
||||
ZERO_BL *b0p;
|
||||
int b0_ff;
|
||||
char_u *b0_fenc = NULL;
|
||||
#ifdef FEAT_CRYPT
|
||||
int b0_cm = -1;
|
||||
#endif
|
||||
PTR_BL *pp;
|
||||
DATA_BL *dp;
|
||||
infoptr_T *ip;
|
||||
@@ -892,14 +1117,14 @@ ml_recover()
|
||||
&& ASCII_ISALPHA(fname[len - 1]))
|
||||
{
|
||||
directly = TRUE;
|
||||
fname = vim_strsave(fname); /* make a copy for mf_open() */
|
||||
fname_used = vim_strsave(fname); /* make a copy for mf_open() */
|
||||
}
|
||||
else
|
||||
{
|
||||
directly = FALSE;
|
||||
|
||||
/* count the number of matching swap files */
|
||||
len = recover_names(&fname, FALSE, 0);
|
||||
len = recover_names(fname, FALSE, 0, NULL);
|
||||
if (len == 0) /* no swap files found */
|
||||
{
|
||||
EMSG2(_("E305: No swap file found for %s"), fname);
|
||||
@@ -910,7 +1135,7 @@ ml_recover()
|
||||
else /* several swap files found, choose */
|
||||
{
|
||||
/* list the names of the swap files */
|
||||
(void)recover_names(&fname, TRUE, 0);
|
||||
(void)recover_names(fname, TRUE, 0, NULL);
|
||||
msg_putchar('\n');
|
||||
MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
|
||||
i = get_number(FALSE, NULL);
|
||||
@@ -918,28 +1143,26 @@ ml_recover()
|
||||
goto theend;
|
||||
}
|
||||
/* get the swap file name that will be used */
|
||||
(void)recover_names(&fname, FALSE, i);
|
||||
(void)recover_names(fname, FALSE, i, &fname_used);
|
||||
}
|
||||
if (fname == NULL)
|
||||
if (fname_used == NULL)
|
||||
goto theend; /* out of memory */
|
||||
|
||||
/* When called from main() still need to initialize storage structure */
|
||||
if (called_from_main && ml_open(curbuf) == FAIL)
|
||||
getout(1);
|
||||
|
||||
/*
|
||||
* allocate a buffer structure (only the memline in it is really used)
|
||||
*/
|
||||
/*
|
||||
* Allocate a buffer structure for the swap file that is used for recovery.
|
||||
* Only the memline in it is really used.
|
||||
*/
|
||||
buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
|
||||
if (buf == NULL)
|
||||
{
|
||||
vim_free(fname);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
/*
|
||||
* init fields in memline struct
|
||||
*/
|
||||
/*
|
||||
* init fields in memline struct
|
||||
*/
|
||||
buf->b_ml.ml_stack_size = 0; /* no stack yet */
|
||||
buf->b_ml.ml_stack = NULL; /* no stack yet */
|
||||
buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
|
||||
@@ -947,23 +1170,24 @@ ml_recover()
|
||||
buf->b_ml.ml_locked = NULL; /* no locked block */
|
||||
buf->b_ml.ml_flags = 0;
|
||||
|
||||
/*
|
||||
* open the memfile from the old swap file
|
||||
*/
|
||||
p = vim_strsave(fname); /* save fname for the message
|
||||
(mf_open() may free fname) */
|
||||
mfp = mf_open(fname, O_RDONLY); /* consumes fname! */
|
||||
/*
|
||||
* open the memfile from the old swap file
|
||||
*/
|
||||
p = vim_strsave(fname_used); /* save "fname_used" for the message:
|
||||
mf_open() will consume "fname_used"! */
|
||||
mfp = mf_open(fname_used, O_RDONLY);
|
||||
fname_used = p;
|
||||
if (mfp == NULL || mfp->mf_fd < 0)
|
||||
{
|
||||
if (p != NULL)
|
||||
{
|
||||
EMSG2(_("E306: Cannot open %s"), p);
|
||||
vim_free(p);
|
||||
}
|
||||
if (fname_used != NULL)
|
||||
EMSG2(_("E306: Cannot open %s"), fname_used);
|
||||
goto theend;
|
||||
}
|
||||
vim_free(p);
|
||||
buf->b_ml.ml_mfp = mfp;
|
||||
#ifdef FEAT_CRYPT
|
||||
mfp->mf_buffer = buf;
|
||||
buf->b_p_key = empty_option;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The page size set in mf_open() might be different from the page size
|
||||
@@ -973,16 +1197,15 @@ ml_recover()
|
||||
*/
|
||||
mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* try to read block 0
|
||||
*/
|
||||
/*
|
||||
* try to read block 0
|
||||
*/
|
||||
if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
|
||||
{
|
||||
msg_start();
|
||||
MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
|
||||
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
|
||||
MSG_PUTS_ATTR(
|
||||
_("\nMaybe no changes were made or Vim did not update the swap file."),
|
||||
MSG_PUTS_ATTR(_("\nMaybe no changes were made or Vim did not update the swap file."),
|
||||
attr | MSG_HIST);
|
||||
msg_end();
|
||||
goto theend;
|
||||
@@ -998,7 +1221,7 @@ ml_recover()
|
||||
msg_end();
|
||||
goto theend;
|
||||
}
|
||||
if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
|
||||
if (ml_check_b0_id(b0p) == FAIL)
|
||||
{
|
||||
EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
|
||||
goto theend;
|
||||
@@ -1024,6 +1247,22 @@ ml_recover()
|
||||
goto theend;
|
||||
}
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (b0p->b0_id[1] == BLOCK0_ID1_C0)
|
||||
buf->b_p_cm = b0_cm = 0;
|
||||
else if (b0p->b0_id[1] == BLOCK0_ID1_C1)
|
||||
{
|
||||
buf->b_p_cm = b0_cm = 1;
|
||||
mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
|
||||
}
|
||||
#else
|
||||
if (b0p->b0_id[1] != BLOCK0_ID1)
|
||||
{
|
||||
EMSG2(_("E000: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
|
||||
goto theend;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we guessed the wrong page size, we have to recalculate the
|
||||
* highest block number in the file.
|
||||
@@ -1058,9 +1297,9 @@ ml_recover()
|
||||
b0p = (ZERO_BL *)(hp->bh_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* If .swp file name given directly, use name from swap file for buffer.
|
||||
*/
|
||||
/*
|
||||
* If .swp file name given directly, use name from swap file for buffer.
|
||||
*/
|
||||
if (directly)
|
||||
{
|
||||
expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
|
||||
@@ -1078,9 +1317,9 @@ ml_recover()
|
||||
smsg((char_u *)_("Original file \"%s\""), NameBuff);
|
||||
msg_putchar('\n');
|
||||
|
||||
/*
|
||||
* check date of swap file and original file
|
||||
*/
|
||||
/*
|
||||
* check date of swap file and original file
|
||||
*/
|
||||
mtime = char_to_long(b0p->b0_mtime);
|
||||
if (curbuf->b_ffname != NULL
|
||||
&& mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
|
||||
@@ -1096,10 +1335,16 @@ ml_recover()
|
||||
b0_ff = (b0p->b0_flags & B0_FF_MASK);
|
||||
if (b0p->b0_flags & B0_HAS_FENC)
|
||||
{
|
||||
for (p = b0p->b0_fname + B0_FNAME_SIZE;
|
||||
p > b0p->b0_fname && p[-1] != NUL; --p)
|
||||
int size = B0_FNAME_SIZE_NOCRYPT;
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
/* Use the same size as in add_b0_fenc(). */
|
||||
if (b0p->b0_id[1] != BLOCK0_ID1)
|
||||
size = B0_FNAME_SIZE_CRYPT;
|
||||
#endif
|
||||
for (p = b0p->b0_fname + size; p > b0p->b0_fname && p[-1] != NUL; --p)
|
||||
;
|
||||
b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + B0_FNAME_SIZE - p));
|
||||
b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + size - p));
|
||||
}
|
||||
|
||||
mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
|
||||
@@ -1115,11 +1360,40 @@ ml_recover()
|
||||
/*
|
||||
* Try reading the original file to obtain the values of 'fileformat',
|
||||
* 'fileencoding', etc. Ignore errors. The text itself is not used.
|
||||
* When the file is encrypted the user is asked to enter the key.
|
||||
*/
|
||||
if (curbuf->b_ffname != NULL)
|
||||
orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
|
||||
(linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (b0_cm >= 0)
|
||||
{
|
||||
/* Need to ask the user for the crypt key. If this fails we continue
|
||||
* without a key, will probably get garbage text. */
|
||||
if (*curbuf->b_p_key != NUL)
|
||||
{
|
||||
smsg((char_u *)_("Swap file is encrypted: \"%s\""), fname_used);
|
||||
MSG_PUTS(_("\nIf you entered a new crypt key but did not write the text file,"));
|
||||
MSG_PUTS(_("\nenter the new crypt key."));
|
||||
MSG_PUTS(_("\nIf you wrote the text file after changing the crypt key press enter"));
|
||||
MSG_PUTS(_("\nto use the same key for text file and swap file"));
|
||||
}
|
||||
else
|
||||
smsg((char_u *)_(need_key_msg), fname_used);
|
||||
buf->b_p_key = get_crypt_key(FALSE, FALSE);
|
||||
if (buf->b_p_key == NULL)
|
||||
buf->b_p_key = curbuf->b_p_key;
|
||||
else if (*buf->b_p_key == NUL)
|
||||
{
|
||||
vim_free(buf->b_p_key);
|
||||
buf->b_p_key = curbuf->b_p_key;
|
||||
}
|
||||
if (buf->b_p_key == NULL)
|
||||
buf->b_p_key = empty_option;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
|
||||
if (b0_ff != 0)
|
||||
set_fileformat(b0_ff - 1, OPT_LOCAL);
|
||||
@@ -1386,9 +1660,17 @@ ml_recover()
|
||||
MSG_PUTS(_("\nYou may want to delete the .swp file now.\n\n"));
|
||||
cmdline_row = msg_row;
|
||||
}
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key != NUL && STRCMP(curbuf->b_p_key, buf->b_p_key) != 0)
|
||||
{
|
||||
MSG_PUTS(_("Using crypt key from swap file for the text file.\n"));
|
||||
set_option_value((char_u *)"key", 0L, buf->b_p_key, OPT_LOCAL);
|
||||
}
|
||||
#endif
|
||||
redraw_curbuf_later(NOT_VALID);
|
||||
|
||||
theend:
|
||||
vim_free(fname_used);
|
||||
recoverymode = FALSE;
|
||||
if (mfp != NULL)
|
||||
{
|
||||
@@ -1398,6 +1680,10 @@ theend:
|
||||
}
|
||||
if (buf != NULL)
|
||||
{
|
||||
#ifdef FEAT_CRYPT
|
||||
if (buf->b_p_key != curbuf->b_p_key)
|
||||
free_string_option(buf->b_p_key);
|
||||
#endif
|
||||
vim_free(buf->b_ml.ml_stack);
|
||||
vim_free(buf);
|
||||
}
|
||||
@@ -1424,10 +1710,11 @@ theend:
|
||||
* - find the name of the n'th swap file when recovering
|
||||
*/
|
||||
int
|
||||
recover_names(fname, list, nr)
|
||||
char_u **fname; /* base for swap file name */
|
||||
int list; /* when TRUE, list the swap file names */
|
||||
int nr; /* when non-zero, return nr'th swap file name */
|
||||
recover_names(fname, list, nr, fname_out)
|
||||
char_u *fname; /* base for swap file name */
|
||||
int list; /* when TRUE, list the swap file names */
|
||||
int nr; /* when non-zero, return nr'th swap file name */
|
||||
char_u **fname_out; /* result when "nr" > 0 */
|
||||
{
|
||||
int num_names;
|
||||
char_u *(names[6]);
|
||||
@@ -1447,13 +1734,13 @@ recover_names(fname, list, nr)
|
||||
if (fname != NULL)
|
||||
{
|
||||
#ifdef HAVE_READLINK
|
||||
/* Expand symlink in the file name, because the swap file is created with
|
||||
* the actual file instead of with the symlink. */
|
||||
if (resolve_symlink(*fname, fname_buf) == OK)
|
||||
fname_res = fname_buf;
|
||||
else
|
||||
/* Expand symlink in the file name, because the swap file is created
|
||||
* with the actual file instead of with the symlink. */
|
||||
if (resolve_symlink(fname, fname_buf) == OK)
|
||||
fname_res = fname_buf;
|
||||
else
|
||||
#endif
|
||||
fname_res = *fname;
|
||||
fname_res = fname;
|
||||
}
|
||||
|
||||
if (list)
|
||||
@@ -1480,7 +1767,7 @@ recover_names(fname, list, nr)
|
||||
|
||||
if (dir_name[0] == '.' && dir_name[1] == NUL) /* check current dir */
|
||||
{
|
||||
if (fname == NULL || *fname == NULL)
|
||||
if (fname == NULL)
|
||||
{
|
||||
#ifdef VMS
|
||||
names[0] = vim_strsave((char_u *)"*_sw%");
|
||||
@@ -1511,7 +1798,7 @@ recover_names(fname, list, nr)
|
||||
}
|
||||
else /* check directory dir_name */
|
||||
{
|
||||
if (fname == NULL || *fname == NULL)
|
||||
if (fname == NULL)
|
||||
{
|
||||
#ifdef VMS
|
||||
names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
|
||||
@@ -1583,8 +1870,7 @@ recover_names(fname, list, nr)
|
||||
* not able to execute the shell).
|
||||
* Try finding a swap file by simply adding ".swp" to the file name.
|
||||
*/
|
||||
if (*dirp == NUL && file_count + num_files == 0
|
||||
&& fname != NULL && *fname != NULL)
|
||||
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL)
|
||||
{
|
||||
struct stat st;
|
||||
char_u *swapname;
|
||||
@@ -1637,7 +1923,8 @@ recover_names(fname, list, nr)
|
||||
file_count += num_files;
|
||||
if (nr <= file_count)
|
||||
{
|
||||
*fname = vim_strsave(files[nr - 1 + num_files - file_count]);
|
||||
*fname_out = vim_strsave(
|
||||
files[nr - 1 + num_files - file_count]);
|
||||
dirp = (char_u *)""; /* stop searching */
|
||||
}
|
||||
}
|
||||
@@ -1645,7 +1932,7 @@ recover_names(fname, list, nr)
|
||||
{
|
||||
if (dir_name[0] == '.' && dir_name[1] == NUL)
|
||||
{
|
||||
if (fname == NULL || *fname == NULL)
|
||||
if (fname == NULL)
|
||||
MSG_PUTS(_(" In current directory:\n"));
|
||||
else
|
||||
MSG_PUTS(_(" Using specified name:\n"));
|
||||
@@ -1772,7 +2059,7 @@ swapfile_info(fname)
|
||||
{
|
||||
MSG_PUTS(_(" [from Vim version 3.0]"));
|
||||
}
|
||||
else if (b0.b0_id[0] != BLOCK0_ID0 || b0.b0_id[1] != BLOCK0_ID1)
|
||||
else if (ml_check_b0_id(&b0) == FAIL)
|
||||
{
|
||||
MSG_PUTS(_(" [does not look like a Vim swap file]"));
|
||||
}
|
||||
@@ -3478,11 +3765,11 @@ ml_find_line(buf, lnum, action)
|
||||
error_block:
|
||||
mf_put(mfp, hp, FALSE, FALSE);
|
||||
error_noblock:
|
||||
/*
|
||||
* If action is ML_DELETE or ML_INSERT we have to correct the tree for
|
||||
* the incremented/decremented line counts, because there won't be a line
|
||||
* inserted/deleted after all.
|
||||
*/
|
||||
/*
|
||||
* If action is ML_DELETE or ML_INSERT we have to correct the tree for
|
||||
* the incremented/decremented line counts, because there won't be a line
|
||||
* inserted/deleted after all.
|
||||
*/
|
||||
if (action == ML_DELETE)
|
||||
ml_lineadd(buf, 1);
|
||||
else if (action == ML_INSERT)
|
||||
@@ -3505,10 +3792,10 @@ ml_add_stack(buf)
|
||||
|
||||
top = buf->b_ml.ml_stack_top;
|
||||
|
||||
/* may have to increase the stack size */
|
||||
/* may have to increase the stack size */
|
||||
if (top == buf->b_ml.ml_stack_size)
|
||||
{
|
||||
CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
|
||||
CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
|
||||
|
||||
newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
|
||||
(buf->b_ml.ml_stack_size + STACK_INCR));
|
||||
@@ -4518,6 +4805,132 @@ ml_setflags(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(FEAT_CRYPT) || defined(PROTO)
|
||||
/*
|
||||
* If "data" points to a data block encrypt the text in it and return a copy
|
||||
* in allocated memory. Return NULL when out of memory.
|
||||
* Otherwise return "data".
|
||||
*/
|
||||
char_u *
|
||||
ml_encrypt_data(mfp, data, offset, size)
|
||||
memfile_T *mfp;
|
||||
char_u *data;
|
||||
off_t offset;
|
||||
unsigned size;
|
||||
{
|
||||
DATA_BL *dp = (DATA_BL *)data;
|
||||
char_u *head_end;
|
||||
char_u *text_start;
|
||||
char_u *new_data;
|
||||
int text_len;
|
||||
|
||||
if (dp->db_id != DATA_ID)
|
||||
return data;
|
||||
|
||||
new_data = (char_u *)alloc(size);
|
||||
if (new_data == NULL)
|
||||
return NULL;
|
||||
head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
|
||||
text_start = (char_u *)dp + dp->db_txt_start;
|
||||
text_len = size - dp->db_txt_start;
|
||||
|
||||
/* Copy the header and the text. */
|
||||
mch_memmove(new_data, dp, head_end - (char_u *)dp);
|
||||
|
||||
/* Encrypt the text. */
|
||||
crypt_push_state();
|
||||
ml_crypt_prepare(mfp, offset, FALSE);
|
||||
crypt_encode(text_start, text_len, new_data + dp->db_txt_start);
|
||||
crypt_pop_state();
|
||||
|
||||
/* Clear the gap. */
|
||||
if (head_end < text_start)
|
||||
vim_memset(new_data + (head_end - data), 0, text_start - head_end);
|
||||
|
||||
return new_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt the text in "data" if it points to a data block.
|
||||
*/
|
||||
void
|
||||
ml_decrypt_data(mfp, data, offset, size)
|
||||
memfile_T *mfp;
|
||||
char_u *data;
|
||||
off_t offset;
|
||||
unsigned size;
|
||||
{
|
||||
DATA_BL *dp = (DATA_BL *)data;
|
||||
char_u *head_end;
|
||||
char_u *text_start;
|
||||
int text_len;
|
||||
|
||||
if (dp->db_id == DATA_ID)
|
||||
{
|
||||
head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
|
||||
text_start = (char_u *)dp + dp->db_txt_start;
|
||||
text_len = dp->db_txt_end - dp->db_txt_start;
|
||||
|
||||
if (head_end > text_start || dp->db_txt_start > size
|
||||
|| dp->db_txt_end > size)
|
||||
return; /* data was messed up */
|
||||
|
||||
/* Decrypt the text in place. */
|
||||
crypt_push_state();
|
||||
ml_crypt_prepare(mfp, offset, TRUE);
|
||||
crypt_decode(text_start, text_len);
|
||||
crypt_pop_state();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for encryption/decryption, using the key, seed and offset.
|
||||
*/
|
||||
static void
|
||||
ml_crypt_prepare(mfp, offset, reading)
|
||||
memfile_T *mfp;
|
||||
off_t offset;
|
||||
int reading;
|
||||
{
|
||||
buf_T *buf = mfp->mf_buffer;
|
||||
char_u salt[50];
|
||||
int method;
|
||||
char_u *key;
|
||||
char_u *seed;
|
||||
|
||||
if (reading && mfp->mf_old_key != NULL)
|
||||
{
|
||||
/* Reading back blocks with the previous key/method/seed. */
|
||||
method = mfp->mf_old_cm;
|
||||
key = mfp->mf_old_key;
|
||||
seed = mfp->mf_old_seed;
|
||||
}
|
||||
else
|
||||
{
|
||||
method = buf->b_p_cm;
|
||||
key = buf->b_p_key;
|
||||
seed = mfp->mf_seed;
|
||||
}
|
||||
|
||||
use_crypt_method = method; /* select pkzip or blowfish */
|
||||
if (method == 0)
|
||||
{
|
||||
vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
|
||||
crypt_init_keys(salt);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Using blowfish, add salt and seed. We use the byte offset of the
|
||||
* block for the salt. */
|
||||
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
|
||||
bf_key_init(key, salt, STRLEN(salt));
|
||||
bf_ofb_init(seed, MF_SEED_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(FEAT_BYTEOFF) || defined(PROTO)
|
||||
|
||||
#define MLCS_MAXL 800 /* max no of lines in chunk */
|
||||
|
Reference in New Issue
Block a user