]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/fs/ram/v2_0/src/ramfs.c
Initial revision
[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+pos, 0, CYGNUM_RAMFS_REALLOC_INCREMENT );
672         
673         node->data = newdata;
674         node->datasize = pos+CYGNUM_RAMFS_REALLOC_INCREMENT;
675     }
676     else if( pos > node->datasize )
677     {
678         // Indicate end of data.
679         *size = 0;
680         return ENOERR;
681     }
682
683     *buffer = node->data+pos;
684     *size = node->datasize-pos;
685
686     return ENOERR;
687 }
688
689 // -------------------------------------------------------------------------
690 // freebuffer_node()
691 // Empty out the data storage from the node.
692
693 static int freebuffer_node( ramfs_node *node )
694 {
695     if( node->data != NULL )
696     {
697         free( node->data );
698     }
699
700     node->data = NULL;
701     node->datasize = 0;
702
703     return ENOERR;
704 }
705
706 //==========================================================================
707
708 #else
709
710 //==========================================================================
711 // _BLOCKS storage management.
712 // Data storage in the node is by means of a set of arrays of pointers to
713 // blocks. The first array points directly to the data blocks. Subsequent
714 // arrays point to single and double indirect blocks respectively. 
715
716 // -------------------------------------------------------------------------
717 // findbuffer_direct()
718 // Indexes into an array of block pointers and extracts a pointer to the
719 // data at offset _pos_, allocating new blocks if required.
720
721 static int findbuffer_direct( off_t pos,
722                               ramfs_block **blocks,
723                               int nblocks,
724                               cyg_uint8 **buffer,
725                               size_t *size,
726                               cyg_bool alloc)
727 {
728     int bi = pos / CYGNUM_RAMFS_BLOCK_SIZE;
729     int bpos = pos % CYGNUM_RAMFS_BLOCK_SIZE;
730     ramfs_block *b;
731     
732     *buffer = NULL;
733     *size = 0;
734     
735     if( bi >= nblocks )
736         return ENOERR;
737
738     b = blocks[bi];
739
740     if( b == NULL )
741     {
742         // There is no block there. If _alloc_ is true we can fill the
743         // slot in with a new block. If it is false, we indicate end of
744         // data with a zero size result.
745         if( alloc )
746         {
747             b = block_alloc();
748             if( b == NULL )
749                 return ENOSPC;
750             blocks[bi] = b;
751         }
752         else return ENOERR;
753     }
754
755     *buffer = &((*b)[bpos]);
756     *size = CYGNUM_RAMFS_BLOCK_SIZE - bpos;
757
758     return ENOERR;
759 }
760
761 // -------------------------------------------------------------------------
762 // findbuffer_indirect1()
763 // Indexes into an array of pointers to blocks containing pointers to
764 // blocks and extracts a pointer to the data at offset _pos_,
765 // allocating new blocks if required.
766
767 #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
768
769 static int findbuffer_indirect1( off_t pos,
770                                  ramfs_block ***blocks,
771                                  int nblocks,
772                                  cyg_uint8 **buffer,
773                                  size_t *size,
774                                  cyg_bool alloc)
775 {
776
777     int bi = pos / RAMFS_INDIRECT1_BLOCK_EXTENT;
778     int bpos = pos % RAMFS_INDIRECT1_BLOCK_EXTENT;
779     int err;
780     cyg_uint8 *b;
781     size_t sz;
782
783     // Use findbuffer_direct() to index and allocate
784     // the first level indirect block.
785     
786     err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
787                              (ramfs_block **)blocks,
788                              nblocks,
789                              &b,
790                              &sz,
791                              alloc);
792
793     if( err != ENOERR )
794         return err;
795
796     if( sz == 0 )
797     {
798         *size = 0;
799         return ENOERR;
800     }
801
802     // Use findbuffer_direct() on the first level indirect
803     // block to allocate and return the data pointer.
804     
805     return findbuffer_direct( bpos,
806                               blocks[bi],
807                               RAMFS_INDIRECT_PER_BLOCK,
808                               buffer,
809                               size,
810                               alloc);
811 }
812
813 #endif
814
815 // -------------------------------------------------------------------------
816 // findbuffer_indirect1()
817 // Indexes into an array of pointers to blocks containing pointers to
818 // blocks containing pointers to blocks (!) and extracts a pointer to
819 // the data at offset _pos_, allocating new blocks if required.
820
821 #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
822
823 static int findbuffer_indirect2( off_t pos,
824                                  ramfs_block ****blocks,
825                                  int nblocks,
826                                  cyg_uint8 **buffer,
827                                  size_t *size,
828                                  cyg_bool alloc)
829 {
830     int bi = pos / RAMFS_INDIRECT2_BLOCK_EXTENT;
831     int bpos = pos % RAMFS_INDIRECT2_BLOCK_EXTENT;
832     int err;
833     cyg_uint8 *b;
834     size_t sz;
835
836     // Use findbuffer_direct() to index and allocate
837     // the first level indirect block.
838
839     err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
840                              (ramfs_block **)blocks,
841                              nblocks,
842                              &b,
843                              &sz,
844                              alloc);
845
846     if( err != ENOERR )
847         return err;
848
849     if( sz == 0 )
850     {
851         *size = 0;
852         return ENOERR;
853     }
854
855     // Use findbuffer_indirect1() on the first level indirect block to
856     // index and allocate the next level indirect block and the data
857     // block.
858     
859     return findbuffer_indirect1( bpos,
860                                  blocks[bi],
861                                  RAMFS_INDIRECT_PER_BLOCK,
862                                  buffer,
863                                  size,
864                                  alloc);
865 }
866
867 #endif
868
869 // -------------------------------------------------------------------------
870 // findbuffer_node()
871 // Depending on the offset and configuration, call the appropriate
872 // function to get the buffer pointer.
873
874 static int findbuffer_node( ramfs_node  *node,
875                             off_t pos,
876                             cyg_uint8 **buffer,
877                             size_t *size,
878                             cyg_bool alloc)
879 {
880 #if CYGNUM_RAMFS_BLOCKS_DIRECT > 0    
881     if( pos < RAMFS_DIRECT_MAX )
882         return findbuffer_direct( pos,
883                                   node->direct,
884                                   CYGNUM_RAMFS_BLOCKS_DIRECT,
885                                   buffer,
886                                   size,
887                                   alloc);
888 #endif        
889 #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0    
890     if( pos < RAMFS_INDIRECT1_MAX )
891         return findbuffer_indirect1( pos - RAMFS_DIRECT_MAX,
892                                      node->indirect1,
893                                      CYGNUM_RAMFS_BLOCKS_INDIRECT1,
894                                      buffer,
895                                      size,
896                                      alloc);
897 #endif        
898 #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0    
899     if( pos < RAMFS_INDIRECT2_MAX )
900         return findbuffer_indirect2( pos - RAMFS_INDIRECT1_MAX,
901                                      node->indirect2,
902                                      CYGNUM_RAMFS_BLOCKS_INDIRECT2,
903                                      buffer,
904                                      size,
905                                      alloc);
906 #endif
907
908     return ENOSPC;
909 }
910
911 // -------------------------------------------------------------------------
912 // freeblock_list()
913 // Free a list of data blocks.
914
915 static void freeblock_list( ramfs_block *blocks[],int nblocks )
916 {
917     int i;
918     for( i = 0; i < nblocks ; i++ )
919     {
920         if( blocks[i] != NULL )
921         {
922             block_free( blocks[i] );
923             blocks[i] = NULL;
924         }
925     }
926 }
927
928 // -------------------------------------------------------------------------
929 // freebuffer_node()
930 // Free all the data blocks in the node and clear the pointers.
931
932 static int freebuffer_node( ramfs_node *node )
933 {
934 #if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
935     freeblock_list( node->direct, CYGNUM_RAMFS_BLOCKS_DIRECT );
936 #endif
937
938 #if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
939     {
940         int i;
941         for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT1 ; i++ )
942         {
943             if( node->indirect1[i] != NULL )
944             {
945                 freeblock_list( (ramfs_block **)node->indirect1[i], RAMFS_INDIRECT_PER_BLOCK );
946                 block_free( (ramfs_block *)node->indirect1[i] );
947                 node->indirect1[i] = NULL;
948             }
949         }
950     }
951 #endif    
952
953 #if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
954     {
955         int i;
956         for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT2 ; i++ )
957         {
958             if( node->indirect2[i] != NULL )
959             {
960                 ramfs_block ***b = node->indirect2[i];
961                 int j;
962                 for( j = 0; j < RAMFS_INDIRECT_PER_BLOCK ; j++ )
963                 {
964                     if( b[j] != NULL )
965                     {
966                         freeblock_list( (ramfs_block **)b[j], RAMFS_INDIRECT_PER_BLOCK );
967                         block_free( (ramfs_block *)b[j] );
968                         b[j] = NULL;
969                     }
970                 }
971                 block_free( (ramfs_block *)node->indirect2[i] );
972                 node->indirect2[i] = NULL;
973             }
974         }
975     }
976 #endif
977
978     return ENOERR;
979 }
980
981 //==========================================================================
982
983 #endif
984
985 //==========================================================================
986 // Node allocation
987
988 // -------------------------------------------------------------------------
989 // alloc_node()
990 // Allocate a node and initialize it.
991 // For the _SIMPLE allocation option, we just malloc it. For the
992 // _BLOCKS option we allocate a block and use that. In theory we could
993 // pack several nodes into a single block, but we don't at present due
994 // to sheer lazyness.
995
996 static ramfs_node *alloc_node( mode_t mode )
997 {
998 #ifdef CYGPKG_FS_RAM_SIMPLE
999     ramfs_node *node = malloc( sizeof( ramfs_node ) );
1000
1001     if( node == NULL )
1002         return NULL;
1003     
1004 #else
1005     ramfs_block *b = block_alloc();
1006     ramfs_node *node;
1007
1008     if( b == NULL )
1009         return NULL;
1010
1011     node = (ramfs_node *)b;
1012     
1013 #endif
1014
1015     memset( node, 0, sizeof(ramfs_node) );
1016     
1017     node->mode          = mode;
1018     node->refcnt        = 0;
1019     node->nlink         = 0;
1020     node->size          = 0;
1021     node->atime         = 
1022     node->mtime         = 
1023     node->ctime         = cyg_timestamp();
1024
1025 #ifdef CYGPKG_FS_RAM_SIMPLE    
1026     node->datasize      = 0;
1027     node->data          = NULL;
1028 #else
1029
1030     // The node is already all zero
1031     
1032 #endif    
1033     return node;
1034 }
1035
1036 // -------------------------------------------------------------------------
1037 // free_node()
1038 // Release a node either back to the free pool or back into the block
1039 // pool.
1040
1041 static void free_node( ramfs_node *node )
1042 {
1043 #ifdef CYGPKG_FS_RAM_SIMPLE    
1044
1045     free( node );
1046
1047 #else
1048
1049     block_free( (ramfs_block *)node );
1050
1051 #endif    
1052     
1053 }
1054
1055
1056 //==========================================================================
1057 // Ref count and nlink management
1058
1059 // -------------------------------------------------------------------------
1060 // dec_refcnt()
1061 // Decrment the reference count on a node. If this makes the ref count
1062 // zero, and the number of links is either zero for a file or one for
1063 // a node, then this node is detached from the directory tree and can
1064 // be freed.
1065
1066 static int dec_refcnt( ramfs_node *node )
1067 {
1068     int err = ENOERR;
1069     node->refcnt--;
1070
1071     if( node->refcnt == 0 &&
1072         ((S_ISREG(node->mode) && node->nlink == 0 ) ||
1073          (S_ISDIR(node->mode) && node->nlink == 1) )
1074         )
1075     {
1076         // This node it now totally detached from the directory tree,
1077         // so delete it.
1078
1079         if( S_ISDIR(node->mode) )
1080         {
1081             del_direntry( node, ".", 1 );
1082             del_direntry( node, "..", 2 );
1083         }
1084         
1085         err = freebuffer_node( node );
1086
1087         if( err == ENOERR )
1088             free_node( node );
1089     }
1090
1091     return err;
1092 }
1093
1094 // -------------------------------------------------------------------------
1095 // dec_nlink()
1096 // Decrement a node's link count. Since this has to do all the same
1097 // work as dec_refcnt() we implement this using that function by
1098 // essentially transferring the count to refcnt and then decrement
1099 // that.
1100
1101 static int dec_nlink( ramfs_node *node )
1102 {
1103     node->refcnt++;
1104     
1105     node->nlink--;
1106
1107     return dec_refcnt( node );
1108 }
1109
1110 //==========================================================================
1111 // Directory operations
1112
1113 // -------------------------------------------------------------------------
1114 // add_direntry()
1115 // Add an entry to a directory. This is added as a chain of entry
1116 // fragments until the name is exhausted.
1117
1118 static int add_direntry( ramfs_node *dir,       // dir to add to
1119                          const char *name,      // name to add
1120                          int namelen,           // length of name
1121                          ramfs_node *node       // node to reference
1122                        )
1123 {
1124     off_t pos = 0;
1125     ramfs_dirent *d = NULL, *dp = NULL;
1126     cyg_bool isfirst = true;
1127
1128     // Loop inserting fragments of the name into the directory until we
1129     // have found a home for them all.
1130     
1131     while( namelen > 0 )
1132     {
1133         int fraglen = namelen;
1134
1135         if( fraglen > sizeof(d->name) )
1136             fraglen = sizeof(d->name);
1137
1138         // Find a free fragment
1139         for(;;)
1140         {
1141             cyg_uint8 *buf;
1142             size_t size;
1143             int err = findbuffer_node( dir, pos, &buf, &size, true );
1144             if( err != ENOERR ) return err;
1145
1146             d = (ramfs_dirent *)buf;
1147
1148             if( size < sizeof(ramfs_dirent) || d->inuse )
1149             {
1150                 pos += sizeof(ramfs_dirent);
1151                 continue;
1152             }
1153
1154             break;
1155         }
1156
1157         // d now points to a free dirent structure
1158
1159         d->node         = node;
1160         d->inuse        = 1;
1161         d->first        = isfirst;
1162         d->namelen      = namelen;
1163         d->fraglen      = fraglen;
1164         if( dp ) dp->next = pos;
1165
1166         memcpy( d->name, name, fraglen );
1167
1168         name            += fraglen;
1169         namelen         -= fraglen;
1170         pos             += sizeof(ramfs_dirent);
1171         dp              = d;
1172         isfirst         = false;
1173         
1174     }
1175
1176     
1177     d->last = 1;        // Mark last fragment
1178     
1179     // Update directory times
1180     dir->mtime =
1181     dir->ctime = cyg_timestamp();
1182     
1183     // Extend dir size if necessary
1184     if( pos > dir->size )
1185         dir->size = pos;
1186     
1187     // Count the new link
1188     node->nlink++;
1189     
1190     return ENOERR;
1191 }
1192
1193 // -------------------------------------------------------------------------
1194 // find_direntry()
1195 // Find a directory entry for the name and return a pointer to the first
1196 // entry fragment.
1197
1198 static ramfs_dirent *find_direntry( ramfs_node *dir, const char *name, int namelen )
1199 {
1200     ramfs_dirent *first = NULL;
1201     off_t pos = 0;
1202     int err;
1203
1204     // Loop over all the entries until a match is found or we run out
1205     // of data.
1206     while( pos < dir->size )
1207     {
1208         const char *frag = name;
1209         ramfs_dirent *d;
1210         cyg_uint8 *buf;
1211         size_t size;
1212         
1213         // look for a first name fragment
1214         for(;;)
1215         {
1216             err = findbuffer_node( dir, pos, &buf, &size, false );
1217             if( err != ENOERR || size == 0)
1218                 return NULL;
1219
1220             d = (ramfs_dirent *)buf;
1221
1222             if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
1223             {
1224                 pos += sizeof(ramfs_dirent);
1225                 continue;
1226             }
1227
1228             break;
1229         }
1230
1231         // Here we have got a first fragment of a name, check it
1232         // against the name we are looking for. First check that they
1233         // are the same length.
1234
1235         if( d->namelen == namelen )
1236         {
1237             // We have a potential candidate here...
1238             
1239             first = d;      // Save it for later
1240
1241             // Now check that all the name fragments match
1242             for(;;)
1243             {
1244                 int fraglen = namelen-(frag-name);
1245
1246                 if( fraglen > d->fraglen )
1247                     fraglen = d->fraglen;
1248
1249                 // compare strings, if different, look for another
1250                 if( memcmp( frag, d->name, fraglen ) != 0 )
1251                     break;
1252
1253                 frag        += fraglen;
1254             
1255                 // If we are at the last fragment, then the whole name string
1256                 // has matched and we have a successful search.
1257                 
1258                 if( d->last )
1259                         return first;
1260
1261                 // Otherwise move on to next entry in chain
1262                 err = findbuffer_node( dir, d->next, &buf, &size, false );
1263                 if( err != ENOERR )
1264                     return NULL;
1265
1266                 d = (ramfs_dirent *)buf;
1267
1268             }
1269         }
1270
1271         pos += sizeof(ramfs_dirent);        
1272     }
1273
1274     return NULL;
1275 }
1276
1277 // -------------------------------------------------------------------------
1278 // del_direntry()
1279 // Delete a named directory entry. Find it and then follow the chain
1280 // deleting the fragments as we go.
1281
1282 static int del_direntry( ramfs_node *dir, const char *name, int namelen )
1283 {
1284     ramfs_dirent *d = find_direntry( dir, name, namelen );
1285     
1286     if( d == NULL )
1287         return ENOENT;
1288
1289     for(;;)
1290     {
1291         int err;
1292         cyg_uint8 *buf;
1293         size_t size;
1294
1295         d->inuse = 0;
1296         if( d->last ) break;
1297
1298         err = findbuffer_node( dir, d->next, &buf, &size, false );
1299         if( err != ENOERR )
1300             return ENOENT;
1301
1302         d = (ramfs_dirent *)buf;
1303     }
1304
1305     dec_nlink( d->node );
1306     
1307     return ENOERR;
1308 }
1309
1310 //==========================================================================
1311 // Directory search
1312
1313 // -------------------------------------------------------------------------
1314 // init_dirsearch()
1315 // Initialize a dirsearch object to start a search
1316
1317 static void init_dirsearch( ramfs_dirsearch *ds,
1318                             ramfs_node *dir,
1319                             const char *name)
1320 {
1321     ds->dir      = dir;
1322     ds->path     = name;
1323     ds->node     = dir;
1324     ds->name     = name;
1325     ds->namelen  = 0;
1326     ds->last     = false;    
1327 }
1328
1329 // -------------------------------------------------------------------------
1330 // find_entry()
1331 // Search a single directory for the next name in a path and update the
1332 // dirsearch object appropriately.
1333
1334 static int find_entry( ramfs_dirsearch *ds )
1335 {
1336     ramfs_node *dir = ds->dir;
1337     const char *name = ds->path;
1338     const char *n = name;
1339     char namelen = 0;
1340     ramfs_dirent *d;
1341     
1342     // check that we really have a directory
1343     if( !S_ISDIR(dir->mode) )
1344         return ENOTDIR;
1345
1346     // Isolate the next element of the path name. 
1347     while( *n != '\0' && *n != '/' )
1348         n++, namelen++;
1349
1350     // Check if this is the last path element.
1351     while( *n == '/') n++;
1352     if( *n == '\0' ) 
1353         ds->last = true;
1354
1355     // update name in dirsearch object
1356     ds->name = name;
1357     ds->namelen = namelen;
1358     
1359     // Here we have the name and its length set up.
1360     // Search the directory for a matching entry
1361
1362     d = find_direntry( dir, name, namelen );
1363
1364     if( d == NULL )
1365         return ENOENT;
1366
1367     // pass back the node we have found
1368     ds->node = d->node;
1369
1370     return ENOERR;
1371
1372 }
1373
1374 // -------------------------------------------------------------------------
1375 // ramfs_find()
1376 // Main interface to directory search code. This is used in all file
1377 // level operations to locate the object named by the pathname.
1378
1379 static int ramfs_find( ramfs_dirsearch *d )
1380 {
1381     int err;
1382
1383     // Short circuit empty paths
1384     if( *(d->path) == '\0' )
1385         return ENOERR;
1386
1387     // iterate down directory tree until we find the object
1388     // we want.
1389     for(;;)
1390     {
1391         err = find_entry( d );
1392
1393         if( err != ENOERR )
1394             return err;
1395
1396         if( d->last )
1397             return ENOERR;
1398
1399         // Update dirsearch object to search next directory.
1400         d->dir = d->node;
1401         d->path += d->namelen;
1402         while( *(d->path) == '/' ) d->path++; // skip dirname separators
1403     }
1404 }
1405
1406 //==========================================================================
1407 // Pathconf support
1408 // This function provides support for pathconf() and fpathconf().
1409
1410 static int ramfs_pathconf( ramfs_node *node, struct cyg_pathconf_info *info )
1411 {
1412     int err = ENOERR;
1413     
1414     switch( info->name )
1415     {
1416     case _PC_LINK_MAX:
1417         info->value = LINK_MAX;
1418         break;
1419         
1420     case _PC_MAX_CANON:
1421         info->value = -1;       // not supported
1422         err = EINVAL;
1423         break;
1424         
1425     case _PC_MAX_INPUT:
1426         info->value = -1;       // not supported
1427         err = EINVAL;        
1428         break;
1429         
1430     case _PC_NAME_MAX:
1431         info->value = NAME_MAX;
1432         break;
1433         
1434     case _PC_PATH_MAX:
1435         info->value = PATH_MAX;
1436         break;        
1437
1438     case _PC_PIPE_BUF:
1439         info->value = -1;       // not supported
1440         err = EINVAL;        
1441         break;        
1442
1443         
1444     case _PC_ASYNC_IO:
1445         info->value = -1;       // not supported
1446         err = EINVAL;        
1447         break;
1448         
1449     case _PC_CHOWN_RESTRICTED:
1450         info->value = -1;       // not supported
1451         err = EINVAL;
1452         break;
1453         
1454     case _PC_NO_TRUNC:
1455         info->value = 0;
1456         break;
1457         
1458     case _PC_PRIO_IO:
1459         info->value = 0;
1460         break;
1461         
1462     case _PC_SYNC_IO:
1463         info->value = 0;
1464         break;
1465         
1466     case _PC_VDISABLE:
1467         info->value = -1;       // not supported
1468         err = EINVAL;        
1469         break;
1470         
1471     default:
1472         err = EINVAL;
1473         break;
1474     }
1475
1476     return err;
1477 }
1478
1479 //==========================================================================
1480 // Filesystem operations
1481
1482 // -------------------------------------------------------------------------
1483 // ramfs_mount()
1484 // Process a mount request. This mainly creates a root for the
1485 // filesystem.
1486
1487 static int ramfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
1488 {
1489     ramfs_node *root;
1490     int err;
1491     
1492     // Allocate a node to be the root of this filesystem and initialize it.
1493
1494     root = alloc_node(__stat_mode_DIR);
1495
1496     if( root == NULL )
1497         return ENOSPC;
1498
1499     // Add . and .. entries back to self.
1500         
1501     err = add_direntry( root, ".", 1, root );
1502     if( err == ENOERR )
1503         err = add_direntry( root, "..", 2, root );
1504
1505     if( err != ENOERR )
1506     {
1507         free_node( root );
1508         return err;
1509     }
1510     
1511     mte->root = (cyg_dir)root;
1512     
1513     return ENOERR;
1514 }
1515
1516 // -------------------------------------------------------------------------
1517 // ramfs_umount()
1518 // Unmount the filesystem. This will currently only succeed if the
1519 // filesystem is empty.
1520
1521 static int ramfs_umount   ( cyg_mtab_entry *mte )
1522 {
1523     ramfs_node *root = (ramfs_node *)mte->root;
1524
1525     // Check for open/inuse root
1526     if( root->refcnt != 0 )
1527         return EBUSY;
1528
1529     // Check that root directory is clear of extra links.
1530     if( root->nlink != 2 )
1531         return EBUSY;
1532
1533     // Just return it to free pool
1534     free_node( root );
1535
1536     // Clear root pointer
1537     mte->root = CYG_DIR_NULL;
1538     
1539     // That's all folks.
1540         
1541     return ENOERR;
1542 }
1543
1544 // -------------------------------------------------------------------------
1545 // ramfs_open()
1546 // Open a file for reading or writing.
1547
1548 static int ramfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1549                              int mode,  cyg_file *file )
1550 {
1551
1552     ramfs_dirsearch ds;
1553     ramfs_node *node = NULL;
1554     int err;
1555
1556     init_dirsearch( &ds, (ramfs_node *)dir, name );
1557     
1558     err = ramfs_find( &ds );
1559
1560     if( err == ENOENT )
1561     {
1562         if( ds.last && (mode & O_CREAT) )
1563         {
1564             // No node there, if the O_CREAT bit is set then we must
1565             // create a new one. The dir and name fields of the dirsearch
1566             // object will have been updated so we know where to put it.
1567
1568             node = alloc_node( __stat_mode_REG );
1569
1570             if( node == NULL )
1571                 return ENOSPC;
1572
1573             err = add_direntry( ds.dir, ds.name, ds.namelen, node );
1574
1575             if( err != ENOERR )
1576             {
1577                 free_node( node );
1578                 return err;
1579             }
1580         
1581             err = ENOERR;
1582         }
1583     }
1584     else if( err == ENOERR )
1585     {
1586         // The node exists. If the O_CREAT and O_EXCL bits are set, we
1587         // must fail the open.
1588         
1589         if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
1590             err = EEXIST;
1591         else node = ds.node;
1592     }
1593     
1594     if( err == ENOERR && (mode & O_TRUNC ) )
1595     {
1596         // If the O_TRUNC bit is set we must clean out the file data.
1597
1598         err = freebuffer_node( node );
1599         node->size = 0;
1600
1601         // Update file times
1602         node->ctime =
1603         node->mtime = cyg_timestamp();
1604     }
1605
1606     if( err != ENOERR ) return err;
1607
1608     // Check that we actually have a file here
1609     if( S_ISDIR(node->mode) ) return EISDIR;
1610
1611     node->refcnt++;       // Count successful open
1612     
1613     // Initialize the file object
1614     
1615     file->f_flag        |= mode & CYG_FILE_MODE_MASK;
1616     file->f_type        = CYG_FILE_TYPE_FILE;
1617     file->f_ops         = &ramfs_fileops;
1618     file->f_offset      = (mode&O_APPEND) ? node->size : 0;
1619     file->f_data        = (CYG_ADDRWORD)node;
1620     file->f_xops        = 0;
1621
1622     return ENOERR;
1623 }
1624
1625 // -------------------------------------------------------------------------
1626 // ramfs_unlink()
1627 // Remove a file link from its directory.
1628
1629 static int ramfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1630 {
1631     ramfs_dirsearch ds;
1632     int err;
1633
1634     init_dirsearch( &ds, (ramfs_node *)dir, name );
1635     
1636     err = ramfs_find( &ds );
1637
1638     if( err != ENOERR ) return err;
1639
1640     // Cannot unlink directories, use rmdir() instead
1641     if( S_ISDIR(ds.node->mode) )
1642         return EPERM;
1643
1644     // Delete it from its directory
1645     err = del_direntry( ds.dir, ds.name, ds.namelen );
1646     
1647     return err;
1648 }
1649
1650 // -------------------------------------------------------------------------
1651 // ramfs_mkdir()
1652 // Create a new directory.
1653
1654 static int ramfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1655 {
1656     ramfs_dirsearch ds;
1657     ramfs_node *node = NULL;
1658     int err;
1659
1660     init_dirsearch( &ds, (ramfs_node *)dir, name );
1661     
1662     err = ramfs_find( &ds );
1663
1664     if( err == ENOENT )
1665     {
1666         if( ds.last )
1667         {
1668             // The entry does not exist, and it is the last element in
1669             // the pathname, so we can create it here.
1670             int doterr, dotdoterr, direrr;
1671         
1672             node = alloc_node( __stat_mode_DIR );
1673
1674             if( node == NULL )
1675                 return ENOSPC;
1676
1677             // Add "." and ".." entries.
1678             doterr = add_direntry( node, ".", 1, node );
1679             dotdoterr = add_direntry( node, "..", 2, ds.dir );
1680
1681             // And add to parent directory.
1682             direrr = add_direntry( ds.dir, ds.name, ds.namelen, node );
1683
1684             // check for any errors in that...
1685             if( doterr+dotdoterr+direrr != ENOERR )
1686             {
1687                 // For each of the add_direntry() calls that succeeded,
1688                 // we must now undo it.
1689                 
1690                 if( doterr == ENOERR )
1691                     del_direntry( node, ".", 1 );
1692                 else err = doterr;
1693
1694                 if( dotdoterr == ENOERR )
1695                     del_direntry( node, "..", 2 );
1696                 else err = dotdoterr;
1697
1698                 if( direrr == ENOERR )
1699                     del_direntry( ds.dir, ds.name, ds.namelen );
1700                 else err = direrr;
1701
1702                 // Free the data and the node itself.
1703                 freebuffer_node( node );
1704                 free_node( node );
1705             }
1706             else err = ENOERR;
1707         }
1708         // If this was not the last element, then and intermediate
1709         // directory does not exist.
1710     }
1711     else
1712     {
1713         // If there we no error, something already exists with that
1714         // name, so we cannot create another one.
1715         
1716         if( err == ENOERR )
1717             err = EEXIST;
1718     }
1719
1720     return err;
1721 }
1722
1723 // -------------------------------------------------------------------------
1724 // ramfs_rmdir()
1725 // Remove a directory.
1726
1727 static int ramfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1728 {
1729     ramfs_dirsearch ds;
1730     int err;
1731
1732     init_dirsearch( &ds, (ramfs_node *)dir, name );
1733     
1734     err = ramfs_find( &ds );
1735
1736     if( err != ENOERR ) return err;
1737
1738     // Check that this is actually a directory.
1739     if( !S_ISDIR(ds.node->mode) )
1740         return EPERM;
1741
1742     // Delete the entry. This will adjust the link values
1743     // accordingly and if the directory is now unreferenced,
1744     // will cause it to be deleted.
1745     
1746     err = del_direntry( ds.dir, ds.name, ds.namelen );
1747     
1748     return err;
1749 }
1750
1751 // -------------------------------------------------------------------------
1752 // ramfs_rename()
1753 // Rename a file/dir.
1754
1755 static int ramfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
1756                              cyg_dir dir2, const char *name2 )
1757 {
1758     ramfs_dirsearch ds1, ds2;
1759     int err;
1760
1761     init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
1762     
1763     err = ramfs_find( &ds1 );
1764
1765     if( err != ENOERR ) return err;
1766
1767     init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
1768     
1769     err = ramfs_find( &ds2 );
1770
1771     // Allow through renames to non-existent objects.
1772     if( ds2.last && err == ENOENT )
1773         ds2.node = NULL, err = ENOERR;
1774     
1775     if( err != ENOERR ) return err;
1776
1777     // Null rename, just return
1778     if( ds1.node == ds2.node )
1779         return ENOERR;
1780
1781     // First deal with any entry that is at the destination
1782     if( ds2.node )
1783     {
1784         // Check that we are renaming like-for-like
1785
1786         if( !S_ISDIR(ds1.node->mode) && S_ISDIR(ds2.node->mode) )
1787             return EISDIR;
1788
1789         if( S_ISDIR(ds1.node->mode) && !S_ISDIR(ds2.node->mode) )
1790             return ENOTDIR;
1791
1792         // Now delete the destination directory entry
1793         
1794         err = del_direntry( ds2.dir, ds2.name, ds2.namelen );
1795         
1796         if( err != ENOERR ) return err;
1797
1798     }
1799
1800     // Now we know that there is no clashing node at the destination,
1801     // make a new direntry at the destination and delete the old entry
1802     // at the source.
1803
1804     err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
1805
1806     if( err == ENOERR )
1807         err = del_direntry( ds1.dir, ds1.name, ds1.namelen );
1808
1809     // Update directory times
1810     if( err == ENOERR )
1811         ds1.dir->ctime =
1812         ds1.dir->mtime =
1813         ds2.dir->ctime =
1814         ds2.dir->mtime = cyg_timestamp();
1815             
1816     return err;
1817 }
1818
1819 // -------------------------------------------------------------------------
1820 // ramfs_link()
1821 // Make a new directory entry for a file.
1822
1823 static int ramfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
1824                              cyg_dir dir2, const char *name2, int type )
1825 {
1826     ramfs_dirsearch ds1, ds2;
1827     int err;
1828
1829     // Only do hard links for now in this filesystem
1830     if( type != CYG_FSLINK_HARD )
1831         return EINVAL;
1832     
1833     init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
1834     
1835     err = ramfs_find( &ds1 );
1836
1837     if( err != ENOERR ) return err;
1838
1839     init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
1840     
1841     err = ramfs_find( &ds2 );
1842
1843     // Don't allow links to existing objects
1844     if( err == ENOERR ) return EEXIST;
1845     
1846     // Allow through links to non-existing terminal objects
1847     if( ds2.last && err == ENOENT )
1848         ds2.node = NULL, err = ENOERR;
1849
1850     if( err != ENOERR ) return err;
1851     
1852     // Now we know that there is no existing node at the destination,
1853     // make a new direntry at the destination.
1854
1855     err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
1856
1857     if( err == ENOERR )
1858         ds1.node->ctime =
1859         ds2.dir->ctime =
1860         ds2.dir->mtime = cyg_timestamp();
1861             
1862     return err;
1863 }
1864
1865 // -------------------------------------------------------------------------
1866 // ramfs_opendir()
1867 // Open a directory for reading.
1868
1869 static int ramfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1870                              cyg_file *file )
1871 {
1872     ramfs_dirsearch ds;
1873     int err;
1874
1875     init_dirsearch( &ds, (ramfs_node *)dir, name );
1876     
1877     err = ramfs_find( &ds );
1878
1879     if( err != ENOERR ) return err;
1880
1881     // check it is really a directory.
1882     if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
1883
1884     ds.node->refcnt++;       // Count successful open
1885     
1886     // Initialize the file object, setting the f_ops field to a
1887     // special set of file ops.
1888     
1889     file->f_type        = CYG_FILE_TYPE_FILE;
1890     file->f_ops         = &ramfs_dirops;
1891     file->f_offset      = 0;
1892     file->f_data        = (CYG_ADDRWORD)ds.node;
1893     file->f_xops        = 0;
1894         
1895     return ENOERR;
1896
1897 }
1898
1899 // -------------------------------------------------------------------------
1900 // ramfs_chdir()
1901 // Change directory support.
1902
1903 static int ramfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1904                              cyg_dir *dir_out )
1905 {
1906     if( dir_out != NULL )
1907     {
1908         // This is a request to get a new directory pointer in
1909         // *dir_out.
1910
1911         ramfs_dirsearch ds;
1912         int err;
1913     
1914         init_dirsearch( &ds, (ramfs_node *)dir, name );
1915     
1916         err = ramfs_find( &ds );
1917
1918         if( err != ENOERR ) return err;
1919
1920         // check it is a directory
1921         if( !S_ISDIR(ds.node->mode) )
1922             return ENOTDIR;
1923         
1924         // Increment ref count to keep this directory in existent
1925         // while it is the current cdir.
1926         ds.node->refcnt++;
1927
1928         // Pass it out
1929         *dir_out = (cyg_dir)ds.node;
1930     }
1931     else
1932     {
1933         // If no output dir is required, this means that the mte and
1934         // dir arguments are the current cdir setting and we should
1935         // forget this fact.
1936
1937         ramfs_node *node = (ramfs_node *)dir;
1938
1939         // Just decrement directory reference count.
1940         dec_refcnt( node );
1941     }
1942         
1943     return ENOERR;
1944 }
1945
1946 // -------------------------------------------------------------------------
1947 // ramfs_stat()
1948 // Get struct stat info for named object.
1949
1950 static int ramfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1951                              struct stat *buf)
1952 {
1953     ramfs_dirsearch ds;
1954     int err;
1955
1956     init_dirsearch( &ds, (ramfs_node *)dir, name );
1957     
1958     err = ramfs_find( &ds );
1959
1960     if( err != ENOERR ) return err;
1961
1962     // Fill in the status
1963     buf->st_mode        = ds.node->mode;
1964     buf->st_ino         = (ino_t)ds.node;
1965     buf->st_dev         = 0;
1966     buf->st_nlink       = ds.node->nlink;
1967     buf->st_uid         = 0;
1968     buf->st_gid         = 0;
1969     buf->st_size        = ds.node->size;
1970     buf->st_atime       = ds.node->atime;
1971     buf->st_mtime       = ds.node->mtime;
1972     buf->st_ctime       = ds.node->ctime;
1973     
1974     return err;
1975 }
1976
1977 // -------------------------------------------------------------------------
1978 // ramfs_getinfo()
1979 // Getinfo. Currently only support pathconf().
1980
1981 static int ramfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1982                              int key, void *buf, int len )
1983 {
1984     ramfs_dirsearch ds;
1985     int err;
1986
1987     init_dirsearch( &ds, (ramfs_node *)dir, name );
1988     
1989     err = ramfs_find( &ds );
1990
1991     if( err != ENOERR ) return err;
1992
1993     switch( key )
1994     {
1995     case FS_INFO_CONF:
1996         err = ramfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
1997         break;
1998         
1999     default:
2000         err = EINVAL;
2001     }
2002     return err;
2003 }
2004
2005 // -------------------------------------------------------------------------
2006 // ramfs_setinfo()
2007 // Setinfo. Nothing to support here at present.
2008
2009 static int ramfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
2010                              int key, void *buf, int len )
2011 {
2012     // No setinfo keys supported at present
2013     
2014     return EINVAL;
2015 }
2016
2017
2018 //==========================================================================
2019 // File operations
2020
2021 // -------------------------------------------------------------------------
2022 // ramfs_fo_read()
2023 // Read data from the file.
2024
2025 static int ramfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2026 {
2027     ramfs_node *node = (ramfs_node *)fp->f_data;
2028     int i;
2029     off_t pos = fp->f_offset;
2030     ssize_t resid = uio->uio_resid;
2031
2032     // Loop over the io vectors until there are none left
2033     for( i = 0; i < uio->uio_iovcnt; i++ )
2034     {
2035         cyg_iovec *iov = &uio->uio_iov[i];
2036         char *buf = (char *)iov->iov_base;
2037         off_t len = iov->iov_len;
2038
2039         // Loop over each vector filling it with data from the file.
2040         while( len > 0 && pos < node->size )
2041         {
2042             cyg_uint8 *fbuf;
2043             size_t bsize;
2044             off_t l = len;
2045             int err;
2046
2047             // Get a pointer to the data at offset _pos_.
2048             err = findbuffer_node( node, pos, &fbuf, &bsize, false );
2049
2050             if( err != ENOERR )
2051                 return err;
2052
2053             // adjust size to end of file if necessary
2054             if( l > node->size-pos )
2055                 l = node->size-pos;
2056             
2057             // adjust size to the amount of contiguous data we can see
2058             // at present.
2059             if( l > bsize )
2060                 l = bsize;
2061
2062             // copy data out
2063             memcpy( buf, fbuf, l );
2064
2065             // Update working vars
2066             len -= l;
2067             buf += l;
2068             pos += l;
2069             resid -= l;
2070         }
2071     }
2072
2073     // We successfully read some data, update the node's access time
2074     // and update the file offset and transfer residue.
2075     
2076     node->atime = cyg_timestamp();
2077
2078     uio->uio_resid = resid;
2079     fp->f_offset = pos;
2080     
2081     return ENOERR;
2082 }
2083
2084 // -------------------------------------------------------------------------
2085 // ramfs_fo_write()
2086 // Write data to file.
2087
2088 static int ramfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2089 {
2090     ramfs_node *node = (ramfs_node *)fp->f_data;
2091     off_t pos = fp->f_offset;
2092     ssize_t resid = uio->uio_resid;    
2093     int err = ENOERR;
2094     int i;
2095
2096     // If the APPEND mode bit was supplied, force all writes to
2097     // the end of the file.
2098     if( fp->f_flag & CYG_FAPPEND )
2099         pos = fp->f_offset = node->size;
2100     
2101     // Check that pos is within current file size, or at the very end.
2102     if( pos < 0 || pos > node->size )
2103         return EINVAL;
2104
2105     // Now loop over the iovecs until they are all done, or
2106     // we get an error.
2107     for( i = 0; i < uio->uio_iovcnt; i++ )
2108     {
2109         cyg_iovec *iov = &uio->uio_iov[i];
2110         char *buf = (char *)iov->iov_base;
2111         off_t len = iov->iov_len;
2112
2113         // loop over the vector writing it to the file until it has
2114         // all been done.
2115         while( len > 0 )
2116         {
2117             cyg_uint8 *fbuf;
2118             size_t bsize;
2119             off_t l = len;
2120             
2121             err = findbuffer_node( node, pos, &fbuf, &bsize, true );
2122
2123             // Stop writing if there is no more space in the file and
2124             // indicate end of data.
2125             if( err == ENOSPC )
2126                 break;
2127             
2128             if( err != ENOERR )
2129                 return err;
2130             
2131             // adjust size to this block
2132             if( l > bsize )
2133                 l = bsize;
2134
2135             // copy data in
2136             memcpy( fbuf, buf, l );
2137
2138             // Update working vars
2139             len -= l;
2140             buf += l;
2141             pos += l;
2142             resid -= l;
2143         }
2144     }
2145
2146     // We wrote some data successfully, update the modified and access
2147     // times of the node, increase its size appropriately, and update
2148     // the file offset and transfer residue.
2149     node->mtime =
2150     node->ctime = cyg_timestamp();
2151     if( pos > node->size )
2152         node->size = pos;    
2153
2154     uio->uio_resid = resid;
2155     fp->f_offset = pos;
2156     
2157     return err;
2158 }
2159
2160 // -------------------------------------------------------------------------
2161 // ramfs_fo_lseek()
2162 // Seek to a new file position.
2163
2164 static int ramfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
2165 {
2166     ramfs_node *node = (ramfs_node *)fp->f_data;
2167     off_t pos = *apos;
2168
2169     switch( whence )
2170     {
2171     case SEEK_SET:
2172         // Pos is already where we want to be.
2173         break;
2174
2175     case SEEK_CUR:
2176         // Add pos to current offset.
2177         pos += fp->f_offset;
2178         break;
2179
2180     case SEEK_END:
2181         // Add pos to file size.
2182         pos += node->size;
2183         break;
2184
2185     default:
2186         return EINVAL;
2187     }
2188     
2189     // Check that pos is still within current file size, or at the
2190     // very end.
2191     if( pos < 0 || pos > node->size )
2192         return EINVAL;
2193
2194     // All OK, set fp offset and return new position.
2195     *apos = fp->f_offset = pos;
2196     
2197     return ENOERR;
2198 }
2199
2200 // -------------------------------------------------------------------------
2201 // ramfs_fo_ioctl()
2202 // Handle ioctls. Currently none are defined.
2203
2204 static int ramfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
2205                                 CYG_ADDRWORD data)
2206 {
2207     // No Ioctls currenly defined.
2208
2209     return EINVAL;
2210 }
2211
2212 // -------------------------------------------------------------------------
2213 // ramfs_fo_fsync().
2214 // Force the file out to data storage.
2215
2216 static int ramfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode )
2217 {
2218     // Data is always permanently where it belongs, nothing to do
2219     // here.
2220   
2221     return ENOERR;
2222 }
2223
2224 // -------------------------------------------------------------------------
2225 // ramfs_fo_close()
2226 // Close a file. We just decrement the refcnt and let it go away if
2227 // that is all that is keeping it here.
2228
2229 static int ramfs_fo_close     (struct CYG_FILE_TAG *fp)
2230 {
2231     ramfs_node *node = (ramfs_node *)fp->f_data;
2232
2233     dec_refcnt( node );
2234
2235     fp->f_data = 0;     // zero data pointer
2236     
2237     return ENOERR;
2238 }
2239
2240 // -------------------------------------------------------------------------
2241 //ramfs_fo_fstat()
2242 // Get file status.
2243
2244 static int ramfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
2245 {
2246     ramfs_node *node = (ramfs_node *)fp->f_data;
2247
2248     // Fill in the status
2249     buf->st_mode        = node->mode;
2250     buf->st_ino         = (ino_t)node;
2251     buf->st_dev         = 0;
2252     buf->st_nlink       = node->nlink;
2253     buf->st_uid         = 0;
2254     buf->st_gid         = 0;
2255     buf->st_size        = node->size;
2256     buf->st_atime       = node->atime;
2257     buf->st_mtime       = node->mtime;
2258     buf->st_ctime       = node->ctime;
2259     
2260     return ENOERR;
2261 }
2262
2263 // -------------------------------------------------------------------------
2264 // ramfs_fo_getinfo()
2265 // Get info. Currently only supports fpathconf().
2266
2267 static int ramfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
2268 {
2269     ramfs_node *node = (ramfs_node *)fp->f_data;    
2270     int err;
2271
2272     switch( key )
2273     {
2274     case FS_INFO_CONF:
2275         err = ramfs_pathconf( node, (struct cyg_pathconf_info *)buf );
2276         break;
2277         
2278     default:
2279         err = EINVAL;
2280     }
2281     return err;
2282 }
2283
2284 // -------------------------------------------------------------------------
2285 // ramfs_fo_setinfo()
2286 // Set info. Nothing supported here.
2287
2288 static int ramfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
2289 {
2290     // No setinfo key supported at present
2291     
2292     return ENOERR;
2293 }
2294
2295
2296 //==========================================================================
2297 // Directory operations
2298
2299 // -------------------------------------------------------------------------
2300 // ramfs_fo_dirread()
2301 // Read a single directory entry from a file.
2302
2303 static int ramfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2304 {
2305     ramfs_node *dir = (ramfs_node *)fp->f_data;
2306     off_t pos = fp->f_offset;
2307     int err = ENOERR;
2308     struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
2309     char *nbuf = ent->d_name;
2310     int nlen = sizeof(ent->d_name)-1;
2311     off_t len = uio->uio_iov[0].iov_len;
2312     ramfs_dirent *d = NULL;
2313     cyg_uint8 *buf;
2314     size_t size;
2315         
2316     if( len < sizeof(struct dirent) )
2317         return EINVAL;    
2318     
2319     // look for a first name fragment
2320
2321     while( pos < dir->size )
2322     {
2323         err = findbuffer_node( dir, pos, &buf, &size, false );
2324         if( err != ENOERR || size == 0)
2325             break;
2326
2327         d = (ramfs_dirent *)buf;
2328
2329         if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
2330         {
2331             pos += sizeof(ramfs_dirent);
2332             continue;
2333         }
2334
2335         break;
2336     }
2337
2338     // Check we have not exceeded the size of the directory.
2339     if( pos == dir->size )
2340         return err;
2341     
2342     // Here we  have the first fragment of a directory entry.
2343
2344     for(;;)
2345     {
2346         int fraglen = d->fraglen;
2347
2348         // adjust to allow for remaining space in dirent struct
2349         if( fraglen > nlen )
2350             fraglen = nlen;
2351         
2352         memcpy( nbuf, d->name, fraglen);
2353         nbuf += fraglen;
2354         nlen -= fraglen;
2355             
2356         // if we hit the last entry, we have a successful transfer
2357         if( d->last || nlen == 0)
2358             break;
2359
2360         // Otherwise move on to next entry in chain
2361         err = findbuffer_node( dir, d->next, &buf, &size, false );
2362         if( err != ENOERR )
2363             return err;
2364
2365         d = (ramfs_dirent *)buf;
2366     }
2367
2368     // A successful read. Terminate the entry name with a NUL, set the
2369     // residue and set the file offset to restart at the next
2370     // directory entry.
2371     
2372     *nbuf = '\0';
2373     uio->uio_resid -= sizeof(struct dirent);
2374     fp->f_offset = pos+sizeof(ramfs_dirent);
2375     
2376     return ENOERR;
2377 }
2378
2379 // -------------------------------------------------------------------------
2380 // ramfs_fo_dirlseek()
2381 // Seek directory to start.
2382
2383 static int ramfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
2384 {
2385     // Only allow SEEK_SET to zero
2386     
2387     if( whence != SEEK_SET || *pos != 0)
2388         return EINVAL;
2389
2390     *pos = fp->f_offset = 0;
2391     
2392     return ENOERR;
2393 }
2394
2395 // -------------------------------------------------------------------------
2396 // EOF ramfs.c