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

4.11
Last change on this file since 46ae58a5 was 46ae58a5, checked in by Ralf Corsepius <ralf.corsepius@…>, on Dec 6, 2011 at 7:05:54 AM

2011-12-06 Ralf Corsépius <ralf.corsepius@…>

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