source: rtems/cpukit/libfs/src/imfs/memfile.c @ 07a3253d

4.104.114.84.9
Last change on this file since 07a3253d was 07a3253d, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 23, 1998 at 7:07:58 PM

Added base version of file system infrastructure. This includes a major
overhaul of the RTEMS system call interface. This base file system is
the "In-Memory File System" aka IMFS.

The design and implementation was done by the following people:

+ Joel Sherrill (joel@…)
+ Jennifer Averett (jennifer@…)
+ Steve "Mr Mount" Salitasc (salitasc@…)
+ Kerwin Wade (wade@…)

PROBLEMS
========

+ It is VERY likely that merging this will break the UNIX port. This

can/will be fixed.

+ There is likely some reentrancy/mutual exclusion needed.

+ Eventually, there should be a "mini-IMFS" description table to

eliminate links, symlinks, etc to save memory. All you need to
have "classic RTEMS" functionality is technically directories
and device IO. All the rest could be left out to save memory.

  • Property mode set to 100644
File size: 21.1 KB
Line 
1/*
2 *  IMFS Device Node Handlers
3 *
4 *  This file contains the set of handlers used to process operations on
5 *  IMFS memory file nodes.  The memory files are created in memory using
6 *  malloc'ed memory.  Thus any data stored in one of these files is lost
7 *  at system shutdown unless special arrangements to copy the data to
8 *  some type of non-volailte storage are made by the application.
9 *
10 *  COPYRIGHT (c) 1989-1998.
11 *  On-Line Applications Research Corporation (OAR).
12 *  Copyright assigned to U.S. Government, 1994.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.OARcorp.com/rtems/license.html.
17 *
18 *  $Id$
19 */
20
21#include <stdlib.h>
22#include <assert.h>
23#include <errno.h>
24
25#include <rtems.h>
26#include <rtems/libio.h>
27#include "imfs.h"
28#include "libio_.h"
29
30#define MEMFILE_STATIC
31
32/*
33 *  Prototypes of private routines
34 */
35
36MEMFILE_STATIC int IMFS_memfile_extend(
37   IMFS_jnode_t  *the_jnode,
38   off_t          new_length
39);
40
41MEMFILE_STATIC int IMFS_memfile_addblock(
42   IMFS_jnode_t  *the_jnode,
43   unsigned int   block
44);
45
46MEMFILE_STATIC int IMFS_memfile_remove_block(
47   IMFS_jnode_t  *the_jnode,
48   unsigned int   block
49);
50
51MEMFILE_STATIC block_p *IMFS_memfile_get_block_pointer(
52   IMFS_jnode_t   *the_jnode,
53   unsigned int    block,
54   int             malloc_it
55);
56
57MEMFILE_STATIC int IMFS_memfile_read(
58   IMFS_jnode_t    *the_jnode,
59   off_t            start,
60   unsigned char   *destination,
61   unsigned int     length
62);
63
64MEMFILE_STATIC int IMFS_memfile_write(
65   IMFS_jnode_t          *the_jnode,
66   off_t                  start,
67   const unsigned char   *source,
68   unsigned int           length
69);
70
71void *memfile_alloc_block(void);
72
73void memfile_free_block(
74  void *memory
75);
76
77/*
78 *  memfile_open
79 *
80 *  This routine processes the open() system call.  Note that there is
81 *  nothing special to be done at open() time.
82 */
83
84int memfile_open(
85  rtems_libio_t *iop,
86  const char    *pathname,
87  unsigned32     flag,
88  unsigned32     mode
89)
90{
91  IMFS_jnode_t  *the_jnode;
92
93  the_jnode = iop->file_info;
94
95  return 0;
96}
97
98/*
99 *  memfile_close
100 *
101 *  This routine processes the close() system call.  Note that there is
102 *  nothing to flush or memory to free at this point.
103 */
104
105int memfile_close(
106  rtems_libio_t *iop
107)
108{
109  IMFS_jnode_t   *the_jnode;
110
111  the_jnode = iop->file_info;
112
113  return 0;
114}
115
116/*
117 *  memfile_read
118 *
119 *  This routine processes the read() system call.
120 */
121
122int memfile_read(
123  rtems_libio_t *iop,
124  void          *buffer,
125  unsigned32     count
126)
127{
128  IMFS_jnode_t   *the_jnode;
129
130  the_jnode = iop->file_info;
131
132  return IMFS_memfile_read( the_jnode, iop->offset, buffer, count );
133}
134
135/*
136 *  memfile_write
137 *
138 *  This routine processes the write() system call.
139 */
140
141int memfile_write(
142  rtems_libio_t *iop,
143  const void    *buffer,
144  unsigned32     count
145)
146{
147  IMFS_jnode_t   *the_jnode;
148
149  the_jnode = iop->file_info;
150
151  return IMFS_memfile_write( the_jnode, iop->offset, buffer, count );
152}
153
154/*
155 *  memfile_ioctl
156 *
157 *  This routine processes the ioctl() system call.
158 *
159 *  NOTE:  No ioctl()'s are supported for in-memory files.
160 */
161
162int memfile_ioctl(
163  rtems_libio_t *iop,
164  unsigned32     command,
165  void          *buffer
166)
167{
168  IMFS_jnode_t   *the_jnode;
169
170  the_jnode = iop->file_info;
171
172  return 0;
173}
174
175/*
176 *  memfile_lseek
177 *
178 *  This routine processes the lseek() system call.
179 */
180
181int memfile_lseek(
182  rtems_libio_t   *iop,
183  off_t            offset,
184  int              whence
185)
186{
187  IMFS_jnode_t   *the_jnode;
188
189  the_jnode = iop->file_info;
190
191  if (IMFS_memfile_extend( the_jnode, iop->offset ))
192    set_errno_and_return_minus_one( ENOSPC );
193
194  return 0;
195}
196
197/*
198 *  memfile_stat
199 *
200 *  This IMFS_stat() can be used.
201 */
202
203/*
204 *  memfile_ftruncate
205 *
206 *  This routine processes the ftruncate() system call.
207 */
208
209int memfile_ftruncate(
210  rtems_libio_t        *iop,
211  off_t                 length
212)
213{
214  IMFS_jnode_t   *the_jnode;
215
216  the_jnode = iop->file_info;
217
218  /*
219   *  POSIX 1003.1b does not specify what happens if you truncate a file
220   *  and the new length is greater than the current size.  We treat this
221   *  as an extend operation.
222   */
223
224  if ( length > the_jnode->info.file.size )
225    return IMFS_memfile_extend( the_jnode, length );
226
227  /*
228   *  The in-memory files do not currently reclaim memory until the file is
229   *  deleted.  So we leave the previously allocated blocks in place for
230   *  future use and just set the length.
231   */
232
233  the_jnode->info.file.size = length;
234
235  IMFS_update_atime( the_jnode );
236
237  return 0;
238}
239
240/*
241 *  IMFS_memfile_extend
242 *
243 *  This routine insures that the in-memory file is of the length
244 *  specified.  If necessary, it will allocate memory blocks to
245 *  extend the file.
246 */
247
248MEMFILE_STATIC int IMFS_memfile_extend(
249   IMFS_jnode_t  *the_jnode,
250   off_t          new_length
251)
252{
253  unsigned int   block;
254  unsigned int   new_blocks;
255  unsigned int   old_blocks;
256
257  /*
258   *  Perform internal consistency checks
259   */
260
261  assert( the_jnode );
262  if ( !the_jnode )
263    set_errno_and_return_minus_one( EIO );
264
265  assert( the_jnode->type == IMFS_MEMORY_FILE );
266  if ( the_jnode->type != IMFS_MEMORY_FILE )
267    set_errno_and_return_minus_one( EIO );
268
269  if ( new_length >= IMFS_MEMFILE_MAXIMUM_SIZE )
270    set_errno_and_return_minus_one( EINVAL );
271
272  if ( new_length <= the_jnode->info.file.size )
273    return 0;
274
275  /*
276   *  Calculate the number of range of blocks to allocate
277   */
278
279  new_blocks = new_length / IMFS_MEMFILE_BYTES_PER_BLOCK;
280  old_blocks = the_jnode->info.file.size / IMFS_MEMFILE_BYTES_PER_BLOCK;
281
282  /*
283   *  Now allocate each of those blocks.
284   */
285
286  for ( block=old_blocks ; block<=new_blocks ; block++ ) {
287    if ( IMFS_memfile_addblock( the_jnode, block ) ) {
288       for ( ; block>=old_blocks ; block-- ) {
289          IMFS_memfile_remove_block( the_jnode, block );
290       }
291       set_errno_and_return_minus_one( ENOSPC );
292    }
293  }
294
295  /*
296   *  Set the new length of the file.
297   */
298
299  the_jnode->info.file.size = new_length;
300  return 0;
301}
302
303/*
304 *  IMFS_memfile_addblock
305 *
306 *  This routine adds a single block to the specified in-memory file.
307 */
308
309MEMFILE_STATIC int IMFS_memfile_addblock(
310   IMFS_jnode_t  *the_jnode,
311   unsigned int   block
312)
313{
314  block_p  memory;
315  block_p *block_entry_ptr;
316
317  assert( the_jnode );
318  if ( !the_jnode )
319    set_errno_and_return_minus_one( EIO );
320
321  assert( the_jnode->type == IMFS_MEMORY_FILE );
322  if ( the_jnode->type != IMFS_MEMORY_FILE )
323    set_errno_and_return_minus_one( EIO );
324
325  block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 1 );
326  if ( *block_entry_ptr )
327    return 0;
328
329#if 0
330  printf( "%d %p", block, block_entry_ptr );
331    fflush(stdout);
332#endif
333
334  memory = memfile_alloc_block();
335  assert( memory );
336  if ( !memory )
337    return 1;
338  *block_entry_ptr = memory;
339
340  return 0;
341}
342
343/*
344 *  IMFS_memfile_remove_block
345 *
346 *  This routine removes the specified block from the in-memory file.
347 *
348 *  NOTE:  This is a support routine and is called only to remove
349 *         the last block or set of blocks in a file.  Removing a
350 *         block from the middle of a file would be exceptionally
351 *         dangerous and the results unpredictable.
352 */
353
354MEMFILE_STATIC int IMFS_memfile_remove_block(
355   IMFS_jnode_t  *the_jnode,
356   unsigned int   block
357)
358{
359  block_p *block_entry_ptr;
360  block_p  ptr;
361
362  block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
363  ptr = *block_entry_ptr;
364  *block_entry_ptr = 0;
365
366  memfile_free_block( ptr );
367
368  return 1;
369}
370
371/*
372 *  memfile_free_blocks_in_table
373 *
374 *  This is a support routine for IMFS_memfile_remove.  It frees all the
375 *  blocks in one of the indirection tables.
376 */
377
378void memfile_free_blocks_in_table(
379  block_p **block_table,
380  int       entries
381)
382{
383  int      i;
384  block_p *b;
385
386  /*
387   *  Perform internal consistency checks
388   */
389
390  assert( block_table );
391  if ( !block_table )
392    return;
393
394  /*
395   *  Now go through all the slots in the table and free the memory.
396   */
397
398  b = *block_table;
399
400  for ( i=0 ; i<entries ; i++ ) {
401    if ( b[i] ) {
402      memfile_free_block( b[i] );
403      b[i] = 0;
404    }
405  }
406
407  /*
408   *  Now that all the blocks in the block table are free, we can
409   *  free the block table itself.
410   */
411
412  memfile_free_block( *block_table );
413  *block_table = 0;
414}
415
416/*
417 *  IMFS_memfile_remove
418 *
419 *  This routine frees all memory associated with an in memory file.
420 *
421 *  NOTE:  This is an exceptionally conservative implementation. 
422 *         It will check EVERY pointer which is non-NULL and insure
423 *         any child non-NULL pointers are freed.  Optimistically, all that
424 *         is necessary is to scan until a NULL pointer is found.  There
425 *         should be no allocated data past that point.
426 *
427 *         In experimentation on the powerpc simulator, it was noted
428 *         that using blocks which held 128 slots versus 16 slots made
429 *         a significant difference in the performance of this routine.
430 *
431 *         Regardless until the IMFS implementation is proven, it
432 *         is better to stick to simple, easy to understand algorithms.
433 */
434
435int IMFS_memfile_remove(
436 IMFS_jnode_t  *the_jnode
437)
438{
439  IMFS_memfile_t  *info;
440  int              i;
441  int              j;
442  unsigned int     to_free;
443  block_p         *p;
444
445  /*
446   *  Perform internal consistency checks
447   */
448
449  assert( the_jnode );
450  if ( !the_jnode )
451    set_errno_and_return_minus_one( EIO );
452
453  assert( the_jnode->type == IMFS_MEMORY_FILE );
454  if ( the_jnode->type != IMFS_MEMORY_FILE )
455    set_errno_and_return_minus_one( EIO );
456
457  /*
458   *  Eventually this could be set smarter at each call to
459   *  memfile_free_blocks_in_table to greatly speed this up.
460   */
461
462  to_free = IMFS_MEMFILE_BLOCK_SLOTS;
463
464  /*
465   *  Now start freeing blocks in this order:
466   *    + indirect
467   *    + doubly indirect
468   *    + triply indirect
469   */
470
471  info = &the_jnode->info.file;
472
473  if ( info->indirect ) {
474    memfile_free_blocks_in_table( &info->indirect, to_free );
475  }
476
477  if ( info->doubly_indirect ) {
478
479    for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
480      if ( info->doubly_indirect[i] ) {
481        memfile_free_blocks_in_table(
482         (block_p **)&info->doubly_indirect[i], to_free );
483      }
484    }
485    memfile_free_blocks_in_table( &info->doubly_indirect, to_free );
486
487  }
488 
489  if ( info->triply_indirect ) {
490    for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
491      p = (block_p *) info->triply_indirect[i];
492      for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) {
493        if ( p[j] ) {
494          memfile_free_blocks_in_table( (block_p **)&p[j], to_free);
495        }
496      }
497      memfile_free_blocks_in_table(
498        (block_p **)&info->triply_indirect[i], to_free );
499    }
500    memfile_free_blocks_in_table(
501        (block_p **)&info->triply_indirect, to_free );
502  }
503
504  return 0;
505}
506
507/*
508 *  IMFS_memfile_read
509 *
510 *  This routine read from memory file pointed to by the_jnode into
511 *  the specified data buffer specified by destination.  The file
512 *  is NOT extended.  An offset greater than the length of the file
513 *  is considered an error.  Read from an offset for more bytes than
514 *  are between the offset and the end of the file will result in
515 *  reading the data between offset and the end of the file (truncated
516 *  read).
517 */
518
519MEMFILE_STATIC int IMFS_memfile_read(
520   IMFS_jnode_t    *the_jnode,
521   off_t            start,
522   unsigned char   *destination,
523   unsigned int     length
524)
525{
526  block_p             *block_ptr;
527  unsigned int         block;
528  unsigned int         my_length;
529  unsigned int         to_copy = 0;
530  unsigned int         last_byte;
531  unsigned int         copied;
532  unsigned int         start_offset;
533  unsigned char       *dest;
534
535  dest = destination;
536
537  /*
538   *  Perform internal consistency checks
539   */
540
541  assert( the_jnode );
542  if ( !the_jnode )
543    set_errno_and_return_minus_one( EIO );
544
545  assert( the_jnode->type == IMFS_MEMORY_FILE );
546  if ( the_jnode->type != IMFS_MEMORY_FILE )
547    set_errno_and_return_minus_one( EIO );
548
549  /*
550   *  Error checks on arguments
551   */
552
553  assert( dest );
554  if ( !dest )
555    set_errno_and_return_minus_one( EINVAL );
556
557  /*
558   *  If there is nothing to read, then quick exit.
559   */
560
561  my_length = length;
562  if ( !my_length )
563    set_errno_and_return_minus_one( EINVAL );
564
565  /*
566   *  If the last byte we are supposed to read is past the end of this
567   *  in memory file, then shorten the length to read.
568   */
569
570  last_byte = start + length;
571  if ( last_byte > the_jnode->info.file.size )
572    my_length = the_jnode->info.file.size - start;
573
574  copied = 0;
575
576  /*
577   *  Three phases to the read:
578   *    + possibly the last part of one block
579   *    + all of zero of more blocks
580   *    + possibly the first part of one block
581   */
582
583  /*
584   *  Phase 1: possibly the last part of one block
585   */
586
587  start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
588  block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
589  if ( start_offset )  {
590    to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
591    if ( to_copy > my_length )
592      to_copy = my_length;
593    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
594    assert( block_ptr );
595    if ( !block_ptr )
596      return copied;
597    memcpy( dest, &(*block_ptr)[ start_offset ], to_copy );
598    dest += to_copy;
599    block++;
600    my_length -= to_copy;
601    copied += to_copy;
602  }
603
604  /*
605   *  Phase 2: all of zero of more blocks
606   */
607
608  to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
609  while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
610    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
611    assert( block_ptr );
612    if ( !block_ptr )
613      return copied;
614    memcpy( dest, &(*block_ptr)[ 0 ], to_copy );
615    dest += to_copy;
616    block++;
617    my_length -= to_copy;
618    copied += to_copy;
619  }
620
621  /*
622   *  Phase 3: possibly the first part of one block
623   */
624
625  assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
626
627  if ( my_length ) {
628    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
629    assert( block_ptr );
630    if ( !block_ptr )
631      return copied;
632    memcpy( dest, &(*block_ptr)[ 0 ], my_length );
633    copied += my_length;
634  }
635
636  IMFS_update_atime( the_jnode );
637
638  return copied;
639}
640
641/*
642 *  IMFS_memfile_write
643 *
644 *  This routine writes the specified data buffer into the in memory
645 *  file pointed to by the_jnode.  The file is extended as needed.
646 */
647
648MEMFILE_STATIC int IMFS_memfile_write(
649   IMFS_jnode_t          *the_jnode,
650   off_t                  start,
651   const unsigned char   *source,
652   unsigned int           length
653)
654{
655  block_p             *block_ptr;
656  unsigned int         block;
657  int                  status;
658  unsigned int         my_length;
659  unsigned int         to_copy = 0;
660  unsigned int         last_byte;
661  unsigned int         start_offset;
662  int                  copied;
663  const unsigned char *src;
664
665  src = source;
666
667  /*
668   *  Perform internal consistency checks
669   */
670
671  assert( the_jnode );
672  if ( !the_jnode )
673    set_errno_and_return_minus_one( EIO );
674
675  assert( the_jnode->type == IMFS_MEMORY_FILE );
676  if ( the_jnode->type != IMFS_MEMORY_FILE )
677    set_errno_and_return_minus_one( EIO );
678
679  /*
680   *  Error check arguments
681   */
682
683  assert( source );
684  if ( !source )
685    set_errno_and_return_minus_one( EINVAL );
686
687
688  /*
689   *  If there is nothing to write, then quick exit.
690   */
691
692  my_length = length;
693  if ( !my_length )
694    set_errno_and_return_minus_one( EINVAL );
695
696  /*
697   *  If the last byte we are supposed to write is past the end of this
698   *  in memory file, then extend the length.
699   */
700
701  last_byte = start + length;
702  if ( last_byte > the_jnode->info.file.size ) {
703    status = IMFS_memfile_extend( the_jnode, last_byte );
704    if ( status )
705      set_errno_and_return_minus_one( ENOSPC );
706  }
707
708  copied = 0;
709
710  /*
711   *  Three phases to the write:
712   *    + possibly the last part of one block
713   *    + all of zero of more blocks
714   *    + possibly the first part of one block
715   */
716
717  /*
718   *  Phase 1: possibly the last part of one block
719   */
720
721  start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
722  block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
723  if ( start_offset )  {
724    to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
725    if ( to_copy > my_length )
726      to_copy = my_length;
727    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
728    assert( block_ptr );
729    if ( !block_ptr )
730      return copied;
731    memcpy( &(*block_ptr)[ start_offset ], src, to_copy );
732    src += to_copy;
733    block++;
734    my_length -= to_copy;
735    copied += to_copy;
736  }
737
738  /*
739   *  Phase 2: all of zero of more blocks
740   */
741
742  to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
743  while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
744    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
745    assert( block_ptr );
746    if ( !block_ptr )
747      return copied;
748    memcpy( &(*block_ptr)[ 0 ], src, to_copy );
749    src += to_copy;
750    block++;
751    my_length -= to_copy;
752    copied += to_copy;
753  }
754
755  /*
756   *  Phase 3: possibly the first part of one block
757   */
758
759  assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
760
761  to_copy = my_length;
762  if ( my_length ) {
763    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
764    assert( block_ptr );
765    if ( !block_ptr )
766      return copied;
767    memcpy( &(*block_ptr)[ 0 ], src, my_length );
768    my_length = 0;
769    copied += to_copy;
770  }
771
772  IMFS_atime_mtime_update( the_jnode );
773
774  return copied;
775}
776
777/*
778 *  IMFS_memfile_get_block_pointer
779 *
780 *  This routine looks up the block pointer associated with the given block
781 *  number.  If that block has not been allocated and "malloc_it" is
782 *  TRUE, then the block is allocated.  Otherwise, it is an error.
783 */
784
785block_p *IMFS_memfile_get_block_pointer(
786   IMFS_jnode_t   *the_jnode,
787   unsigned int    block,
788   int             malloc_it
789)
790{
791  unsigned int    my_block;
792  IMFS_memfile_t *info;
793  unsigned int    singly;
794  unsigned int    doubly;
795  unsigned int    triply;
796  block_p        *p;
797  block_p        *p1;
798  block_p        *p2;
799
800  /*
801   *  Perform internal consistency checks
802   */
803
804  assert( the_jnode );
805  if ( !the_jnode )
806    return NULL;
807
808  assert( the_jnode->type == IMFS_MEMORY_FILE );
809  if ( the_jnode->type != IMFS_MEMORY_FILE )
810    return NULL;
811
812  info = &the_jnode->info.file;
813
814  my_block = block;
815
816  /*
817   *  Is the block number in the simple indirect portion?
818   */
819
820  if ( my_block <= LAST_INDIRECT ) {
821#if 0
822printf( "(s %d) ", block );
823fflush(stdout);
824#endif
825    p = info->indirect;
826
827    if ( malloc_it ) {
828
829      if ( !p ) {
830        p = memfile_alloc_block();
831        if ( !p )
832           return 0;
833        info->indirect = p;
834      }
835      return &info->indirect[ my_block ];
836    }
837
838    if ( !p )
839      return 0;
840
841    return &info->indirect[ my_block ];
842  }
843
844  /*
845   *  Is the block number in the doubly indirect portion?
846   */
847
848  if ( my_block <= LAST_DOUBLY_INDIRECT ) {
849#if 0
850printf( "(d %d) ", block );
851fflush(stdout);
852#endif
853
854    my_block -= FIRST_DOUBLY_INDIRECT;
855
856    singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
857    doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
858
859    p = info->doubly_indirect;
860    if ( malloc_it ) {
861
862      if ( !p ) {
863        p = memfile_alloc_block();
864        if ( !p )
865           return 0;
866        info->doubly_indirect = p;
867      }
868
869      p1 = (block_p *)p[ doubly ];
870      if ( !p1 ) {
871        p1 = memfile_alloc_block();
872        if ( !p1 )
873           return 0;
874        p[ doubly ] = (block_p) p1;
875      }
876
877      return (block_p *)&p[ singly ];
878    }
879
880    if ( !p )
881      return 0;
882
883    p = (block_p *)p[ doubly ];
884    if ( !p ) 
885      return 0;
886
887#if 0
888printf( "(d %d %d %d %d %p %p) ", block, my_block, doubly,
889                                       singly, p, &p[singly] );
890fflush(stdout);
891#endif
892    return (block_p *)&p[ singly ];
893  }
894
895#if 0
896printf( "(t %d) ", block );
897fflush(stdout);
898#endif
899  /*
900   *  Is the block number in the triply indirect portion?
901   */
902
903  if ( my_block <= LAST_TRIPLY_INDIRECT ) {
904    my_block -= FIRST_TRIPLY_INDIRECT;
905
906    singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
907    doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
908    triply = doubly / IMFS_MEMFILE_BLOCK_SLOTS;
909    doubly %= IMFS_MEMFILE_BLOCK_SLOTS;
910
911    p = info->triply_indirect;
912
913    if ( malloc_it ) {
914      if ( !p ) {
915        p = memfile_alloc_block();
916        if ( !p )
917           return 0;
918        info->triply_indirect = p;
919      }
920
921      p1 = (block_p *) p[ triply ];
922      if ( !p1 ) {
923        p1 = memfile_alloc_block();
924        if ( !p1 )
925           return 0;
926        p[ triply ] = (block_p) p1;
927      }
928
929      p2 = (block_p *)p1[ doubly ];
930      if ( !p2 ) {
931        p2 = memfile_alloc_block();
932        if ( !p2 )
933           return 0;
934        p1[ doubly ] = (block_p) p2;
935      }
936      return (block_p *)&p2[ singly ];
937    }
938
939    if ( !p )
940      return 0;
941
942#if 0
943printf( "(t %d %d %d %d %d) ", block, my_block, triply, doubly, singly );
944fflush(stdout);
945#endif
946    p1 = (block_p *) p[ triply ];
947    if ( !p1 )
948      return 0;
949
950    p2 = (block_p *)p1[ doubly ];
951    if ( !p )
952      return 0;
953
954    return (block_p *)&p2[ singly ];
955  }
956
957  /*
958   *  This means the requested block number is out of range.
959   */
960
961  return 0;
962}
963
964/*
965 *  memfile_alloc_block
966 *
967 *  Allocate a block for an in-memory file.
968 */
969
970int memfile_blocks_allocated = 0;
971
972void *memfile_alloc_block(void)
973{
974  void *memory;
975
976  memory = (void *)calloc(1, IMFS_MEMFILE_BYTES_PER_BLOCK);
977  if ( memory )
978    memfile_blocks_allocated++;
979
980  return memory;
981}
982
983/*
984 *  memfile_free_blocK
985 *
986 *  Free a block from an in-memory file.
987 */
988
989void memfile_free_block(
990  void *memory
991)
992{
993#if 0
994printf( "(d %p) ", memory );
995fflush(stdout);
996#endif
997  free(memory);
998  memfile_blocks_allocated--;
999}
1000
Note: See TracBrowser for help on using the repository browser.