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

4.104.115
Last change on this file since ad7824bc was ad7824bc, checked in by Joel Sherrill <joel.sherrill@…>, on 01/19/10 at 01:55:28

2010-01-18 Joel Sherrill <joel.sherrill@…>

Coverity Id 12

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