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

4.115
Last change on this file since ef5e452 was ef5e452, checked in by Alex Ivanov <alexivanov97@…>, on Dec 20, 2012 at 3:45:31 PM

libfs: Doxygen Enhancement Task #1

  • 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 int 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 0;
278
279  /*
280   *  There is no memory for this block number so allocate it.
281   */
282  memory = memfile_alloc_block();
283  if ( !memory )
284    return 1;
285
286  *block_entry_ptr = memory;
287  return 0;
288}
289
290/*
291 *  IMFS_memfile_remove_block
292 *
293 *  This routine removes the specified block from the in-memory file.
294 *
295 *  NOTE:  This is a support routine and is called only to remove
296 *         the last block or set of blocks in a file.  Removing a
297 *         block from the middle of a file would be exceptionally
298 *         dangerous and the results unpredictable.
299 */
300MEMFILE_STATIC int IMFS_memfile_remove_block(
301   IMFS_jnode_t  *the_jnode,
302   unsigned int   block
303)
304{
305  block_p *block_ptr;
306  block_p  ptr;
307
308  block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
309  IMFS_assert( block_ptr );
310
311  ptr = *block_ptr;
312  *block_ptr = 0;
313  memfile_free_block( ptr );
314
315  return 1;
316}
317
318/*
319 *  memfile_free_blocks_in_table
320 *
321 *  This is a support routine for IMFS_memfile_remove.  It frees all the
322 *  blocks in one of the indirection tables.
323 */
324static void memfile_free_blocks_in_table(
325  block_p **block_table,
326  int       entries
327)
328{
329  int      i;
330  block_p *b;
331
332  /*
333   *  Perform internal consistency checks
334   */
335  IMFS_assert( block_table );
336
337  /*
338   *  Now go through all the slots in the table and free the memory.
339   */
340  b = *block_table;
341
342  for ( i=0 ; i<entries ; i++ ) {
343    if ( b[i] ) {
344      memfile_free_block( b[i] );
345      b[i] = 0;
346    }
347  }
348
349  /*
350   *  Now that all the blocks in the block table are free, we can
351   *  free the block table itself.
352   */
353  memfile_free_block( *block_table );
354  *block_table = 0;
355}
356
357/*
358 *  IMFS_memfile_remove
359 *
360 *  This routine frees all memory associated with an in memory file.
361 *
362 *  NOTE:  This is an exceptionally conservative implementation.
363 *         It will check EVERY pointer which is non-NULL and insure
364 *         any child non-NULL pointers are freed.  Optimistically, all that
365 *         is necessary is to scan until a NULL pointer is found.  There
366 *         should be no allocated data past that point.
367 *
368 *         In experimentation on the powerpc simulator, it was noted
369 *         that using blocks which held 128 slots versus 16 slots made
370 *         a significant difference in the performance of this routine.
371 *
372 *         Regardless until the IMFS implementation is proven, it
373 *         is better to stick to simple, easy to understand algorithms.
374 */
375IMFS_jnode_t *IMFS_memfile_remove(
376 IMFS_jnode_t  *the_jnode
377)
378{
379  IMFS_memfile_t  *info;
380  int              i;
381  int              j;
382  unsigned int     to_free;
383  block_p         *p;
384
385  /*
386   *  Perform internal consistency checks
387   */
388  IMFS_assert( the_jnode );
389  IMFS_assert( IMFS_type( the_jnode ) == IMFS_MEMORY_FILE );
390
391  /*
392   *  Eventually this could be set smarter at each call to
393   *  memfile_free_blocks_in_table to greatly speed this up.
394   */
395  to_free = IMFS_MEMFILE_BLOCK_SLOTS;
396
397  /*
398   *  Now start freeing blocks in this order:
399   *    + indirect
400   *    + doubly indirect
401   *    + triply indirect
402   */
403  info = &the_jnode->info.file;
404
405  if ( info->indirect ) {
406    memfile_free_blocks_in_table( &info->indirect, to_free );
407  }
408
409  if ( info->doubly_indirect ) {
410    for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
411      if ( info->doubly_indirect[i] ) {
412        memfile_free_blocks_in_table(
413         (block_p **)&info->doubly_indirect[i], to_free );
414      }
415    }
416    memfile_free_blocks_in_table( &info->doubly_indirect, to_free );
417
418  }
419
420  if ( info->triply_indirect ) {
421    for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
422      p = (block_p *) info->triply_indirect[i];
423      if ( !p )  /* ensure we have a valid pointer */
424         break;
425      for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) {
426        if ( p[j] ) {
427          memfile_free_blocks_in_table( (block_p **)&p[j], to_free);
428        }
429      }
430      memfile_free_blocks_in_table(
431        (block_p **)&info->triply_indirect[i], to_free );
432    }
433    memfile_free_blocks_in_table(
434        (block_p **)&info->triply_indirect, to_free );
435  }
436
437  return the_jnode;
438}
439
440/*
441 *  IMFS_memfile_read
442 *
443 *  This routine read from memory file pointed to by the_jnode into
444 *  the specified data buffer specified by destination.  The file
445 *  is NOT extended.  An offset greater than the length of the file
446 *  is considered an error.  Read from an offset for more bytes than
447 *  are between the offset and the end of the file will result in
448 *  reading the data between offset and the end of the file (truncated
449 *  read).
450 */
451MEMFILE_STATIC ssize_t IMFS_memfile_read(
452   IMFS_jnode_t    *the_jnode,
453   off_t            start,
454   unsigned char   *destination,
455   unsigned int     length
456)
457{
458  block_p             *block_ptr;
459  unsigned int         block;
460  unsigned int         my_length;
461  unsigned int         to_copy = 0;
462  unsigned int         last_byte;
463  unsigned int         copied;
464  unsigned int         start_offset;
465  unsigned char       *dest;
466
467  dest = destination;
468
469  /*
470   *  Perform internal consistency checks
471   */
472  IMFS_assert( the_jnode );
473  IMFS_assert( IMFS_type( the_jnode ) == IMFS_MEMORY_FILE ||
474    IMFS_type( the_jnode ) == IMFS_LINEAR_FILE );
475  IMFS_assert( dest );
476
477  /*
478   *  Linear files (as created from a tar file are easier to handle
479   *  than block files).
480   */
481  my_length = length;
482
483  if ( IMFS_type( the_jnode ) == IMFS_LINEAR_FILE ) {
484    unsigned char  *file_ptr;
485
486    file_ptr = (unsigned char *)the_jnode->info.linearfile.direct;
487
488    if (my_length > (the_jnode->info.linearfile.size - start))
489      my_length = the_jnode->info.linearfile.size - start;
490
491    memcpy(dest, &file_ptr[start], my_length);
492
493    IMFS_update_atime( the_jnode );
494
495    return my_length;
496  }
497
498  /*
499   *  If the last byte we are supposed to read is past the end of this
500   *  in memory file, then shorten the length to read.
501   */
502  last_byte = start + length;
503  if ( last_byte > the_jnode->info.file.size )
504    my_length = the_jnode->info.file.size - start;
505
506  copied = 0;
507
508  /*
509   *  Three phases to the read:
510   *    + possibly the last part of one block
511   *    + all of zero of more blocks
512   *    + possibly the first part of one block
513   */
514
515  /*
516   *  Phase 1: possibly the last part of one block
517   */
518  start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
519  block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
520  if ( start_offset )  {
521    to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
522    if ( to_copy > my_length )
523      to_copy = my_length;
524    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
525    if ( !block_ptr )
526      return copied;
527    memcpy( dest, &(*block_ptr)[ start_offset ], to_copy );
528    dest += to_copy;
529    block++;
530    my_length -= to_copy;
531    copied += to_copy;
532  }
533
534  /*
535   *  Phase 2: all of zero of more blocks
536   */
537  to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
538  while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
539    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
540    if ( !block_ptr )
541      return copied;
542    memcpy( dest, &(*block_ptr)[ 0 ], to_copy );
543    dest += to_copy;
544    block++;
545    my_length -= to_copy;
546    copied += to_copy;
547  }
548
549  /*
550   *  Phase 3: possibly the first part of one block
551   */
552  IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
553
554  if ( my_length ) {
555    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
556    if ( !block_ptr )
557      return copied;
558    memcpy( dest, &(*block_ptr)[ 0 ], my_length );
559    copied += my_length;
560  }
561
562  IMFS_update_atime( the_jnode );
563
564  return copied;
565}
566
567/*
568 *  IMFS_memfile_write
569 *
570 *  This routine writes the specified data buffer into the in memory
571 *  file pointed to by the_jnode.  The file is extended as needed.
572 */
573MEMFILE_STATIC ssize_t IMFS_memfile_write(
574   IMFS_jnode_t          *the_jnode,
575   off_t                  start,
576   const unsigned char   *source,
577   unsigned int           length
578)
579{
580  block_p             *block_ptr;
581  unsigned int         block;
582  int                  status;
583  unsigned int         my_length;
584  unsigned int         to_copy = 0;
585  unsigned int         last_byte;
586  unsigned int         start_offset;
587  int                  copied;
588  const unsigned char *src;
589
590  src = source;
591
592  /*
593   *  Perform internal consistency checks
594   */
595  IMFS_assert( source );
596  IMFS_assert( the_jnode );
597  IMFS_assert( IMFS_type( the_jnode ) == IMFS_MEMORY_FILE );
598
599  my_length = length;
600  /*
601   *  If the last byte we are supposed to write is past the end of this
602   *  in memory file, then extend the length.
603   */
604
605  last_byte = start + my_length;
606  if ( last_byte > the_jnode->info.file.size ) {
607    bool zero_fill = start > the_jnode->info.file.size;
608
609    status = IMFS_memfile_extend( the_jnode, zero_fill, last_byte );
610    if ( status )
611      return status;
612  }
613
614  copied = 0;
615
616  /*
617   *  Three phases to the write:
618   *    + possibly the last part of one block
619   *    + all of zero of more blocks
620   *    + possibly the first part of one block
621   */
622
623  /*
624   *  Phase 1: possibly the last part of one block
625   */
626  start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
627  block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
628  if ( start_offset )  {
629    to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
630    if ( to_copy > my_length )
631      to_copy = my_length;
632    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
633    if ( !block_ptr )
634      return copied;
635    #if 0
636      fprintf(
637        stderr,
638        "write %d at %d in %d: %*s\n",
639        to_copy,
640        start_offset,
641        block,
642        to_copy,
643        src
644      );
645    #endif
646    memcpy( &(*block_ptr)[ start_offset ], src, to_copy );
647    src += to_copy;
648    block++;
649    my_length -= to_copy;
650    copied += to_copy;
651  }
652
653  /*
654   *  Phase 2: all of zero of more blocks
655   */
656
657  to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
658  while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
659    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
660    if ( !block_ptr )
661      return copied;
662    #if 0
663      fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
664    #endif
665    memcpy( &(*block_ptr)[ 0 ], src, to_copy );
666    src += to_copy;
667    block++;
668    my_length -= to_copy;
669    copied += to_copy;
670  }
671
672  /*
673   *  Phase 3: possibly the first part of one block
674   */
675  IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
676
677  to_copy = my_length;
678  if ( my_length ) {
679    block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
680    if ( !block_ptr )
681      return copied;
682    #if 0
683    fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
684    #endif
685    memcpy( &(*block_ptr)[ 0 ], src, my_length );
686    my_length = 0;
687    copied += to_copy;
688  }
689
690  IMFS_mtime_ctime_update( the_jnode );
691
692  return copied;
693}
694
695/*
696 *  IMFS_memfile_get_block_pointer
697 *
698 *  This routine looks up the block pointer associated with the given block
699 *  number.  If that block has not been allocated and "malloc_it" is
700 *  TRUE, then the block is allocated.  Otherwise, it is an error.
701 */
702#if 0
703block_p *IMFS_memfile_get_block_pointer_DEBUG(
704   IMFS_jnode_t   *the_jnode,
705   unsigned int    block,
706   int             malloc_it
707);
708
709block_p *IMFS_memfile_get_block_pointer(
710   IMFS_jnode_t   *the_jnode,
711   unsigned int    block,
712   int             malloc_it
713)
714{
715  block_p *p;
716
717  p = IMFS_memfile_get_block_pointer_DEBUG( the_jnode, block, malloc_it );
718  fprintf(stdout, "(%d -> %p) ", block, p );
719  return p;
720}
721
722block_p *IMFS_memfile_get_block_pointer_DEBUG(
723#else
724block_p *IMFS_memfile_get_block_pointer(
725#endif
726   IMFS_jnode_t   *the_jnode,
727   unsigned int    block,
728   int             malloc_it
729)
730{
731  unsigned int    my_block;
732  IMFS_memfile_t *info;
733  unsigned int    singly;
734  unsigned int    doubly;
735  unsigned int    triply;
736  block_p        *p;
737  block_p        *p1;
738  block_p        *p2;
739
740  /*
741   *  Perform internal consistency checks
742   */
743  IMFS_assert( the_jnode );
744  IMFS_assert( IMFS_type( the_jnode ) == IMFS_MEMORY_FILE );
745
746  info = &the_jnode->info.file;
747  my_block = block;
748
749  /*
750   *  Is the block number in the simple indirect portion?
751   */
752  if ( my_block <= LAST_INDIRECT ) {
753    p = info->indirect;
754
755    if ( malloc_it ) {
756
757      if ( !p ) {
758        p = memfile_alloc_block();
759        if ( !p )
760           return 0;
761        info->indirect = p;
762      }
763      return &info->indirect[ my_block ];
764    }
765
766    if ( !p )
767      return 0;
768
769    return &info->indirect[ my_block ];
770  }
771
772  /*
773   *  Is the block number in the doubly indirect portion?
774   */
775
776  if ( my_block <= LAST_DOUBLY_INDIRECT ) {
777    my_block -= FIRST_DOUBLY_INDIRECT;
778
779    singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
780    doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
781
782    p = info->doubly_indirect;
783    if ( malloc_it ) {
784
785      if ( !p ) {
786        p = memfile_alloc_block();
787        if ( !p )
788           return 0;
789        info->doubly_indirect = p;
790      }
791
792      p1 = (block_p *)p[ doubly ];
793      if ( !p1 ) {
794        p1 = memfile_alloc_block();
795        if ( !p1 )
796           return 0;
797        p[ doubly ] = (block_p) p1;
798      }
799
800      return (block_p *)&p1[ singly ];
801    }
802
803    if ( !p )
804      return 0;
805
806    p = (block_p *)p[ doubly ];
807    if ( !p )
808      return 0;
809
810    return (block_p *)&p[ singly ];
811  }
812
813  /*
814   *  Is the block number in the triply indirect portion?
815   */
816  if ( my_block <= LAST_TRIPLY_INDIRECT ) {
817    my_block -= FIRST_TRIPLY_INDIRECT;
818
819    singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
820    doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
821    triply = doubly / IMFS_MEMFILE_BLOCK_SLOTS;
822    doubly %= IMFS_MEMFILE_BLOCK_SLOTS;
823
824    p = info->triply_indirect;
825
826    if ( malloc_it ) {
827      if ( !p ) {
828        p = memfile_alloc_block();
829        if ( !p )
830           return 0;
831        info->triply_indirect = p;
832      }
833
834      p1 = (block_p *) p[ triply ];
835      if ( !p1 ) {
836        p1 = memfile_alloc_block();
837        if ( !p1 )
838           return 0;
839        p[ triply ] = (block_p) p1;
840      }
841
842      p2 = (block_p *)p1[ doubly ];
843      if ( !p2 ) {
844        p2 = memfile_alloc_block();
845        if ( !p2 )
846           return 0;
847        p1[ doubly ] = (block_p) p2;
848      }
849      return (block_p *)&p2[ singly ];
850    }
851
852    if ( !p )
853      return 0;
854
855    p1 = (block_p *) p[ triply ];
856    if ( !p1 )
857      return 0;
858
859    p2 = (block_p *)p1[ doubly ];
860    if ( !p2 )
861      return 0;
862
863    return (block_p *)&p2[ singly ];
864  }
865
866  /*
867   *  This means the requested block number is out of range.
868   */
869  return 0;
870}
871
872/*
873 *  memfile_alloc_block
874 *
875 *  Allocate a block for an in-memory file.
876 */
877int memfile_blocks_allocated = 0;
878
879void *memfile_alloc_block(void)
880{
881  void *memory;
882
883  memory = (void *)calloc(1, IMFS_MEMFILE_BYTES_PER_BLOCK);
884  if ( memory )
885    memfile_blocks_allocated++;
886
887  return memory;
888}
889
890/*
891 *  memfile_free_block
892 *
893 *  Free a block from an in-memory file.
894 */
895void memfile_free_block(
896  void *memory
897)
898{
899  free(memory);
900  memfile_blocks_allocated--;
901}
Note: See TracBrowser for help on using the repository browser.