1 //==========================================================================
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.
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.
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
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.
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.
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.
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####
44 // Contributors: nickg, richard.panton@3glab.com
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.
53 //####DESCRIPTIONEND####
55 //==========================================================================
57 // General Description
58 // ===================
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.
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:
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
77 // Immediately following thisin memory is the node table, consisting of
78 // 'nodes' repetitions of the node object.
83 // All files and directories are represented by node objects. Each
84 // romfs_node structure contains the following fields:
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
96 // A directory is a node whose data is a list of directory entries.
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.
108 // Each file has its data stored in a single contiguous memory block
109 // referenced by the offset in the node.
111 //==========================================================================
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>
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
124 #include <sys/types.h>
126 #include <sys/stat.h>
135 #include <cyg/fileio/fileio.h>
137 #include <cyg/kernel/kapi.h>
138 #include <cyg/infra/diag.h>
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.
146 // Forward definitions
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,
155 static int romfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
157 static int romfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
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 );
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,
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 );
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 );
180 //==========================================================================
181 // Filesystem table entries
183 // -------------------------------------------------------------------------
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.
189 FSTAB_ENTRY( romfs_fste, "romfs", 0,
190 CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
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,
205 // -------------------------------------------------------------------------
207 // This defines a single ROMFS loaded into ROM at the configured address
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
217 // -------------------------------------------------------------------------
219 // This set of file operations are used for normal open files.
221 static cyg_fileops romfs_fileops =
224 (cyg_fileop_write *)cyg_fileio_erofs,
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.
241 static cyg_fileops romfs_dirops =
244 (cyg_fileop_write *)cyg_fileio_enosys,
246 (cyg_fileop_ioctl *)cyg_fileio_enosys,
248 (cyg_fileop_fsync *)cyg_fileio_enosys,
250 (cyg_fileop_fstat *)cyg_fileio_enosys,
251 (cyg_fileop_getinfo *)cyg_fileio_enosys,
252 (cyg_fileop_setinfo *)cyg_fileio_enosys
255 //==========================================================================
257 // Some forward typedefs for the main data structures.
260 typedef struct romfs_disk romfs_disk;
263 typedef struct romfs_node romfs_node;
266 typedef struct romfs_dirent romfs_dirent;
268 //==========================================================================
269 // File and directory node
270 // This data structure represents a file or directory.
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
284 //==========================================================================
286 // Variable sized entry containing the name and node of a directory entry
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
297 //==========================================================================
299 // This data structure contains overall information on the ROMFS
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
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
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.
319 struct romfs_dirsearch
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?
330 typedef struct romfs_dirsearch romfs_dirsearch;
332 //==========================================================================
333 // This seems to be the only string function referenced. Define as static
334 // here to avoid having to load the string library
336 static bool match( const char *a, const char *b, int len )
338 for ( ; len > 0 && *a && *b && *a == *b ; a++, b++, len-- )
344 //==========================================================================
345 // SIMPLE buffer management.
346 // Each node has a data buffer pointer and a size.
348 // -------------------------------------------------------------------------
350 // return a pointer to the data at the indicated file position.
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
358 if ( pos >= node->size || node->size == 0 )
360 // Indicate end of data.
364 // Calculate the buffer position
365 *buffer = (cyg_uint8*)disk + node->offset + pos;
366 *size = node->size-pos;
372 //==========================================================================
373 // Directory operations
376 // -------------------------------------------------------------------------
378 // Find a directory entry for the name and return a pointer to the first
381 static romfs_dirent *find_direntry( romfs_disk *disk, romfs_node *dir, const char *name, int namelen )
386 // Loop over all the entries until a match is found or we run out
388 while( pos < dir->size )
394 err = findbuffer_node( disk, dir, pos, &buf, &size );
395 if( err != ENOERR || size == 0)
398 d = (romfs_dirent *)buf;
400 // Is this the directory entry we're looking for?
401 if ( match( d->name, name, namelen ) )
404 // Otherwise move on to next entry in chain
411 //==========================================================================
414 // -------------------------------------------------------------------------
416 // Initialize a dirsearch object to start a search
418 static void init_dirsearch( romfs_dirsearch *ds,
432 // -------------------------------------------------------------------------
434 // Search a single directory for the next name in a path and update the
435 // dirsearch object appropriately.
437 static int find_entry( romfs_dirsearch *ds )
439 romfs_node *dir = ds->dir;
440 const char *name = ds->path;
441 const char *n = name;
445 // check that we really have a directory
446 if( !S_ISDIR(dir->mode) )
449 // Isolate the next element of the path name.
450 while( *n != '\0' && *n != '/' )
453 // Check if this is the last path element.
454 while( *n == '/') n++;
458 // update name in dirsearch object
460 ds->namelen = namelen;
462 // Here we have the name and its length set up.
463 // Search the directory for a matching entry
465 d = find_direntry( ds->disk, dir, name, namelen );
470 // pass back the node we have found
471 ds->node = &ds->disk->node[d->node];
477 // -------------------------------------------------------------------------
479 // Main interface to directory search code. This is used in all file
480 // level operations to locate the object named by the pathname.
482 static int romfs_find( romfs_dirsearch *d )
486 // Short circuit empty paths
487 if( *(d->path) == '\0' )
490 // iterate down directory tree until we find the object
494 err = find_entry( d );
502 // Update dirsearch object to search next directory.
504 d->path += d->namelen;
505 while( *(d->path) == '/' ) d->path++; // skip dirname separators
509 //==========================================================================
511 // This function provides support for pathconf() and fpathconf().
513 static int romfs_pathconf( romfs_node *node, struct cyg_pathconf_info *info )
520 info->value = LINK_MAX;
524 info->value = -1; // not supported
529 info->value = -1; // not supported
534 info->value = NAME_MAX;
538 info->value = PATH_MAX;
542 info->value = -1; // not supported
548 info->value = -1; // not supported
552 case _PC_CHOWN_RESTRICTED:
553 info->value = -1; // not supported
570 info->value = -1; // not supported
582 //==========================================================================
583 // Filesystem operations
585 // -------------------------------------------------------------------------
587 // Process a mount request. This mainly finds root for the
590 static int romfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
592 romfs_disk *disk=NULL;
595 // If the image address was not in the MTE data word,
596 if ( mte->devname && mte->devname[0] ) {
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;
604 disk = (romfs_disk *)mte->data;
608 // If still no address, try the FSTAB entry data word
609 disk = (romfs_disk *)fste->data;
613 // If still no address, give up...
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!!!
623 } else if ( disk->magic != ROMFS_MAGIC || disk->nodecount == 0 ) {
628 mte->root = (cyg_dir)&disk->node[0];
630 mte->data = (CYG_ADDRWORD)disk;
634 // -------------------------------------------------------------------------
636 // Unmount the filesystem. This will currently always succeed.
638 static int romfs_umount ( cyg_mtab_entry *mte )
640 // Clear root pointer
641 mte->root = CYG_DIR_NULL;
648 // -------------------------------------------------------------------------
650 // Open a file for reading
652 static int romfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
653 int mode, cyg_file *file )
657 romfs_node *node = NULL;
660 init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
662 err = romfs_find( &ds );
668 else if( err == ENOERR )
670 // The node exists. If the O_CREAT and O_EXCL bits are set, we
671 // must fail the open.
673 if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
678 if( err == ENOERR && (mode & O_TRUNC ) )
680 // If the O_TRUNC bit is set we must fail the open
685 if( err != ENOERR ) return err;
687 // Check that we actually have a file here
688 if( S_ISDIR(node->mode) ) return EISDIR;
690 // Initialize the file object
692 file->f_flag |= mode & CYG_FILE_MODE_MASK;
693 file->f_type = CYG_FILE_TYPE_FILE;
694 file->f_ops = &romfs_fileops;
696 file->f_data = (CYG_ADDRWORD)node;
702 // -------------------------------------------------------------------------
704 // Open a directory for reading.
706 static int romfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
712 init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
714 err = romfs_find( &ds );
716 if( err != ENOERR ) return err;
718 // check it is really a directory.
719 if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
721 // Initialize the file object, setting the f_ops field to a
722 // special set of file ops.
724 file->f_type = CYG_FILE_TYPE_FILE;
725 file->f_ops = &romfs_dirops;
727 file->f_data = (CYG_ADDRWORD)ds.node;
734 // -------------------------------------------------------------------------
736 // Change directory support.
738 static int romfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
741 if( dir_out != NULL )
743 // This is a request to get a new directory pointer in
749 init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
751 err = romfs_find( &ds );
753 if( err != ENOERR ) return err;
755 // check it is a directory
756 if( !S_ISDIR(ds.node->mode) )
760 *dir_out = (cyg_dir)ds.node;
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.
769 // -------------------------------------------------------------------------
771 // Get struct stat info for named object.
773 static int romfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
778 romfs_disk *disk = (romfs_disk *)mte->data;
780 init_dirsearch( &ds, disk, (romfs_node *)dir, name );
782 err = romfs_find( &ds );
784 if( err != ENOERR ) return err;
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;
801 // -------------------------------------------------------------------------
803 // Getinfo. Currently only support pathconf().
805 static int romfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
806 int key, void *buf, int len )
811 init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
813 err = romfs_find( &ds );
815 if( err != ENOERR ) return err;
820 err = romfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
829 // -------------------------------------------------------------------------
831 // Setinfo. Nothing to support here at present.
833 static int romfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
834 int key, void *buf, int len )
836 // No setinfo keys supported at present
842 //==========================================================================
845 // -------------------------------------------------------------------------
847 // Read data from the file.
849 static int romfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
851 romfs_node *node = (romfs_node *)fp->f_data;
853 off_t pos = fp->f_offset;
854 ssize_t resid = uio->uio_resid;
856 // Loop over the io vectors until there are none left
857 for( i = 0; i < uio->uio_iovcnt; i++ )
859 cyg_iovec *iov = &uio->uio_iov[i];
860 char *buf = (char *)iov->iov_base;
861 off_t len = iov->iov_len;
863 // Loop over each vector filling it with data from the file.
864 while( len > 0 && pos < node->size )
871 // Get a pointer to the data at offset _pos_.
872 err = findbuffer_node( (romfs_disk *)fp->f_mte->data, node, pos, &fbuf, &bsize );
877 // adjust size to end of file if necessary
878 if( l > node->size-pos )
881 // adjust size to the amount of contiguous data we can see
887 memcpy( buf, fbuf, l );
889 // Update working vars
897 // We successfully read some data
898 // Update the file offset and transfer residue.
900 uio->uio_resid = resid;
906 // -------------------------------------------------------------------------
908 // Seek to a new file position.
910 static int romfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
912 romfs_node *node = (romfs_node *)fp->f_data;
918 // Pos is already where we want to be.
922 // Add pos to current offset.
927 // Add pos to file size.
935 // Check that pos is still within current file size, or at the
937 if( pos < 0 || pos > node->size )
940 // All OK, set fp offset and return new position.
941 *apos = fp->f_offset = pos;
946 // -------------------------------------------------------------------------
948 // Handle ioctls. Currently none are defined.
950 static int romfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
953 // No Ioctls currenly defined.
958 // -------------------------------------------------------------------------
960 // Force the file out to data storage.
962 static int romfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode )
964 // Data is always permanently where it belongs, nothing to do
970 // -------------------------------------------------------------------------
972 // Close a file. We just clear out the data pointer.
974 static int romfs_fo_close (struct CYG_FILE_TAG *fp)
976 fp->f_data = 0; // zero data pointer
981 // -------------------------------------------------------------------------
985 static int romfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
987 romfs_node *node = (romfs_node *)fp->f_data;
988 romfs_disk *disk = (romfs_disk*)(fp->f_mte->data);
990 // Fill in the status
991 buf->st_mode = node->mode;
992 buf->st_ino = (ino_t)(node - &disk->node[0]);
993 buf->st_dev = disk->dev_id;
994 buf->st_nlink = node->nlink;
995 buf->st_uid = node->uid;
996 buf->st_gid = node->gid;
997 buf->st_size = node->size;
998 buf->st_atime = node->ctime;
999 buf->st_mtime = node->ctime;
1000 buf->st_ctime = node->ctime;
1005 // -------------------------------------------------------------------------
1006 // romfs_fo_getinfo()
1007 // Get info. Currently only supports fpathconf().
1009 static int romfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
1011 romfs_node *node = (romfs_node *)fp->f_data;
1017 err = romfs_pathconf( node, (struct cyg_pathconf_info *)buf );
1026 // -------------------------------------------------------------------------
1027 // romfs_fo_setinfo()
1028 // Set info. Nothing supported here.
1030 static int romfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
1032 // No setinfo key supported at present
1038 //==========================================================================
1039 // Directory operations
1041 // -------------------------------------------------------------------------
1042 // romfs_fo_dirread()
1043 // Read a single directory entry from a file.
1045 static int romfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1047 romfs_node *dir = (romfs_node *)fp->f_data;
1048 off_t pos = fp->f_offset;
1050 struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
1051 char *nbuf = ent->d_name;
1052 int nlen = sizeof(ent->d_name)-1;
1053 off_t len = uio->uio_iov[0].iov_len;
1054 romfs_dirent *d = NULL;
1059 if( len < sizeof(struct dirent) )
1062 // Get the next entry
1063 err = findbuffer_node( (romfs_disk *)fp->f_mte->data, dir, pos, &buf, &size );
1064 if( err != ENOERR || size == 0 || pos >= dir->size )
1067 d = (romfs_dirent *)buf;
1069 for ( i = 0 ; i < nlen && d->name[i] ; i++, nbuf++ )
1072 // A successful read. Terminate the entry name with a NUL, set the
1073 // residue and set the file offset to restart at the next
1077 uio->uio_resid -= sizeof(struct dirent);
1078 fp->f_offset = d->next;
1083 // -------------------------------------------------------------------------
1084 // romfs_fo_dirlseek()
1085 // Seek directory to start.
1087 static int romfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
1089 // Only allow SEEK_SET to zero
1091 if( whence != SEEK_SET || *pos != 0)
1094 *pos = fp->f_offset = 0;
1099 // -------------------------------------------------------------------------