summaryrefslogtreecommitdiff
path: root/src/undo.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2014-08-10 13:38:34 +0200
committerBram Moolenaar <Bram@vim.org>2014-08-10 13:38:34 +0200
commit8f4ac01544b44bdd906d241e4f203de7496e5ac8 (patch)
tree52ee7ff7368d7953f2baa3d7d015c539b11a345e /src/undo.c
parent0106b4b89127b043eddf711c750364b487deb794 (diff)
downloadvim-git-8f4ac01544b44bdd906d241e4f203de7496e5ac8.tar.gz
updated for version 7.4.399v7.4.399
Problem: Encryption implementation is messy. Blowfish encryption has a weakness. Solution: Refactor the encryption, store the state in an allocated struct instead of using a save/restore mechanism. Introduce the "blowfish2" method, which does not have the weakness and encrypts the whole undo file. (largely by David Leadbeater)
Diffstat (limited to 'src/undo.c')
-rw-r--r--src/undo.c692
1 files changed, 485 insertions, 207 deletions
diff --git a/src/undo.c b/src/undo.c
index 5db25f04e..1661c8074 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -81,8 +81,25 @@
#define UH_MAGIC 0x18dade /* value for uh_magic when in use */
#define UE_MAGIC 0xabc123 /* value for ue_magic when in use */
+/* Size of buffer used for encryption. */
+#define CRYPT_BUF_SIZE 8192
+
#include "vim.h"
+/* Structure passed around between functions.
+ * Avoids passing cryptstate_T when encryption not available. */
+typedef struct {
+ buf_T *bi_buf;
+ FILE *bi_fp;
+#ifdef FEAT_CRYPT
+ cryptstate_T *bi_state;
+ char_u *bi_buffer; /* CRYPT_BUF_SIZE, NULL when not buffering */
+ size_t bi_used; /* bytes written to/read from bi_buffer */
+ size_t bi_avail; /* bytes available in bi_buffer */
+#endif
+} bufinfo_T;
+
+
static long get_undolevel __ARGS((void));
static void u_unch_branch __ARGS((u_header_T *uhp));
static u_entry_T *u_get_headentry __ARGS((void));
@@ -98,18 +115,26 @@ static void u_freeentry __ARGS((u_entry_T *, long));
#ifdef FEAT_PERSISTENT_UNDO
static void corruption_error __ARGS((char *mesg, char_u *file_name));
static void u_free_uhp __ARGS((u_header_T *uhp));
-static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, FILE *fp));
-static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len));
-static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash));
-static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp));
-static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name));
-static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep));
-static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name));
-static void serialize_pos __ARGS((pos_T pos, FILE *fp));
-static void unserialize_pos __ARGS((pos_T *pos, FILE *fp));
-static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
-static void unserialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
-static void put_header_ptr __ARGS((FILE *fp, u_header_T *uhp));
+static int undo_write __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
+static int undo_flush __ARGS((bufinfo_T *bi));
+static int fwrite_crypt __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
+static int undo_write_bytes __ARGS((bufinfo_T *bi, long_u nr, int len));
+static void put_header_ptr __ARGS((bufinfo_T *bi, u_header_T *uhp));
+static int undo_read_4c __ARGS((bufinfo_T *bi));
+static int undo_read_2c __ARGS((bufinfo_T *bi));
+static int undo_read_byte __ARGS((bufinfo_T *bi));
+static time_t undo_read_time __ARGS((bufinfo_T *bi));
+static int undo_read __ARGS((bufinfo_T *bi, char_u *buffer, size_t size));
+static char_u *read_string_decrypt __ARGS((bufinfo_T *bi, int len));
+static int serialize_header __ARGS((bufinfo_T *bi, char_u *hash));
+static int serialize_uhp __ARGS((bufinfo_T *bi, u_header_T *uhp));
+static u_header_T *unserialize_uhp __ARGS((bufinfo_T *bi, char_u *file_name));
+static int serialize_uep __ARGS((bufinfo_T *bi, u_entry_T *uep));
+static u_entry_T *unserialize_uep __ARGS((bufinfo_T *bi, int *error, char_u *file_name));
+static void serialize_pos __ARGS((bufinfo_T *bi, pos_T pos));
+static void unserialize_pos __ARGS((bufinfo_T *bi, pos_T *pos));
+static void serialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info));
+static void unserialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info));
#endif
#define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE)
@@ -859,68 +884,294 @@ u_free_uhp(uhp)
}
/*
- * Like fwrite() but crypt the bytes when 'key' is set.
- * Returns 1 if successful.
+ * Write a sequence of bytes to the undo file.
+ * Buffers and encrypts as needed.
+ * Returns OK or FAIL.
*/
- static size_t
-fwrite_crypt(buf, ptr, len, fp)
- buf_T *buf UNUSED;
+ static int
+undo_write(bi, ptr, len)
+ bufinfo_T *bi;
+ char_u *ptr;
+ size_t len;
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ size_t len_todo = len;
+ char_u *p = ptr;
+
+ while (bi->bi_used + len_todo >= CRYPT_BUF_SIZE)
+ {
+ size_t n = CRYPT_BUF_SIZE - bi->bi_used;
+
+ mch_memmove(bi->bi_buffer + bi->bi_used, p, n);
+ len_todo -= n;
+ p += n;
+ bi->bi_used = CRYPT_BUF_SIZE;
+ if (undo_flush(bi) == FAIL)
+ return FAIL;
+ }
+ if (len_todo > 0)
+ {
+ mch_memmove(bi->bi_buffer + bi->bi_used, p, len_todo);
+ bi->bi_used += len_todo;
+ }
+ return OK;
+ }
+#endif
+ if (fwrite(ptr, len, (size_t)1, bi->bi_fp) != 1)
+ return FAIL;
+ return OK;
+}
+
+#ifdef FEAT_CRYPT
+ static int
+undo_flush(bi)
+ bufinfo_T *bi;
+{
+ if (bi->bi_used > 0)
+ {
+ crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used);
+ if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
+ return FAIL;
+ bi->bi_used = 0;
+ }
+ return OK;
+}
+#endif
+
+/*
+ * Write "ptr[len]" and crypt the bytes when needed.
+ * Returns OK or FAIL.
+ */
+ static int
+fwrite_crypt(bi, ptr, len)
+ bufinfo_T *bi;
char_u *ptr;
size_t len;
- FILE *fp;
{
#ifdef FEAT_CRYPT
char_u *copy;
char_u small_buf[100];
size_t i;
- if (*buf->b_p_key == NUL)
- return fwrite(ptr, len, (size_t)1, fp);
- if (len < 100)
- copy = small_buf; /* no malloc()/free() for short strings */
- else
+ if (bi->bi_state != NULL && bi->bi_buffer == NULL)
{
- copy = lalloc(len, FALSE);
- if (copy == NULL)
- return 0;
+ /* crypting every piece of text separately */
+ if (len < 100)
+ copy = small_buf; /* no malloc()/free() for short strings */
+ else
+ {
+ copy = lalloc(len, FALSE);
+ if (copy == NULL)
+ return 0;
+ }
+ crypt_encode(bi->bi_state, ptr, len, copy);
+ i = fwrite(copy, len, (size_t)1, bi->bi_fp);
+ if (copy != small_buf)
+ vim_free(copy);
+ return i == 1 ? OK : FAIL;
}
- crypt_encode(ptr, len, copy);
- i = fwrite(copy, len, (size_t)1, fp);
- if (copy != small_buf)
- vim_free(copy);
- return i;
-#else
- return fwrite(ptr, len, (size_t)1, fp);
#endif
+ return undo_write(bi, ptr, len);
}
/*
- * Read a string of length "len" from "fd".
- * When 'key' is set decrypt the bytes.
+ * Write a number, MSB first, in "len" bytes.
+ * Must match with undo_read_?c() functions.
+ * Returns OK or FAIL.
*/
- static char_u *
-read_string_decrypt(buf, fd, len)
- buf_T *buf UNUSED;
- FILE *fd;
+ static int
+undo_write_bytes(bi, nr, len)
+ bufinfo_T *bi;
+ long_u nr;
int len;
{
- char_u *ptr;
+ char_u buf[8];
+ int i;
+ int bufi = 0;
+
+ for (i = len - 1; i >= 0; --i)
+ buf[bufi++] = nr >> (i * 8);
+ return undo_write(bi, buf, (size_t)len);
+}
+
+/*
+ * Write the pointer to an undo header. Instead of writing the pointer itself
+ * we use the sequence number of the header. This is converted back to
+ * pointers when reading. */
+ static void
+put_header_ptr(bi, uhp)
+ bufinfo_T *bi;
+ u_header_T *uhp;
+{
+ undo_write_bytes(bi, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
+}
+
+ static int
+undo_read_4c(bi)
+ bufinfo_T *bi;
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[4];
+ int n;
+
+ undo_read(bi, buf, (size_t)4);
+ n = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+ return n;
+ }
+#endif
+ return get4c(bi->bi_fp);
+}
+
+ static int
+undo_read_2c(bi)
+ bufinfo_T *bi;
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[2];
+ int n;
+
+ undo_read(bi, buf, (size_t)2);
+ n = (buf[0] << 8) + buf[1];
+ return n;
+ }
+#endif
+ return get2c(bi->bi_fp);
+}
+
+ static int
+undo_read_byte(bi)
+ bufinfo_T *bi;
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[1];
+
+ undo_read(bi, buf, (size_t)1);
+ return buf[0];
+ }
+#endif
+ return getc(bi->bi_fp);
+}
+
+ static time_t
+undo_read_time(bi)
+ bufinfo_T *bi;
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ char_u buf[8];
+ time_t n = 0;
+ int i;
+
+ undo_read(bi, buf, (size_t)8);
+ for (i = 0; i < 8; ++i)
+ n = (n << 8) + buf[i];
+ return n;
+ }
+#endif
+ return get8ctime(bi->bi_fp);
+}
+
+/*
+ * Read "buffer[size]" from the undo file.
+ * Return OK or FAIL.
+ */
+ static int
+undo_read(bi, buffer, size)
+ bufinfo_T *bi;
+ char_u *buffer;
+ size_t size;
+{
+#ifdef FEAT_CRYPT
+ if (bi->bi_buffer != NULL)
+ {
+ int size_todo = size;
+ char_u *p = buffer;
+
+ while (size_todo > 0)
+ {
+ size_t n;
+
+ if (bi->bi_used >= bi->bi_avail)
+ {
+ n = fread(bi->bi_buffer, 1, (size_t)CRYPT_BUF_SIZE, bi->bi_fp);
+ if (n <= 0)
+ {
+ /* Error may be checked for only later. Fill with zeros,
+ * so that the reader won't use garbage. */
+ vim_memset(p, 0, size_todo);
+ return FAIL;
+ }
+ bi->bi_avail = n;
+ bi->bi_used = 0;
+ crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail);
+ }
+ n = size_todo;
+ if (n > bi->bi_avail - bi->bi_used)
+ n = bi->bi_avail - bi->bi_used;
+ mch_memmove(p, bi->bi_buffer + bi->bi_used, n);
+ bi->bi_used += n;
+ size_todo -= n;
+ p += n;
+ }
+ return OK;
+ }
+#endif
+ if (fread(buffer, (size_t)size, 1, bi->bi_fp) != 1)
+ return FAIL;
+ return OK;
+}
+
+/*
+ * Read a string of length "len" from "bi->bi_fd".
+ * "len" can be zero to allocate an empty line.
+ * Decrypt the bytes if needed.
+ * Append a NUL.
+ * Returns a pointer to allocated memory or NULL for failure.
+ */
+ static char_u *
+read_string_decrypt(bi, len)
+ bufinfo_T *bi;
+ int len;
+{
+ char_u *ptr = alloc((unsigned)len + 1);
- ptr = read_string(fd, len);
+ if (ptr != NULL)
+ {
+ if (len > 0 && undo_read(bi, ptr, len) == FAIL)
+ {
+ vim_free(ptr);
+ return NULL;
+ }
+ ptr[len] = NUL;
#ifdef FEAT_CRYPT
- if (ptr != NULL && *buf->b_p_key != NUL)
- crypt_decode(ptr, len);
+ if (bi->bi_state != NULL && bi->bi_buffer == NULL)
+ crypt_decode_inplace(bi->bi_state, ptr, len);
#endif
+ }
return ptr;
}
+/*
+ * Writes the (not encrypted) header and initializes encryption if needed.
+ */
static int
-serialize_header(fp, buf, hash)
- FILE *fp;
- buf_T *buf;
+serialize_header(bi, hash)
+ bufinfo_T *bi;
char_u *hash;
{
- int len;
+ int len;
+ buf_T *buf = bi->bi_buf;
+ FILE *fp = bi->bi_fp;
+ char_u time_buf[8];
/* Start writing, first the magic marker and undo info version. */
if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
@@ -934,108 +1185,124 @@ serialize_header(fp, buf, hash)
char_u *header;
int header_len;
- put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2);
- header = prepare_crypt_write(buf, &header_len);
- if (header == NULL)
+ undo_write_bytes(bi, (long_u)UF_VERSION_CRYPT, 2);
+ bi->bi_state = crypt_create_for_writing(crypt_get_method_nr(buf),
+ buf->b_p_key, &header, &header_len);
+ if (bi->bi_state == NULL)
return FAIL;
len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp);
vim_free(header);
if (len != 1)
{
- crypt_pop_state();
+ crypt_free_state(bi->bi_state);
+ bi->bi_state = NULL;
return FAIL;
}
+
+ if (crypt_whole_undofile(crypt_get_method_nr(buf)))
+ {
+ bi->bi_buffer = alloc(CRYPT_BUF_SIZE);
+ if (bi->bi_buffer == NULL)
+ {
+ crypt_free_state(bi->bi_state);
+ bi->bi_state = NULL;
+ return FAIL;
+ }
+ bi->bi_used = 0;
+ }
}
else
#endif
- put_bytes(fp, (long_u)UF_VERSION, 2);
+ undo_write_bytes(bi, (long_u)UF_VERSION, 2);
/* Write a hash of the buffer text, so that we can verify it is still the
* same when reading the buffer text. */
- if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1)
+ if (undo_write(bi, hash, (size_t)UNDO_HASH_SIZE) == FAIL)
return FAIL;
/* buffer-specific data */
- put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4);
+ undo_write_bytes(bi, (long_u)buf->b_ml.ml_line_count, 4);
len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0;
- put_bytes(fp, (long_u)len, 4);
- if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1)
+ undo_write_bytes(bi, (long_u)len, 4);
+ if (len > 0 && fwrite_crypt(bi, buf->b_u_line_ptr, (size_t)len) == FAIL)
return FAIL;
- put_bytes(fp, (long_u)buf->b_u_line_lnum, 4);
- put_bytes(fp, (long_u)buf->b_u_line_colnr, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_line_lnum, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_line_colnr, 4);
/* Undo structures header data */
- put_header_ptr(fp, buf->b_u_oldhead);
- put_header_ptr(fp, buf->b_u_newhead);
- put_header_ptr(fp, buf->b_u_curhead);
+ put_header_ptr(bi, buf->b_u_oldhead);
+ put_header_ptr(bi, buf->b_u_newhead);
+ put_header_ptr(bi, buf->b_u_curhead);
- put_bytes(fp, (long_u)buf->b_u_numhead, 4);
- put_bytes(fp, (long_u)buf->b_u_seq_last, 4);
- put_bytes(fp, (long_u)buf->b_u_seq_cur, 4);
- put_time(fp, buf->b_u_time_cur);
+ undo_write_bytes(bi, (long_u)buf->b_u_numhead, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_seq_last, 4);
+ undo_write_bytes(bi, (long_u)buf->b_u_seq_cur, 4);
+ time_to_bytes(buf->b_u_time_cur, time_buf);
+ undo_write(bi, time_buf, 8);
/* Optional fields. */
- putc(4, fp);
- putc(UF_LAST_SAVE_NR, fp);
- put_bytes(fp, (long_u)buf->b_u_save_nr_last, 4);
+ undo_write_bytes(bi, 4, 1);
+ undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
+ undo_write_bytes(bi, (long_u)buf->b_u_save_nr_last, 4);
- putc(0, fp); /* end marker */
+ undo_write_bytes(bi, 0, 1); /* end marker */
return OK;
}
static int
-serialize_uhp(fp, buf, uhp)
- FILE *fp;
- buf_T *buf;
+serialize_uhp(bi, uhp)
+ bufinfo_T *bi;
u_header_T *uhp;
{
int i;
u_entry_T *uep;
+ char_u time_buf[8];
- if (put_bytes(fp, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
+ if (undo_write_bytes(bi, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
return FAIL;
- put_header_ptr(fp, uhp->uh_next.ptr);
- put_header_ptr(fp, uhp->uh_prev.ptr);
- put_header_ptr(fp, uhp->uh_alt_next.ptr);
- put_header_ptr(fp, uhp->uh_alt_prev.ptr);
- put_bytes(fp, uhp->uh_seq, 4);
- serialize_pos(uhp->uh_cursor, fp);
+ put_header_ptr(bi, uhp->uh_next.ptr);
+ put_header_ptr(bi, uhp->uh_prev.ptr);
+ put_header_ptr(bi, uhp->uh_alt_next.ptr);
+ put_header_ptr(bi, uhp->uh_alt_prev.ptr);
+ undo_write_bytes(bi, uhp->uh_seq, 4);
+ serialize_pos(bi, uhp->uh_cursor);
#ifdef FEAT_VIRTUALEDIT
- put_bytes(fp, (long_u)uhp->uh_cursor_vcol, 4);
+ undo_write_bytes(bi, (long_u)uhp->uh_cursor_vcol, 4);
#else
- put_bytes(fp, (long_u)0, 4);
+ undo_write_bytes(bi, (long_u)0, 4);
#endif
- put_bytes(fp, (long_u)uhp->uh_flags, 2);
+ undo_write_bytes(bi, (long_u)uhp->uh_flags, 2);
/* Assume NMARKS will stay the same. */
for (i = 0; i < NMARKS; ++i)
- serialize_pos(uhp->uh_namedm[i], fp);
- serialize_visualinfo(&uhp->uh_visual, fp);
- put_time(fp, uhp->uh_time);
+ serialize_pos(bi, uhp->uh_namedm[i]);
+ serialize_visualinfo(bi, &uhp->uh_visual);
+ time_to_bytes(uhp->uh_time, time_buf);
+ undo_write(bi, time_buf, 8);
/* Optional fields. */
- putc(4, fp);
- putc(UHP_SAVE_NR, fp);
- put_bytes(fp, (long_u)uhp->uh_save_nr, 4);
+ undo_write_bytes(bi, 4, 1);
+ undo_write_bytes(bi, UHP_SAVE_NR, 1);
+ undo_write_bytes(bi, (long_u)uhp->uh_save_nr, 4);
- putc(0, fp); /* end marker */
+ undo_write_bytes(bi, 0, 1); /* end marker */
/* Write all the entries. */
for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
{
- put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2);
- if (serialize_uep(fp, buf, uep) == FAIL)
+ undo_write_bytes(bi, (long_u)UF_ENTRY_MAGIC, 2);
+ if (serialize_uep(bi, uep) == FAIL)
return FAIL;
}
- put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2);
+ undo_write_bytes(bi, (long_u)UF_ENTRY_END_MAGIC, 2);
return OK;
}
static u_header_T *
-unserialize_uhp(fp, file_name)
- FILE *fp;
+unserialize_uhp(bi, file_name)
+ bufinfo_T *bi;
char_u *file_name;
{
u_header_T *uhp;
@@ -1051,56 +1318,56 @@ unserialize_uhp(fp, file_name)
#ifdef U_DEBUG
uhp->uh_magic = UH_MAGIC;
#endif
- uhp->uh_next.seq = get4c(fp);
- uhp->uh_prev.seq = get4c(fp);
- uhp->uh_alt_next.seq = get4c(fp);
- uhp->uh_alt_prev.seq = get4c(fp);
- uhp->uh_seq = get4c(fp);
+ uhp->uh_next.seq = undo_read_4c(bi);
+ uhp->uh_prev.seq = undo_read_4c(bi);
+ uhp->uh_alt_next.seq = undo_read_4c(bi);
+ uhp->uh_alt_prev.seq = undo_read_4c(bi);
+ uhp->uh_seq = undo_read_4c(bi);
if (uhp->uh_seq <= 0)
{
corruption_error("uh_seq", file_name);
vim_free(uhp);
return NULL;
}
- unserialize_pos(&uhp->uh_cursor, fp);
+ unserialize_pos(bi, &uhp->uh_cursor);
#ifdef FEAT_VIRTUALEDIT
- uhp->uh_cursor_vcol = get4c(fp);
+ uhp->uh_cursor_vcol = undo_read_4c(bi);
#else
- (void)get4c(fp);
+ (void)undo_read_4c(bi);
#endif
- uhp->uh_flags = get2c(fp);
+ uhp->uh_flags = undo_read_2c(bi);
for (i = 0; i < NMARKS; ++i)
- unserialize_pos(&uhp->uh_namedm[i], fp);
- unserialize_visualinfo(&uhp->uh_visual, fp);
- uhp->uh_time = get8ctime(fp);
+ unserialize_pos(bi, &uhp->uh_namedm[i]);
+ unserialize_visualinfo(bi, &uhp->uh_visual);
+ uhp->uh_time = undo_read_time(bi);
/* Optional fields. */
for (;;)
{
- int len = getc(fp);
+ int len = undo_read_byte(bi);
int what;
if (len == 0)
break;
- what = getc(fp);
+ what = undo_read_byte(bi);
switch (what)
{
case UHP_SAVE_NR:
- uhp->uh_save_nr = get4c(fp);
+ uhp->uh_save_nr = undo_read_4c(bi);
break;
default:
/* field not supported, skip */
while (--len >= 0)
- (void)getc(fp);
+ (void)undo_read_byte(bi);
}
}
/* Unserialize the uep list. */
last_uep = NULL;
- while ((c = get2c(fp)) == UF_ENTRY_MAGIC)
+ while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC)
{
error = FALSE;
- uep = unserialize_uep(fp, &error, file_name);
+ uep = unserialize_uep(bi, &error, file_name);
if (last_uep == NULL)
uhp->uh_entry = uep;
else
@@ -1123,35 +1390,34 @@ unserialize_uhp(fp, file_name)
}
/*
- * Serialize "uep" to "fp".
+ * Serialize "uep".
*/
static int
-serialize_uep(fp, buf, uep)
- FILE *fp;
- buf_T *buf;
+serialize_uep(bi, uep)
+ bufinfo_T *bi;
u_entry_T *uep;
{
int i;
size_t len;
- put_bytes(fp, (long_u)uep->ue_top, 4);
- put_bytes(fp, (long_u)uep->ue_bot, 4);
- put_bytes(fp, (long_u)uep->ue_lcount, 4);
- put_bytes(fp, (long_u)uep->ue_size, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_top, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_bot, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_lcount, 4);
+ undo_write_bytes(bi, (long_u)uep->ue_size, 4);
for (i = 0; i < uep->ue_size; ++i)
{
len = STRLEN(uep->ue_array[i]);
- if (put_bytes(fp, (long_u)len, 4) == FAIL)
+ if (undo_write_bytes(bi, (long_u)len, 4) == FAIL)
return FAIL;
- if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1)
+ if (len > 0 && fwrite_crypt(bi, uep->ue_array[i], len) == FAIL)
return FAIL;
}
return OK;
}
static u_entry_T *
-unserialize_uep(fp, error, file_name)
- FILE *fp;
+unserialize_uep(bi, error, file_name)
+ bufinfo_T *bi;
int *error;
char_u *file_name;
{
@@ -1168,10 +1434,10 @@ unserialize_uep(fp, error, file_name)
#ifdef U_DEBUG
uep->ue_magic = UE_MAGIC;
#endif
- uep->ue_top = get4c(fp);
- uep->ue_bot = get4c(fp);
- uep->ue_lcount = get4c(fp);
- uep->ue_size = get4c(fp);
+ uep->ue_top = undo_read_4c(bi);
+ uep->ue_bot = undo_read_4c(bi);
+ uep->ue_lcount = undo_read_4c(bi);
+ uep->ue_size = undo_read_4c(bi);
if (uep->ue_size > 0)
{
array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size);
@@ -1188,9 +1454,9 @@ unserialize_uep(fp, error, file_name)
for (i = 0; i < uep->ue_size; ++i)
{
- line_len = get4c(fp);
+ line_len = undo_read_4c(bi);
if (line_len >= 0)
- line = read_string_decrypt(curbuf, fp, line_len);
+ line = read_string_decrypt(bi, line_len);
else
{
line = NULL;
@@ -1207,83 +1473,71 @@ unserialize_uep(fp, error, file_name)
}
/*
- * Serialize "pos" to "fp".
+ * Serialize "pos".
*/
static void
-serialize_pos(pos, fp)
+serialize_pos(bi, pos)
+ bufinfo_T *bi;
pos_T pos;
- FILE *fp;
{
- put_bytes(fp, (long_u)pos.lnum, 4);
- put_bytes(fp, (long_u)pos.col, 4);
+ undo_write_bytes(bi, (long_u)pos.lnum, 4);
+ undo_write_bytes(bi, (long_u)pos.col, 4);
#ifdef FEAT_VIRTUALEDIT
- put_bytes(fp, (long_u)pos.coladd, 4);
+ undo_write_bytes(bi, (long_u)pos.coladd, 4);
#else
- put_bytes(fp, (long_u)0, 4);
+ undo_write_bytes(bi, (long_u)0, 4);
#endif
}
/*
- * Unserialize the pos_T at the current position in fp.
+ * Unserialize the pos_T at the current position.
*/
static void
-unserialize_pos(pos, fp)
+unserialize_pos(bi, pos)
+ bufinfo_T *bi;
pos_T *pos;
- FILE *fp;
{
- pos->lnum = get4c(fp);
+ pos->lnum = undo_read_4c(bi);
if (pos->lnum < 0)
pos->lnum = 0;
- pos->col = get4c(fp);
+ pos->col = undo_read_4c(bi);
if (pos->col < 0)
pos->col = 0;
#ifdef FEAT_VIRTUALEDIT
- pos->coladd = get4c(fp);
+ pos->coladd = undo_read_4c(bi);
if (pos->coladd < 0)
pos->coladd = 0;
#else
- (void)get4c(fp);
+ (void)undo_read_4c(bi);
#endif
}
/*
- * Serialize "info" to "fp".
+ * Serialize "info".
*/
static void
-serialize_visualinfo(info, fp)
+serialize_visualinfo(bi, info)
+ bufinfo_T *bi;
visualinfo_T *info;
- FILE *fp;
{
- serialize_pos(info->vi_start, fp);
- serialize_pos(info->vi_end, fp);
- put_bytes(fp, (long_u)info->vi_mode, 4);
- put_bytes(fp, (long_u)info->vi_curswant, 4);
+ serialize_pos(bi, info->vi_start);
+ serialize_pos(bi, info->vi_end);
+ undo_write_bytes(bi, (long_u)info->vi_mode, 4);
+ undo_write_bytes(bi, (long_u)info->vi_curswant, 4);
}
/*
- * Unserialize the visualinfo_T at the current position in fp.
+ * Unserialize the visualinfo_T at the current position.
*/
static void
-unserialize_visualinfo(info, fp)
+unserialize_visualinfo(bi, info)
+ bufinfo_T *bi;
visualinfo_T *info;
- FILE *fp;
-{
- unserialize_pos(&info->vi_start, fp);
- unserialize_pos(&info->vi_end, fp);
- info->vi_mode = get4c(fp);
- info->vi_curswant = get4c(fp);
-}
-
-/*
- * Write the pointer to an undo header. Instead of writing the pointer itself
- * we use the sequence number of the header. This is converted back to
- * pointers when reading. */
- static void
-put_header_ptr(fp, uhp)
- FILE *fp;
- u_header_T *uhp;
{
- put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
+ unserialize_pos(bi, &info->vi_start);
+ unserialize_pos(bi, &info->vi_end);
+ info->vi_mode = undo_read_4c(bi);
+ info->vi_curswant = undo_read_4c(bi);
}
/*
@@ -1317,8 +1571,11 @@ u_write_undo(name, forceit, buf, hash)
struct stat st_old;
struct stat st_new;
#endif
+ bufinfo_T bi;
+
#ifdef FEAT_CRYPT
- int do_crypt = FALSE;
+ bi.bi_state = NULL;
+ bi.bi_buffer = NULL;
#endif
if (name == NULL)
@@ -1474,14 +1731,12 @@ u_write_undo(name, forceit, buf, hash)
u_sync(TRUE);
/*
- * Write the header.
+ * Write the header. Initializes encryption, if enabled.
*/
- if (serialize_header(fp, buf, hash) == FAIL)
+ bi.bi_buf = buf;
+ bi.bi_fp = fp;
+ if (serialize_header(&bi, hash) == FAIL)
goto write_error;
-#ifdef FEAT_CRYPT
- if (*buf->b_p_key != NUL)
- do_crypt = TRUE;
-#endif
/*
* Iteratively serialize UHPs and their UEPs from the top down.
@@ -1497,7 +1752,7 @@ u_write_undo(name, forceit, buf, hash)
#ifdef U_DEBUG
++headers_written;
#endif
- if (serialize_uhp(fp, buf, uhp) == FAIL)
+ if (serialize_uhp(&bi, uhp) == FAIL)
goto write_error;
}
@@ -1516,7 +1771,7 @@ u_write_undo(name, forceit, buf, hash)
uhp = uhp->uh_next.ptr;
}
- if (put_bytes(fp, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
+ if (undo_write_bytes(&bi, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
write_ok = TRUE;
#ifdef U_DEBUG
if (headers_written != buf->b_u_numhead)
@@ -1526,6 +1781,11 @@ u_write_undo(name, forceit, buf, hash)
}
#endif
+#ifdef FEAT_CRYPT
+ if (bi.bi_state != NULL && undo_flush(&bi) == FAIL)
+ write_ok = FALSE;
+#endif
+
write_error:
fclose(fp);
if (!write_ok)
@@ -1551,8 +1811,9 @@ write_error:
theend:
#ifdef FEAT_CRYPT
- if (do_crypt)
- crypt_pop_state();
+ if (bi.bi_state != NULL)
+ crypt_free_state(bi.bi_state);
+ vim_free(bi.bi_buffer);
#endif
if (file_name != name)
vim_free(file_name);
@@ -1598,9 +1859,7 @@ u_read_undo(name, hash, orig_name)
struct stat st_orig;
struct stat st_undo;
#endif
-#ifdef FEAT_CRYPT
- int do_decrypt = FALSE;
-#endif
+ bufinfo_T bi;
if (name == NULL)
{
@@ -1644,6 +1903,12 @@ u_read_undo(name, hash, orig_name)
EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name);
goto error;
}
+ bi.bi_buf = curbuf;
+ bi.bi_fp = fp;
+#ifdef FEAT_CRYPT
+ bi.bi_state = NULL;
+ bi.bi_buffer = NULL;
+#endif
/*
* Read the undo file header.
@@ -1664,12 +1929,24 @@ u_read_undo(name, hash, orig_name)
file_name);
goto error;
}
- if (prepare_crypt_read(fp) == FAIL)
+ bi.bi_state = crypt_create_from_file(fp, curbuf->b_p_key);
+ if (bi.bi_state == NULL)
{
EMSG2(_("E826: Undo file decryption failed: %s"), file_name);
goto error;
}
- do_decrypt = TRUE;
+ if (crypt_whole_undofile(bi.bi_state->method_nr))
+ {
+ bi.bi_buffer = alloc(CRYPT_BUF_SIZE);
+ if (bi.bi_buffer == NULL)
+ {
+ crypt_free_state(bi.bi_state);
+ bi.bi_state = NULL;
+ goto error;
+ }
+ bi.bi_avail = 0;
+ bi.bi_used = 0;
+ }
#else
EMSG2(_("E827: Undo file is encrypted: %s"), file_name);
goto error;
@@ -1681,12 +1958,12 @@ u_read_undo(name, hash, orig_name)
goto error;
}
- if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1)
+ if (undo_read(&bi, read_hash, (size_t)UNDO_HASH_SIZE) == FAIL)
{
corruption_error("hash", file_name);
goto error;
}
- line_count = (linenr_T)get4c(fp);
+ line_count = (linenr_T)undo_read_4c(&bi);
if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
|| line_count != curbuf->b_ml.ml_line_count)
{
@@ -1703,13 +1980,13 @@ u_read_undo(name, hash, orig_name)
}
/* Read undo data for "U" command. */
- str_len = get4c(fp);
+ str_len = undo_read_4c(&bi);
if (str_len < 0)
goto error;
if (str_len > 0)
- line_ptr = read_string_decrypt(curbuf, fp, str_len);
- line_lnum = (linenr_T)get4c(fp);
- line_colnr = (colnr_T)get4c(fp);
+ line_ptr = read_string_decrypt(&bi, str_len);
+ line_lnum = (linenr_T)undo_read_4c(&bi);
+ line_colnr = (colnr_T)undo_read_4c(&bi);
if (line_lnum < 0 || line_colnr < 0)
{
corruption_error("line lnum/col", file_name);
@@ -1717,32 +1994,32 @@ u_read_undo(name, hash, orig_name)
}
/* Begin general undo data */
- old_header_seq = get4c(fp);
- new_header_seq = get4c(fp);
- cur_header_seq = get4c(fp);
- num_head = get4c(fp);
- seq_last = get4c(fp);
- seq_cur = get4c(fp);
- seq_time = get8ctime(fp);
+ old_header_seq = undo_read_4c(&bi);
+ new_header_seq = undo_read_4c(&bi);
+ cur_header_seq = undo_read_4c(&bi);
+ num_head = undo_read_4c(&bi);
+ seq_last = undo_read_4c(&bi);
+ seq_cur = undo_read_4c(&bi);
+ seq_time = undo_read_time(&bi);
/* Optional header fields. */
for (;;)
{
- int len = getc(fp);
+ int len = undo_read_byte(&bi);
int what;
if (len == 0 || len == EOF)
break;
- what = getc(fp);
+ what = undo_read_byte(&bi);
switch (what)
{
case UF_LAST_SAVE_NR:
- last_save_nr = get4c(fp);
+ last_save_nr = undo_read_4c(&bi);
break;
default:
/* field not supported, skip */
while (--len >= 0)
- (void)getc(fp);
+ (void)undo_read_byte(&bi);
}
}
@@ -1758,7 +2035,7 @@ u_read_undo(name, hash, orig_name)
goto error;
}
- while ((c = get2c(fp)) == UF_HEADER_MAGIC)
+ while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC)
{
if (num_read_uhps >= num_head)
{
@@ -1766,7 +2043,7 @@ u_read_undo(name, hash, orig_name)
goto error;
}
- uhp = unserialize_uhp(fp, file_name);
+ uhp = unserialize_uhp(&bi, file_name);
if (uhp == NULL)
goto error;
uhp_table[num_read_uhps++] = uhp;
@@ -1898,8 +2175,9 @@ error:
theend:
#ifdef FEAT_CRYPT
- if (do_decrypt)
- crypt_pop_state();
+ if (bi.bi_state != NULL)
+ crypt_free_state(bi.bi_state);
+ vim_free(bi.bi_buffer);
#endif
if (fp != NULL)
fclose(fp);