1 /**
2  * @namespace   biewlib
3  * @file        biewlib/sysdep/generic/linux/mmfio.c
4  * @brief       This file contains implementation of memory mapped file i/o routines for POSIX compatible OS.
5  * @version     -
6  * @remark      this source file is part of Binary vIEW project (BIEW).
7  *              The Binary vIEW (BIEW) is copyright (C) 1995 Nickols_K.
8  *              All rights reserved. This software is redistributable under the
9  *              licence given in the file "Licence.en" ("Licence.ru" in russian
10  *              translation) distributed in the BIEW archive.
11  * @note        Requires POSIX compatible development system
12  *
13  * @author      Nickols_K
14  * @since       2000
15  * @note        Development, fixes and improvements
16 **/
17 #ifdef __DISABLE_MMF
18 #include "biewlib/sysdep/ia16/dos/mmfio.c"
19 #else
20 #include <sys/mman.h>
21 #include "biewlib/pmalloc.h"
22 #include "biewlib/biewlib.h"
23 
24 #ifndef MREMAP_MAYMOVE
25 #define MREMAP_MAYMOVE 1
26 #endif
27 
28 /* The lack of this function declaration on some systems and may cause segfault */
29 extern void *mremap (void *__addr, size_t __old_len, size_t __new_len,
30 		     int __flags, ...);
31 
32 struct mmfRecord
33 {
34   void *    addr;
35   long      length;
36   bhandle_t fhandle;
37   int       mode;
38 };
39 
mk_prot(int mode)40 static int __FASTCALL__ mk_prot(int mode)
41 {
42   int pflg;
43   pflg = PROT_READ;
44   if(mode & FO_WRITEONLY) pflg = PROT_WRITE;
45   else
46    if(mode & FO_READWRITE) pflg |= PROT_WRITE;
47   return pflg;
48 }
49 
mk_flags(int mode)50 static int __FASTCALL__ mk_flags(int mode)
51 {
52   int pflg;
53   pflg = 0;
54 #ifdef MAP_SHARED
55   if((mode & SO_DENYREAD) ||
56      (mode & SO_DENYWRITE) ||
57      (mode & SO_DENYNONE))          pflg |= MAP_SHARED;
58 #endif
59 #ifdef MAP_PRIVATE
60   if(mode & SO_PRIVATE) pflg |= MAP_PRIVATE;
61 #endif
62   return pflg;
63 }
64 
__mmfOpen(const char * fname,int mode)65 mmfHandle          __FASTCALL__ __mmfOpen(const char *fname,int mode)
66 {
67   struct mmfRecord *mret;
68   bhandle_t fhandle;
69   fhandle = __OsOpen(fname,mode);
70   if(((int)fhandle) != -1)
71   {
72     mret = PMalloc(sizeof(struct mmfRecord));
73     if(mret)
74     {
75       __fileoff_t length;
76       void *addr;
77       length = __FileLength(fhandle);
78       if(length <= PTRDIFF_MAX)
79       {
80 	addr = mmap(NULL,length,mk_prot(mode),
81                   mk_flags(mode),(int)fhandle,0L);
82 	if(addr != (void *)-1)
83 	{
84 	    mret->fhandle = fhandle;
85 	    mret->addr    = addr;
86 	    mret->length  = length;
87 	    mret->mode    = mode;
88 	    return mret;
89 	}
90      }
91      PFree(mret);
92     }
93     __OsClose(fhandle);
94   }
95   return NULL;
96 }
97 
__mmfFlush(mmfHandle mh)98 tBool              __FASTCALL__ __mmfFlush(mmfHandle mh)
99 {
100   struct mmfRecord *mrec = (struct mmfRecord *)mh;
101   return msync(mrec->addr,mrec->length,MS_SYNC) ? False : True;
102 }
103 
__mmfSync(mmfHandle mh)104 mmfHandle       __FASTCALL__ __mmfSync(mmfHandle mh)
105 {
106   struct mmfRecord *mrec = (struct mmfRecord *)mh;
107   long length;
108   void * new_addr;
109   length = __FileLength(mrec->fhandle);
110   msync(mrec->addr,min(length,mrec->length),MS_SYNC);
111   if(length!=mrec->length) {
112     if((new_addr = mremap(mrec->addr,mrec->length,length,0)) != (void *)-1)
113     {
114 	mrec->length = length;
115 	mrec->addr = new_addr;
116     }
117     else
118     {
119 	__OsClose(mrec->fhandle);
120 	PFree(mrec);
121 	return NULL;
122     }
123   }
124   return mrec;
125 }
126 
__mmfProtect(mmfHandle mh,int flags)127 tBool              __FASTCALL__ __mmfProtect(mmfHandle mh,int flags)
128 {
129   struct mmfRecord *mrec = (struct mmfRecord *)mh;
130   mrec->mode = flags;
131   return mprotect(mrec->addr,mrec->length,mk_prot(flags)) ? False : True;
132 }
133 
__mmfResize(mmfHandle mh,long size)134 tBool              __FASTCALL__ __mmfResize(mmfHandle mh,long size)
135 {
136   struct mmfRecord *mrec = (struct mmfRecord *)mh;
137   void *new_addr;
138   tBool can_continue = False;
139   if(mrec->length > size) /* truncate */
140   {
141     if((new_addr = mremap(mrec->addr,mrec->length,size,MREMAP_MAYMOVE)) != (void *)-1) can_continue = True;
142     if(can_continue)
143       can_continue = __OsChSize(mrec->fhandle,size) != -1 ? True : False;
144   }
145   else /* expand */
146   {
147     if(__OsChSize(mrec->fhandle,size) != -1) can_continue = True;
148     if(can_continue)
149       can_continue = (new_addr = mremap(mrec->addr,mrec->length,size,MREMAP_MAYMOVE)) != (void *)-1 ? True : False;
150   }
151   if(can_continue)
152   {
153       mrec->addr = new_addr;
154       mrec->length = size;
155       return True;
156   }
157   else /* Attempt to unroll transaction back */
158     __OsChSize(mrec->fhandle,mrec->length);
159   return False;
160 }
161 
__mmfClose(mmfHandle mh)162 void               __FASTCALL__ __mmfClose(mmfHandle mh)
163 {
164   struct mmfRecord *mrec = (struct mmfRecord *)mh;
165   munmap(mrec->addr,mrec->length);
166   __OsClose(mrec->fhandle);
167   PFree(mrec);
168 }
169 
__mmfAddress(mmfHandle mh)170 void *             __FASTCALL__ __mmfAddress(mmfHandle mh)
171 {
172   return ((struct mmfRecord *)mh)->addr;
173 }
174 
__mmfSize(mmfHandle mh)175 long              __FASTCALL__ __mmfSize(mmfHandle mh)
176 {
177   return ((struct mmfRecord *)mh)->length;
178 }
179 
__mmfIsWorkable(void)180 tBool             __FASTCALL__ __mmfIsWorkable( void ) { return True; }
181 
182 #endif
183