Annotation of src/usr.bin/vim/memfile.c, Revision 1.1.1.1
1.1 downsj 1: /* $OpenBSD$ */
2: /* vi:set ts=4 sw=4:
3: *
4: * VIM - Vi IMproved by Bram Moolenaar
5: *
6: * Do ":help uganda" in Vim to read copying and usage conditions.
7: * Do ":help credits" in Vim to see a list of people who contributed.
8: */
9:
10: /* for debugging */
11: #define CHECK(c, s) if (c) printf(s)
12:
13: /*
14: * memfile.c: Contains the functions for handling blocks of memory which can
15: * be stored in a file. This is the implementation of a sort of virtual memory.
16: *
17: * A memfile consists of a sequence of blocks. The blocks numbered from 0
18: * upwards have been assigned a place in the actual file. The block number
19: * is equal to the page number in the file. The
20: * blocks with negative numbers are currently in memory only. They can be
21: * assigned a place in the file when too much memory is being used. At that
22: * moment they get a new, positive, number. A list is used for translation of
23: * negative to positive numbers.
24: *
25: * The size of a block is a multiple of a page size, normally the page size of
26: * the device the file is on. Most blocks are 1 page long. A Block of multiple
27: * pages is used for a line that does not fit in a single page.
28: *
29: * Each block can be in memory and/or in a file. The block stays in memory
30: * as long as it is locked. If it is no longer locked it can be swapped out to
31: * the file. It is only written to the file if it has been changed.
32: *
33: * Under normal operation the file is created when opening the memory file and
34: * deleted when closing the memory file. Only with recovery an existing memory
35: * file is opened.
36: */
37:
38: #if defined MSDOS || defined WIN32
39: # include <io.h> /* for lseek(), must be before vim.h */
40: #endif
41:
42: #include "vim.h"
43: #include "globals.h"
44: #include "proto.h"
45: #include "option.h"
46: #ifdef HAVE_FCNTL_H
47: # include <fcntl.h>
48: #endif
49:
50: /*
51: * Some systems have the page size in statfs, some in stat
52: */
53: #ifdef HAVE_SYS_STATFS_H
54: # include <sys/statfs.h>
55: # define STATFS statfs
56: # define F_BSIZE f_bsize
57: # ifdef MINT
58: # define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
59: # endif
60: #else
61: # define STATFS stat
62: # define F_BSIZE st_blksize
63: # define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
64: #endif
65:
66: /*
67: * for Amiga Dos 2.0x we use Flush
68: */
69: #ifdef AMIGA
70: # ifndef NO_ARP
71: extern int dos2; /* this is in amiga.c */
72: # endif
73: # ifdef SASC
74: # include <proto/dos.h>
75: # include <ios1.h> /* for chkufb() */
76: # endif
77: #endif
78:
79: #define MEMFILE_PAGE_SIZE 4096 /* default page size */
80:
81: static long total_mem_used = 0; /* total memory used for memfiles */
82:
83: static void mf_ins_hash __ARGS((MEMFILE *, BHDR *));
84: static void mf_rem_hash __ARGS((MEMFILE *, BHDR *));
85: static BHDR *mf_find_hash __ARGS((MEMFILE *, blocknr_t));
86: static void mf_ins_used __ARGS((MEMFILE *, BHDR *));
87: static void mf_rem_used __ARGS((MEMFILE *, BHDR *));
88: static BHDR *mf_release __ARGS((MEMFILE *, int));
89: static BHDR *mf_alloc_bhdr __ARGS((MEMFILE *, int));
90: static void mf_free_bhdr __ARGS((BHDR *));
91: static void mf_ins_free __ARGS((MEMFILE *, BHDR *));
92: static BHDR *mf_rem_free __ARGS((MEMFILE *));
93: static int mf_read __ARGS((MEMFILE *, BHDR *));
94: static int mf_write __ARGS((MEMFILE *, BHDR *));
95: static int mf_trans_add __ARGS((MEMFILE *, BHDR *));
96: static void mf_do_open __ARGS((MEMFILE *, char_u *, int));
97:
98: /*
99: * The functions for using a memfile:
100: *
101: * mf_open() open a new or existing memfile
102: * mf_open_file() open a swap file for an existing memfile
103: * mf_close() close (and delete) a memfile
104: * mf_new() create a new block in a memfile and lock it
105: * mf_get() get an existing block and lock it
106: * mf_put() unlock a block, may be marked for writing
107: * mf_free() remove a block
108: * mf_sync() sync changed parts of memfile to disk
109: * mf_release_all() release as much memory as possible
110: * mf_trans_del() may translate negative to positive block number
111: * mf_fullname() make file name full path (use before first :cd)
112: */
113:
114: /*
115: * mf_open: open an existing or new memory block file
116: *
117: * fname: name of file to use (NULL means no file at all)
118: * Note: fname must have been allocated, it is not copied!
119: * If opening the file fails, fname is NOT freed.
120: * trunc_file: if TRUE: file should be truncated when opening
121: *
122: * If fname != NULL and file cannot be opened, fail.
123: *
124: * return value: identifier for this memory block file.
125: */
126: MEMFILE *
127: mf_open(fname, trunc_file)
128: char_u *fname;
129: int trunc_file;
130: {
131: MEMFILE *mfp;
132: int i;
133: long size;
134: #ifdef UNIX
135: struct STATFS stf;
136: #endif
137:
138: if ((mfp = (MEMFILE *)alloc((unsigned)sizeof(MEMFILE))) == NULL)
139: return NULL;
140:
141: if (fname == NULL) /* no file for this memfile, use memory only */
142: {
143: mfp->mf_fname = NULL;
144: mfp->mf_xfname = NULL;
145: mfp->mf_fd = -1;
146: }
147: else
148: {
149: mf_do_open(mfp, fname, trunc_file); /* try to open the file */
150:
151: /* if the file cannot be opened, return here */
152: if (mfp->mf_fd < 0)
153: {
154: vim_free(mfp);
155: return NULL;
156: }
157: }
158:
159: mfp->mf_free_first = NULL; /* free list is empty */
160: mfp->mf_used_first = NULL; /* used list is empty */
161: mfp->mf_used_last = NULL;
162: mfp->mf_dirty = FALSE;
163: mfp->mf_used_count = 0;
164: for (i = 0; i < MEMHASHSIZE; ++i)
165: {
166: mfp->mf_hash[i] = NULL; /* hash lists are empty */
167: mfp->mf_trans[i] = NULL; /* trans lists are empty */
168: }
169: mfp->mf_page_size = MEMFILE_PAGE_SIZE;
170:
171: #ifdef UNIX
172: /*
173: * Try to set the page size equal to the block size of the device.
174: * Speeds up I/O a lot.
175: * NOTE: minimal block size depends on size of block 0 data! It's not done
176: * with a sizeof(), because block 0 is defined in memline.c (Sorry).
177: * The maximal block size is arbitrary.
178: */
179: if (mfp->mf_fd >= 0 &&
180: fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 &&
181: stf.F_BSIZE >= 1048 && stf.F_BSIZE <= 50000)
182: mfp->mf_page_size = stf.F_BSIZE;
183: #endif
184:
185: if (mfp->mf_fd < 0 || trunc_file ||
186: (size = lseek(mfp->mf_fd, 0L, SEEK_END)) <= 0)
187: mfp->mf_blocknr_max = 0; /* no file or empty file */
188: else
189: mfp->mf_blocknr_max = size / mfp->mf_page_size;
190: mfp->mf_blocknr_min = -1;
191: mfp->mf_neg_count = 0;
192: mfp->mf_infile_count = mfp->mf_blocknr_max;
193: if (mfp->mf_fd < 0)
194: mfp->mf_used_count_max = 0; /* no limit */
195: else
196: mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
197:
198: return mfp;
199: }
200:
201: /*
202: * mf_open_file: open a file for an existing memfile. Used when updatecount
203: * set from 0 to some value.
204: *
205: * fname: name of file to use (NULL means no file at all)
206: * Note: fname must have been allocated, it is not copied!
207: * If opening the file fails, fname is NOT freed.
208: *
209: * return value: FAIL if file could not be opened, OK otherwise
210: */
211: int
212: mf_open_file(mfp, fname)
213: MEMFILE *mfp;
214: char_u *fname;
215: {
216: mf_do_open(mfp, fname, TRUE); /* try to open the file */
217:
218: if (mfp->mf_fd < 0)
219: return FAIL;
220:
221: mfp->mf_dirty = TRUE;
222: return OK;
223: }
224:
225: /*
226: * close a memory file and delete the associated file if 'del_file' is TRUE
227: */
228: void
229: mf_close(mfp, del_file)
230: MEMFILE *mfp;
231: int del_file;
232: {
233: BHDR *hp, *nextp;
234: NR_TRANS *tp, *tpnext;
235: int i;
236:
237: if (mfp == NULL) /* safety check */
238: return;
239: if (mfp->mf_fd >= 0)
240: {
241: if (close(mfp->mf_fd) < 0)
242: EMSG("Close error on swap file");
243: }
244: if (del_file && mfp->mf_fname != NULL)
245: vim_remove(mfp->mf_fname);
246: /* free entries in used list */
247: for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
248: {
249: total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
250: nextp = hp->bh_next;
251: mf_free_bhdr(hp);
252: }
253: while (mfp->mf_free_first != NULL) /* free entries in free list */
254: vim_free(mf_rem_free(mfp));
255: for (i = 0; i < MEMHASHSIZE; ++i) /* free entries in trans lists */
256: for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
257: {
258: tpnext = tp->nt_next;
259: vim_free(tp);
260: }
261: vim_free(mfp->mf_fname);
262: vim_free(mfp->mf_xfname);
263: vim_free(mfp);
264: }
265:
266: /*
267: * get a new block
268: *
269: * negative: TRUE if negative block number desired (data block)
270: */
271: BHDR *
272: mf_new(mfp, negative, page_count)
273: MEMFILE *mfp;
274: int negative;
275: int page_count;
276: {
277: BHDR *hp; /* new BHDR */
278: BHDR *freep; /* first block in free list */
279: char_u *p;
280:
281: /*
282: * If we reached the maximum size for the used memory blocks, release one
283: * If a BHDR is returned, use it and adjust the page_count if necessary.
284: */
285: hp = mf_release(mfp, page_count);
286:
287: /*
288: * Decide on the number to use:
289: * If there is a free block, use its number.
290: * Otherwise use mf_block_min for a negative number, mf_block_max for
291: * a positive number.
292: */
293: freep = mfp->mf_free_first;
294: if (!negative && freep != NULL && freep->bh_page_count >= page_count)
295: {
296: /*
297: * If the block in the free list has more pages, take only the number
298: * of pages needed and allocate a new BHDR with data
299: *
300: * If the number of pages matches and mf_release did not return a BHDR,
301: * use the BHDR from the free list and allocate the data
302: *
303: * If the number of pages matches and mf_release returned a BHDR,
304: * just use the number and free the BHDR from the free list
305: */
306: if (freep->bh_page_count > page_count)
307: {
308: if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
309: return NULL;
310: hp->bh_bnum = freep->bh_bnum;
311: freep->bh_bnum += page_count;
312: freep->bh_page_count -= page_count;
313: }
314: else if (hp == NULL) /* need to allocate memory for this block */
315: {
316: if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
317: return NULL;
318: hp = mf_rem_free(mfp);
319: hp->bh_data = p;
320: }
321: else /* use the number, remove entry from free list */
322: {
323: freep = mf_rem_free(mfp);
324: hp->bh_bnum = freep->bh_bnum;
325: vim_free(freep);
326: }
327: }
328: else /* get a new number */
329: {
330: if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
331: return NULL;
332: if (negative)
333: {
334: hp->bh_bnum = mfp->mf_blocknr_min--;
335: mfp->mf_neg_count++;
336: }
337: else
338: {
339: hp->bh_bnum = mfp->mf_blocknr_max;
340: mfp->mf_blocknr_max += page_count;
341: }
342: }
343: hp->bh_flags = BH_LOCKED | BH_DIRTY; /* new block is always dirty */
344: mfp->mf_dirty = TRUE;
345: hp->bh_page_count = page_count;
346: mf_ins_used(mfp, hp);
347: mf_ins_hash(mfp, hp);
348:
349: return hp;
350: }
351:
352: /*
353: * get existing block 'nr' with 'page_count' pages
354: *
355: * Note: The caller should first check a negative nr with mf_trans_del()
356: */
357: BHDR *
358: mf_get(mfp, nr, page_count)
359: MEMFILE *mfp;
360: blocknr_t nr;
361: int page_count;
362: {
363: BHDR *hp;
364: /* doesn't exist */
365: if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
366: return NULL;
367:
368: /*
369: * see if it is in the cache
370: */
371: hp = mf_find_hash(mfp, nr);
372: if (hp == NULL) /* not in the hash list */
373: {
374: if (nr < 0 || nr >= mfp->mf_infile_count) /* can't be in the file */
375: return NULL;
376:
377: /* could check here if the block is in the free list */
378:
379: /*
380: * Check if we need to flush an existing block.
381: * If so, use that block.
382: * If not, allocate a new block.
383: */
384: hp = mf_release(mfp, page_count);
385: if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
386: return NULL;
387:
388: hp->bh_bnum = nr;
389: hp->bh_flags = 0;
390: hp->bh_page_count = page_count;
391: if (mf_read(mfp, hp) == FAIL) /* cannot read the block! */
392: {
393: mf_free_bhdr(hp);
394: return NULL;
395: }
396: }
397: else
398: {
399: mf_rem_used(mfp, hp); /* remove from list, insert in front below */
400: mf_rem_hash(mfp, hp);
401: }
402:
403: hp->bh_flags |= BH_LOCKED;
404: mf_ins_used(mfp, hp); /* put in front of used list */
405: mf_ins_hash(mfp, hp); /* put in front of hash list */
406:
407: return hp;
408: }
409:
410: /*
411: * release the block *hp
412: *
413: * dirty: Block must be written to file later
414: * infile: Block should be in file (needed for recovery)
415: *
416: * no return value, function cannot fail
417: */
418: void
419: mf_put(mfp, hp, dirty, infile)
420: MEMFILE *mfp;
421: BHDR *hp;
422: int dirty;
423: int infile;
424: {
425: int flags;
426:
427: flags = hp->bh_flags;
428: CHECK((flags & BH_LOCKED) == 0, "block was not locked");
429: flags &= ~BH_LOCKED;
430: if (dirty)
431: {
432: flags |= BH_DIRTY;
433: mfp->mf_dirty = TRUE;
434: }
435: hp->bh_flags = flags;
436: if (infile)
437: mf_trans_add(mfp, hp); /* may translate negative in positive nr */
438: }
439:
440: /*
441: * block *hp is no longer in used, may put it in the free list of memfile *mfp
442: */
443: void
444: mf_free(mfp, hp)
445: MEMFILE *mfp;
446: BHDR *hp;
447: {
448: vim_free(hp->bh_data); /* free the memory */
449: mf_rem_hash(mfp, hp); /* get *hp out of the hash list */
450: mf_rem_used(mfp, hp); /* get *hp out of the used list */
451: if (hp->bh_bnum < 0)
452: {
453: vim_free(hp); /* don't want negative numbers in free list */
454: mfp->mf_neg_count--;
455: }
456: else
457: mf_ins_free(mfp, hp); /* put *hp in the free list */
458: }
459:
460: /*
461: * sync the memory file *mfp to disk
462: * if 'all' is FALSE blocks with negative numbers are not synced, even when
463: * they are dirty!
464: * if 'check_char' is TRUE, stop syncing when a character becomes available,
465: * but sync at least one block.
466: * if 'do_fsync' is TRUE make sure buffers are flushed to disk, so they will
467: * survive a system crash.
468: *
469: * Return FAIL for failure, OK otherwise
470: */
471: int
472: mf_sync(mfp, all, check_char, do_fsync)
473: MEMFILE *mfp;
474: int all;
475: int check_char;
476: int do_fsync;
477: {
478: int status;
479: BHDR *hp;
480: #ifdef SYNC_DUP_CLOSE
481: int fd;
482: #endif
483:
484: if (mfp->mf_fd < 0) /* there is no file, nothing to do */
485: {
486: mfp->mf_dirty = FALSE;
487: return FAIL;
488: }
489:
490: /*
491: * sync from last to first (may reduce the probability of an inconsistent
492: * file) If a write fails, it is very likely caused by a full filesystem.
493: * Then we only try to write blocks within the existing file. If that also
494: * fails then we give up.
495: */
496: status = OK;
497: for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
498: if ((all || hp->bh_bnum >= 0) && (hp->bh_flags & BH_DIRTY) &&
499: (status == OK || (hp->bh_bnum >= 0 &&
500: hp->bh_bnum < mfp->mf_infile_count)))
501: {
502: if (mf_write(mfp, hp) == FAIL)
503: {
504: if (status == FAIL) /* double error: quit syncing */
505: break;
506: status = FAIL;
507: }
508: if (check_char && mch_char_avail()) /* char available now */
509: break;
510: }
511:
512: /*
513: * If the whole list is flushed, the memfile is not dirty anymore.
514: * In case of an error this flag is also set, to avoid trying all the time.
515: */
516: if (hp == NULL || status == FAIL)
517: mfp->mf_dirty = FALSE;
518:
519: if (do_fsync && *p_sws != NUL)
520: {
521: #if defined(UNIX)
522: # ifdef HAVE_FSYNC
523: /*
524: * most Unixes have the very useful fsync() function, just what we need.
525: * However, with OS/2 and EMX it is also available, but there are
526: * reports of bad problems with it (a bug in HPFS.IFS).
527: * So we disable use of it here in case someone tries to be smart
528: * and changes conf_os2.h... (even though there is no __EMX__ test
529: * in the #if, as __EMX__ does not have sync(); we hope for a timely
530: * sync from the system itself).
531: */
532: # if defined(__EMX__)
533: error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
534: # endif
535: if (STRCMP(p_sws, "fsync") == 0)
536: {
537: if (fsync(mfp->mf_fd))
538: status = FAIL;
539: }
540: else
541: # endif
542: sync();
543: #endif
544: #ifdef DJGPP
545: if (_dos_commit(mfp->mf_fd))
546: status = FAIL;
547: #else
548: # ifdef SYNC_DUP_CLOSE
549: /*
550: * MSdos is a bit more work: Duplicate the file handle and close it.
551: * This should flush the file to disk.
552: */
553: if ((fd = dup(mfp->mf_fd)) >= 0)
554: close(fd);
555: # endif
556: #endif
557: #ifdef AMIGA
558: /*
559: * Flush() only exists for AmigaDos 2.0.
560: * For 1.3 it should be done with close() + open(), but then the risk
561: * is that the open() may fail and lose the file....
562: */
563: # ifndef NO_ARP
564: if (dos2)
565: # endif
566: # ifdef SASC
567: {
568: struct UFB *fp = chkufb(mfp->mf_fd);
569:
570: if (fp != NULL)
571: Flush(fp->ufbfh);
572: }
573: # else
574: # ifdef _DCC
575: {
576: BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
577:
578: if (fh != 0)
579: Flush(fh);
580: }
581: # else /* assume Manx */
582: Flush(_devtab[mfp->mf_fd].fd);
583: # endif
584: # endif
585: #endif /* AMIGA */
586: }
587:
588: return status;
589: }
590:
591: /*
592: * insert block *hp in front of hashlist of memfile *mfp
593: */
594: static void
595: mf_ins_hash(mfp, hp)
596: MEMFILE *mfp;
597: BHDR *hp;
598: {
599: BHDR *hhp;
600: int hash;
601:
602: hash = MEMHASH(hp->bh_bnum);
603: hhp = mfp->mf_hash[hash];
604: hp->bh_hash_next = hhp;
605: hp->bh_hash_prev = NULL;
606: if (hhp != NULL)
607: hhp->bh_hash_prev = hp;
608: mfp->mf_hash[hash] = hp;
609: }
610:
611: /*
612: * remove block *hp from hashlist of memfile list *mfp
613: */
614: static void
615: mf_rem_hash(mfp, hp)
616: MEMFILE *mfp;
617: BHDR *hp;
618: {
619: if (hp->bh_hash_prev == NULL)
620: mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
621: else
622: hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
623:
624: if (hp->bh_hash_next)
625: hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
626: }
627:
628: /*
629: * look in hash lists of memfile *mfp for block header with number 'nr'
630: */
631: static BHDR *
632: mf_find_hash(mfp, nr)
633: MEMFILE *mfp;
634: blocknr_t nr;
635: {
636: BHDR *hp;
637:
638: for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
639: if (hp->bh_bnum == nr)
640: break;
641: return hp;
642: }
643:
644: /*
645: * insert block *hp in front of used list of memfile *mfp
646: */
647: static void
648: mf_ins_used(mfp, hp)
649: MEMFILE *mfp;
650: BHDR *hp;
651: {
652: hp->bh_next = mfp->mf_used_first;
653: mfp->mf_used_first = hp;
654: hp->bh_prev = NULL;
655: if (hp->bh_next == NULL) /* list was empty, adjust last pointer */
656: mfp->mf_used_last = hp;
657: else
658: hp->bh_next->bh_prev = hp;
659: mfp->mf_used_count += hp->bh_page_count;
660: total_mem_used += hp->bh_page_count * mfp->mf_page_size;
661: }
662:
663: /*
664: * remove block *hp from used list of memfile *mfp
665: */
666: static void
667: mf_rem_used(mfp, hp)
668: MEMFILE *mfp;
669: BHDR *hp;
670: {
671: if (hp->bh_next == NULL) /* last block in used list */
672: mfp->mf_used_last = hp->bh_prev;
673: else
674: hp->bh_next->bh_prev = hp->bh_prev;
675: if (hp->bh_prev == NULL) /* first block in used list */
676: mfp->mf_used_first = hp->bh_next;
677: else
678: hp->bh_prev->bh_next = hp->bh_next;
679: mfp->mf_used_count -= hp->bh_page_count;
680: total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
681: }
682:
683: /*
684: * Release the least recently used block from the used list if the number
685: * of used memory blocks gets to big.
686: *
687: * Return the block header to the caller, including the memory block, so
688: * it can be re-used. Make sure the page_count is right.
689: */
690: static BHDR *
691: mf_release(mfp, page_count)
692: MEMFILE *mfp;
693: int page_count;
694: {
695: BHDR *hp;
696:
697: /*
698: * don't release a block if
699: * there is no file for this memfile
700: * or
701: * there is no limit to the number of blocks for this memfile or
702: * the maximum is not reached yet
703: * and
704: * total memory used is not up to 'maxmemtot'
705: */
706: if (mfp->mf_fd < 0 || ((mfp->mf_used_count < mfp->mf_used_count_max ||
707: mfp->mf_used_count_max == 0) &&
708: (total_mem_used >> 10) < p_mmt))
709: return NULL;
710:
711: for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
712: if (!(hp->bh_flags & BH_LOCKED))
713: break;
714: if (hp == NULL) /* not a single one that can be released */
715: return NULL;
716:
717: /*
718: * If the block is dirty, write it.
719: * If the write fails we don't free it.
720: */
721: if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
722: return NULL;
723:
724: mf_rem_used(mfp, hp);
725: mf_rem_hash(mfp, hp);
726:
727: /*
728: * If a BHDR is returned, make sure that the page_count of bh_data is right
729: */
730: if (hp->bh_page_count != page_count)
731: {
732: vim_free(hp->bh_data);
733: if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
734: {
735: vim_free(hp);
736: return NULL;
737: }
738: hp->bh_page_count = page_count;
739: }
740: return hp;
741: }
742:
743: /*
744: * release as many blocks as possible
745: * Used in case of out of memory
746: *
747: * return TRUE if any memory was released
748: */
749: int
750: mf_release_all()
751: {
752: BUF *buf;
753: MEMFILE *mfp;
754: BHDR *hp;
755: int retval = FALSE;
756:
757: for (buf = firstbuf; buf != NULL; buf = buf->b_next)
758: {
759: mfp = buf->b_ml.ml_mfp;
760: if (mfp != NULL && mfp->mf_fd >= 0) /* only if there is a memfile with a file */
761: for (hp = mfp->mf_used_last; hp != NULL; )
762: {
763: if (!(hp->bh_flags & BH_LOCKED) &&
764: (!(hp->bh_flags & BH_DIRTY) || mf_write(mfp, hp) != FAIL))
765: {
766: mf_rem_used(mfp, hp);
767: mf_rem_hash(mfp, hp);
768: mf_free_bhdr(hp);
769: hp = mfp->mf_used_last; /* re-start, list was changed */
770: retval = TRUE;
771: }
772: else
773: hp = hp->bh_prev;
774: }
775: }
776: return retval;
777: }
778:
779: /*
780: * Allocate a block header and a block of memory for it
781: */
782: static BHDR *
783: mf_alloc_bhdr(mfp, page_count)
784: MEMFILE *mfp;
785: int page_count;
786: {
787: BHDR *hp;
788:
789: if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
790: {
791: if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
792: == NULL)
793: {
794: vim_free(hp); /* not enough memory */
795: return NULL;
796: }
797: hp->bh_page_count = page_count;
798: }
799: return hp;
800: }
801:
802: /*
803: * Free a block header and the block of memory for it
804: */
805: static void
806: mf_free_bhdr(hp)
807: BHDR *hp;
808: {
809: vim_free(hp->bh_data);
810: vim_free(hp);
811: }
812:
813: /*
814: * insert entry *hp in the free list
815: */
816: static void
817: mf_ins_free(mfp, hp)
818: MEMFILE *mfp;
819: BHDR *hp;
820: {
821: hp->bh_next = mfp->mf_free_first;
822: mfp->mf_free_first = hp;
823: }
824:
825: /*
826: * remove the first entry from the free list and return a pointer to it
827: * Note: caller must check that mfp->mf_free_first is not NULL!
828: */
829: static BHDR *
830: mf_rem_free(mfp)
831: MEMFILE *mfp;
832: {
833: BHDR *hp;
834:
835: hp = mfp->mf_free_first;
836: mfp->mf_free_first = hp->bh_next;
837: return hp;
838: }
839:
840: /*
841: * read a block from disk
842: *
843: * Return FAIL for failure, OK otherwise
844: */
845: static int
846: mf_read(mfp, hp)
847: MEMFILE *mfp;
848: BHDR *hp;
849: {
850: long_u offset;
851: unsigned page_size;
852: unsigned size;
853:
854: if (mfp->mf_fd < 0) /* there is no file, can't read */
855: return FAIL;
856:
857: page_size = mfp->mf_page_size;
858: offset = page_size * hp->bh_bnum;
859: size = page_size * hp->bh_page_count;
860: if ((long_u)lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
861: {
862: EMSG("Seek error in swap file read");
863: return FAIL;
864: }
865: if ((unsigned)read(mfp->mf_fd, (char *)hp->bh_data, (size_t)size) != size)
866: {
867: EMSG("Read error in swap file");
868: return FAIL;
869: }
870: return OK;
871: }
872:
873: /*
874: * write a block to disk
875: *
876: * Return FAIL for failure, OK otherwise
877: */
878: static int
879: mf_write(mfp, hp)
880: MEMFILE *mfp;
881: BHDR *hp;
882: {
883: long_u offset; /* offset in the file */
884: blocknr_t nr; /* block nr which is being written */
885: BHDR *hp2;
886: unsigned page_size; /* number of bytes in a page */
887: unsigned page_count; /* number of pages written */
888: unsigned size; /* number of bytes written */
889:
890: if (mfp->mf_fd < 0) /* there is no file, can't write */
891: return FAIL;
892:
893: if (hp->bh_bnum < 0) /* must assign file block number */
894: if (mf_trans_add(mfp, hp) == FAIL)
895: return FAIL;
896:
897: page_size = mfp->mf_page_size;
898:
899: /*
900: * We don't want gaps in the file. Write the blocks in front of *hp
901: * to extend the file.
902: * If block 'mf_infile_count' is not in the hash list, it has been
903: * freed. Fill the space in the file with data from the current block.
904: */
905: for (;;)
906: {
907: nr = hp->bh_bnum;
908: if (nr > mfp->mf_infile_count) /* beyond end of file */
909: {
910: nr = mfp->mf_infile_count;
911: hp2 = mf_find_hash(mfp, nr); /* NULL catched below */
912: }
913: else
914: hp2 = hp;
915:
916: offset = page_size * nr;
917: if ((long_u)lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
918: {
919: EMSG("Seek error in swap file write");
920: return FAIL;
921: }
922: if (hp2 == NULL) /* freed block, fill with dummy data */
923: page_count = 1;
924: else
925: page_count = hp2->bh_page_count;
926: size = page_size * page_count;
927: if ((unsigned)write(mfp->mf_fd,
928: (char *)(hp2 == NULL ? hp : hp2)->bh_data, (size_t)size) != size)
929: {
930: /*
931: * Avoid repeating the error message, this mostly happens when the
932: * disk is full. We give the message again only after a succesful
933: * write or when hitting a key. We keep on trying, in case some
934: * space becomes available.
935: */
936: if (!did_swapwrite_msg)
937: EMSG("Write error in swap file");
938: did_swapwrite_msg = TRUE;
939: return FAIL;
940: }
941: did_swapwrite_msg = FALSE;
942: if (hp2 != NULL) /* written a non-dummy block */
943: hp2->bh_flags &= ~BH_DIRTY;
944: /* appended to the file */
945: if (nr + (blocknr_t)page_count > mfp->mf_infile_count)
946: mfp->mf_infile_count = nr + page_count;
947: if (nr == hp->bh_bnum) /* written the desired block */
948: break;
949: }
950: return OK;
951: }
952:
953: /*
954: * Make block number for *hp positive and add it to the translation list
955: *
956: * Return FAIL for failure, OK otherwise
957: */
958: static int
959: mf_trans_add(mfp, hp)
960: MEMFILE *mfp;
961: BHDR *hp;
962: {
963: BHDR *freep;
964: blocknr_t new_bnum;
965: int hash;
966: NR_TRANS *np;
967: int page_count;
968:
969: if (hp->bh_bnum >= 0) /* it's already positive */
970: return OK;
971:
972: if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
973: return FAIL;
974:
975: /*
976: * get a new number for the block.
977: * If the first item in the free list has sufficient pages, use its number
978: * Otherwise use mf_blocknr_max.
979: */
980: freep = mfp->mf_free_first;
981: page_count = hp->bh_page_count;
982: if (freep != NULL && freep->bh_page_count >= page_count)
983: {
984: new_bnum = freep->bh_bnum;
985: /*
986: * If the page count of the free block was larger, recude it.
987: * If the page count matches, remove the block from the free list
988: */
989: if (freep->bh_page_count > page_count)
990: {
991: freep->bh_bnum += page_count;
992: freep->bh_page_count -= page_count;
993: }
994: else
995: {
996: freep = mf_rem_free(mfp);
997: vim_free(freep);
998: }
999: }
1000: else
1001: {
1002: new_bnum = mfp->mf_blocknr_max;
1003: mfp->mf_blocknr_max += page_count;
1004: }
1005:
1006: np->nt_old_bnum = hp->bh_bnum; /* adjust number */
1007: np->nt_new_bnum = new_bnum;
1008:
1009: mf_rem_hash(mfp, hp); /* remove from old hash list */
1010: hp->bh_bnum = new_bnum;
1011: mf_ins_hash(mfp, hp); /* insert in new hash list */
1012:
1013: hash = MEMHASH(np->nt_old_bnum); /* insert in trans list */
1014: np->nt_next = mfp->mf_trans[hash];
1015: mfp->mf_trans[hash] = np;
1016: if (np->nt_next != NULL)
1017: np->nt_next->nt_prev = np;
1018: np->nt_prev = NULL;
1019:
1020: return OK;
1021: }
1022:
1023: /*
1024: * Lookup a tranlation from the trans lists and delete the entry
1025: *
1026: * Return the positive new number when found, the old number when not found
1027: */
1028: blocknr_t
1029: mf_trans_del(mfp, old_nr)
1030: MEMFILE *mfp;
1031: blocknr_t old_nr;
1032: {
1033: int hash;
1034: NR_TRANS *np;
1035: blocknr_t new_bnum;
1036:
1037: hash = MEMHASH(old_nr);
1038: for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
1039: if (np->nt_old_bnum == old_nr)
1040: break;
1041: if (np == NULL) /* not found */
1042: return old_nr;
1043:
1044: mfp->mf_neg_count--;
1045: new_bnum = np->nt_new_bnum;
1046: if (np->nt_prev != NULL) /* remove entry from the trans list */
1047: np->nt_prev->nt_next = np->nt_next;
1048: else
1049: mfp->mf_trans[hash] = np->nt_next;
1050: if (np->nt_next != NULL)
1051: np->nt_next->nt_prev = np->nt_prev;
1052: vim_free(np);
1053:
1054: return new_bnum;
1055: }
1056:
1057: /*
1058: * Set mfp->mf_xfname according to mfp->mf_fname and some other things.
1059: * Don't get the full path name if did_cd is TRUE, then fname should
1060: * already be a full path name.
1061: */
1062: void
1063: mf_set_xfname(mfp)
1064: MEMFILE *mfp;
1065: {
1066: mfp->mf_xfname = NULL;
1067: if (!did_cd)
1068: mfp->mf_xfname = FullName_save(mfp->mf_fname);
1069: }
1070:
1071: /*
1072: * Make the name of the file used for the memfile a full path.
1073: * Used before doing a :cd
1074: */
1075: void
1076: mf_fullname(mfp)
1077: MEMFILE *mfp;
1078: {
1079: if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_xfname != NULL)
1080: {
1081: vim_free(mfp->mf_fname);
1082: mfp->mf_fname = mfp->mf_xfname;
1083: mfp->mf_xfname = NULL;
1084: }
1085: }
1086:
1087: /*
1088: * return TRUE if there are any translations pending for 'mfp'
1089: */
1090: int
1091: mf_need_trans(mfp)
1092: MEMFILE *mfp;
1093: {
1094: return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
1095: }
1096:
1097: #if 1 /* included for beta release, TODO: remove later */
1098: /*
1099: * print statistics for a memfile (for debugging)
1100: */
1101: void
1102: mf_statistics()
1103: {
1104: MEMFILE *mfp;
1105: BHDR *hp;
1106: int used = 0;
1107: int locked = 0;
1108: int dirty = 0;
1109: int nfree = 0;
1110: int negative = 0;
1111:
1112: mfp = curbuf->b_ml.ml_mfp;
1113: if (mfp == NULL)
1114: MSG("No memfile");
1115: else
1116: {
1117: for (hp = mfp->mf_used_first; hp != NULL; hp = hp->bh_next)
1118: {
1119: ++used;
1120: if (hp->bh_flags & BH_LOCKED)
1121: ++locked;
1122: if (hp->bh_flags & BH_DIRTY)
1123: ++dirty;
1124: if (hp->bh_bnum < 0)
1125: ++negative;
1126: }
1127: for (hp = mfp->mf_free_first; hp != NULL; hp = hp->bh_next)
1128: ++nfree;
1129: sprintf((char *)IObuff, "%d used (%d locked, %d dirty, %d (%d) negative), %d free",
1130: used, locked, dirty, negative, (int)mfp->mf_neg_count, nfree);
1131: msg(IObuff);
1132: sprintf((char *)IObuff, "Total mem used is %ld bytes", total_mem_used);
1133: msg(IObuff);
1134: }
1135: }
1136: #endif
1137:
1138: /*
1139: * open a swap file for a memfile
1140: */
1141: static void
1142: mf_do_open(mfp, fname, trunc_file)
1143: MEMFILE *mfp;
1144: char_u *fname;
1145: int trunc_file;
1146: {
1147: mfp->mf_fname = fname;
1148: /*
1149: * Get the full path name before the open, because this is
1150: * not possible after the open on the Amiga.
1151: * fname cannot be NameBuff, because it must have been allocated.
1152: */
1153: mf_set_xfname(mfp);
1154:
1155: /*
1156: * try to open the file
1157: */
1158: mfp->mf_fd = open((char *)fname,
1159: (trunc_file ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)) | O_EXTRA
1160:
1161: #ifdef AMIGA /* Amiga has no mode argument */
1162: );
1163: #endif
1164: #ifdef UNIX /* open in rw------- mode */
1165: , (mode_t)0600);
1166: #endif
1167: #if defined(MSDOS) || defined(WIN32) || defined(__EMX__)
1168: , S_IREAD | S_IWRITE); /* open read/write */
1169: #endif
1170: #ifdef VMS /* open in rw------- mode */
1171: , 0600);
1172: #endif
1173:
1174: /*
1175: * If the file cannot be opened, use memory only
1176: */
1177: if (mfp->mf_fd < 0)
1178: {
1179: vim_free(mfp->mf_xfname);
1180: mfp->mf_fname = NULL;
1181: mfp->mf_xfname = NULL;
1182: }
1183: }