xref: /vim-8.2.3635/src/memfile.c (revision d653293c)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * memfile.c: Contains the functions for handling blocks of memory which can
12  * be stored in a file. This is the implementation of a sort of virtual memory.
13  *
14  * A memfile consists of a sequence of blocks. The blocks numbered from 0
15  * upwards have been assigned a place in the actual file. The block number
16  * is equal to the page number in the file. The
17  * blocks with negative numbers are currently in memory only. They can be
18  * assigned a place in the file when too much memory is being used. At that
19  * moment they get a new, positive, number. A list is used for translation of
20  * negative to positive numbers.
21  *
22  * The size of a block is a multiple of a page size, normally the page size of
23  * the device the file is on. Most blocks are 1 page long. A Block of multiple
24  * pages is used for a line that does not fit in a single page.
25  *
26  * Each block can be in memory and/or in a file. The block stays in memory
27  * as long as it is locked. If it is no longer locked it can be swapped out to
28  * the file. It is only written to the file if it has been changed.
29  *
30  * Under normal operation the file is created when opening the memory file and
31  * deleted when closing the memory file. Only with recovery an existing memory
32  * file is opened.
33  */
34 
35 #include "vim.h"
36 
37 /*
38  * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize
39  */
40 #ifdef HAVE_ST_BLKSIZE
41 # define STATFS stat
42 # define F_BSIZE st_blksize
43 # define fstatfs(fd, buf, len, nul) mch_fstat((fd), (buf))
44 #else
45 # ifdef HAVE_SYS_STATFS_H
46 #  include <sys/statfs.h>
47 #  define STATFS statfs
48 #  define F_BSIZE f_bsize
49 # endif
50 #endif
51 
52 /*
53  * for Amiga Dos 2.0x we use Flush
54  */
55 #ifdef AMIGA
56 # ifdef FEAT_ARP
57 extern int dos2;			// this is in os_amiga.c
58 # endif
59 # ifdef SASC
60 #  include <proto/dos.h>
61 #  include <ios1.h>			// for chkufb()
62 # endif
63 #endif
64 
65 #define MEMFILE_PAGE_SIZE 4096		// default page size
66 
67 static long_u	total_mem_used = 0;	// total memory used for memfiles
68 
69 static void mf_ins_hash(memfile_T *, bhdr_T *);
70 static void mf_rem_hash(memfile_T *, bhdr_T *);
71 static bhdr_T *mf_find_hash(memfile_T *, blocknr_T);
72 static void mf_ins_used(memfile_T *, bhdr_T *);
73 static void mf_rem_used(memfile_T *, bhdr_T *);
74 static bhdr_T *mf_release(memfile_T *, int);
75 static bhdr_T *mf_alloc_bhdr(memfile_T *, int);
76 static void mf_free_bhdr(bhdr_T *);
77 static void mf_ins_free(memfile_T *, bhdr_T *);
78 static bhdr_T *mf_rem_free(memfile_T *);
79 static int  mf_read(memfile_T *, bhdr_T *);
80 static int  mf_write(memfile_T *, bhdr_T *);
81 static int  mf_write_block(memfile_T *mfp, bhdr_T *hp, off_T offset, unsigned size);
82 static int  mf_trans_add(memfile_T *, bhdr_T *);
83 static void mf_do_open(memfile_T *, char_u *, int);
84 static void mf_hash_init(mf_hashtab_T *);
85 static void mf_hash_free(mf_hashtab_T *);
86 static void mf_hash_free_all(mf_hashtab_T *);
87 static mf_hashitem_T *mf_hash_find(mf_hashtab_T *, blocknr_T);
88 static void mf_hash_add_item(mf_hashtab_T *, mf_hashitem_T *);
89 static void mf_hash_rem_item(mf_hashtab_T *, mf_hashitem_T *);
90 static int mf_hash_grow(mf_hashtab_T *);
91 
92 /*
93  * The functions for using a memfile:
94  *
95  * mf_open()	    open a new or existing memfile
96  * mf_open_file()   open a swap file for an existing memfile
97  * mf_close()	    close (and delete) a memfile
98  * mf_new()	    create a new block in a memfile and lock it
99  * mf_get()	    get an existing block and lock it
100  * mf_put()	    unlock a block, may be marked for writing
101  * mf_free()	    remove a block
102  * mf_sync()	    sync changed parts of memfile to disk
103  * mf_release_all() release as much memory as possible
104  * mf_trans_del()   may translate negative to positive block number
105  * mf_fullname()    make file name full path (use before first :cd)
106  */
107 
108 /*
109  * Open an existing or new memory block file.
110  *
111  *  fname:	name of file to use (NULL means no file at all)
112  *		Note: fname must have been allocated, it is not copied!
113  *			If opening the file fails, fname is freed.
114  *  flags:	flags for open() call
115  *
116  *  If fname != NULL and file cannot be opened, fail.
117  *
118  * return value: identifier for this memory block file.
119  */
120     memfile_T *
mf_open(char_u * fname,int flags)121 mf_open(char_u *fname, int flags)
122 {
123     memfile_T		*mfp;
124     off_T		size;
125 #if defined(STATFS) && defined(UNIX) && !defined(__QNX__) && !defined(__minix)
126 # define USE_FSTATFS
127     struct STATFS	stf;
128 #endif
129 
130     if ((mfp = ALLOC_ONE(memfile_T)) == NULL)
131 	return NULL;
132 
133     if (fname == NULL)	    // no file for this memfile, use memory only
134     {
135 	mfp->mf_fname = NULL;
136 	mfp->mf_ffname = NULL;
137 	mfp->mf_fd = -1;
138     }
139     else
140     {
141 	mf_do_open(mfp, fname, flags);	// try to open the file
142 
143 	// if the file cannot be opened, return here
144 	if (mfp->mf_fd < 0)
145 	{
146 	    vim_free(mfp);
147 	    return NULL;
148 	}
149     }
150 
151     mfp->mf_free_first = NULL;		// free list is empty
152     mfp->mf_used_first = NULL;		// used list is empty
153     mfp->mf_used_last = NULL;
154     mfp->mf_dirty = FALSE;
155     mfp->mf_used_count = 0;
156     mf_hash_init(&mfp->mf_hash);
157     mf_hash_init(&mfp->mf_trans);
158     mfp->mf_page_size = MEMFILE_PAGE_SIZE;
159 #ifdef FEAT_CRYPT
160     mfp->mf_old_key = NULL;
161 #endif
162 
163 #ifdef USE_FSTATFS
164     /*
165      * Try to set the page size equal to the block size of the device.
166      * Speeds up I/O a lot.
167      * When recovering, the actual block size will be retrieved from block 0
168      * in ml_recover().  The size used here may be wrong, therefore
169      * mf_blocknr_max must be rounded up.
170      */
171     if (mfp->mf_fd >= 0
172 	    && fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0
173 	    && stf.F_BSIZE >= MIN_SWAP_PAGE_SIZE
174 	    && stf.F_BSIZE <= MAX_SWAP_PAGE_SIZE)
175 	mfp->mf_page_size = stf.F_BSIZE;
176 #endif
177 
178     if (mfp->mf_fd < 0 || (flags & (O_TRUNC|O_EXCL))
179 		  || (size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0)
180 	mfp->mf_blocknr_max = 0;	// no file or empty file
181     else
182 	mfp->mf_blocknr_max = (blocknr_T)((size + mfp->mf_page_size - 1)
183 							 / mfp->mf_page_size);
184     mfp->mf_blocknr_min = -1;
185     mfp->mf_neg_count = 0;
186     mfp->mf_infile_count = mfp->mf_blocknr_max;
187 
188     /*
189      * Compute maximum number of pages ('maxmem' is in Kbyte):
190      *	'mammem' * 1Kbyte / page-size-in-bytes.
191      * Avoid overflow by first reducing page size as much as possible.
192      */
193     {
194 	int	    shift = 10;
195 	unsigned    page_size = mfp->mf_page_size;
196 
197 	while (shift > 0 && (page_size & 1) == 0)
198 	{
199 	    page_size = page_size >> 1;
200 	    --shift;
201 	}
202 	mfp->mf_used_count_max = (p_mm << shift) / page_size;
203 	if (mfp->mf_used_count_max < 10)
204 	    mfp->mf_used_count_max = 10;
205     }
206 
207     return mfp;
208 }
209 
210 /*
211  * Open a file for an existing memfile.  Used when updatecount set from 0 to
212  * some value.
213  * If the file already exists, this fails.
214  * "fname" is the name of file to use (NULL means no file at all)
215  * Note: "fname" must have been allocated, it is not copied!  If opening the
216  * file fails, "fname" is freed.
217  *
218  * return value: FAIL if file could not be opened, OK otherwise
219  */
220     int
mf_open_file(memfile_T * mfp,char_u * fname)221 mf_open_file(memfile_T *mfp, char_u *fname)
222 {
223     mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); // try to open the file
224 
225     if (mfp->mf_fd < 0)
226 	return FAIL;
227 
228     mfp->mf_dirty = TRUE;
229     return OK;
230 }
231 
232 /*
233  * Close a memory file and delete the associated file if 'del_file' is TRUE.
234  */
235     void
mf_close(memfile_T * mfp,int del_file)236 mf_close(memfile_T *mfp, int del_file)
237 {
238     bhdr_T	*hp, *nextp;
239 
240     if (mfp == NULL)		    // safety check
241 	return;
242     if (mfp->mf_fd >= 0)
243     {
244 	if (close(mfp->mf_fd) < 0)
245 	    emsg(_(e_swapclose));
246     }
247     if (del_file && mfp->mf_fname != NULL)
248 	mch_remove(mfp->mf_fname);
249 					    // free entries in used list
250     for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
251     {
252 	total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
253 	nextp = hp->bh_next;
254 	mf_free_bhdr(hp);
255     }
256     while (mfp->mf_free_first != NULL)	    // free entries in free list
257 	vim_free(mf_rem_free(mfp));
258     mf_hash_free(&mfp->mf_hash);
259     mf_hash_free_all(&mfp->mf_trans);	    // free hashtable and its items
260     vim_free(mfp->mf_fname);
261     vim_free(mfp->mf_ffname);
262     vim_free(mfp);
263 }
264 
265 /*
266  * Close the swap file for a memfile.  Used when 'swapfile' is reset.
267  */
268     void
mf_close_file(buf_T * buf,int getlines)269 mf_close_file(
270     buf_T	*buf,
271     int		getlines)	// get all lines into memory?
272 {
273     memfile_T	*mfp;
274     linenr_T	lnum;
275 
276     mfp = buf->b_ml.ml_mfp;
277     if (mfp == NULL || mfp->mf_fd < 0)		// nothing to close
278 	return;
279 
280     if (getlines)
281     {
282 	// get all blocks in memory by accessing all lines (clumsy!)
283 	mf_dont_release = TRUE;
284 	for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
285 	    (void)ml_get_buf(buf, lnum, FALSE);
286 	mf_dont_release = FALSE;
287 	// TODO: should check if all blocks are really in core
288     }
289 
290     if (close(mfp->mf_fd) < 0)			// close the file
291 	emsg(_(e_swapclose));
292     mfp->mf_fd = -1;
293 
294     if (mfp->mf_fname != NULL)
295     {
296 	mch_remove(mfp->mf_fname);		// delete the swap file
297 	VIM_CLEAR(mfp->mf_fname);
298 	VIM_CLEAR(mfp->mf_ffname);
299     }
300 }
301 
302 /*
303  * Set new size for a memfile.  Used when block 0 of a swapfile has been read
304  * and the size it indicates differs from what was guessed.
305  */
306     void
mf_new_page_size(memfile_T * mfp,unsigned new_size)307 mf_new_page_size(memfile_T *mfp, unsigned new_size)
308 {
309     // Correct the memory used for block 0 to the new size, because it will be
310     // freed with that size later on.
311     total_mem_used += new_size - mfp->mf_page_size;
312     mfp->mf_page_size = new_size;
313 }
314 
315 /*
316  * get a new block
317  *
318  *   negative: TRUE if negative block number desired (data block)
319  */
320     bhdr_T *
mf_new(memfile_T * mfp,int negative,int page_count)321 mf_new(memfile_T *mfp, int negative, int page_count)
322 {
323     bhdr_T	*hp;	// new bhdr_T
324     bhdr_T	*freep;	// first block in free list
325     char_u	*p;
326 
327     /*
328      * If we reached the maximum size for the used memory blocks, release one
329      * If a bhdr_T is returned, use it and adjust the page_count if necessary.
330      */
331     hp = mf_release(mfp, page_count);
332 
333 /*
334  * Decide on the number to use:
335  * If there is a free block, use its number.
336  * Otherwise use mf_block_min for a negative number, mf_block_max for
337  * a positive number.
338  */
339     freep = mfp->mf_free_first;
340     if (!negative && freep != NULL && freep->bh_page_count >= page_count)
341     {
342 	/*
343 	 * If the block in the free list has more pages, take only the number
344 	 * of pages needed and allocate a new bhdr_T with data
345 	 *
346 	 * If the number of pages matches and mf_release() did not return a
347 	 * bhdr_T, use the bhdr_T from the free list and allocate the data
348 	 *
349 	 * If the number of pages matches and mf_release() returned a bhdr_T,
350 	 * just use the number and free the bhdr_T from the free list
351 	 */
352 	if (freep->bh_page_count > page_count)
353 	{
354 	    if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
355 		return NULL;
356 	    hp->bh_bnum = freep->bh_bnum;
357 	    freep->bh_bnum += page_count;
358 	    freep->bh_page_count -= page_count;
359 	}
360 	else if (hp == NULL)	    // need to allocate memory for this block
361 	{
362 	    if ((p = alloc(mfp->mf_page_size * page_count)) == NULL)
363 		return NULL;
364 	    hp = mf_rem_free(mfp);
365 	    hp->bh_data = p;
366 	}
367 	else		    // use the number, remove entry from free list
368 	{
369 	    freep = mf_rem_free(mfp);
370 	    hp->bh_bnum = freep->bh_bnum;
371 	    vim_free(freep);
372 	}
373     }
374     else	// get a new number
375     {
376 	if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
377 	    return NULL;
378 	if (negative)
379 	{
380 	    hp->bh_bnum = mfp->mf_blocknr_min--;
381 	    mfp->mf_neg_count++;
382 	}
383 	else
384 	{
385 	    hp->bh_bnum = mfp->mf_blocknr_max;
386 	    mfp->mf_blocknr_max += page_count;
387 	}
388     }
389     hp->bh_flags = BH_LOCKED | BH_DIRTY;	// new block is always dirty
390     mfp->mf_dirty = TRUE;
391     hp->bh_page_count = page_count;
392     mf_ins_used(mfp, hp);
393     mf_ins_hash(mfp, hp);
394 
395     /*
396      * Init the data to all zero, to avoid reading uninitialized data.
397      * This also avoids that the passwd file ends up in the swap file!
398      */
399     (void)vim_memset((char *)(hp->bh_data), 0,
400 				      (size_t)mfp->mf_page_size * page_count);
401 
402     return hp;
403 }
404 
405 /*
406  * Get existing block "nr" with "page_count" pages.
407  *
408  * Note: The caller should first check a negative nr with mf_trans_del()
409  */
410     bhdr_T *
mf_get(memfile_T * mfp,blocknr_T nr,int page_count)411 mf_get(memfile_T *mfp, blocknr_T nr, int page_count)
412 {
413     bhdr_T    *hp;
414 						// doesn't exist
415     if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
416 	return NULL;
417 
418     /*
419      * see if it is in the cache
420      */
421     hp = mf_find_hash(mfp, nr);
422     if (hp == NULL)	// not in the hash list
423     {
424 	if (nr < 0 || nr >= mfp->mf_infile_count)   // can't be in the file
425 	    return NULL;
426 
427 	// could check here if the block is in the free list
428 
429 	/*
430 	 * Check if we need to flush an existing block.
431 	 * If so, use that block.
432 	 * If not, allocate a new block.
433 	 */
434 	hp = mf_release(mfp, page_count);
435 	if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
436 	    return NULL;
437 
438 	hp->bh_bnum = nr;
439 	hp->bh_flags = 0;
440 	hp->bh_page_count = page_count;
441 	if (mf_read(mfp, hp) == FAIL)	    // cannot read the block!
442 	{
443 	    mf_free_bhdr(hp);
444 	    return NULL;
445 	}
446     }
447     else
448     {
449 	mf_rem_used(mfp, hp);	// remove from list, insert in front below
450 	mf_rem_hash(mfp, hp);
451     }
452 
453     hp->bh_flags |= BH_LOCKED;
454     mf_ins_used(mfp, hp);	// put in front of used list
455     mf_ins_hash(mfp, hp);	// put in front of hash list
456 
457     return hp;
458 }
459 
460 /*
461  * release the block *hp
462  *
463  *   dirty: Block must be written to file later
464  *   infile: Block should be in file (needed for recovery)
465  *
466  *  no return value, function cannot fail
467  */
468     void
mf_put(memfile_T * mfp,bhdr_T * hp,int dirty,int infile)469 mf_put(
470     memfile_T	*mfp,
471     bhdr_T	*hp,
472     int		dirty,
473     int		infile)
474 {
475     int		flags;
476 
477     flags = hp->bh_flags;
478 
479     if ((flags & BH_LOCKED) == 0)
480 	iemsg(_("E293: block was not locked"));
481     flags &= ~BH_LOCKED;
482     if (dirty)
483     {
484 	flags |= BH_DIRTY;
485 	mfp->mf_dirty = TRUE;
486     }
487     hp->bh_flags = flags;
488     if (infile)
489 	mf_trans_add(mfp, hp);	    // may translate negative in positive nr
490 }
491 
492 /*
493  * block *hp is no longer in used, may put it in the free list of memfile *mfp
494  */
495     void
mf_free(memfile_T * mfp,bhdr_T * hp)496 mf_free(memfile_T *mfp, bhdr_T *hp)
497 {
498     vim_free(hp->bh_data);	// free the memory
499     mf_rem_hash(mfp, hp);	// get *hp out of the hash list
500     mf_rem_used(mfp, hp);	// get *hp out of the used list
501     if (hp->bh_bnum < 0)
502     {
503 	vim_free(hp);		// don't want negative numbers in free list
504 	mfp->mf_neg_count--;
505     }
506     else
507 	mf_ins_free(mfp, hp);	// put *hp in the free list
508 }
509 
510 /*
511  * Sync the memory file *mfp to disk.
512  * Flags:
513  *  MFS_ALL	If not given, blocks with negative numbers are not synced,
514  *		even when they are dirty!
515  *  MFS_STOP	Stop syncing when a character becomes available, but sync at
516  *		least one block.
517  *  MFS_FLUSH	Make sure buffers are flushed to disk, so they will survive a
518  *		system crash.
519  *  MFS_ZERO	Only write block 0.
520  *
521  * Return FAIL for failure, OK otherwise
522  */
523     int
mf_sync(memfile_T * mfp,int flags)524 mf_sync(memfile_T *mfp, int flags)
525 {
526     int		status;
527     bhdr_T	*hp;
528     int		got_int_save = got_int;
529 
530     if (mfp->mf_fd < 0)	    // there is no file, nothing to do
531     {
532 	mfp->mf_dirty = FALSE;
533 	return FAIL;
534     }
535 
536     // Only a CTRL-C while writing will break us here, not one typed
537     // previously.
538     got_int = FALSE;
539 
540     /*
541      * sync from last to first (may reduce the probability of an inconsistent
542      * file) If a write fails, it is very likely caused by a full filesystem.
543      * Then we only try to write blocks within the existing file. If that also
544      * fails then we give up.
545      */
546     status = OK;
547     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
548 	if (((flags & MFS_ALL) || hp->bh_bnum >= 0)
549 		&& (hp->bh_flags & BH_DIRTY)
550 		&& (status == OK || (hp->bh_bnum >= 0
551 		    && hp->bh_bnum < mfp->mf_infile_count)))
552 	{
553 	    if ((flags & MFS_ZERO) && hp->bh_bnum != 0)
554 		continue;
555 	    if (mf_write(mfp, hp) == FAIL)
556 	    {
557 		if (status == FAIL)	// double error: quit syncing
558 		    break;
559 		status = FAIL;
560 	    }
561 	    if (flags & MFS_STOP)
562 	    {
563 		// Stop when char available now.
564 		if (ui_char_avail())
565 		    break;
566 	    }
567 	    else
568 		ui_breakcheck();
569 	    if (got_int)
570 		break;
571 	}
572 
573     /*
574      * If the whole list is flushed, the memfile is not dirty anymore.
575      * In case of an error this flag is also set, to avoid trying all the time.
576      */
577     if (hp == NULL || status == FAIL)
578 	mfp->mf_dirty = FALSE;
579 
580     if ((flags & MFS_FLUSH) && *p_sws != NUL)
581     {
582 #if defined(UNIX)
583 # ifdef HAVE_FSYNC
584 	/*
585 	 * most Unixes have the very useful fsync() function, just what we need.
586 	 */
587 	if (STRCMP(p_sws, "fsync") == 0)
588 	{
589 	    if (vim_fsync(mfp->mf_fd))
590 		status = FAIL;
591 	}
592 	else
593 # endif
594 	    // OpenNT is strictly POSIX (Benzinger)
595 	    // Tandem/Himalaya NSK-OSS doesn't have sync()
596 	    // No sync() on Stratus VOS
597 # if defined(__OPENNT) || defined(__TANDEM) || defined(__VOS__)
598 	    fflush(NULL);
599 # else
600 	    sync();
601 # endif
602 #endif
603 #ifdef VMS
604 	if (STRCMP(p_sws, "fsync") == 0)
605 	{
606 	    if (vim_fsync(mfp->mf_fd))
607 		status = FAIL;
608 	}
609 #endif
610 #ifdef MSWIN
611 	if (_commit(mfp->mf_fd))
612 	    status = FAIL;
613 #endif
614 #ifdef AMIGA
615 # if defined(__AROS__) || defined(__amigaos4__)
616 	if (vim_fsync(mfp->mf_fd) != 0)
617 	    status = FAIL;
618 # else
619 	/*
620 	 * Flush() only exists for AmigaDos 2.0.
621 	 * For 1.3 it should be done with close() + open(), but then the risk
622 	 * is that the open() may fail and lose the file....
623 	 */
624 #  ifdef FEAT_ARP
625 	if (dos2)
626 #  endif
627 #  ifdef SASC
628 	{
629 	    struct UFB *fp = chkufb(mfp->mf_fd);
630 
631 	    if (fp != NULL)
632 		Flush(fp->ufbfh);
633 	}
634 #  else
635 #   if defined(_DCC) || defined(__GNUC__) || defined(__MORPHOS__)
636 	{
637 #    if defined(__GNUC__) && !defined(__MORPHOS__) && defined(__libnix__)
638 	    // Have function (in libnix at least),
639 	    // but ain't got no prototype anywhere.
640 	    extern unsigned long fdtofh(int filedescriptor);
641 #    endif
642 #    if !defined(__libnix__)
643 	    fflush(NULL);
644 #    else
645 	    BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
646 
647 	    if (fh != 0)
648 		Flush(fh);
649 #    endif
650 	}
651 #   else // assume Manx
652 	    Flush(_devtab[mfp->mf_fd].fd);
653 #   endif
654 #  endif
655 # endif
656 #endif // AMIGA
657     }
658 
659     got_int |= got_int_save;
660 
661     return status;
662 }
663 
664 /*
665  * For all blocks in memory file *mfp that have a positive block number set
666  * the dirty flag.  These are blocks that need to be written to a newly
667  * created swapfile.
668  */
669     void
mf_set_dirty(memfile_T * mfp)670 mf_set_dirty(memfile_T *mfp)
671 {
672     bhdr_T	*hp;
673 
674     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
675 	if (hp->bh_bnum > 0)
676 	    hp->bh_flags |= BH_DIRTY;
677     mfp->mf_dirty = TRUE;
678 }
679 
680 /*
681  * insert block *hp in front of hashlist of memfile *mfp
682  */
683     static void
mf_ins_hash(memfile_T * mfp,bhdr_T * hp)684 mf_ins_hash(memfile_T *mfp, bhdr_T *hp)
685 {
686     mf_hash_add_item(&mfp->mf_hash, (mf_hashitem_T *)hp);
687 }
688 
689 /*
690  * remove block *hp from hashlist of memfile list *mfp
691  */
692     static void
mf_rem_hash(memfile_T * mfp,bhdr_T * hp)693 mf_rem_hash(memfile_T *mfp, bhdr_T *hp)
694 {
695     mf_hash_rem_item(&mfp->mf_hash, (mf_hashitem_T *)hp);
696 }
697 
698 /*
699  * look in hash lists of memfile *mfp for block header with number 'nr'
700  */
701     static bhdr_T *
mf_find_hash(memfile_T * mfp,blocknr_T nr)702 mf_find_hash(memfile_T *mfp, blocknr_T nr)
703 {
704     return (bhdr_T *)mf_hash_find(&mfp->mf_hash, nr);
705 }
706 
707 /*
708  * insert block *hp in front of used list of memfile *mfp
709  */
710     static void
mf_ins_used(memfile_T * mfp,bhdr_T * hp)711 mf_ins_used(memfile_T *mfp, bhdr_T *hp)
712 {
713     hp->bh_next = mfp->mf_used_first;
714     mfp->mf_used_first = hp;
715     hp->bh_prev = NULL;
716     if (hp->bh_next == NULL)	    // list was empty, adjust last pointer
717 	mfp->mf_used_last = hp;
718     else
719 	hp->bh_next->bh_prev = hp;
720     mfp->mf_used_count += hp->bh_page_count;
721     total_mem_used += hp->bh_page_count * mfp->mf_page_size;
722 }
723 
724 /*
725  * remove block *hp from used list of memfile *mfp
726  */
727     static void
mf_rem_used(memfile_T * mfp,bhdr_T * hp)728 mf_rem_used(memfile_T *mfp, bhdr_T *hp)
729 {
730     if (hp->bh_next == NULL)	    // last block in used list
731 	mfp->mf_used_last = hp->bh_prev;
732     else
733 	hp->bh_next->bh_prev = hp->bh_prev;
734     if (hp->bh_prev == NULL)	    // first block in used list
735 	mfp->mf_used_first = hp->bh_next;
736     else
737 	hp->bh_prev->bh_next = hp->bh_next;
738     mfp->mf_used_count -= hp->bh_page_count;
739     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
740 }
741 
742 /*
743  * Release the least recently used block from the used list if the number
744  * of used memory blocks gets to big.
745  *
746  * Return the block header to the caller, including the memory block, so
747  * it can be re-used. Make sure the page_count is right.
748  *
749  * Returns NULL if no block is released.
750  */
751     static bhdr_T *
mf_release(memfile_T * mfp,int page_count)752 mf_release(memfile_T *mfp, int page_count)
753 {
754     bhdr_T	*hp;
755     int		need_release;
756     buf_T	*buf;
757 
758     // don't release while in mf_close_file()
759     if (mf_dont_release)
760 	return NULL;
761 
762     /*
763      * Need to release a block if the number of blocks for this memfile is
764      * higher than the maximum or total memory used is over 'maxmemtot'
765      */
766     need_release = ((mfp->mf_used_count >= mfp->mf_used_count_max)
767 				  || (total_mem_used >> 10) >= (long_u)p_mmt);
768 
769     /*
770      * Try to create a swap file if the amount of memory used is getting too
771      * high.
772      */
773     if (mfp->mf_fd < 0 && need_release && p_uc)
774     {
775 	// find for which buffer this memfile is
776 	FOR_ALL_BUFFERS(buf)
777 	    if (buf->b_ml.ml_mfp == mfp)
778 		break;
779 	if (buf != NULL && buf->b_may_swap)
780 	    ml_open_file(buf);
781     }
782 
783     /*
784      * don't release a block if
785      *	there is no file for this memfile
786      * or
787      *	the number of blocks for this memfile is lower than the maximum
788      *	  and
789      *	total memory used is not up to 'maxmemtot'
790      */
791     if (mfp->mf_fd < 0 || !need_release)
792 	return NULL;
793 
794     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
795 	if (!(hp->bh_flags & BH_LOCKED))
796 	    break;
797     if (hp == NULL)	// not a single one that can be released
798 	return NULL;
799 
800     /*
801      * If the block is dirty, write it.
802      * If the write fails we don't free it.
803      */
804     if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
805 	return NULL;
806 
807     mf_rem_used(mfp, hp);
808     mf_rem_hash(mfp, hp);
809 
810     /*
811      * If a bhdr_T is returned, make sure that the page_count of bh_data is
812      * right
813      */
814     if (hp->bh_page_count != page_count)
815     {
816 	vim_free(hp->bh_data);
817 	if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
818 	{
819 	    vim_free(hp);
820 	    return NULL;
821 	}
822 	hp->bh_page_count = page_count;
823     }
824     return hp;
825 }
826 
827 /*
828  * release as many blocks as possible
829  * Used in case of out of memory
830  *
831  * return TRUE if any memory was released
832  */
833     int
mf_release_all(void)834 mf_release_all(void)
835 {
836     buf_T	*buf;
837     memfile_T	*mfp;
838     bhdr_T	*hp;
839     int		retval = FALSE;
840 
841     FOR_ALL_BUFFERS(buf)
842     {
843 	mfp = buf->b_ml.ml_mfp;
844 	if (mfp != NULL)
845 	{
846 	    // If no swap file yet, may open one
847 	    if (mfp->mf_fd < 0 && buf->b_may_swap)
848 		ml_open_file(buf);
849 
850 	    // only if there is a swapfile
851 	    if (mfp->mf_fd >= 0)
852 	    {
853 		for (hp = mfp->mf_used_last; hp != NULL; )
854 		{
855 		    if (!(hp->bh_flags & BH_LOCKED)
856 			    && (!(hp->bh_flags & BH_DIRTY)
857 				|| mf_write(mfp, hp) != FAIL))
858 		    {
859 			mf_rem_used(mfp, hp);
860 			mf_rem_hash(mfp, hp);
861 			mf_free_bhdr(hp);
862 			hp = mfp->mf_used_last;	// re-start, list was changed
863 			retval = TRUE;
864 		    }
865 		    else
866 			hp = hp->bh_prev;
867 		}
868 	    }
869 	}
870     }
871     return retval;
872 }
873 
874 /*
875  * Allocate a block header and a block of memory for it
876  */
877     static bhdr_T *
mf_alloc_bhdr(memfile_T * mfp,int page_count)878 mf_alloc_bhdr(memfile_T *mfp, int page_count)
879 {
880     bhdr_T	*hp;
881 
882     if ((hp = ALLOC_ONE(bhdr_T)) != NULL)
883     {
884 	if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
885 	{
886 	    vim_free(hp);	    // not enough memory
887 	    return NULL;
888 	}
889 	hp->bh_page_count = page_count;
890     }
891     return hp;
892 }
893 
894 /*
895  * Free a block header and the block of memory for it
896  */
897     static void
mf_free_bhdr(bhdr_T * hp)898 mf_free_bhdr(bhdr_T *hp)
899 {
900     vim_free(hp->bh_data);
901     vim_free(hp);
902 }
903 
904 /*
905  * insert entry *hp in the free list
906  */
907     static void
mf_ins_free(memfile_T * mfp,bhdr_T * hp)908 mf_ins_free(memfile_T *mfp, bhdr_T *hp)
909 {
910     hp->bh_next = mfp->mf_free_first;
911     mfp->mf_free_first = hp;
912 }
913 
914 /*
915  * remove the first entry from the free list and return a pointer to it
916  * Note: caller must check that mfp->mf_free_first is not NULL!
917  */
918     static bhdr_T *
mf_rem_free(memfile_T * mfp)919 mf_rem_free(memfile_T *mfp)
920 {
921     bhdr_T	*hp;
922 
923     hp = mfp->mf_free_first;
924     mfp->mf_free_first = hp->bh_next;
925     return hp;
926 }
927 
928 /*
929  * read a block from disk
930  *
931  * Return FAIL for failure, OK otherwise
932  */
933     static int
mf_read(memfile_T * mfp,bhdr_T * hp)934 mf_read(memfile_T *mfp, bhdr_T *hp)
935 {
936     off_T	offset;
937     unsigned	page_size;
938     unsigned	size;
939 
940     if (mfp->mf_fd < 0)	    // there is no file, can't read
941 	return FAIL;
942 
943     page_size = mfp->mf_page_size;
944     offset = (off_T)page_size * hp->bh_bnum;
945     size = page_size * hp->bh_page_count;
946     if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
947     {
948 	PERROR(_("E294: Seek error in swap file read"));
949 	return FAIL;
950     }
951     if ((unsigned)read_eintr(mfp->mf_fd, hp->bh_data, size) != size)
952     {
953 	PERROR(_("E295: Read error in swap file"));
954 	return FAIL;
955     }
956 
957 #ifdef FEAT_CRYPT
958     // Decrypt if 'key' is set and this is a data block. And when changing the
959     // key.
960     if (*mfp->mf_buffer->b_p_key != NUL || mfp->mf_old_key != NULL)
961 	ml_decrypt_data(mfp, hp->bh_data, offset, size);
962 #endif
963 
964     return OK;
965 }
966 
967 /*
968  * write a block to disk
969  *
970  * Return FAIL for failure, OK otherwise
971  */
972     static int
mf_write(memfile_T * mfp,bhdr_T * hp)973 mf_write(memfile_T *mfp, bhdr_T *hp)
974 {
975     off_T	offset;	    // offset in the file
976     blocknr_T	nr;	    // block nr which is being written
977     bhdr_T	*hp2;
978     unsigned	page_size;  // number of bytes in a page
979     unsigned	page_count; // number of pages written
980     unsigned	size;	    // number of bytes written
981 
982     if (mfp->mf_fd < 0 && !mfp->mf_reopen)
983 	// there is no file and there was no file, can't write
984 	return FAIL;
985 
986     if (hp->bh_bnum < 0)	// must assign file block number
987 	if (mf_trans_add(mfp, hp) == FAIL)
988 	    return FAIL;
989 
990     page_size = mfp->mf_page_size;
991 
992     /*
993      * We don't want gaps in the file. Write the blocks in front of *hp
994      * to extend the file.
995      * If block 'mf_infile_count' is not in the hash list, it has been
996      * freed. Fill the space in the file with data from the current block.
997      */
998     for (;;)
999     {
1000 	int attempt;
1001 
1002 	nr = hp->bh_bnum;
1003 	if (nr > mfp->mf_infile_count)		// beyond end of file
1004 	{
1005 	    nr = mfp->mf_infile_count;
1006 	    hp2 = mf_find_hash(mfp, nr);	// NULL caught below
1007 	}
1008 	else
1009 	    hp2 = hp;
1010 
1011 	offset = (off_T)page_size * nr;
1012 	if (hp2 == NULL)	    // freed block, fill with dummy data
1013 	    page_count = 1;
1014 	else
1015 	    page_count = hp2->bh_page_count;
1016 	size = page_size * page_count;
1017 
1018 	for (attempt = 1; attempt <= 2; ++attempt)
1019 	{
1020 	    if (mfp->mf_fd >= 0)
1021 	    {
1022 		if (vim_lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
1023 		{
1024 		    PERROR(_("E296: Seek error in swap file write"));
1025 		    return FAIL;
1026 		}
1027 		if (mf_write_block(mfp,
1028 				   hp2 == NULL ? hp : hp2, offset, size) == OK)
1029 		    break;
1030 	    }
1031 
1032 	    if (attempt == 1)
1033 	    {
1034 		// If the swap file is on a network drive, and the network
1035 		// gets disconnected and then re-connected, we can maybe fix it
1036 		// by closing and then re-opening the file.
1037 		if (mfp->mf_fd >= 0)
1038 		    close(mfp->mf_fd);
1039 		mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, mfp->mf_flags);
1040 		mfp->mf_reopen = (mfp->mf_fd < 0);
1041 	    }
1042 	    if (attempt == 2 || mfp->mf_fd < 0)
1043 	    {
1044 		// Avoid repeating the error message, this mostly happens when
1045 		// the disk is full. We give the message again only after a
1046 		// successful write or when hitting a key. We keep on trying,
1047 		// in case some space becomes available.
1048 		if (!did_swapwrite_msg)
1049 		    emsg(_("E297: Write error in swap file"));
1050 		did_swapwrite_msg = TRUE;
1051 		return FAIL;
1052 	    }
1053 	}
1054 
1055 	did_swapwrite_msg = FALSE;
1056 	if (hp2 != NULL)		    // written a non-dummy block
1057 	    hp2->bh_flags &= ~BH_DIRTY;
1058 					    // appended to the file
1059 	if (nr + (blocknr_T)page_count > mfp->mf_infile_count)
1060 	    mfp->mf_infile_count = nr + page_count;
1061 	if (nr == hp->bh_bnum)		    // written the desired block
1062 	    break;
1063     }
1064     return OK;
1065 }
1066 
1067 /*
1068  * Write block "hp" with data size "size" to file "mfp->mf_fd".
1069  * Takes care of encryption.
1070  * Return FAIL or OK.
1071  */
1072     static int
mf_write_block(memfile_T * mfp,bhdr_T * hp,off_T offset UNUSED,unsigned size)1073 mf_write_block(
1074     memfile_T	*mfp,
1075     bhdr_T	*hp,
1076     off_T	offset UNUSED,
1077     unsigned	size)
1078 {
1079     char_u	*data = hp->bh_data;
1080     int		result = OK;
1081 
1082 #ifdef FEAT_CRYPT
1083     // Encrypt if 'key' is set and this is a data block.
1084     if (*mfp->mf_buffer->b_p_key != NUL)
1085     {
1086 	data = ml_encrypt_data(mfp, data, offset, size);
1087 	if (data == NULL)
1088 	    return FAIL;
1089     }
1090 #endif
1091 
1092     if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size)
1093 	result = FAIL;
1094 
1095 #ifdef FEAT_CRYPT
1096     if (data != hp->bh_data)
1097 	vim_free(data);
1098 #endif
1099 
1100     return result;
1101 }
1102 
1103 /*
1104  * Make block number for *hp positive and add it to the translation list
1105  *
1106  * Return FAIL for failure, OK otherwise
1107  */
1108     static int
mf_trans_add(memfile_T * mfp,bhdr_T * hp)1109 mf_trans_add(memfile_T *mfp, bhdr_T *hp)
1110 {
1111     bhdr_T	*freep;
1112     blocknr_T	new_bnum;
1113     NR_TRANS	*np;
1114     int		page_count;
1115 
1116     if (hp->bh_bnum >= 0)		    // it's already positive
1117 	return OK;
1118 
1119     if ((np = ALLOC_ONE(NR_TRANS)) == NULL)
1120 	return FAIL;
1121 
1122 /*
1123  * Get a new number for the block.
1124  * If the first item in the free list has sufficient pages, use its number
1125  * Otherwise use mf_blocknr_max.
1126  */
1127     freep = mfp->mf_free_first;
1128     page_count = hp->bh_page_count;
1129     if (freep != NULL && freep->bh_page_count >= page_count)
1130     {
1131 	new_bnum = freep->bh_bnum;
1132 	/*
1133 	 * If the page count of the free block was larger, reduce it.
1134 	 * If the page count matches, remove the block from the free list
1135 	 */
1136 	if (freep->bh_page_count > page_count)
1137 	{
1138 	    freep->bh_bnum += page_count;
1139 	    freep->bh_page_count -= page_count;
1140 	}
1141 	else
1142 	{
1143 	    freep = mf_rem_free(mfp);
1144 	    vim_free(freep);
1145 	}
1146     }
1147     else
1148     {
1149 	new_bnum = mfp->mf_blocknr_max;
1150 	mfp->mf_blocknr_max += page_count;
1151     }
1152 
1153     np->nt_old_bnum = hp->bh_bnum;	    // adjust number
1154     np->nt_new_bnum = new_bnum;
1155 
1156     mf_rem_hash(mfp, hp);		    // remove from old hash list
1157     hp->bh_bnum = new_bnum;
1158     mf_ins_hash(mfp, hp);		    // insert in new hash list
1159 
1160     // Insert "np" into "mf_trans" hashtable with key "np->nt_old_bnum"
1161     mf_hash_add_item(&mfp->mf_trans, (mf_hashitem_T *)np);
1162 
1163     return OK;
1164 }
1165 
1166 /*
1167  * Lookup a translation from the trans lists and delete the entry.
1168  *
1169  * Return the positive new number when found, the old number when not found
1170  */
1171     blocknr_T
mf_trans_del(memfile_T * mfp,blocknr_T old_nr)1172 mf_trans_del(memfile_T *mfp, blocknr_T old_nr)
1173 {
1174     NR_TRANS	*np;
1175     blocknr_T	new_bnum;
1176 
1177     np = (NR_TRANS *)mf_hash_find(&mfp->mf_trans, old_nr);
1178 
1179     if (np == NULL)		// not found
1180 	return old_nr;
1181 
1182     mfp->mf_neg_count--;
1183     new_bnum = np->nt_new_bnum;
1184 
1185     // remove entry from the trans list
1186     mf_hash_rem_item(&mfp->mf_trans, (mf_hashitem_T *)np);
1187 
1188     vim_free(np);
1189 
1190     return new_bnum;
1191 }
1192 
1193 /*
1194  * Set mfp->mf_ffname according to mfp->mf_fname and some other things.
1195  * Only called when creating or renaming the swapfile.	Either way it's a new
1196  * name so we must work out the full path name.
1197  */
1198     void
mf_set_ffname(memfile_T * mfp)1199 mf_set_ffname(memfile_T *mfp)
1200 {
1201     mfp->mf_ffname = FullName_save(mfp->mf_fname, FALSE);
1202 }
1203 
1204 /*
1205  * Make the name of the file used for the memfile a full path.
1206  * Used before doing a :cd
1207  */
1208     void
mf_fullname(memfile_T * mfp)1209 mf_fullname(memfile_T *mfp)
1210 {
1211     if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL)
1212     {
1213 	vim_free(mfp->mf_fname);
1214 	mfp->mf_fname = mfp->mf_ffname;
1215 	mfp->mf_ffname = NULL;
1216     }
1217 }
1218 
1219 /*
1220  * return TRUE if there are any translations pending for 'mfp'
1221  */
1222     int
mf_need_trans(memfile_T * mfp)1223 mf_need_trans(memfile_T *mfp)
1224 {
1225     return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
1226 }
1227 
1228 /*
1229  * Open a swap file for a memfile.
1230  * The "fname" must be in allocated memory, and is consumed (also when an
1231  * error occurs).
1232  */
1233     static void
mf_do_open(memfile_T * mfp,char_u * fname,int flags)1234 mf_do_open(
1235     memfile_T	*mfp,
1236     char_u	*fname,
1237     int		flags)		// flags for open()
1238 {
1239 #ifdef HAVE_LSTAT
1240     stat_T	sb;
1241 #endif
1242 
1243     mfp->mf_fname = fname;
1244 
1245     /*
1246      * Get the full path name before the open, because this is
1247      * not possible after the open on the Amiga.
1248      * fname cannot be NameBuff, because it must have been allocated.
1249      */
1250     mf_set_ffname(mfp);
1251 #if defined(MSWIN)
1252     /*
1253      * A ":!cd e:xxx" may change the directory without us knowing, use the
1254      * full pathname always.  Careful: This frees fname!
1255      */
1256     mf_fullname(mfp);
1257 #endif
1258 
1259 #ifdef HAVE_LSTAT
1260     /*
1261      * Extra security check: When creating a swap file it really shouldn't
1262      * exist yet.  If there is a symbolic link, this is most likely an attack.
1263      */
1264     if ((flags & O_CREAT) && mch_lstat((char *)mfp->mf_fname, &sb) >= 0)
1265     {
1266 	mfp->mf_fd = -1;
1267 	emsg(_("E300: Swap file already exists (symlink attack?)"));
1268     }
1269     else
1270 #endif
1271     {
1272 	/*
1273 	 * try to open the file
1274 	 */
1275 	flags |= O_EXTRA | O_NOFOLLOW;
1276 #ifdef MSWIN
1277 	// Prevent handle inheritance that cause problems with Cscope
1278 	// (swap file may not be deleted if cscope connection was open after
1279 	// the file)
1280 	flags |= O_NOINHERIT;
1281 #endif
1282 	mfp->mf_flags = flags;
1283 	mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, flags);
1284     }
1285 
1286     /*
1287      * If the file cannot be opened, use memory only
1288      */
1289     if (mfp->mf_fd < 0)
1290     {
1291 	VIM_CLEAR(mfp->mf_fname);
1292 	VIM_CLEAR(mfp->mf_ffname);
1293     }
1294     else
1295     {
1296 #ifdef HAVE_FD_CLOEXEC
1297 	int fdflags = fcntl(mfp->mf_fd, F_GETFD);
1298 	if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
1299 	    (void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
1300 #endif
1301 #if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
1302 	mch_copy_sec(fname, mfp->mf_fname);
1303 #endif
1304 	mch_hide(mfp->mf_fname);    // try setting the 'hidden' flag
1305     }
1306 }
1307 
1308 /*
1309  * Implementation of mf_hashtab_T follows.
1310  */
1311 
1312 /*
1313  * The number of buckets in the hashtable is increased by a factor of
1314  * MHT_GROWTH_FACTOR when the average number of items per bucket
1315  * exceeds 2 ^ MHT_LOG_LOAD_FACTOR.
1316  */
1317 #define MHT_LOG_LOAD_FACTOR 6
1318 #define MHT_GROWTH_FACTOR   2   // must be a power of two
1319 
1320 /*
1321  * Initialize an empty hash table.
1322  */
1323     static void
mf_hash_init(mf_hashtab_T * mht)1324 mf_hash_init(mf_hashtab_T *mht)
1325 {
1326     CLEAR_POINTER(mht);
1327     mht->mht_buckets = mht->mht_small_buckets;
1328     mht->mht_mask = MHT_INIT_SIZE - 1;
1329 }
1330 
1331 /*
1332  * Free the array of a hash table.  Does not free the items it contains!
1333  * The hash table must not be used again without another mf_hash_init() call.
1334  */
1335     static void
mf_hash_free(mf_hashtab_T * mht)1336 mf_hash_free(mf_hashtab_T *mht)
1337 {
1338     if (mht->mht_buckets != mht->mht_small_buckets)
1339 	vim_free(mht->mht_buckets);
1340 }
1341 
1342 /*
1343  * Free the array of a hash table and all the items it contains.
1344  */
1345     static void
mf_hash_free_all(mf_hashtab_T * mht)1346 mf_hash_free_all(mf_hashtab_T *mht)
1347 {
1348     long_u	    idx;
1349     mf_hashitem_T   *mhi;
1350     mf_hashitem_T   *next;
1351 
1352     for (idx = 0; idx <= mht->mht_mask; idx++)
1353 	for (mhi = mht->mht_buckets[idx]; mhi != NULL; mhi = next)
1354 	{
1355 	    next = mhi->mhi_next;
1356 	    vim_free(mhi);
1357 	}
1358 
1359     mf_hash_free(mht);
1360 }
1361 
1362 /*
1363  * Find "key" in hashtable "mht".
1364  * Returns a pointer to a mf_hashitem_T or NULL if the item was not found.
1365  */
1366     static mf_hashitem_T *
mf_hash_find(mf_hashtab_T * mht,blocknr_T key)1367 mf_hash_find(mf_hashtab_T *mht, blocknr_T key)
1368 {
1369     mf_hashitem_T   *mhi;
1370 
1371     mhi = mht->mht_buckets[key & mht->mht_mask];
1372     while (mhi != NULL && mhi->mhi_key != key)
1373 	mhi = mhi->mhi_next;
1374 
1375     return mhi;
1376 }
1377 
1378 /*
1379  * Add item "mhi" to hashtable "mht".
1380  * "mhi" must not be NULL.
1381  */
1382     static void
mf_hash_add_item(mf_hashtab_T * mht,mf_hashitem_T * mhi)1383 mf_hash_add_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
1384 {
1385     long_u	    idx;
1386 
1387     idx = mhi->mhi_key & mht->mht_mask;
1388     mhi->mhi_next = mht->mht_buckets[idx];
1389     mhi->mhi_prev = NULL;
1390     if (mhi->mhi_next != NULL)
1391 	mhi->mhi_next->mhi_prev = mhi;
1392     mht->mht_buckets[idx] = mhi;
1393 
1394     mht->mht_count++;
1395 
1396     /*
1397      * Grow hashtable when we have more thank 2^MHT_LOG_LOAD_FACTOR
1398      * items per bucket on average
1399      */
1400     if (mht->mht_fixed == 0
1401 	&& (mht->mht_count >> MHT_LOG_LOAD_FACTOR) > mht->mht_mask)
1402     {
1403 	if (mf_hash_grow(mht) == FAIL)
1404 	{
1405 	    // stop trying to grow after first failure to allocate memory
1406 	    mht->mht_fixed = 1;
1407 	}
1408     }
1409 }
1410 
1411 /*
1412  * Remove item "mhi" from hashtable "mht".
1413  * "mhi" must not be NULL and must have been inserted into "mht".
1414  */
1415     static void
mf_hash_rem_item(mf_hashtab_T * mht,mf_hashitem_T * mhi)1416 mf_hash_rem_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
1417 {
1418     if (mhi->mhi_prev == NULL)
1419 	mht->mht_buckets[mhi->mhi_key & mht->mht_mask] = mhi->mhi_next;
1420     else
1421 	mhi->mhi_prev->mhi_next = mhi->mhi_next;
1422 
1423     if (mhi->mhi_next != NULL)
1424 	mhi->mhi_next->mhi_prev = mhi->mhi_prev;
1425 
1426     mht->mht_count--;
1427 
1428     // We could shrink the table here, but it typically takes little memory,
1429     // so why bother?
1430 }
1431 
1432 /*
1433  * Increase number of buckets in the hashtable by MHT_GROWTH_FACTOR and
1434  * rehash items.
1435  * Returns FAIL when out of memory.
1436  */
1437     static int
mf_hash_grow(mf_hashtab_T * mht)1438 mf_hash_grow(mf_hashtab_T *mht)
1439 {
1440     long_u	    i, j;
1441     int		    shift;
1442     mf_hashitem_T   *mhi;
1443     mf_hashitem_T   *tails[MHT_GROWTH_FACTOR];
1444     mf_hashitem_T   **buckets;
1445     size_t	    size;
1446 
1447     size = (mht->mht_mask + 1) * MHT_GROWTH_FACTOR * sizeof(void *);
1448     buckets = lalloc_clear(size, FALSE);
1449     if (buckets == NULL)
1450 	return FAIL;
1451 
1452     shift = 0;
1453     while ((mht->mht_mask >> shift) != 0)
1454 	shift++;
1455 
1456     for (i = 0; i <= mht->mht_mask; i++)
1457     {
1458 	/*
1459 	 * Traverse the items in the i-th original bucket and move them into
1460 	 * MHT_GROWTH_FACTOR new buckets, preserving their relative order
1461 	 * within each new bucket.  Preserving the order is important because
1462 	 * mf_get() tries to keep most recently used items at the front of
1463 	 * each bucket.
1464 	 *
1465 	 * Here we strongly rely on the fact the hashes are computed modulo
1466 	 * a power of two.
1467 	 */
1468 
1469 	CLEAR_FIELD(tails);
1470 
1471 	for (mhi = mht->mht_buckets[i]; mhi != NULL; mhi = mhi->mhi_next)
1472 	{
1473 	    j = (mhi->mhi_key >> shift) & (MHT_GROWTH_FACTOR - 1);
1474 	    if (tails[j] == NULL)
1475 	    {
1476 		buckets[i + (j << shift)] = mhi;
1477 		tails[j] = mhi;
1478 		mhi->mhi_prev = NULL;
1479 	    }
1480 	    else
1481 	    {
1482 		tails[j]->mhi_next = mhi;
1483 		mhi->mhi_prev = tails[j];
1484 		tails[j] = mhi;
1485 	    }
1486 	}
1487 
1488 	for (j = 0; j < MHT_GROWTH_FACTOR; j++)
1489 	    if (tails[j] != NULL)
1490 		tails[j]->mhi_next = NULL;
1491     }
1492 
1493     if (mht->mht_buckets != mht->mht_small_buckets)
1494 	vim_free(mht->mht_buckets);
1495 
1496     mht->mht_buckets = buckets;
1497     mht->mht_mask = (mht->mht_mask + 1) * MHT_GROWTH_FACTOR - 1;
1498 
1499     return OK;
1500 }
1501