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

4.115
Last change on this file since 13c4f853 was 13c4f853, checked in by Joel Sherrill <joel.sherrill@…>, on 08/02/11 at 19:25:59

2011-08-02 Joel Sherrill <joel.sherrill@…>

PR 1877/cpukit

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