]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/fs/ram/v2_0/src/ramfs.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / fs / ram / v2_0 / src / ramfs.c
1 //==========================================================================
2 //
3 //      ramfs.c
4 //
5 //      RAM file system
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):           nickg
44 // Contributors:        nickg
45 // Date:                2000-07-25
46 // Purpose:             RAM file system
47 // Description:         This is a RAM filesystem for eCos. It attempts to
48 //                      provide full POSIX-compatible filesystem behaviour
49 //                      while at the same time being efficient in terms of
50 //                      time and space used.
51 //                      
52 //
53 //####DESCRIPTIONEND####
54 //
55 //==========================================================================
56 // 
57 // General Description
58 // ===================
59 // 
60 // This is an implementation of a RAM filesystem for eCos. Its goal is
61 // to provide a working example of a filesystem that provides most of
62 // the required POSIX functionality. And obviously it may also be
63 // useful in its own right.
64 //
65 //
66 // Nodes
67 // -----
68 //
69 // All files and directories are represented by node objects. Each
70 // ramfs_node structure contains the following fields:
71 //
72 // mode   - Node type, file or directory.
73 // refcnt - Number of references to this node. For files each open counts as
74 //          a reference and for directories a node is referenced when it is made
75 //          current directory, or is opened for reading.
76 // nlink  - Number of links to this node. Each directory entry that references
77 //          this node is a link. 
78 // size   - Size of the data in this node in bytes.
79 // atime  - Last time this node was accessed.
80 // mtime  - Last time the data in this node was modified.
81 // ctime  - Last time the status information in this node was changed.
82 //
83 // The data storage in a node is controlled by the configuration and
84 // can take two forms. These will be described later.
85 //          
86 // Directories
87 // -----------
88 //
89 // A directory is a node whose data is a list of directory entries. To
90 // simplify management of these, long directory entries are split into
91 // a chain of fixed size ramfs_dirent structures. These contain the
92 // following fields:
93 //
94 // node    - Pointer to node referenced by this entry. This is present in
95 //           every directory entry fragment
96 // inuse   - Set to 1 if this entry is in use, zero if it is free.
97 // first   - Set to 1 if this is the first fragment of a directory entry.
98 // last    - Set to 1 if this is the last fragment of a directory entry.
99 // namelen - The size of the whole file name.
100 // fraglen - The number of bytes of the file name that are stored in this
101 //           fragment.
102 // next    - The offset of the next fragment of this directory entry.
103 // name    - The characters of the fragment of the file name stored in this
104 //           entry.
105 //
106 // Small file names are stored in a single fragment. Longer names are
107 // stored in a chain of fragments.
108 //
109 // Data Storage
110 // ------------
111 //
112 // Two data storage mechanisms may be configured, the SIMPLE and the
113 // BLOCKS mechanisms.
114 //
115 // SIMPLE Data Storage
116 // ~~~~~~~~~~~~~~~~~~~
117 //
118 // This mechanism simply uses malloc() and free() to allocate the
119 // memory for both nodes and file data. File data is stored in a
120 // single malloced vector that is realloced as necessary to acquire
121 // more space. 
122 //
123 // The advantage of this approach is that the RAM filesystem only uses
124 // as much memory as it needs, the rest is available for use by other
125 // components. It also requires much simpler data structures and code
126 // in the filesystem to manage. However, if any files get to be a
127 // significant proportion of the size of the heap, there is the danger
128 // that fragmentation will prevent any further extension of some
129 // files, even if there is enough memory in total. It also requires an
130 // implementation of malloc() to be present. If this needs to be
131 // present for other components,then this is not a significant
132 // overhead, but including it just for use by this filesystem
133 // represents a major addition of code and data structures.
134 //
135 //
136 // BLOCKS Data Storage
137 // ~~~~~~~~~~~~~~~~~~~
138 //
139 // This mechanism divides the memory used for file storage into fixed
140 // sized blocks. These blocks may either be allocated using
141 // malloc()/free(), or may be obtained from a array of blocks reserved
142 // for the purpose. Configuration allows the block size to be
143 // selected, as well as the allocation mechanism, and in the case of a
144 // block array, whether it is defined here or by an external
145 // component.
146 // 
147 // Data storage in nodes is arranges in three arrays of pointers to
148 // blocks. The first array points directly to data blocks, the second
149 // to blocks which themselves contain pointers to data blocks, and the
150 // third to blocks which contain pointers to blocks which contain
151 // pointers to data blocks. In the default configuration These last
152 // two arrays have only one element each.
153 // 
154 // The following shows how the data is arranged in a fully populated
155 // file with a 256 byte block size using the default configuration.
156 // 
157 //      Node
158 // ~            ~
159 // |            |
160 // |            |
161 // +------------+
162 // |     *------+--------> data block 0
163 // +------------+
164 // |     *------+--------> data block 1
165 // +------------+
166 // |     *------+--------> data block 2
167 // +------------+
168 // |     *------+--------> data block 3
169 // +------------+
170 // |     *------+--------> data block 4
171 // +------------+
172 // |     *------+--------> data block 5
173 // +------------+
174 // |     *------+--------> data block 6
175 // +------------+
176 // |     *------+--------> data block 7
177 // +------------+
178 // |     *------+--------> +------------+
179 // +------------+          |     *------+--------> data block 8
180 // |     *------+----+     +------------+
181 // +------------+    |     |            |
182 //                   |     ~            ~
183 //                   |     |            |
184 //                   |     +------------+
185 //                   |     |     *------+--------> data block 71
186 //                   |     +------------+
187 //                   |     
188 //                   +---->+------------+         +------------+
189 //                         |     *------+-------->|     *------+---->data block 72
190 //                         +------------+         +------------+
191 //                         |            |         |            |
192 //                         ~            ~         ~            ~
193 //                         |            |         |            |
194 //                         +------------+         +------------+
195 //                         |     *------+---+     |     *------+----> data block 135
196 //                         +------------+   |     +------------+
197 //                                          |
198 //                                          |     +------------+
199 //                                          +---->|     *------+----> data block 4104
200 //                                                +------------+
201 //                                                |            |
202 //                                                ~            ~
203 //                                                |            |
204 //                                                +------------+
205 //                                                |     *------+----> data block 4167
206 //                                                +------------+
207 // 
208 // 
209 //
210 // The advantages of this approach are that, first, memory usage is
211 // divided into discreet fixed size blocks which are easier to
212 // manage. When using malloc() to allocate them, they will fit into
213 // any free memory of at least the right size. Using the block array
214 // option removes the need to have a malloc() implementation at all.
215 //
216 // The disadvantages of this mechanism are that, first, when using
217 // malloc() to allocate blocks, the per-block memory allocator
218 // overhead is paid for each block, rather than per file. This may
219 // result in less memory overall being available for data
220 // storage. When using the block array, it is permanently reserved for
221 // use by the ram filesystem, and is not available for use by other
222 // components.
223 //
224 //==========================================================================
225
226 #include <pkgconf/system.h>
227 #include <pkgconf/hal.h>
228 #include <pkgconf/kernel.h>
229 #include <pkgconf/io_fileio.h>
230 #include <pkgconf/fs_ram.h>
231
232 #include <cyg/kernel/ktypes.h>         // base kernel types
233 #include <cyg/infra/cyg_trac.h>        // tracing macros
234 #include <cyg/infra/cyg_ass.h>         // assertion macros
235
236 #include <unistd.h>
237 #include <sys/types.h>
238 #include <fcntl.h>
239 #include <sys/stat.h>
240 #include <errno.h>
241 #include <dirent.h>
242
243 #include <stdlib.h>
244 #include <string.h>
245
246 #include <cyg/fileio/fileio.h>
247
248 #include <cyg/kernel/kapi.h>
249 #include <cyg/infra/diag.h>
250
251 //==========================================================================
252 // Sizes derived from configuration
253
254 // -------------------------------------------------------------------------
255 // Simple malloc based allocator parameters
256
257 #ifdef CYGPKG_FS_RAM_SIMPLE
258
259 #define RAMFS_FILESIZE_MAX      UINT_MAX
260
261 #else
262
263 // -------------------------------------------------------------------------
264 // Block allocator parameters
265
266 // The number of nodes per block
267 #define RAMFS_NODES_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_node))
268
269 // The number of indirect pointers that can be stored in a single data block
270 #define RAMFS_INDIRECT_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_block *))
271
272 // The number of directory entries that can be stored in a single data block
273 #define RAMFS_DIRENT_PER_BLOCK  (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_dirent))
274
275 // Number of bytes contained in a one level indirect block
276 #define RAMFS_INDIRECT1_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
277                                       CYGNUM_RAMFS_BLOCK_SIZE)
278
279 // number of bytes contained in a two level indirect block
280 #define RAMFS_INDIRECT2_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
281                                       RAMFS_INDIRECT_PER_BLOCK* \
282                                       CYGNUM_RAMFS_BLOCK_SIZE)
283
284 // The maximum data offset for data directly accessed from the node
285 #define RAMFS_DIRECT_MAX        (CYGNUM_RAMFS_BLOCKS_DIRECT*CYGNUM_RAMFS_BLOCK_SIZE)
286
287 // The maximum data offset for data accessed from the single level indirect blocks
288 #define RAMFS_INDIRECT1_MAX     (RAMFS_DIRECT_MAX+                      \
289                                  (CYGNUM_RAMFS_BLOCKS_INDIRECT1*        \
290                                   RAMFS_INDIRECT1_BLOCK_EXTENT))
291
292 // The maximum data offset for data accessed from the two level indirect blocks
293 #define RAMFS_INDIRECT2_MAX     (RAMFS_INDIRECT1_MAX+                   \
294                                  (CYGNUM_RAMFS_BLOCKS_INDIRECT2*        \
295                                   RAMFS_INDIRECT2_BLOCK_EXTENT))
296
297 // The maximum size of a file
298 #define RAMFS_FILESIZE_MAX      RAMFS_INDIRECT2_MAX
299
300 #endif
301
302 //==========================================================================
303 // Forward definitions
304
305 // Filesystem operations
306 static int ramfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
307 static int ramfs_umount   ( cyg_mtab_entry *mte );
308 static int ramfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
309                              int mode,  cyg_file *fte );
310 static int ramfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
311 static int ramfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
312 static int ramfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
313 static int ramfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
314                              cyg_dir dir2, const char *name2 );
315 static int ramfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
316                              cyg_dir dir2, const char *name2, int type );
317 static int ramfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
318                              cyg_file *fte );
319 static int ramfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
320                              cyg_dir *dir_out );
321 static int ramfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
322                              struct stat *buf);
323 static int ramfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
324                              int key, void *buf, int len );
325 static int ramfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
326                              int key, void *buf, int len );
327
328 // File operations
329 static int ramfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
330 static int ramfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
331 static int ramfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
332 static int ramfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
333                                 CYG_ADDRWORD data);
334 static int ramfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode );        
335 static int ramfs_fo_close     (struct CYG_FILE_TAG *fp);
336 static int ramfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf );
337 static int ramfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
338 static int ramfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
339
340 // Directory operations
341 static int ramfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
342 static int ramfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
343
344
345 //==========================================================================
346 // Filesystem table entries
347
348 // -------------------------------------------------------------------------
349 // Fstab entry.
350 // This defines the entry in the filesystem table.
351 // For simplicity we use _FILESYSTEM synchronization for all accesses since
352 // we should never block in any filesystem operations.
353
354 FSTAB_ENTRY( ramfs_fste, "ramfs", 0,
355              CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
356              ramfs_mount,
357              ramfs_umount,
358              ramfs_open,
359              ramfs_unlink,
360              ramfs_mkdir,
361              ramfs_rmdir,
362              ramfs_rename,
363              ramfs_link,
364              ramfs_opendir,
365              ramfs_chdir,
366              ramfs_stat,
367              ramfs_getinfo,
368              ramfs_setinfo);
369
370 // -------------------------------------------------------------------------
371 // File operations.
372 // This set of file operations are used for normal open files.
373
374 static cyg_fileops ramfs_fileops =
375 {
376     ramfs_fo_read,
377     ramfs_fo_write,
378     ramfs_fo_lseek,
379     ramfs_fo_ioctl,
380     cyg_fileio_seltrue,
381     ramfs_fo_fsync,
382     ramfs_fo_close,
383     ramfs_fo_fstat,
384     ramfs_fo_getinfo,
385     ramfs_fo_setinfo
386 };
387
388 // -------------------------------------------------------------------------
389 // Directory file operations.
390 // This set of operations are used for open directories. Most entries
391 // point to error-returning stub functions. Only the read, lseek and
392 // close entries are functional.
393
394 static cyg_fileops ramfs_dirops =
395 {
396     ramfs_fo_dirread,
397     (cyg_fileop_write *)cyg_fileio_enosys,
398     ramfs_fo_dirlseek,
399     (cyg_fileop_ioctl *)cyg_fileio_enosys,
400     cyg_fileio_seltrue,
401     (cyg_fileop_fsync *)cyg_fileio_enosys,
402     ramfs_fo_close,
403     (cyg_fileop_fstat *)cyg_fileio_enosys,
404     (cyg_fileop_getinfo *)cyg_fileio_enosys,
405     (cyg_fileop_setinfo *)cyg_fileio_enosys
406 };
407
408 //==========================================================================
409 // Data typedefs
410 // Some forward typedefs for the main data structures.
411
412 struct ramfs_node;
413 typedef struct ramfs_node ramfs_node;
414
415 struct ramfs_dirent;
416 typedef struct ramfs_dirent ramfs_dirent;
417
418 #ifndef CYGPKG_FS_RAM_SIMPLE
419
420 typedef cyg_uint8 ramfs_block[CYGNUM_RAMFS_BLOCK_SIZE];
421
422 #endif
423
424 //==========================================================================
425 // File and directory node
426 // This data structure represents a file or directory.
427
428 struct ramfs_node
429 {
430     mode_t              mode;           // node type
431     cyg_ucount32        refcnt;         // open file/current dir references
432     nlink_t             nlink;          // number of links to this node
433     size_t              size;           // size of file in bytes
434     time_t              atime;          // last access time
435     time_t              mtime;          // last modified time
436     time_t              ctime;          // last changed status time
437
438 #ifdef CYGPKG_FS_RAM_SIMPLE
439
440     // The data storage in this case consists of a single
441     // malloced memory block, together with its size.
442     
443     size_t              datasize;       // size of data block
444     cyg_uint8           *data;          // malloced data buffer
445
446 #else
447
448     // The data storage in this case consists of arrays of pointers
449     // to data blocks. 
450     
451 #if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
452     // Directly accessible blocks from the inode.
453     ramfs_block         *direct[CYGNUM_RAMFS_BLOCKS_DIRECT];
454 #endif
455 #if  CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
456     // Single level indirection
457     ramfs_block         **indirect1[CYGNUM_RAMFS_BLOCKS_INDIRECT1];
458 #endif
459 #if  CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
460     // Two level indirection
461     ramfs_block         ***indirect2[CYGNUM_RAMFS_BLOCKS_INDIRECT2];
462 #endif
463
464 #endif
465     
466 };
467
468 //==========================================================================
469 // Directory entry.
470 // Fixed sized entry containing a fragment of the name of a file/directory.
471
472 struct ramfs_dirent
473 {
474     ramfs_node          *node;          // pointer to node
475     unsigned int        inuse:1,        // entry in use?
476                         first:1,        // first directory entry fragment?
477                         last:1,         // last directory entry fragment?
478                         namelen:8,      // bytes in whole name
479                         fraglen:8;      // bytes in name fragment
480     off_t               next;           // offset of next dirent
481
482     // Name fragment, fills rest of entry.
483     char                name[CYGNUM_RAMFS_DIRENT_SIZE-
484                              sizeof(ramfs_node *)-
485                              sizeof( cyg_uint32)-
486                              sizeof(off_t)];
487 };
488
489 //==========================================================================
490 // Directory search data
491 // Parameters for a directory search. The fields of this structure are
492 // updated as we follow a pathname through the directory tree.
493
494 struct ramfs_dirsearch
495 {
496     ramfs_node          *dir;           // directory to search
497     const char          *path;          // path to follow
498     ramfs_node          *node;          // Node found
499     const char          *name;          // last name fragment used
500     int                 namelen;        // name fragment length
501     cyg_bool            last;           // last name in path?
502 };
503
504 typedef struct ramfs_dirsearch ramfs_dirsearch;
505
506 //==========================================================================
507 // Forward defs
508
509 static int del_direntry( ramfs_node *dir, const char *name, int namelen );
510
511
512 //==========================================================================
513 // Block array
514 // This is used for block allocation when malloc is not being used.
515
516 #ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
517
518 # ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY_EXTERN
519
520 // Array is defined externally with a user-supplied name
521
522 __externC ramfs_block CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
523
524 // Translate into a usable common name
525 #define ramfs_block_array CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME
526
527 # else
528
529 // Array is defined here
530
531 static ramfs_block cyg_ramfs_block_array[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
532
533 #define ramfs_block_array cyg_ramfs_block_array
534
535 # endif
536
537 // Pointer to list of free blocks
538 static ramfs_block *block_free_list = NULL;
539
540 #endif
541
542 //==========================================================================
543 // Block allocation
544
545 #ifndef CYGPKG_FS_RAM_SIMPLE
546
547 // -------------------------------------------------------------------------
548 // block_init()
549 // Initialize the block allocator by chaining them all together on
550 // block_free_list.
551
552 #ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
553
554 static void block_init(void)
555 {
556     static cyg_bool initialized = false;
557     int i;
558
559     if( !initialized )
560     {
561         for( i = 0; i < CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE; i++ )
562         {
563             ramfs_block *b = &ramfs_block_array[i];
564             *(ramfs_block **)b = block_free_list;
565             block_free_list = b;
566         }
567         initialized = true;
568     }
569 }
570
571 #endif
572
573 // -------------------------------------------------------------------------
574 // block_alloc()
575 // Allocate a block for data storage.
576 // If we have a block array, just pick the first off the free list.
577 // If we are mallocing, call malloc() to get it.
578
579 static ramfs_block *block_alloc(void)
580 {
581     ramfs_block *b;
582
583 #ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
584
585     block_init();       // Check blocks are initialized
586
587     // pick first block off free list.
588     b = block_free_list;
589
590     // and advance list
591     if( b != NULL )
592         block_free_list = *(ramfs_block **)b;
593
594 #else
595
596     b = malloc(CYGNUM_RAMFS_BLOCK_SIZE);
597
598 #endif
599
600     // Clear the block to zero if it was allocated
601     if( b != NULL )
602         memset( b, 0, CYGNUM_RAMFS_BLOCK_SIZE );
603
604     return b;
605
606 }
607
608 // -------------------------------------------------------------------------
609 // block_free()
610 // Free a block. Depending on the configuration send it back to the
611 // heap or put it back on free list.
612
613 static void block_free( ramfs_block *b )
614 {
615 #ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
616
617     // Put the block back on the free list
618     
619     *(ramfs_block **)b = block_free_list;
620     block_free_list = b;
621     
622 #else    
623
624     // Call free() to return it to the memory pool
625     
626     free( b );
627
628 #endif
629 }
630
631 #endif
632
633 //==========================================================================
634 // Node buffer management
635 // There are two versions of this, one for the _SIMPLE variant and one for
636 // the _BLOCKS variant. In both cases the interface to this code is via the
637 // findbuffer_node() and freebuffer_node() functions.
638
639 #ifdef CYGPKG_FS_RAM_SIMPLE
640
641 //==========================================================================
642 // SIMPLE buffer management.
643 // Each node has a data buffer pointer and a size. This buffer is
644 // realloc()ed as needed.
645
646 // -------------------------------------------------------------------------
647 // findbuffer_node()
648 // return a pointer to the data at the indicated file position, extending
649 // the buffer if required.
650
651 static int findbuffer_node( ramfs_node  *node,  // node pointer
652                             off_t pos,          // data position to get
653                             cyg_uint8 **buffer, // returned buffer pointer
654                             size_t *size,       // returned buffer size
655                             cyg_bool alloc)     // extend allocation?
656 {
657     if( alloc && (pos >= node->datasize || node->datasize == 0) )
658     {
659         // If we are allowed to alloc new data, and we are at the end of the
660         // current data allocation, or there is no data present, allocate or
661         // extend the data buffer.
662         
663         cyg_uint8 *newdata;
664         
665         if( node->data == NULL )
666             newdata = malloc( CYGNUM_RAMFS_REALLOC_INCREMENT );
667         else
668             newdata = realloc( node->data, pos+CYGNUM_RAMFS_REALLOC_INCREMENT );
669         
670         if( newdata == NULL ) return ENOSPC;
671         else memset( newdata + node->datasize, 0, 
672                      pos + CYGNUM_RAMFS_REALLOC_INCREMENT - node->datasize );
673         
674         node->data = newdata;
675         node->datasize = pos+CYGNUM_RAMFS_REALLOC_INCREMENT;
676     }
677     else if( pos > node->datasize )
678     {
679         // Indicate end of data.
680         *size = 0;
681         return ENOERR;
682     }
683
684     *buffer = node->data+pos;
685     *size = node->datasize-pos;
686
687     return ENOERR;
688 }
689
690 // -------------------------------------------------------------------------
691 // freebuffer_node()
692 // Empty out the data storage from the node.
693
694 static int freebuffer_node( ramfs_node *node )
695 {
696     if( node->data != NULL )
697     {
698         free( node->data );
699     }
700
701     node->data = NULL;
702     node->datasize = 0;
703
704     return ENOERR;
705 }
706
707 //==========================================================================
708
709 #else
710
711 //==========================================================================
712 // _BLOCKS storage management.
713 // Data storage in the node is by means of a set of arrays of pointers to
714 // blocks. The first array points directly to the data blocks. Subsequent
715 // arrays point to single and double indirect blocks respectively. 
716
717 // -------------------------------------------------------------------------
718 // findbuffer_direct()
719 // Indexes into an array of block pointers and extracts a pointer to the
720 // data at offset _pos_, allocating new blocks if required.
721
722 static int findbuffer_direct( off_t pos,
723                               ramfs_block **blocks,
724                               int nblocks,
725                               cyg_uint8 **buffer,
726                               size_t *size,
727                               cyg_bool alloc)
728 {
729     int bi = pos / CYGNUM_RAMFS_BLOCK_SIZE;
730     int bpos = pos % CYGNUM_RAMFS_BLOCK_SIZE;
731     ramfs_block *b;
732     
733     *buffer = NULL;
734     *size = CYGNUM_RAMFS_BLOCK_SIZE - bpos;
735     
736     if( bi >= nblocks )
737         return ENOERR;
738
739     b = blocks[bi];
740
741     if( b == NULL )
742     {
743         // There is no block there. If _alloc_ is true we can fill the
744         // slot in with a new block. If it is false, we indicate there
745         // is no block and size indicates where the block would end if
746         // it existed.
747         if( alloc )
748         {
749             b = block_alloc();
750             if( b == NULL )
751                 return ENOSPC;
752             blocks[bi] = b;
753         }
754         else return ENOERR;
755     }
756
757     *buffer = &((*b)[bpos]);
758
759     return ENOERR;
760 }
761
762 // -------------------------------------------------------------------------
763 // findbuffer_indirect1()
764 // Indexes into an array of pointers to blocks containing pointers to
765 // blocks and extracts a pointer to the data at offset _pos_,
766 // allocating new blocks if required.
767
768 #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
769
770 static int findbuffer_indirect1( off_t pos,
771                                  ramfs_block ***blocks,
772                                  int nblocks,
773                                  cyg_uint8 **buffer,
774                                  size_t *size,
775                                  cyg_bool alloc)
776 {
777
778     int bi = pos / RAMFS_INDIRECT1_BLOCK_EXTENT;
779     int bpos = pos % RAMFS_INDIRECT1_BLOCK_EXTENT;
780     int err;
781     cyg_uint8 *b;
782     size_t sz;
783
784     // Use findbuffer_direct() to index and allocate
785     // the first level indirect block.
786     
787     err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
788                              (ramfs_block **)blocks,
789                              nblocks,
790                              &b,
791                              &sz,
792                              alloc);
793
794     if( err != ENOERR )
795         return err;
796
797     if( sz == 0 )
798     {
799         *size = 0;
800         return ENOERR;
801     }
802
803     // Use findbuffer_direct() on the first level indirect
804     // block to allocate and return the data pointer.
805     
806     return findbuffer_direct( bpos,
807                               blocks[bi],
808                               RAMFS_INDIRECT_PER_BLOCK,
809                               buffer,
810                               size,
811                               alloc);
812 }
813
814 #endif
815
816 // -------------------------------------------------------------------------
817 // findbuffer_indirect1()
818 // Indexes into an array of pointers to blocks containing pointers to
819 // blocks containing pointers to blocks (!) and extracts a pointer to
820 // the data at offset _pos_, allocating new blocks if required.
821
822 #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
823
824 static int findbuffer_indirect2( off_t pos,
825                                  ramfs_block ****blocks,
826                                  int nblocks,
827                                  cyg_uint8 **buffer,
828                                  size_t *size,
829                                  cyg_bool alloc)
830 {
831     int bi = pos / RAMFS_INDIRECT2_BLOCK_EXTENT;
832     int bpos = pos % RAMFS_INDIRECT2_BLOCK_EXTENT;
833     int err;
834     cyg_uint8 *b;
835     size_t sz;
836
837     // Use findbuffer_direct() to index and allocate
838     // the first level indirect block.
839
840     err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
841                              (ramfs_block **)blocks,
842                              nblocks,
843                              &b,
844                              &sz,
845                              alloc);
846
847     if( err != ENOERR )
848         return err;
849
850     if( sz == 0 )
851     {
852         *size = 0;
853         return ENOERR;
854     }
855
856     // Use findbuffer_indirect1() on the first level indirect block to
857     // index and allocate the next level indirect block and the data
858     // block.
859     
860     return findbuffer_indirect1( bpos,
861                                  blocks[bi],
862                                  RAMFS_INDIRECT_PER_BLOCK,
863                                  buffer,
864                                  size,
865                                  alloc);
866 }
867
868 #endif
869
870 // -------------------------------------------------------------------------
871 // findbuffer_node()
872 // Depending on the offset and configuration, call the appropriate
873 // function to get the buffer pointer.
874
875 static int findbuffer_node( ramfs_node  *node,
876                             off_t pos,
877                             cyg_uint8 **buffer,
878                             size_t *size,
879                             cyg_bool alloc)
880 {
881 #if CYGNUM_RAMFS_BLOCKS_DIRECT > 0    
882     if( pos < RAMFS_DIRECT_MAX )
883         return findbuffer_direct( pos,
884                                   node->direct,
885                                   CYGNUM_RAMFS_BLOCKS_DIRECT,
886                                   buffer,
887                                   size,
888                                   alloc);
889 #endif        
890 #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0    
891     if( pos < RAMFS_INDIRECT1_MAX )
892         return findbuffer_indirect1( pos - RAMFS_DIRECT_MAX,
893                                      node->indirect1,
894                                      CYGNUM_RAMFS_BLOCKS_INDIRECT1,
895                                      buffer,
896                                      size,
897                                      alloc);
898 #endif        
899 #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0    
900     if( pos < RAMFS_INDIRECT2_MAX )
901         return findbuffer_indirect2( pos - RAMFS_INDIRECT1_MAX,
902                                      node->indirect2,
903                                      CYGNUM_RAMFS_BLOCKS_INDIRECT2,
904                                      buffer,
905                                      size,
906                                      alloc);
907 #endif
908
909     return ENOSPC;
910 }
911
912 // -------------------------------------------------------------------------
913 // freeblock_list()
914 // Free a list of data blocks.
915
916 static void freeblock_list( ramfs_block *blocks[],int nblocks )
917 {
918     int i;
919     for( i = 0; i < nblocks ; i++ )
920     {
921         if( blocks[i] != NULL )
922         {
923             block_free( blocks[i] );
924             blocks[i] = NULL;
925         }
926     }
927 }
928
929 // -------------------------------------------------------------------------
930 // freebuffer_node()
931 // Free all the data blocks in the node and clear the pointers.
932
933 static int freebuffer_node( ramfs_node *node )
934 {
935 #if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
936     freeblock_list( node->direct, CYGNUM_RAMFS_BLOCKS_DIRECT );
937 #endif
938
939 #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
940     {
941         int i;
942         for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT1 ; i++ )
943         {
944             if( node->indirect1[i] != NULL )
945             {
946                 freeblock_list( (ramfs_block **)node->indirect1[i], RAMFS_INDIRECT_PER_BLOCK );
947                 block_free( (ramfs_block *)node->indirect1[i] );
948                 node->indirect1[i] = NULL;
949             }
950         }
951     }
952 #endif    
953
954 #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
955     {
956         int i;
957         for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT2 ; i++ )
958         {
959             if( node->indirect2[i] != NULL )
960             {
961                 ramfs_block ***b = node->indirect2[i];
962                 int j;
963                 for( j = 0; j < RAMFS_INDIRECT_PER_BLOCK ; j++ )
964                 {
965                     if( b[j] != NULL )
966                     {
967                         freeblock_list( (ramfs_block **)b[j], RAMFS_INDIRECT_PER_BLOCK );
968                         block_free( (ramfs_block *)b[j] );
969                         b[j] = NULL;
970                     }
971                 }
972                 block_free( (ramfs_block *)node->indirect2[i] );
973                 node->indirect2[i] = NULL;
974             }
975         }
976     }
977 #endif
978
979     return ENOERR;
980 }
981
982 //==========================================================================
983
984 #endif
985
986 //==========================================================================
987 // Node allocation
988
989 // -------------------------------------------------------------------------
990 // alloc_node()
991 // Allocate a node and initialize it.
992 // For the _SIMPLE allocation option, we just malloc it. For the
993 // _BLOCKS option we allocate a block and use that. In theory we could
994 // pack several nodes into a single block, but we don't at present due
995 // to sheer lazyness.
996
997 static ramfs_node *alloc_node( mode_t mode )
998 {
999 #ifdef CYGPKG_FS_RAM_SIMPLE
1000     ramfs_node *node = malloc( sizeof( ramfs_node ) );
1001
1002     if( node == NULL )
1003         return NULL;
1004     
1005 #else
1006     ramfs_block *b = block_alloc();
1007     ramfs_node *node;
1008
1009     if( b == NULL )
1010         return NULL;
1011
1012     node = (ramfs_node *)b;
1013     
1014 #endif
1015
1016     memset( node, 0, sizeof(ramfs_node) );
1017     
1018     node->mode          = mode;
1019     node->refcnt        = 0;
1020     node->nlink         = 0;
1021     node->size          = 0;
1022     node->atime         = 
1023     node->mtime         = 
1024     node->ctime         = cyg_timestamp();
1025
1026 #ifdef CYGPKG_FS_RAM_SIMPLE    
1027     node->datasize      = 0;
1028     node->data          = NULL;
1029 #else
1030
1031     // The node is already all zero
1032     
1033 #endif    
1034     return node;
1035 }
1036
1037 // -------------------------------------------------------------------------
1038 // free_node()
1039 // Release a node either back to the free pool or back into the block
1040 // pool.
1041
1042 static void free_node( ramfs_node *node )
1043 {
1044 #ifdef CYGPKG_FS_RAM_SIMPLE    
1045
1046     free( node );
1047
1048 #else
1049
1050     block_free( (ramfs_block *)node );
1051
1052 #endif    
1053     
1054 }
1055
1056
1057 //==========================================================================
1058 // Ref count and nlink management
1059
1060 // -------------------------------------------------------------------------
1061 // dec_refcnt()
1062 // Decrment the reference count on a node. If this makes the ref count
1063 // zero, and the number of links is either zero for a file or one for
1064 // a node, then this node is detached from the directory tree and can
1065 // be freed.
1066
1067 static int dec_refcnt( ramfs_node *node )
1068 {
1069     int err = ENOERR;
1070     node->refcnt--;
1071
1072     if( node->refcnt == 0 &&
1073         ((S_ISREG(node->mode) && node->nlink == 0 ) ||
1074          (S_ISDIR(node->mode) && node->nlink == 1) )
1075         )
1076     {
1077         // This node it now totally detached from the directory tree,
1078         // so delete it.
1079
1080         if( S_ISDIR(node->mode) )
1081         {
1082             del_direntry( node, ".", 1 );
1083             del_direntry( node, "..", 2 );
1084         }
1085         
1086         err = freebuffer_node( node );
1087
1088         if( err == ENOERR )
1089             free_node( node );
1090     }
1091
1092     return err;
1093 }
1094
1095 // -------------------------------------------------------------------------
1096 // dec_nlink()
1097 // Decrement a node's link count. Since this has to do all the same
1098 // work as dec_refcnt() we implement this using that function by
1099 // essentially transferring the count to refcnt and then decrement
1100 // that.
1101
1102 static int dec_nlink( ramfs_node *node )
1103 {
1104     node->refcnt++;
1105     
1106     node->nlink--;
1107
1108     return dec_refcnt( node );
1109 }
1110
1111 //==========================================================================
1112 // Directory operations
1113
1114 // -------------------------------------------------------------------------
1115 // add_direntry()
1116 // Add an entry to a directory. This is added as a chain of entry
1117 // fragments until the name is exhausted.
1118
1119 static int add_direntry( ramfs_node *dir,       // dir to add to
1120                          const char *name,      // name to add
1121                          int namelen,           // length of name
1122                          ramfs_node *node       // node to reference
1123                        )
1124 {
1125     off_t pos = 0;
1126     ramfs_dirent *d = NULL, *dp = NULL;
1127     cyg_bool isfirst = true;
1128
1129     // Loop inserting fragments of the name into the directory until we
1130     // have found a home for them all.
1131     
1132     while( namelen > 0 )
1133     {
1134         int fraglen = namelen;
1135
1136         if( fraglen > sizeof(d->name) )
1137             fraglen = sizeof(d->name);
1138
1139         // Find a free fragment
1140         for(;;)
1141         {
1142             cyg_uint8 *buf;
1143             size_t size;
1144             int err = findbuffer_node( dir, pos, &buf, &size, true );
1145             if( err != ENOERR ) return err;
1146
1147             d = (ramfs_dirent *)buf;
1148
1149             if( size < sizeof(ramfs_dirent) || d->inuse )
1150             {
1151                 pos += sizeof(ramfs_dirent);
1152                 continue;
1153             }
1154
1155             break;
1156         }
1157
1158         // d now points to a free dirent structure
1159
1160         d->node         = node;
1161         d->inuse        = 1;
1162         d->first        = isfirst;
1163         d->namelen      = namelen;
1164         d->fraglen      = fraglen;
1165         if( dp ) dp->next = pos;
1166
1167         memcpy( d->name, name, fraglen );
1168
1169         name            += fraglen;
1170         namelen         -= fraglen;
1171         pos             += sizeof(ramfs_dirent);
1172         dp              = d;
1173         isfirst         = false;
1174         
1175     }
1176
1177     
1178     d->last = 1;        // Mark last fragment
1179     
1180     // Update directory times
1181     dir->mtime =
1182     dir->ctime = cyg_timestamp();
1183     
1184     // Extend dir size if necessary
1185     if( pos > dir->size )
1186         dir->size = pos;
1187     
1188     // Count the new link
1189     node->nlink++;
1190     
1191     return ENOERR;
1192 }
1193
1194 // -------------------------------------------------------------------------
1195 // find_direntry()
1196 // Find a directory entry for the name and return a pointer to the first
1197 // entry fragment.
1198
1199 static ramfs_dirent *find_direntry( ramfs_node *dir, const char *name, int namelen )
1200 {
1201     ramfs_dirent *first = NULL;
1202     off_t pos = 0;
1203     int err;
1204
1205     // Loop over all the entries until a match is found or we run out
1206     // of data.
1207     while( pos < dir->size )
1208     {
1209         const char *frag = name;
1210         ramfs_dirent *d;
1211         cyg_uint8 *buf;
1212         size_t size;
1213
1214         // look for a first name fragment
1215         for(;;)
1216         {
1217           err = findbuffer_node( dir, pos, &buf, &size, false );
1218             if( err != ENOERR || size == 0)
1219                 return NULL;
1220
1221             d = (ramfs_dirent *)buf;
1222
1223             if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
1224             {
1225                 pos += sizeof(ramfs_dirent);
1226                 if ( pos < dir->size )
1227                   continue;
1228                 // End if directory, didn't find it.
1229                 return NULL;
1230             }
1231
1232             break;
1233         }
1234
1235         // Here we have got a first fragment of a name, check it
1236         // against the name we are looking for. First check that they
1237         // are the same length.
1238
1239         if( d->namelen == namelen )
1240         {
1241             // We have a potential candidate here...
1242             
1243             first = d;      // Save it for later
1244
1245             // Now check that all the name fragments match
1246             for(;;)
1247             {
1248                 int fraglen = namelen-(frag-name);
1249
1250                 if( fraglen > d->fraglen )
1251                     fraglen = d->fraglen;
1252
1253                 // compare strings, if different, look for another
1254                 if( memcmp( frag, d->name, fraglen ) != 0 ) {
1255                   break;
1256                 }
1257                 frag        += fraglen;
1258             
1259                 // If we are at the last fragment, then the whole name string
1260                 // has matched and we have a successful search.
1261                 
1262                 if( d->last ) 
1263                   return first;
1264                 
1265                 // Otherwise move on to next entry in chain
1266                 err = findbuffer_node( dir, d->next, &buf, &size, false );
1267                 if( err != ENOERR )
1268                     return NULL;
1269
1270                 d = (ramfs_dirent *)buf;
1271
1272             }
1273         }
1274
1275         pos += sizeof(ramfs_dirent);        
1276     }
1277
1278     return NULL;
1279 }
1280
1281 // -------------------------------------------------------------------------
1282 // del_direntry()
1283 // Delete a named directory entry. Find it and then follow the chain
1284 // deleting the fragments as we go.
1285
1286 static int del_direntry( ramfs_node *dir, const char *name, int namelen )
1287 {
1288     ramfs_dirent *d = find_direntry( dir, name, namelen );
1289     
1290     if( d == NULL )
1291         return ENOENT;
1292
1293     for(;;)
1294     {
1295         int err;
1296         cyg_uint8 *buf;
1297         size_t size;
1298
1299         d->inuse = 0;
1300         if( d->last ) break;
1301
1302         err = findbuffer_node( dir, d->next, &buf, &size, false );
1303         if( err != ENOERR )
1304             return ENOENT;
1305
1306         d = (ramfs_dirent *)buf;
1307     }
1308
1309     dec_nlink( d->node );
1310     
1311     return ENOERR;
1312 }
1313
1314 //==========================================================================
1315 // Directory search
1316
1317 // -------------------------------------------------------------------------
1318 // init_dirsearch()
1319 // Initialize a dirsearch object to start a search
1320
1321 static void init_dirsearch( ramfs_dirsearch *ds,
1322                             ramfs_node *dir,
1323                             const char *name)
1324 {
1325     ds->dir      = dir;
1326     ds->path     = name;
1327     ds->node     = dir;
1328     ds->name     = name;
1329     ds->namelen  = 0;
1330     ds->last     = false;    
1331 }
1332
1333 // -------------------------------------------------------------------------
1334 // find_entry()
1335 // Search a single directory for the next name in a path and update the
1336 // dirsearch object appropriately.
1337
1338 static int find_entry( ramfs_dirsearch *ds )
1339 {
1340     ramfs_node *dir = ds->dir;
1341     const char *name = ds->path;
1342     const char *n = name;
1343     char namelen = 0;
1344     ramfs_dirent *d;
1345     
1346     // check that we really have a directory
1347     if( !S_ISDIR(dir->mode) )
1348         return ENOTDIR;
1349
1350     // Isolate the next element of the path name. 
1351     while( *n != '\0' && *n != '/' )
1352         n++, namelen++;
1353
1354     // Check if this is the last path element.
1355     while( *n == '/') n++;
1356     if( *n == '\0' ) 
1357         ds->last = true;
1358
1359     // update name in dirsearch object
1360     ds->name = name;
1361     ds->namelen = namelen;
1362     
1363     // Here we have the name and its length set up.
1364     // Search the directory for a matching entry
1365
1366     d = find_direntry( dir, name, namelen );
1367
1368     if( d == NULL )
1369         return ENOENT;
1370
1371     // pass back the node we have found
1372     ds->node = d->node;
1373
1374     return ENOERR;
1375
1376 }
1377
1378 // -------------------------------------------------------------------------
1379 // ramfs_find()
1380 // Main interface to directory search code. This is used in all file
1381 // level operations to locate the object named by the pathname.
1382
1383 static int ramfs_find( ramfs_dirsearch *d )
1384 {
1385     int err;
1386
1387     // Short circuit empty paths
1388     if( *(d->path) == '\0' )
1389         return ENOERR;
1390
1391     // iterate down directory tree until we find the object
1392     // we want.
1393     for(;;)
1394     {
1395         err = find_entry( d );
1396
1397         if( err != ENOERR )
1398             return err;
1399
1400         if( d->last )
1401             return ENOERR;
1402
1403         // Update dirsearch object to search next directory.
1404         d->dir = d->node;
1405         d->path += d->namelen;
1406         while( *(d->path) == '/' ) d->path++; // skip dirname separators
1407     }
1408 }
1409
1410 //==========================================================================
1411 // Pathconf support
1412 // This function provides support for pathconf() and fpathconf().
1413
1414 static int ramfs_pathconf( ramfs_node *node, struct cyg_pathconf_info *info )
1415 {
1416     int err = ENOERR;
1417     
1418     switch( info->name )
1419     {
1420     case _PC_LINK_MAX:
1421         info->value = LINK_MAX;
1422         break;
1423         
1424     case _PC_MAX_CANON:
1425         info->value = -1;       // not supported
1426         err = EINVAL;
1427         break;
1428         
1429     case _PC_MAX_INPUT:
1430         info->value = -1;       // not supported
1431         err = EINVAL;        
1432         break;
1433         
1434     case _PC_NAME_MAX:
1435         info->value = NAME_MAX;
1436         break;
1437         
1438     case _PC_PATH_MAX:
1439         info->value = PATH_MAX;
1440         break;        
1441
1442     case _PC_PIPE_BUF:
1443         info->value = -1;       // not supported
1444         err = EINVAL;        
1445         break;        
1446
1447         
1448     case _PC_ASYNC_IO:
1449         info->value = -1;       // not supported
1450         err = EINVAL;        
1451         break;
1452         
1453     case _PC_CHOWN_RESTRICTED:
1454         info->value = -1;       // not supported
1455         err = EINVAL;
1456         break;
1457         
1458     case _PC_NO_TRUNC:
1459         info->value = 0;
1460         break;
1461         
1462     case _PC_PRIO_IO:
1463         info->value = 0;
1464         break;
1465         
1466     case _PC_SYNC_IO:
1467         info->value = 0;
1468         break;
1469         
1470     case _PC_VDISABLE:
1471         info->value = -1;       // not supported
1472         err = EINVAL;        
1473         break;
1474         
1475     default:
1476         err = EINVAL;
1477         break;
1478     }
1479
1480     return err;
1481 }
1482
1483 //==========================================================================
1484 // Filesystem operations
1485
1486 // -------------------------------------------------------------------------
1487 // ramfs_mount()
1488 // Process a mount request. This mainly creates a root for the
1489 // filesystem.
1490
1491 static int ramfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
1492 {
1493     ramfs_node *root;
1494     int err;
1495     
1496     // Allocate a node to be the root of this filesystem and initialize it.
1497
1498     root = alloc_node(__stat_mode_DIR|S_IRWXU|S_IRWXG|S_IRWXO);
1499
1500     if( root == NULL )
1501         return ENOSPC;
1502
1503     // Add . and .. entries back to self.
1504         
1505     err = add_direntry( root, ".", 1, root );
1506     if( err == ENOERR )
1507         err = add_direntry( root, "..", 2, root );
1508
1509     if( err != ENOERR )
1510     {
1511         free_node( root );
1512         return err;
1513     }
1514     
1515     mte->root = (cyg_dir)root;
1516     
1517     return ENOERR;
1518 }
1519
1520 // -------------------------------------------------------------------------
1521 // ramfs_umount()
1522 // Unmount the filesystem. This will currently only succeed if the
1523 // filesystem is empty.
1524
1525 static int ramfs_umount   ( cyg_mtab_entry *mte )
1526 {
1527     ramfs_node *root = (ramfs_node *)mte->root;
1528
1529     // Check for open/inuse root
1530     if( root->refcnt != 0 )
1531         return EBUSY;
1532
1533     // Check that root directory is clear of extra links.
1534     if( root->nlink != 2 )
1535         return EBUSY;
1536
1537     // Just return it to free pool
1538     free_node( root );
1539
1540     // Clear root pointer
1541     mte->root = CYG_DIR_NULL;
1542     
1543     // That's all folks.
1544         
1545     return ENOERR;
1546 }
1547
1548 // -------------------------------------------------------------------------
1549 // ramfs_open()
1550 // Open a file for reading or writing.
1551
1552 static int ramfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1553                              int mode,  cyg_file *file )
1554 {
1555
1556     ramfs_dirsearch ds;
1557     ramfs_node *node = NULL;
1558     int err;
1559
1560     init_dirsearch( &ds, (ramfs_node *)dir, name );
1561     
1562     err = ramfs_find( &ds );
1563
1564     if( err == ENOENT )
1565     {
1566         if( ds.last && (mode & O_CREAT) )
1567         {
1568             // No node there, if the O_CREAT bit is set then we must
1569             // create a new one. The dir and name fields of the dirsearch
1570             // object will have been updated so we know where to put it.
1571
1572             node = alloc_node( __stat_mode_REG|S_IRWXU|S_IRWXG|S_IRWXO);
1573
1574             if( node == NULL )
1575                 return ENOSPC;
1576
1577             err = add_direntry( ds.dir, ds.name, ds.namelen, node );
1578
1579             if( err != ENOERR )
1580             {
1581                 free_node( node );
1582                 return err;
1583             }
1584         
1585             err = ENOERR;
1586         }
1587     }
1588     else if( err == ENOERR )
1589     {
1590         // The node exists. If the O_CREAT and O_EXCL bits are set, we
1591         // must fail the open.
1592         
1593         if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
1594             err = EEXIST;
1595         else node = ds.node;
1596     }
1597     
1598     if( err == ENOERR && (mode & O_TRUNC ) )
1599     {
1600         // If the O_TRUNC bit is set we must clean out the file data.
1601
1602         err = freebuffer_node( node );
1603         node->size = 0;
1604
1605         // Update file times
1606         node->ctime =
1607         node->mtime = cyg_timestamp();
1608     }
1609
1610     if( err != ENOERR ) return err;
1611
1612     // Check that we actually have a file here
1613     if( S_ISDIR(node->mode) ) return EISDIR;
1614
1615     node->refcnt++;       // Count successful open
1616     
1617     // Initialize the file object
1618     
1619     file->f_flag        |= mode & CYG_FILE_MODE_MASK;
1620     file->f_type        = CYG_FILE_TYPE_FILE;
1621     file->f_ops         = &ramfs_fileops;
1622     file->f_offset      = (mode&O_APPEND) ? node->size : 0;
1623     file->f_data        = (CYG_ADDRWORD)node;
1624     file->f_xops        = 0;
1625
1626     return ENOERR;
1627 }
1628
1629 // -------------------------------------------------------------------------
1630 // ramfs_unlink()
1631 // Remove a file link from its directory.
1632
1633 static int ramfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1634 {
1635     ramfs_dirsearch ds;
1636     int err;
1637
1638     init_dirsearch( &ds, (ramfs_node *)dir, name );
1639     
1640     err = ramfs_find( &ds );
1641
1642     if( err != ENOERR ) return err;
1643
1644     // Cannot unlink directories, use rmdir() instead
1645     if( S_ISDIR(ds.node->mode) )
1646         return EPERM;
1647
1648     // Delete it from its directory
1649     err = del_direntry( ds.dir, ds.name, ds.namelen );
1650     
1651     return err;
1652 }
1653
1654 // -------------------------------------------------------------------------
1655 // ramfs_mkdir()
1656 // Create a new directory.
1657
1658 static int ramfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1659 {
1660     ramfs_dirsearch ds;
1661     ramfs_node *node = NULL;
1662     int err;
1663
1664     init_dirsearch( &ds, (ramfs_node *)dir, name );
1665     
1666     err = ramfs_find( &ds );
1667
1668     if( err == ENOENT )
1669     {
1670         if( ds.last )
1671         {
1672             // The entry does not exist, and it is the last element in
1673             // the pathname, so we can create it here.
1674             int doterr, dotdoterr, direrr;
1675         
1676             node = alloc_node( __stat_mode_DIR | S_IRWXU|S_IRWXG|S_IRWXO);
1677
1678             if( node == NULL )
1679                 return ENOSPC;
1680
1681             // Add "." and ".." entries.
1682             doterr = add_direntry( node, ".", 1, node );
1683             dotdoterr = add_direntry( node, "..", 2, ds.dir );
1684
1685             // And add to parent directory.
1686             direrr = add_direntry( ds.dir, ds.name, ds.namelen, node );
1687
1688             // check for any errors in that...
1689             if( doterr+dotdoterr+direrr != ENOERR )
1690             {
1691                 // For each of the add_direntry() calls that succeeded,
1692                 // we must now undo it.
1693                 
1694                 if( doterr == ENOERR )
1695                     del_direntry( node, ".", 1 );
1696                 else err = doterr;
1697
1698                 if( dotdoterr == ENOERR )
1699                     del_direntry( node, "..", 2 );
1700                 else err = dotdoterr;
1701
1702                 if( direrr == ENOERR )
1703                     del_direntry( ds.dir, ds.name, ds.namelen );
1704                 else err = direrr;
1705
1706                 // Free the data and the node itself.
1707                 freebuffer_node( node );
1708                 free_node( node );
1709             }
1710             else err = ENOERR;
1711         }
1712         // If this was not the last element, then and intermediate
1713         // directory does not exist.
1714     }
1715     else
1716     {
1717         // If there we no error, something already exists with that
1718         // name, so we cannot create another one.
1719         
1720         if( err == ENOERR )
1721             err = EEXIST;
1722     }
1723
1724     return err;
1725 }
1726
1727 // -------------------------------------------------------------------------
1728 // ramfs_rmdir()
1729 // Remove a directory.
1730
1731 static int ramfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1732 {
1733     ramfs_dirsearch ds;
1734     int err;
1735
1736     init_dirsearch( &ds, (ramfs_node *)dir, name );
1737     
1738     err = ramfs_find( &ds );
1739
1740     if( err != ENOERR ) return err;
1741
1742     // Check that this is actually a directory.
1743     if( !S_ISDIR(ds.node->mode) )
1744         return EPERM;
1745
1746     // Delete the entry. This will adjust the link values
1747     // accordingly and if the directory is now unreferenced,
1748     // will cause it to be deleted.
1749     
1750     err = del_direntry( ds.dir, ds.name, ds.namelen );
1751     
1752     return err;
1753 }
1754
1755 // -------------------------------------------------------------------------
1756 // ramfs_rename()
1757 // Rename a file/dir.
1758
1759 static int ramfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
1760                              cyg_dir dir2, const char *name2 )
1761 {
1762     ramfs_dirsearch ds1, ds2;
1763     int err;
1764
1765     init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
1766     
1767     err = ramfs_find( &ds1 );
1768
1769     if( err != ENOERR ) return err;
1770
1771     init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
1772     
1773     err = ramfs_find( &ds2 );
1774
1775     // Allow through renames to non-existent objects.
1776     if( ds2.last && err == ENOENT )
1777         ds2.node = NULL, err = ENOERR;
1778     
1779     if( err != ENOERR ) return err;
1780
1781     // Null rename, just return
1782     if( ds1.node == ds2.node )
1783         return ENOERR;
1784
1785     // First deal with any entry that is at the destination
1786     if( ds2.node )
1787     {
1788         // Check that we are renaming like-for-like
1789
1790         if( !S_ISDIR(ds1.node->mode) && S_ISDIR(ds2.node->mode) )
1791             return EISDIR;
1792
1793         if( S_ISDIR(ds1.node->mode) && !S_ISDIR(ds2.node->mode) )
1794             return ENOTDIR;
1795
1796         // Now delete the destination directory entry
1797         
1798         err = del_direntry( ds2.dir, ds2.name, ds2.namelen );
1799         
1800         if( err != ENOERR ) return err;
1801
1802     }
1803
1804     // Now we know that there is no clashing node at the destination,
1805     // make a new direntry at the destination and delete the old entry
1806     // at the source.
1807
1808     err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
1809
1810     if( err == ENOERR )
1811         err = del_direntry( ds1.dir, ds1.name, ds1.namelen );
1812
1813     // Update directory times
1814     if( err == ENOERR )
1815         ds1.dir->ctime =
1816         ds1.dir->mtime =
1817         ds2.dir->ctime =
1818         ds2.dir->mtime = cyg_timestamp();
1819             
1820     return err;
1821 }
1822
1823 // -------------------------------------------------------------------------
1824 // ramfs_link()
1825 // Make a new directory entry for a file.
1826
1827 static int ramfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
1828                              cyg_dir dir2, const char *name2, int type )
1829 {
1830     ramfs_dirsearch ds1, ds2;
1831     int err;
1832
1833     // Only do hard links for now in this filesystem
1834     if( type != CYG_FSLINK_HARD )
1835         return EINVAL;
1836     
1837     init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
1838     
1839     err = ramfs_find( &ds1 );
1840
1841     if( err != ENOERR ) return err;
1842
1843     init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
1844     
1845     err = ramfs_find( &ds2 );
1846
1847     // Don't allow links to existing objects
1848     if( err == ENOERR ) return EEXIST;
1849     
1850     // Allow through links to non-existing terminal objects
1851     if( ds2.last && err == ENOENT )
1852         ds2.node = NULL, err = ENOERR;
1853
1854     if( err != ENOERR ) return err;
1855     
1856     // Now we know that there is no existing node at the destination,
1857     // make a new direntry at the destination.
1858
1859     err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
1860
1861     if( err == ENOERR )
1862         ds1.node->ctime =
1863         ds2.dir->ctime =
1864         ds2.dir->mtime = cyg_timestamp();
1865             
1866     return err;
1867 }
1868
1869 // -------------------------------------------------------------------------
1870 // ramfs_opendir()
1871 // Open a directory for reading.
1872
1873 static int ramfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1874                              cyg_file *file )
1875 {
1876     ramfs_dirsearch ds;
1877     int err;
1878
1879     init_dirsearch( &ds, (ramfs_node *)dir, name );
1880     
1881     err = ramfs_find( &ds );
1882
1883     if( err != ENOERR ) return err;
1884
1885     // check it is really a directory.
1886     if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
1887
1888     ds.node->refcnt++;       // Count successful open
1889     
1890     // Initialize the file object, setting the f_ops field to a
1891     // special set of file ops.
1892     
1893     file->f_type        = CYG_FILE_TYPE_FILE;
1894     file->f_ops         = &ramfs_dirops;
1895     file->f_offset      = 0;
1896     file->f_data        = (CYG_ADDRWORD)ds.node;
1897     file->f_xops        = 0;
1898         
1899     return ENOERR;
1900
1901 }
1902
1903 // -------------------------------------------------------------------------
1904 // ramfs_chdir()
1905 // Change directory support.
1906
1907 static int ramfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1908                              cyg_dir *dir_out )
1909 {
1910     if( dir_out != NULL )
1911     {
1912         // This is a request to get a new directory pointer in
1913         // *dir_out.
1914
1915         ramfs_dirsearch ds;
1916         int err;
1917     
1918         init_dirsearch( &ds, (ramfs_node *)dir, name );
1919     
1920         err = ramfs_find( &ds );
1921
1922         if( err != ENOERR ) return err;
1923
1924         // check it is a directory
1925         if( !S_ISDIR(ds.node->mode) )
1926             return ENOTDIR;
1927         
1928         // Increment ref count to keep this directory in existent
1929         // while it is the current cdir.
1930         ds.node->refcnt++;
1931
1932         // Pass it out
1933         *dir_out = (cyg_dir)ds.node;
1934     }
1935     else
1936     {
1937         // If no output dir is required, this means that the mte and
1938         // dir arguments are the current cdir setting and we should
1939         // forget this fact.
1940
1941         ramfs_node *node = (ramfs_node *)dir;
1942
1943         // Just decrement directory reference count.
1944         dec_refcnt( node );
1945     }
1946         
1947     return ENOERR;
1948 }
1949
1950 // -------------------------------------------------------------------------
1951 // ramfs_stat()
1952 // Get struct stat info for named object.
1953
1954 static int ramfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1955                              struct stat *buf)
1956 {
1957     ramfs_dirsearch ds;
1958     int err;
1959
1960     init_dirsearch( &ds, (ramfs_node *)dir, name );
1961     
1962     err = ramfs_find( &ds );
1963
1964     if( err != ENOERR ) return err;
1965
1966     // Fill in the status
1967     buf->st_mode        = ds.node->mode;
1968     buf->st_ino         = (ino_t)ds.node;
1969     buf->st_dev         = 0;
1970     buf->st_nlink       = ds.node->nlink;
1971     buf->st_uid         = 0;
1972     buf->st_gid         = 0;
1973     buf->st_size        = ds.node->size;
1974     buf->st_atime       = ds.node->atime;
1975     buf->st_mtime       = ds.node->mtime;
1976     buf->st_ctime       = ds.node->ctime;
1977     
1978     return err;
1979 }
1980
1981 // -------------------------------------------------------------------------
1982 // ramfs_getinfo()
1983 // Getinfo. Currently only support pathconf() and filesystem usage.
1984
1985 static int ramfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1986                              int key, void *buf, int len )
1987 {
1988     ramfs_dirsearch ds;
1989     int err;
1990
1991     init_dirsearch( &ds, (ramfs_node *)dir, name );
1992     
1993     err = ramfs_find( &ds );
1994
1995     if( err != ENOERR ) return err;
1996
1997     switch( key )
1998     {
1999     case FS_INFO_CONF:
2000         err = ramfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
2001         break;
2002 #if defined(CYGSEM_FILEIO_BLOCK_USAGE) && defined(CYGPKG_FS_RAM_BLOCKS_ARRAY)
2003         // When using malloc for storage this does not make much
2004         // sense, so only implement this when using pre-allocated
2005         // blocks
2006     case FS_INFO_BLOCK_USAGE: {
2007       struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
2008       ramfs_block *b;
2009       
2010       usage->total_blocks = CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE;
2011       usage->free_blocks = 0;
2012       // Iterate over the free list to count its size
2013       b = block_free_list;
2014       while(b) {
2015         usage->free_blocks++;
2016         b=*(ramfs_block **)b;
2017       }
2018       usage->block_size = CYGNUM_RAMFS_BLOCK_SIZE;
2019       return ENOERR;
2020     }
2021 #endif
2022     default:
2023         err = EINVAL;
2024     }
2025     return err;
2026 }
2027
2028 // -------------------------------------------------------------------------
2029 // ramfs_setinfo()
2030 // Setinfo. Nothing to support here at present.
2031
2032 static int ramfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
2033                              int key, void *buf, int len )
2034 {
2035     // No setinfo keys supported at present
2036     
2037     return EINVAL;
2038 }
2039
2040
2041 //==========================================================================
2042 // File operations
2043
2044 // -------------------------------------------------------------------------
2045 // ramfs_fo_read()
2046 // Read data from the file.
2047
2048 static int ramfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2049 {
2050     ramfs_node *node = (ramfs_node *)fp->f_data;
2051     int i;
2052     off_t pos = fp->f_offset;
2053     ssize_t resid = uio->uio_resid;
2054
2055     // Loop over the io vectors until there are none left
2056     for( i = 0; i < uio->uio_iovcnt; i++ )
2057     {
2058         cyg_iovec *iov = &uio->uio_iov[i];
2059         char *buf = (char *)iov->iov_base;
2060         off_t len = iov->iov_len;
2061
2062         // Loop over each vector filling it with data from the file.
2063         while( len > 0 && pos < node->size )
2064         {
2065             cyg_uint8 *fbuf;
2066             size_t bsize;
2067             off_t l = len;
2068             int err;
2069
2070             // Get a pointer to the data at offset _pos_.
2071             err = findbuffer_node( node, pos, &fbuf, &bsize, false );
2072
2073             if( err != ENOERR )
2074                 return err;
2075
2076             // adjust size to end of file if necessary
2077             if( l > node->size-pos )
2078                 l = node->size-pos;
2079             
2080             // adjust size to the amount of contiguous data we can see
2081             // at present.
2082             if( l > bsize )
2083                 l = bsize;
2084             
2085             if (fbuf) {
2086               // copy data out
2087               memcpy( buf, fbuf, l );
2088             } else { // hole, so return zeros here.
2089               memset( buf, 0, l );
2090             }
2091  
2092             // Update working vars
2093             len -= l;
2094             buf += l;
2095             pos += l;
2096             resid -= l;
2097         }
2098     }
2099
2100     // We successfully read some data, update the node's access time
2101     // and update the file offset and transfer residue.
2102     
2103     node->atime = cyg_timestamp();
2104
2105     uio->uio_resid = resid;
2106     fp->f_offset = pos;
2107     
2108     return ENOERR;
2109 }
2110
2111 // -------------------------------------------------------------------------
2112 // ramfs_fo_write()
2113 // Write data to file.
2114
2115 static int ramfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2116 {
2117     ramfs_node *node = (ramfs_node *)fp->f_data;
2118     off_t pos = fp->f_offset;
2119     ssize_t resid = uio->uio_resid;    
2120     int err = ENOERR;
2121     int i;
2122
2123     // If the APPEND mode bit was supplied, force all writes to
2124     // the end of the file.
2125     if( fp->f_flag & CYG_FAPPEND )
2126         pos = fp->f_offset = node->size;
2127     
2128     // Now loop over the iovecs until they are all done, or
2129     // we get an error.
2130     for( i = 0; i < uio->uio_iovcnt; i++ )
2131     {
2132         cyg_iovec *iov = &uio->uio_iov[i];
2133         char *buf = (char *)iov->iov_base;
2134         off_t len = iov->iov_len;
2135
2136         // loop over the vector writing it to the file until it has
2137         // all been done.
2138         while( len > 0 )
2139         {
2140             cyg_uint8 *fbuf;
2141             size_t bsize;
2142             off_t l = len;
2143             
2144             err = findbuffer_node( node, pos, &fbuf, &bsize, true );
2145
2146             // Stop writing if there is no more space in the file and
2147             // indicate end of data.
2148             if( err == ENOSPC )
2149                 break;
2150             
2151             if( err != ENOERR )
2152                 return err;
2153             
2154             // adjust size to this block
2155             if( l > bsize )
2156                 l = bsize;
2157
2158             // copy data in
2159             memcpy( fbuf, buf, l );
2160
2161             // Update working vars
2162             len -= l;
2163             buf += l;
2164             pos += l;
2165             resid -= l;
2166         }
2167     }
2168
2169     // We wrote some data successfully, update the modified and access
2170     // times of the node, increase its size appropriately, and update
2171     // the file offset and transfer residue.
2172     node->mtime =
2173     node->ctime = cyg_timestamp();
2174     if( pos > node->size )
2175         node->size = pos;    
2176
2177     uio->uio_resid = resid;
2178     fp->f_offset = pos;
2179     
2180     return err;
2181 }
2182
2183 // -------------------------------------------------------------------------
2184 // ramfs_fo_lseek()
2185 // Seek to a new file position.
2186
2187 static int ramfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
2188 {
2189     ramfs_node *node = (ramfs_node *)fp->f_data;
2190     off_t pos = *apos;
2191
2192     switch( whence )
2193     {
2194     case SEEK_SET:
2195         // Pos is already where we want to be.
2196         break;
2197
2198     case SEEK_CUR:
2199         // Add pos to current offset.
2200         pos += fp->f_offset;
2201         break;
2202
2203     case SEEK_END:
2204         // Add pos to file size.
2205         pos += node->size;
2206         break;
2207
2208     default:
2209         return EINVAL;
2210     }
2211     
2212     // All OK, set fp offset and return new position.
2213     *apos = fp->f_offset = pos;
2214     
2215     return ENOERR;
2216 }
2217
2218 // -------------------------------------------------------------------------
2219 // ramfs_fo_ioctl()
2220 // Handle ioctls. Currently none are defined.
2221
2222 static int ramfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
2223                                 CYG_ADDRWORD data)
2224 {
2225     // No Ioctls currenly defined.
2226
2227     return EINVAL;
2228 }
2229
2230 // -------------------------------------------------------------------------
2231 // ramfs_fo_fsync().
2232 // Force the file out to data storage.
2233
2234 static int ramfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode )
2235 {
2236     // Data is always permanently where it belongs, nothing to do
2237     // here.
2238   
2239     return ENOERR;
2240 }
2241
2242 // -------------------------------------------------------------------------
2243 // ramfs_fo_close()
2244 // Close a file. We just decrement the refcnt and let it go away if
2245 // that is all that is keeping it here.
2246
2247 static int ramfs_fo_close     (struct CYG_FILE_TAG *fp)
2248 {
2249     ramfs_node *node = (ramfs_node *)fp->f_data;
2250
2251     dec_refcnt( node );
2252
2253     fp->f_data = 0;     // zero data pointer
2254     
2255     return ENOERR;
2256 }
2257
2258 // -------------------------------------------------------------------------
2259 //ramfs_fo_fstat()
2260 // Get file status.
2261
2262 static int ramfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
2263 {
2264     ramfs_node *node = (ramfs_node *)fp->f_data;
2265
2266     // Fill in the status
2267     buf->st_mode        = node->mode;
2268     buf->st_ino         = (ino_t)node;
2269     buf->st_dev         = 0;
2270     buf->st_nlink       = node->nlink;
2271     buf->st_uid         = 0;
2272     buf->st_gid         = 0;
2273     buf->st_size        = node->size;
2274     buf->st_atime       = node->atime;
2275     buf->st_mtime       = node->mtime;
2276     buf->st_ctime       = node->ctime;
2277     
2278     return ENOERR;
2279 }
2280
2281 // -------------------------------------------------------------------------
2282 // ramfs_fo_getinfo()
2283 // Get info. Currently only supports fpathconf().
2284
2285 static int ramfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
2286 {
2287     ramfs_node *node = (ramfs_node *)fp->f_data;    
2288     int err;
2289
2290     switch( key )
2291     {
2292     case FS_INFO_CONF:
2293         err = ramfs_pathconf( node, (struct cyg_pathconf_info *)buf );
2294         break;
2295         
2296     default:
2297         err = EINVAL;
2298     }
2299     return err;
2300 }
2301
2302 // -------------------------------------------------------------------------
2303 // ramfs_fo_setinfo()
2304 // Set info. Nothing supported here.
2305
2306 static int ramfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
2307 {
2308     // No setinfo key supported at present
2309     
2310     return ENOERR;
2311 }
2312
2313
2314 //==========================================================================
2315 // Directory operations
2316
2317 // -------------------------------------------------------------------------
2318 // ramfs_fo_dirread()
2319 // Read a single directory entry from a file.
2320
2321 static int ramfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2322 {
2323     ramfs_node *dir = (ramfs_node *)fp->f_data;
2324     off_t pos = fp->f_offset;
2325     int err = ENOERR;
2326     struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
2327     char *nbuf = ent->d_name;
2328     int nlen = sizeof(ent->d_name)-1;
2329     off_t len = uio->uio_iov[0].iov_len;
2330     ramfs_dirent *d = NULL;
2331     cyg_uint8 *buf;
2332     size_t size;
2333         
2334     if( len < sizeof(struct dirent) )
2335         return EINVAL;    
2336     
2337     // look for a first name fragment
2338
2339     while( pos < dir->size )
2340     {
2341         err = findbuffer_node( dir, pos, &buf, &size, false );
2342         if( err != ENOERR || size == 0)
2343             break;
2344
2345         d = (ramfs_dirent *)buf;
2346
2347         if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
2348         {
2349             pos += sizeof(ramfs_dirent);
2350             continue;
2351         }
2352
2353         break;
2354     }
2355
2356     // Check we have not exceeded the size of the directory.
2357     if( pos == dir->size )
2358         return err;
2359     
2360     // Here we  have the first fragment of a directory entry.
2361
2362     for(;;)
2363     {
2364         int fraglen = d->fraglen;
2365
2366         // adjust to allow for remaining space in dirent struct
2367         if( fraglen > nlen )
2368             fraglen = nlen;
2369         
2370         memcpy( nbuf, d->name, fraglen);
2371         nbuf += fraglen;
2372         nlen -= fraglen;
2373 #ifdef CYGPKG_FS_RAM_RET_DIRENT_DTYPE
2374         ent->d_type = d->node->mode;
2375 #endif
2376             
2377         // if we hit the last entry, we have a successful transfer
2378         if( d->last || nlen == 0)
2379             break;
2380
2381         // Otherwise move on to next entry in chain
2382         err = findbuffer_node( dir, d->next, &buf, &size, false );
2383         if( err != ENOERR )
2384             return err;
2385
2386         d = (ramfs_dirent *)buf;
2387     }
2388
2389     // A successful read. Terminate the entry name with a NUL, set the
2390     // residue and set the file offset to restart at the next
2391     // directory entry.
2392     
2393     *nbuf = '\0';
2394     uio->uio_resid -= sizeof(struct dirent);
2395     fp->f_offset = pos+sizeof(ramfs_dirent);
2396     
2397     return ENOERR;
2398 }
2399
2400 // -------------------------------------------------------------------------
2401 // ramfs_fo_dirlseek()
2402 // Seek directory to start.
2403
2404 static int ramfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
2405 {
2406     // Only allow SEEK_SET to zero
2407     
2408     if( whence != SEEK_SET || *pos != 0)
2409         return EINVAL;
2410
2411     *pos = fp->f_offset = 0;
2412     
2413     return ENOERR;
2414 }
2415
2416 // -------------------------------------------------------------------------
2417 // EOF ramfs.c