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

4.115
Last change on this file since fd2b1634 was fd2b1634, checked in by Sebastian Huber <sebastian.huber@…>, on 07/15/10 at 08:10:48

2010-07-16 Sebastian Huber <sebastian.huber@…>

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