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

4.115
Last change on this file since c5b2d79 was c5b2d79, checked in by Sebastian Huber <sebastian.huber@…>, on 09/13/13 at 13:17:57

IMFS: Fix truncate according to POSIX

ftruncate() and open() with O_TRUNC shall upon successful completion
mark for update the st_ctime and st_mtime fields of the file.

truncate() shall upon successful completion, if the file size is
changed, mark for update the st_ctime and st_mtime fields of the file.

The POSIX standard "The Open Group Base Specifications Issue 7", IEEE
Std 1003.1, 2013 Edition says nothing about the behaviour of truncate()
if the file size remains unchanged.

Future directions of the standard may mandate the behaviour specified in
ftruncate():

http://austingroupbugs.net/view.php?id=489

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