1 /*
2 --------------------------------------------------------------------------------
3 -   Module      :   mem_file.c
4 -   Description :   A general purpose library for manipulating a memory area
5 -                   as if it were a file.
6 -                   mfs_ stands for memory file system.
7 -   Author      :   Mike Johnson - Banctec AB 03/07/96
8 -
9 --------------------------------------------------------------------------------
10 */
11 
12 /*
13 
14 Copyright (c) 1996 Mike Johnson
15 Copyright (c) 1996 BancTec AB
16 
17 Permission to use, copy, modify, distribute, and sell this software
18 for any purpose is hereby granted without fee, provided
19 that (i) the above copyright notices and this permission notice appear in
20 all copies of the software and related documentation, and (ii) the names of
21 Mike Johnson and BancTec may not be used in any advertising or
22 publicity relating to the software.
23 
24 THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
25 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
26 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
27 
28 IN NO EVENT SHALL MIKE JOHNSON OR BANCTEC BE LIABLE FOR
29 ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
30 OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
31 WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
32 LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
33 OF THIS SOFTWARE.
34 
35 */
36 
37 
38 /*
39 --------------------------------------------------------------------------------
40 -   Includes
41 --------------------------------------------------------------------------------
42 */
43 
44 #include    <stdio.h>
45 #include    <stdlib.h>
46 #include    <string.h>
47 
48 /*
49 --------------------------------------------------------------------------------
50 -   Definitions
51 --------------------------------------------------------------------------------
52 */
53 
54 #define MAX_BUFFS   20
55 #define FALSE       0
56 #define TRUE        1
57 
58 /*
59 --------------------------------------------------------------------------------
60 -   Globals
61 --------------------------------------------------------------------------------
62 */
63 
64 static char *buf[MAX_BUFFS];        /* Memory for each open buf */
65 static long  buf_off[MAX_BUFFS];    /* File pointer for each buf */
66 static long  buf_size[MAX_BUFFS];   /* Count of bytes allocated for each buf */
67 static long  fds[MAX_BUFFS];        /* File descriptor status */
68 static int   buf_mode[MAX_BUFFS];   /* Mode of buffer (r, w, a) */
69 
70 static int library_init_done = FALSE;
71 
72 
73 /*
74 --------------------------------------------------------------------------------
75 -   Function prototypes
76 --------------------------------------------------------------------------------
77 */
78 
79 int mfs_open (void *ptr, int size, char *mode);
80 int mfs_lseek (int fd, int offset, int whence);
81 int mfs_read (int fd, void *buf, int size);
82 int mfs_write (int fd, void *buf, int size);
83 int mfs_size (int fd);
84 int mfs_map (int fd, char **addr, size_t *len);
85 int mfs_unmap (int fd);
86 int mfs_close (int fd);
87 static int extend_mem_file (int fd, int size);
88 static void mem_init ();
89 
90 /*
91 --------------------------------------------------------------------------------
92 -   Function code
93 --------------------------------------------------------------------------------
94 */
95 
96 /*
97 --------------------------------------------------------------------------------
98 -   Function    :   mfs_open ()
99 -
100 -   Arguments   :   Pointer to allocated buffer, initial size of buffer,
101 -                   mode spec (r, w, a)
102 -
103 -   Returns     :   File descriptor or -1 if error.
104 -
105 -   Description :   Register this area of memory (which has been allocated
106 -                   and has a file read into it) under the mem_file library.
107 -                   A file descriptor is returned which can the be passed
108 -                   back to TIFFClientOpen and used as if it was a disk
109 -                   based fd.
110 -                   If the call is for mode 'w' then pass (void *)NULL as
111 -                   the buffer and zero size and the library will
112 -                   allocate memory for you.
113 -                   If the mode is append then pass (void *)NULL and size
114 -                   zero or with a valid address.
115 -
116 --------------------------------------------------------------------------------
117 */
118 
mfs_open(void * buffer,int size,char * mode)119 int mfs_open (void *buffer, int size, char *mode)
120 {
121     int ret, i;
122     void *tmp;
123 
124     if (library_init_done == FALSE)
125     {
126         mem_init ();
127         library_init_done = TRUE;
128     }
129 
130     ret = -1;
131 
132     /* Find a free fd */
133 
134     for (i = 0; i < MAX_BUFFS; i++)
135     {
136         if (fds[i] == -1)
137         {
138             ret = i;
139             break;
140         }
141     }
142 
143     if (i == MAX_BUFFS)     /* No more free descriptors */
144     {
145         ret = -1;
146         errno = EMFILE;
147     }
148 
149     if (ret >= 0 && *mode == 'r')
150     {
151         if (buffer == (void *)NULL)
152         {
153             ret = -1;
154             errno = EINVAL;
155         }
156         else
157         {
158             buf[ret] = (char *)buffer;
159             buf_size[ret] = size;
160             buf_off[ret] = 0;
161         }
162     }
163     else if (ret >= 0 && *mode == 'w')
164     {
165 
166         if (buffer != (void *)NULL)
167         {
168             ret = -1;
169             errno = EINVAL;
170         }
171 
172         else
173         {
174             tmp = malloc (0);   /* Get a pointer */
175             if (tmp == (void *)NULL)
176             {
177                 ret = -1;
178                 errno = EDQUOT;
179             }
180             else
181             {
182                 buf[ret] = (char *)tmp;
183                 buf_size[ret] = 0;
184                 buf_off[ret] = 0;
185             }
186         }
187     }
188     else if (ret >= 0 && *mode == 'a')
189     {
190         if (buffer == (void *) NULL)    /* Create space for client */
191         {
192             tmp = malloc (0);   /* Get a pointer */
193             if (tmp == (void *)NULL)
194             {
195                 ret = -1;
196                 errno = EDQUOT;
197             }
198             else
199             {
200                 buf[ret] = (char *)tmp;
201                 buf_size[ret] = 0;
202                 buf_off[ret] = 0;
203             }
204         }
205         else                            /* Client has file read in already */
206         {
207             buf[ret] = (char *)buffer;
208             buf_size[ret] = size;
209             buf_off[ret] = 0;
210         }
211     }
212     else        /* Some other invalid combination of parameters */
213     {
214         ret = -1;
215         errno = EINVAL;
216     }
217 
218     if (ret != -1)
219     {
220         fds[ret] = 0;
221         buf_mode[ret] = *mode;
222     }
223 
224     return (ret);
225 }
226 
227 /*
228 --------------------------------------------------------------------------------
229 -   Function    :   mfs_lseek ()
230 -
231 -   Arguments   :   File descriptor, offset, whence
232 -
233 -   Returns     :   as per man lseek (2)
234 -
235 -   Description :   Does the same as lseek (2) except on a memory based file.
236 -                   Note: the memory area will be extended if the caller
237 -                   attempts to seek past the current end of file (memory).
238 -
239 --------------------------------------------------------------------------------
240 */
241 
mfs_lseek(int fd,int offset,int whence)242 int mfs_lseek (int fd, int offset, int whence)
243 {
244     int ret;
245     long test_off;
246 
247     if (fds[fd] == -1)  /* Not open */
248     {
249         ret = -1;
250         errno = EBADF;
251     }
252     else if (offset < 0 && whence == SEEK_SET)
253     {
254         ret = -1;
255         errno = EINVAL;
256     }
257     else
258     {
259         switch (whence)
260         {
261             case SEEK_SET:
262                 if (offset > buf_size[fd])
263                     extend_mem_file (fd, offset);
264                 buf_off[fd] = offset;
265                 ret = offset;
266                 break;
267 
268             case SEEK_CUR:
269                 test_off = buf_off[fd] + offset;
270 
271                 if (test_off < 0)
272                 {
273                     ret = -1;
274                     errno = EINVAL;
275                 }
276                 else
277                 {
278                     if (test_off > buf_size[fd])
279                         extend_mem_file (fd, test_off);
280                     buf_off[fd] = test_off;
281                     ret = test_off;
282                 }
283                 break;
284 
285             case SEEK_END:
286                 test_off = buf_size[fd] + offset;
287 
288                 if (test_off < 0)
289                 {
290                     ret = -1;
291                     errno = EINVAL;
292                 }
293                 else
294                 {
295                     if (test_off > buf_size[fd])
296                         extend_mem_file (fd, test_off);
297                     buf_off[fd] = test_off;
298                     ret = test_off;
299                 }
300                 break;
301 
302             default:
303                 errno = EINVAL;
304                 ret = -1;
305                 break;
306         }
307     }
308 
309     return (ret);
310 }
311 
312 /*
313 --------------------------------------------------------------------------------
314 -   Function    :   mfs_read ()
315 -
316 -   Arguments   :   File descriptor, buffer, size
317 -
318 -   Returns     :   as per man read (2)
319 -
320 -   Description :   Does the same as read (2) except on a memory based file.
321 -                   Note: An attempt to read past the end of memory currently
322 -                   allocated to the file will return 0 (End Of File)
323 -
324 --------------------------------------------------------------------------------
325 */
326 
mfs_read(int fd,void * clnt_buf,int size)327 int mfs_read (int fd, void *clnt_buf, int size)
328 {
329     int ret;
330 
331     if (fds[fd] == -1 || buf_mode[fd] != 'r')
332     {
333         /* File is either not open, or not opened for read */
334 
335         ret = -1;
336         errno = EBADF;
337     }
338     else if (buf_off[fd] + size > buf_size[fd])
339     {
340         ret = 0;        /* EOF */
341     }
342     else
343     {
344         memcpy (clnt_buf, (void *) (buf[fd] + buf_off[fd]), size);
345         buf_off[fd] = buf_off[fd] + size;
346         ret = size;
347     }
348 
349     return (ret);
350 }
351 
352 /*
353 --------------------------------------------------------------------------------
354 -   Function    :   mfs_write ()
355 -
356 -   Arguments   :   File descriptor, buffer, size
357 -
358 -   Returns     :   as per man write (2)
359 -
360 -   Description :   Does the same as write (2) except on a memory based file.
361 -                   Note: the memory area will be extended if the caller
362 -                   attempts to write past the current end of file (memory).
363 -
364 --------------------------------------------------------------------------------
365 */
366 
mfs_write(int fd,void * clnt_buf,int size)367 int mfs_write (int fd, void *clnt_buf, int size)
368 {
369     int ret;
370 
371     if (fds[fd] == -1 || buf_mode[fd] == 'r')
372     {
373         /* Either the file is not open or it is opened for reading only */
374 
375         ret = -1;
376         errno = EBADF;
377     }
378     else if (buf_mode[fd] == 'w')
379     {
380         /* Write */
381 
382         if (buf_off[fd] + size > buf_size[fd])
383         {
384             extend_mem_file (fd, buf_off[fd] + size);
385             buf_size[fd] = (buf_off[fd] + size);
386         }
387 
388         memcpy ((buf[fd] + buf_off[fd]), clnt_buf, size);
389         buf_off[fd] = buf_off[fd] + size;
390 
391         ret = size;
392     }
393     else
394     {
395         /* Append */
396 
397         if (buf_off[fd] != buf_size[fd])
398             buf_off[fd] = buf_size[fd];
399 
400         extend_mem_file (fd, buf_off[fd] + size);
401         buf_size[fd] += size;
402 
403         memcpy ((buf[fd] + buf_off[fd]), clnt_buf, size);
404         buf_off[fd] = buf_off[fd] + size;
405 
406         ret = size;
407     }
408 
409     return (ret);
410 }
411 
412 /*
413 --------------------------------------------------------------------------------
414 -   Function    :   mfs_size ()
415 -
416 -   Arguments   :   File descriptor
417 -
418 -   Returns     :   integer file size
419 -
420 -   Description :   This function returns the current size of the file in bytes.
421 -
422 --------------------------------------------------------------------------------
423 */
424 
mfs_size(int fd)425 int mfs_size (int fd)
426 {
427     int ret;
428 
429     if (fds[fd] == -1)  /* Not open */
430     {
431         ret = -1;
432         errno = EBADF;
433     }
434     else
435         ret = buf_size[fd];
436 
437     return (ret);
438 }
439 
440 /*
441 --------------------------------------------------------------------------------
442 -   Function    :   mfs_map ()
443 -
444 -   Arguments   :   File descriptor, ptr to address, ptr to length
445 -
446 -   Returns     :   Map status (succeeded or otherwise)
447 -
448 -   Description :   This function tells the client where the file is mapped
449 -                   in memory and what size the mapped area is. It is provided
450 -                   to satisfy the MapProc function in libtiff. It pretends
451 -                   that the file has been mmap (2)ped.
452 -
453 --------------------------------------------------------------------------------
454 */
455 
mfs_map(int fd,char ** addr,size_t * len)456 int mfs_map (int fd, char **addr, size_t *len)
457 {
458     int ret;
459 
460     if (fds[fd] == -1)  /* Not open */
461     {
462         ret = -1;
463         errno = EBADF;
464     }
465     else
466     {
467         *addr = buf[fd];
468         *len = buf_size[fd];
469         ret = 0;
470     }
471 
472     return (ret);
473 }
474 
475 /*
476 --------------------------------------------------------------------------------
477 -   Function    :   mfs_unmap ()
478 -
479 -   Arguments   :   File descriptor
480 -
481 -   Returns     :   UnMap status (succeeded or otherwise)
482 -
483 -   Description :   This function does nothing as the file is always
484 -                   in memory.
485 -
486 --------------------------------------------------------------------------------
487 */
488 
mfs_unmap(int fd)489 int mfs_unmap (int fd)
490 {
491     return (0);
492 }
493 
494 /*
495 --------------------------------------------------------------------------------
496 -   Function    :   mfs_close ()
497 -
498 -   Arguments   :   File descriptor
499 -
500 -   Returns     :   close status (succeeded or otherwise)
501 -
502 -   Description :   Close the open memory file. (Make fd available again.)
503 -
504 --------------------------------------------------------------------------------
505 */
506 
mfs_close(int fd)507 int mfs_close (int fd)
508 {
509     int ret;
510 
511     if (fds[fd] == -1)  /* Not open */
512     {
513         ret = -1;
514         errno = EBADF;
515     }
516     else
517     {
518         fds[fd] = -1;
519         ret = 0;
520     }
521 
522     return (ret);
523 }
524 
525 /*
526 --------------------------------------------------------------------------------
527 -   Function    :   extend_mem_file ()
528 -
529 -   Arguments   :   File descriptor, length to extend to.
530 -
531 -   Returns     :   0 - All OK, -1 - realloc () failed.
532 -
533 -   Description :   Increase the amount of memory allocated to a file.
534 -
535 --------------------------------------------------------------------------------
536 */
537 
extend_mem_file(int fd,int size)538 static int extend_mem_file (int fd, int size)
539 {
540     void *new_mem;
541     int ret;
542 
543     if ((new_mem = realloc (buf[fd], size)) == (void *) NULL)
544         ret = -1;
545     else
546     {
547         buf[fd] = (char *) new_mem;
548         ret = 0;
549     }
550 
551     return (ret);
552 }
553 
554 /*
555 --------------------------------------------------------------------------------
556 -   Function    :   mem_init ()
557 -
558 -   Arguments   :   None
559 -
560 -   Returns     :   void
561 -
562 -   Description :   Initialise the library.
563 -
564 --------------------------------------------------------------------------------
565 */
566 
mem_init()567 static void mem_init ()
568 {
569     int i;
570 
571     for (i = 0; i < MAX_BUFFS; i++)
572     {
573         fds[i] = -1;
574         buf[i] = (char *)NULL;
575         buf_size[i] = 0;
576         buf_off[i] = 0;
577     }
578 }
579 
580 /*
581  * Local Variables:
582  * mode: c
583  * c-basic-offset: 8
584  * fill-column: 78
585  * End:
586  */
587