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

4.115
Last change on this file since df01da67 was df01da67, checked in by Sebastian Huber <sebastian.huber@…>, on 05/14/12 at 11:16:31

Filesystem: Use ioctl_command_t

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