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

4.115
Last change on this file since 30d4124 was 30d4124, checked in by Sebastian Huber <sebastian.huber@…>, on 05/07/12 at 14:30:37

Filesystem: PR1398: Fix lseek() mechanic

According to POSIX the lseek() function shall not, by itself, extend the
size of a file.

Remove the size field of rtems_libio_t. A file has only one size but
may have multiple open file descriptors. Thus a file size field in the
file descriptor may lead to inconsistencies.

New default handlers rtems_filesystem_default_lseek_file() and
rtems_filesystem_default_lseek_directory().

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