source: rtems/cpukit/libfs/src/imfs/memfile.c @ 6d9ab345

4.115
Last change on this file since 6d9ab345 was 6d9ab345, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 18, 2013 at 2:19:35 PM

IMFS: Fix NULL pointer access

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