]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/fs/rom/v2_0/src/romfs.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / fs / rom / v2_0 / src / romfs.c
1 //==========================================================================
2 //
3 //      romfs.c
4 //
5 //      ROM 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, richard.panton@3glab.com
45 // Date:                2000-07-25
46 // Purpose:             ROM file system
47 // Description:         This is a ROM 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 ROM 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 // Header
67 // ------
68 //
69 // There is a single header that describes the overall format of the ROMFS
70 // disk. The address of this header is used as the base for all offsets used
71 // in the node and directory structures. It contains the following fields:
72 //
73 // label  - A human readable label for various purposes
74 // fssize - The size in bytes of the entire ROMFS disk
75 // nodes  - A count of the nodes in the disk
76 //
77 // Immediately following thisin memory is the node table, consisting of
78 // 'nodes' repetitions of the node object.
79 //
80 // Nodes
81 // -----
82 //
83 // All files and directories are represented by node objects. Each
84 // romfs_node structure contains the following fields:
85 //
86 // mode   - Node type, file or directory.
87 // nlink  - Number of links to this node. Each directory entry that references
88 //          this node is a link. 
89 // size   - Size of the data in this node in bytes.
90 // ctime  - Creation time of the file (NOT the ROMFS)
91 // data   - Offset of the first data byte for this node from the header
92 //
93 // Directories
94 // -----------
95 //
96 // A directory is a node whose data is a list of directory entries.
97 // These contain the
98 // following fields:
99 //
100 // node    - Index of the node in the romfs_disk table that is referenced by
101 //           this entry. This is present in every directory entry fragment.
102 // next    - Offset of the next name entry.
103 // name    - The filename associated with this link to the node.
104 //
105 // Data Storage
106 // ------------
107 //
108 // Each file has its data stored in a single contiguous memory block
109 // referenced by the offset in the node.
110 //
111 //==========================================================================
112
113 #include <pkgconf/system.h>
114 #include <pkgconf/hal.h>
115 #include <pkgconf/kernel.h>
116 #include <pkgconf/io_fileio.h>
117 #include <pkgconf/fs_rom.h>
118
119 #include <cyg/kernel/ktypes.h>         // base kernel types
120 #include <cyg/infra/cyg_trac.h>        // tracing macros
121 #include <cyg/infra/cyg_ass.h>         // assertion macros
122
123 #include <unistd.h>
124 #include <sys/types.h>
125 #include <fcntl.h>
126 #include <sys/stat.h>
127 #include <errno.h>
128 #include <dirent.h>
129
130 #include <stdarg.h>
131 #include <stdio.h>
132 #include <stdlib.h>
133 #include <string.h>
134
135 #include <cyg/fileio/fileio.h>
136
137 #include <cyg/kernel/kapi.h>
138 #include <cyg/infra/diag.h>
139
140 //==========================================================================
141 // Eventually we want to eXecute In Place from the ROM in a protected
142 // environment, so we'll need executables to be aligned to a boundary
143 // suitable for MMU protection. A suitable boundary would be the 4k
144 // boundary in all the CPU architectures I am currently aware of.
145
146 // Forward definitions
147
148 // Filesystem operations
149 static int romfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
150 static int romfs_umount   ( cyg_mtab_entry *mte );
151 static int romfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
152                              int mode,  cyg_file *fte );
153 static int romfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
154                              cyg_file *fte );
155 static int romfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
156                              cyg_dir *dir_out );
157 static int romfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
158                              struct stat *buf);
159 static int romfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
160                              int key, void *buf, int len );
161 static int romfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
162                              int key, void *buf, int len );
163
164 // File operations
165 static int romfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
166 static int romfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
167 static int romfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
168                                 CYG_ADDRWORD data);
169 static int romfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode );        
170 static int romfs_fo_close     (struct CYG_FILE_TAG *fp);
171 static int romfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf );
172 static int romfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
173 static int romfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
174
175 // Directory operations
176 static int romfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
177 static int romfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
178
179
180 //==========================================================================
181 // Filesystem table entries
182
183 // -------------------------------------------------------------------------
184 // Fstab entry.
185 // This defines the entry in the filesystem table.
186 // For simplicity we use _FILESYSTEM synchronization for all accesses since
187 // we should never block in any filesystem operations.
188
189 FSTAB_ENTRY( romfs_fste, "romfs", 0,
190              CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
191              romfs_mount,
192              romfs_umount,
193              romfs_open,
194              (cyg_fsop_unlink *)cyg_fileio_erofs,
195              (cyg_fsop_mkdir *)cyg_fileio_erofs,
196              (cyg_fsop_rmdir *)cyg_fileio_erofs,
197              (cyg_fsop_rename *)cyg_fileio_erofs,
198              (cyg_fsop_link *)cyg_fileio_erofs,
199              romfs_opendir,
200              romfs_chdir,
201              romfs_stat,
202              romfs_getinfo,
203              romfs_setinfo);
204
205 // -------------------------------------------------------------------------
206 // mtab entry.
207 // This defines a single ROMFS loaded into ROM at the configured address
208 //
209 // MTAB_ENTRY(  rom_mte,        // structure name
210 //              "/rom",         // mount point
211 //              "romfs",        // FIlesystem type
212 //              "",             // hardware device
213 //  (CYG_ADDRWORD) CYGNUM_FS_ROM_BASE_ADDRESS   // Address in ROM
214 //           );
215
216
217 // -------------------------------------------------------------------------
218 // File operations.
219 // This set of file operations are used for normal open files.
220
221 static cyg_fileops romfs_fileops =
222 {
223     romfs_fo_read,
224     (cyg_fileop_write *)cyg_fileio_erofs,
225     romfs_fo_lseek,
226     romfs_fo_ioctl,
227     cyg_fileio_seltrue,
228     romfs_fo_fsync,
229     romfs_fo_close,
230     romfs_fo_fstat,
231     romfs_fo_getinfo,
232     romfs_fo_setinfo
233 };
234
235 // -------------------------------------------------------------------------
236 // Directory file operations.
237 // This set of operations are used for open directories. Most entries
238 // point to error-returning stub functions. Only the read, lseek and
239 // close entries are functional.
240
241 static cyg_fileops romfs_dirops =
242 {
243     romfs_fo_dirread,
244     (cyg_fileop_write *)cyg_fileio_enosys,
245     romfs_fo_dirlseek,
246     (cyg_fileop_ioctl *)cyg_fileio_enosys,
247     cyg_fileio_seltrue,
248     (cyg_fileop_fsync *)cyg_fileio_enosys,
249     romfs_fo_close,
250     (cyg_fileop_fstat *)cyg_fileio_enosys,
251     (cyg_fileop_getinfo *)cyg_fileio_enosys,
252     (cyg_fileop_setinfo *)cyg_fileio_enosys
253 };
254
255 //==========================================================================
256 // Data typedefs
257 // Some forward typedefs for the main data structures.
258
259 struct romfs_disk;
260 typedef struct romfs_disk romfs_disk;
261
262 struct romfs_node;
263 typedef struct romfs_node romfs_node;
264
265 struct romfs_dirent;
266 typedef struct romfs_dirent romfs_dirent;
267
268 //==========================================================================
269 // File and directory node
270 // This data structure represents a file or directory. 
271
272 struct romfs_node
273 {
274     cyg_uint32          mode;           // 0-3   node type
275     cyg_ucount32        nlink;          // 4-7   number of links to this node
276     cyg_uint16          uid;            // 8-9   Owner id
277     cyg_uint16          gid;            // 10-11 Group id
278     cyg_uint32          size;           // 12-15 size of file in bytes
279     cyg_uint32          ctime;          // 16-19 creation status time
280     cyg_uint32          offset;         // 20-23 offset of data from start of ROMFS
281     cyg_uint32          pad[2];         // 24-31 padding to align to 32byte boundary
282 };
283
284 //==========================================================================
285 // Directory entry.
286 // Variable sized entry containing the name and node of a directory entry
287
288 struct romfs_dirent
289 {
290     cyg_ucount32        node;           // Index of node in romfs_disk structure
291     cyg_uint32          next;           // Offset from start of directory of
292                                         // a) the next entry, or 
293                                         // b) the end of the directory data
294     char                name[0];        // The name, NUL terminated
295 };
296
297 //==========================================================================
298 // ROMFS header
299 // This data structure contains overall information on the ROMFS
300
301 struct romfs_disk
302 {
303     cyg_uint32          magic;          // 0-3   Marks a valid ROMFS entry
304     cyg_ucount32        nodecount;      // 4-7   Count of nodes in this filesystem
305     cyg_ucount32        disksize;       // 8-11  Count of bytes in this filesystem
306     cyg_uint32          dev_id;         // 12-15 ID of disk (put into stat.st_dev)
307     char                name[16];       // 16-31 Name - pads to 32 bytes
308     romfs_node          node[0];
309 };
310
311 #define ROMFS_MAGIC     0x526f6d2e      // The magic signature word for a romfs
312 #define ROMFS_CIGAM     0x2e6d6f52      // The byte sex is wrong if you see this
313
314 //==========================================================================
315 // Directory search data
316 // Parameters for a directory search. The fields of this structure are
317 // updated as we follow a pathname through the directory tree.
318
319 struct romfs_dirsearch
320 {
321     romfs_disk          *disk;          // disk structure
322     romfs_node          *dir;           // directory to search
323     const char          *path;          // path to follow
324     romfs_node          *node;          // Node found
325     const char          *name;          // last name used
326     int                 namelen;        // name fragment length
327     cyg_bool            last;           // last name in path?
328 };
329
330 typedef struct romfs_dirsearch romfs_dirsearch;
331
332 //==========================================================================
333 // This seems to be the only string function referenced. Define as static
334 // here to avoid having to load the string library
335
336 static bool match( const char *a, const char *b, int len )
337 {
338     for ( ; len > 0 && *a && *b && *a == *b ; a++, b++, len-- )
339         ;
340     return ( len == 0 );
341 }
342
343                 
344 //==========================================================================
345 // SIMPLE buffer management.
346 // Each node has a data buffer pointer and a size.
347
348 // -------------------------------------------------------------------------
349 // findbuffer_node()
350 // return a pointer to the data at the indicated file position.
351
352 static int findbuffer_node( romfs_disk *disk,   // header pointer
353                             romfs_node  *node,  // node pointer
354                             off_t pos,          // data position to get
355                             cyg_uint8 **buffer, // returned buffer pointer
356                             size_t *size)       // returned buffer size
357 {
358     if ( pos >= node->size || node->size == 0 )
359     {
360         // Indicate end of data.
361         *size = 0;
362     } else {
363
364         // Calculate the buffer position
365         *buffer = (cyg_uint8*)disk + node->offset + pos;
366         *size = node->size-pos;
367     }
368
369     return ENOERR;
370 }
371
372 //==========================================================================
373 // Directory operations
374
375
376 // -------------------------------------------------------------------------
377 // find_direntry()
378 // Find a directory entry for the name and return a pointer to the first
379 // entry fragment.
380
381 static romfs_dirent *find_direntry( romfs_disk *disk, romfs_node *dir, const char *name, int namelen )
382 {
383     off_t pos = 0;
384     int err;
385
386     // Loop over all the entries until a match is found or we run out
387     // of data.
388     while( pos < dir->size )
389     {
390         romfs_dirent *d;
391         cyg_uint8 *buf;
392         size_t size;
393         
394         err = findbuffer_node( disk, dir, pos, &buf, &size );
395         if( err != ENOERR || size == 0)
396             return NULL;
397
398         d = (romfs_dirent *)buf;
399
400         // Is this the directory entry we're looking for?
401         if ( match( d->name, name, namelen ) )
402             return d;
403
404         // Otherwise move on to next entry in chain
405         pos = d->next;
406     }
407
408     return NULL;
409 }
410
411 //==========================================================================
412 // Directory search
413
414 // -------------------------------------------------------------------------
415 // init_dirsearch()
416 // Initialize a dirsearch object to start a search
417
418 static void init_dirsearch( romfs_dirsearch *ds,
419                             romfs_disk *disk,
420                             romfs_node *dir,
421                             const char *name)
422 {
423     ds->disk     = disk;
424     ds->dir      = dir;
425     ds->path     = name;
426     ds->node     = dir;
427     ds->name     = name;
428     ds->namelen  = 0;
429     ds->last     = false;
430 }
431
432 // -------------------------------------------------------------------------
433 // find_entry()
434 // Search a single directory for the next name in a path and update the
435 // dirsearch object appropriately.
436
437 static int find_entry( romfs_dirsearch *ds )
438 {
439     romfs_node *dir = ds->dir;
440     const char *name = ds->path;
441     const char *n = name;
442     int namelen = 0;
443     romfs_dirent *d;
444     
445     // check that we really have a directory
446     if( !S_ISDIR(dir->mode) )
447         return ENOTDIR;
448
449     // Isolate the next element of the path name. 
450     while( *n != '\0' && *n != '/' )
451         n++, namelen++;
452
453     // Check if this is the last path element.
454     while( *n == '/') n++;
455     if( *n == '\0' ) 
456         ds->last = true;
457
458     // update name in dirsearch object
459     ds->name = name;
460     ds->namelen = namelen;
461     
462     // Here we have the name and its length set up.
463     // Search the directory for a matching entry
464
465     d = find_direntry( ds->disk, dir, name, namelen );
466
467     if( d == NULL )
468         return ENOENT;
469
470     // pass back the node we have found
471     ds->node = &ds->disk->node[d->node];
472
473     return ENOERR;
474
475 }
476
477 // -------------------------------------------------------------------------
478 // romfs_find()
479 // Main interface to directory search code. This is used in all file
480 // level operations to locate the object named by the pathname.
481
482 static int romfs_find( romfs_dirsearch *d )
483 {
484     int err;
485
486     // Short circuit empty paths
487     if( *(d->path) == '\0' )
488         return ENOERR;
489
490     // iterate down directory tree until we find the object
491     // we want.
492     for(;;)
493     {
494         err = find_entry( d );
495
496         if( err != ENOERR )
497             return err;
498
499         if( d->last )
500             return ENOERR;
501
502         // Update dirsearch object to search next directory.
503         d->dir = d->node;
504         d->path += d->namelen;
505         while( *(d->path) == '/' ) d->path++; // skip dirname separators
506     }
507 }
508
509 //==========================================================================
510 // Pathconf support
511 // This function provides support for pathconf() and fpathconf().
512
513 static int romfs_pathconf( romfs_node *node, struct cyg_pathconf_info *info )
514 {
515     int err = ENOERR;
516     
517     switch( info->name )
518     {
519     case _PC_LINK_MAX:
520         info->value = LINK_MAX;
521         break;
522         
523     case _PC_MAX_CANON:
524         info->value = -1;       // not supported
525         err = EINVAL;
526         break;
527         
528     case _PC_MAX_INPUT:
529         info->value = -1;       // not supported
530         err = EINVAL;        
531         break;
532         
533     case _PC_NAME_MAX:
534         info->value = NAME_MAX;
535         break;
536         
537     case _PC_PATH_MAX:
538         info->value = PATH_MAX;
539         break;        
540
541     case _PC_PIPE_BUF:
542         info->value = -1;       // not supported
543         err = EINVAL;        
544         break;        
545
546         
547     case _PC_ASYNC_IO:
548         info->value = -1;       // not supported
549         err = EINVAL;        
550         break;
551         
552     case _PC_CHOWN_RESTRICTED:
553         info->value = -1;       // not supported
554         err = EINVAL;
555         break;
556         
557     case _PC_NO_TRUNC:
558         info->value = 0;
559         break;
560         
561     case _PC_PRIO_IO:
562         info->value = 0;
563         break;
564         
565     case _PC_SYNC_IO:
566         info->value = 0;
567         break;
568         
569     case _PC_VDISABLE:
570         info->value = -1;       // not supported
571         err = EINVAL;        
572         break;
573         
574     default:
575         err = EINVAL;
576         break;
577     }
578
579     return err;
580 }
581
582 //==========================================================================
583 // Filesystem operations
584
585 // -------------------------------------------------------------------------
586 // romfs_mount()
587 // Process a mount request. This mainly finds root for the
588 // filesystem.
589
590 static int romfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
591 {
592     romfs_disk *disk=NULL;
593     
594     if ( !mte->data ) {
595         // If the image address was not in the MTE data word,
596         if ( mte->devname && mte->devname[0] ) {
597             char *addr;
598             // And there's something in the 'hardware device' field,
599             // then read the address from there.
600             sscanf( mte->devname, "%p", &addr );
601             disk = (romfs_disk *) addr;
602         }
603     } else {
604         disk = (romfs_disk *)mte->data;
605     }
606
607     if ( !disk ) {
608         // If still no address, try the FSTAB entry data word
609         disk = (romfs_disk *)fste->data;
610     }
611
612     if ( !disk ) {
613         // If still no address, give up...
614         return ENOENT;
615     }
616
617
618     
619     // Check the ROMFS magic number to ensure that there's really an fs.
620     if ( disk->magic == ROMFS_CIGAM ) {
621         // The disk image has the wrong byte sex!!!
622         return EIO;
623     } else if ( disk->magic != ROMFS_MAGIC || disk->nodecount == 0 ) {
624         // No image found
625         return ENOENT;
626     }
627
628     mte->root = (cyg_dir)&disk->node[0];
629     
630     mte->data = (CYG_ADDRWORD)disk;
631     return ENOERR;
632 }
633
634 // -------------------------------------------------------------------------
635 // romfs_umount()
636 // Unmount the filesystem. This will currently always succeed.
637
638 static int romfs_umount   ( cyg_mtab_entry *mte )
639 {
640     // Clear root pointer
641     mte->root = CYG_DIR_NULL;
642     
643     // That's all folks.
644         
645     return ENOERR;
646 }
647
648 // -------------------------------------------------------------------------
649 // romfs_open()
650 // Open a file for reading
651
652 static int romfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
653                              int mode,  cyg_file *file )
654 {
655
656     romfs_dirsearch ds;
657     romfs_node *node = NULL;
658     int err;
659
660     init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
661     
662     err = romfs_find( &ds );
663
664     if( err == ENOENT )
665     {
666         return ENOENT;
667     }
668     else if( err == ENOERR )
669     {
670         // The node exists. If the O_CREAT and O_EXCL bits are set, we
671         // must fail the open.
672         
673         if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
674             err = EEXIST;
675         else node = ds.node;
676     }
677     
678     if( err == ENOERR && (mode & O_TRUNC ) )
679     {
680         // If the O_TRUNC bit is set we must fail the open
681
682         err = EPERM;
683     }
684
685     if( err != ENOERR ) return err;
686
687     // Check that we actually have a file here
688     if( S_ISDIR(node->mode) ) return EISDIR;
689
690     // Initialize the file object
691     
692     file->f_flag        |= mode & CYG_FILE_MODE_MASK;
693     file->f_type        = CYG_FILE_TYPE_FILE;
694     file->f_ops         = &romfs_fileops;
695     file->f_offset      = 0;
696     file->f_data        = (CYG_ADDRWORD)node;
697     file->f_xops        = 0;
698
699     return ENOERR;
700 }
701
702 // -------------------------------------------------------------------------
703 // romfs_opendir()
704 // Open a directory for reading.
705
706 static int romfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
707                              cyg_file *file )
708 {
709     romfs_dirsearch ds;
710     int err;
711
712     init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
713     
714     err = romfs_find( &ds );
715
716     if( err != ENOERR ) return err;
717
718     // check it is really a directory.
719     if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
720
721     // Initialize the file object, setting the f_ops field to a
722     // special set of file ops.
723     
724     file->f_type        = CYG_FILE_TYPE_FILE;
725     file->f_ops         = &romfs_dirops;
726     file->f_offset      = 0;
727     file->f_data        = (CYG_ADDRWORD)ds.node;
728     file->f_xops        = 0;
729         
730     return ENOERR;
731
732 }
733
734 // -------------------------------------------------------------------------
735 // romfs_chdir()
736 // Change directory support.
737
738 static int romfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
739                              cyg_dir *dir_out )
740 {
741     if( dir_out != NULL )
742     {
743         // This is a request to get a new directory pointer in
744         // *dir_out.
745
746         romfs_dirsearch ds;
747         int err;
748     
749         init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
750     
751         err = romfs_find( &ds );
752
753         if( err != ENOERR ) return err;
754
755         // check it is a directory
756         if( !S_ISDIR(ds.node->mode) )
757             return ENOTDIR;
758         
759         // Pass it out
760         *dir_out = (cyg_dir)ds.node;
761     }
762     // If no output dir is required, this means that the mte and
763     // dir arguments are the current cdir setting and we should
764     // forget this fact. Do nothing in ROMFS.
765         
766     return ENOERR;
767 }
768
769 // -------------------------------------------------------------------------
770 // romfs_stat()
771 // Get struct stat info for named object.
772
773 static int romfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
774                              struct stat *buf)
775 {
776     romfs_dirsearch ds;
777     int err;
778     romfs_disk *disk = (romfs_disk *)mte->data;
779
780     init_dirsearch( &ds, disk, (romfs_node *)dir, name );
781     
782     err = romfs_find( &ds );
783
784     if( err != ENOERR ) return err;
785
786     // Fill in the status
787     buf->st_mode        = ds.node->mode;
788     buf->st_ino         = (ino_t)(ds.node - &disk->node[0]);
789     buf->st_dev         = (dev_t)disk->dev_id;
790     buf->st_nlink       = ds.node->nlink;
791     buf->st_uid         = ds.node->uid;
792     buf->st_gid         = ds.node->gid;
793     buf->st_size        = ds.node->size;
794     buf->st_atime       = ds.node->ctime;
795     buf->st_mtime       = ds.node->ctime;
796     buf->st_ctime       = ds.node->ctime;
797     
798     return err;
799 }
800
801 // -------------------------------------------------------------------------
802 // romfs_getinfo()
803 // Getinfo. Currently only support pathconf() and file system block usage
804
805 static int romfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
806                              int key, void *buf, int len )
807 {
808     romfs_dirsearch ds;
809     int err;
810
811     init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
812     
813     err = romfs_find( &ds );
814
815     if( err != ENOERR ) return err;
816
817     switch( key )
818     {
819     case FS_INFO_CONF:
820         err = romfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
821         break;
822 #if defined(CYGSEM_FILEIO_BLOCK_USAGE)
823     case FS_INFO_BLOCK_USAGE: {
824       struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
825       struct romfs_disk *disk = (struct romfs_disk*) mte->data;
826       usage->total_blocks = disk->disksize;
827       usage->free_blocks = 0;
828       usage->block_size = 1;
829       return ENOERR;
830     }
831 #endif
832     default:
833         err = EINVAL;
834     }
835     return err;
836 }
837
838 // -------------------------------------------------------------------------
839 // romfs_setinfo()
840 // Setinfo. Nothing to support here at present.
841
842 static int romfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
843                              int key, void *buf, int len )
844 {
845     // No setinfo keys supported at present
846     
847     return EINVAL;
848 }
849
850
851 //==========================================================================
852 // File operations
853
854 // -------------------------------------------------------------------------
855 // romfs_fo_read()
856 // Read data from the file.
857
858 static int romfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
859 {
860     romfs_node *node = (romfs_node *)fp->f_data;
861     int i;
862     off_t pos = fp->f_offset;
863     ssize_t resid = uio->uio_resid;
864
865     // Loop over the io vectors until there are none left
866     for( i = 0; i < uio->uio_iovcnt; i++ )
867     {
868         cyg_iovec *iov = &uio->uio_iov[i];
869         char *buf = (char *)iov->iov_base;
870         off_t len = iov->iov_len;
871
872         // Loop over each vector filling it with data from the file.
873         while( len > 0 && pos < node->size )
874         {
875             cyg_uint8 *fbuf;
876             size_t bsize;
877             off_t l = len;
878             int err;
879
880             // Get a pointer to the data at offset _pos_.
881             err = findbuffer_node( (romfs_disk *)fp->f_mte->data, node, pos, &fbuf, &bsize );
882
883             if( err != ENOERR )
884                 return err;
885
886             // adjust size to end of file if necessary
887             if( l > node->size-pos )
888                 l = node->size-pos;
889             
890             // adjust size to the amount of contiguous data we can see
891             // at present.
892             if( l > bsize )
893                 l = bsize;
894
895             // copy data out
896             memcpy( buf, fbuf, l );
897
898             // Update working vars
899             len -= l;
900             buf += l;
901             pos += l;
902             resid -= l;
903         }
904     }
905
906     // We successfully read some data
907     // Update the file offset and transfer residue.
908     
909     uio->uio_resid = resid;
910     fp->f_offset = pos;
911     
912     return ENOERR;
913 }
914
915 // -------------------------------------------------------------------------
916 // romfs_fo_lseek()
917 // Seek to a new file position.
918
919 static int romfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
920 {
921     romfs_node *node = (romfs_node *)fp->f_data;
922     off_t pos = *apos;
923
924     switch( whence )
925     {
926     case SEEK_SET:
927         // Pos is already where we want to be.
928         break;
929
930     case SEEK_CUR:
931         // Add pos to current offset.
932         pos += fp->f_offset;
933         break;
934
935     case SEEK_END:
936         // Add pos to file size.
937         pos += node->size;
938         break;
939
940     default:
941         return EINVAL;
942     }
943     
944     // Check that pos is still within current file size, or at the
945     // very end.
946     if( pos < 0 || pos > node->size )
947         return EINVAL;
948
949     // All OK, set fp offset and return new position.
950     *apos = fp->f_offset = pos;
951     
952     return ENOERR;
953 }
954
955 // -------------------------------------------------------------------------
956 // romfs_fo_ioctl()
957 // Handle ioctls. Currently none are defined.
958
959 static int romfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
960                                 CYG_ADDRWORD data)
961 {
962     // No Ioctls currenly defined.
963
964     return EINVAL;
965 }
966
967 // -------------------------------------------------------------------------
968 // romfs_fo_fsync().
969 // Force the file out to data storage.
970
971 static int romfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode )
972 {
973     // Data is always permanently where it belongs, nothing to do
974     // here.
975   
976     return ENOERR;
977 }
978
979 // -------------------------------------------------------------------------
980 // romfs_fo_close()
981 // Close a file. We just clear out the data pointer.
982
983 static int romfs_fo_close     (struct CYG_FILE_TAG *fp)
984 {
985     fp->f_data = 0;     // zero data pointer
986     
987     return ENOERR;
988 }
989
990 // -------------------------------------------------------------------------
991 //romfs_fo_fstat()
992 // Get file status.
993
994 static int romfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
995 {
996     romfs_node *node = (romfs_node *)fp->f_data;
997     romfs_disk *disk = (romfs_disk*)(fp->f_mte->data);
998
999     // Fill in the status
1000     buf->st_mode        = node->mode;
1001     buf->st_ino         = (ino_t)(node - &disk->node[0]);
1002     buf->st_dev         = disk->dev_id;
1003     buf->st_nlink       = node->nlink;
1004     buf->st_uid         = node->uid;
1005     buf->st_gid         = node->gid;
1006     buf->st_size        = node->size;
1007     buf->st_atime       = node->ctime;
1008     buf->st_mtime       = node->ctime;
1009     buf->st_ctime       = node->ctime;
1010     
1011     return ENOERR;
1012 }
1013
1014 // -------------------------------------------------------------------------
1015 // romfs_fo_getinfo()
1016 // Get info. Currently only supports fpathconf().
1017
1018 static int romfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
1019 {
1020     romfs_node *node = (romfs_node *)fp->f_data;    
1021     int err;
1022
1023     switch( key )
1024     {
1025     case FS_INFO_CONF:
1026         err = romfs_pathconf( node, (struct cyg_pathconf_info *)buf );
1027         break;
1028         
1029     default:
1030         err = EINVAL;
1031     }
1032     return err;
1033 }
1034
1035 // -------------------------------------------------------------------------
1036 // romfs_fo_setinfo()
1037 // Set info. Nothing supported here.
1038
1039 static int romfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
1040 {
1041     // No setinfo key supported at present
1042     
1043     return ENOERR;
1044 }
1045
1046
1047 //==========================================================================
1048 // Directory operations
1049
1050 // -------------------------------------------------------------------------
1051 // romfs_fo_dirread()
1052 // Read a single directory entry from a file.
1053
1054 static int romfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1055 {
1056     romfs_node *dir = (romfs_node *)fp->f_data;
1057     off_t pos = fp->f_offset;
1058     int err = ENOERR;
1059     struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
1060     char *nbuf = ent->d_name;
1061     int nlen = sizeof(ent->d_name)-1;
1062     off_t len = uio->uio_iov[0].iov_len;
1063     romfs_dirent *d = NULL;
1064     cyg_uint8 *buf;
1065     size_t size;
1066     int i;
1067         
1068     if( len < sizeof(struct dirent) )
1069         return EINVAL;    
1070     
1071     // Get the next entry
1072     err = findbuffer_node( (romfs_disk *)fp->f_mte->data, dir, pos, &buf, &size );
1073     if( err != ENOERR || size == 0 || pos >= dir->size )
1074         return err;
1075
1076     d = (romfs_dirent *)buf;
1077
1078     for ( i = 0 ; i < nlen && d->name[i] ; i++, nbuf++ )
1079         *nbuf = d->name[i];
1080 #ifdef CYGPKG_FS_ROM_RET_DIRENT_DTYPE
1081         ent->d_type = (((romfs_disk *)fp->f_mte->data)->node[d->node]).mode;
1082 #endif
1083
1084     // A successful read. Terminate the entry name with a NUL, set the
1085     // residue and set the file offset to restart at the next
1086     // directory entry.
1087     
1088     *nbuf = '\0';
1089     uio->uio_resid -= sizeof(struct dirent);
1090     fp->f_offset = d->next;
1091     
1092     return ENOERR;
1093 }
1094
1095 // -------------------------------------------------------------------------
1096 // romfs_fo_dirlseek()
1097 // Seek directory to start.
1098
1099 static int romfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
1100 {
1101     // Only allow SEEK_SET to zero
1102     
1103     if( whence != SEEK_SET || *pos != 0)
1104         return EINVAL;
1105
1106     *pos = fp->f_offset = 0;
1107     
1108     return ENOERR;
1109 }
1110
1111 // -------------------------------------------------------------------------
1112 // EOF romfs.c