source: rtems/cpukit/libfs/src/imfs/memfile.c @ 699ac7c

4.115
Last change on this file since 699ac7c was 699ac7c, checked in by Sebastian Huber <sebastian.huber@…>, on 02/24/12 at 16:08:06

IMFS: Add and use node control

Add and use structure IMFS_node_control with support functions. This
helps to make high level functions independent of the node type and
reduces the number of branches in the code.

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