diff options
author | Bram Moolenaar <Bram@vim.org> | 2014-08-10 13:38:34 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2014-08-10 13:38:34 +0200 |
commit | 8f4ac01544b44bdd906d241e4f203de7496e5ac8 (patch) | |
tree | 52ee7ff7368d7953f2baa3d7d015c539b11a345e /src/undo.c | |
parent | 0106b4b89127b043eddf711c750364b487deb794 (diff) | |
download | vim-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.c | 692 |
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); |