Once a file has been opened it is represented by an open file object. These are allocated from an array of available file objects. User code accesses these open file objects via a second array of pointers which is indexed by small integer offsets. This gives the usual Unix file descriptor functionality, complete with the various duplication mechanisms.
A file table entry has the following structure:
struct CYG_FILE_TAG { cyg_uint32 f_flag; /* file state */ cyg_uint16 f_ucount; /* use count */ cyg_uint16 f_type; /* descriptor type */ cyg_uint32 f_syncmode; /* synchronization protocol */ struct CYG_FILEOPS_TAG *f_ops; /* file operations */ off_t f_offset; /* current offset */ CYG_ADDRWORD f_data; /* file or socket */ CYG_ADDRWORD f_xops; /* extra type specific ops */ cyg_mtab_entry *f_mte; /* mount table entry */ }; |
The f_flag
field contains some FILEIO
control bits and some bits propagated from the
flags
argument of the
open()
call (defined by
CYG_FILE_MODE_MASK).
The f_ucount
field contains a use count that
controls when a file will be closed. Each duplicate in the file
descriptor array counts for one reference here. It is also
incremented around each I/O operation to ensure that the file cannot
be closed while it has current I/O operations.
The f_type
field indicates the type of the
underlying file object. Some of the possible values here are
CYG_FILE_TYPE_FILE,
CYG_FILE_TYPE_SOCKET or CYG_FILE_TYPE_DEVICE.
The f_syncmode
field is copied from the
syncmode
field of the implementing
filesystem. Its use is described in Chapter 20.
The f_offset
field records the current file
position. It is the responsibility of the file operation functions to
keep this field up to date.
The f_data
field contains private data
placed here by the underlying filesystem. Normally this will be a
pointer to, or handle on, the filesystem object that implements this
file.
The f_xops
field contains a pointer to any
extra type specific operation functions. For example, the socket I/O
system installs a pointer to a table of functions that implement the
standard socket operations.
The f_mte
field contains a pointer to the
parent mount table entry for this file. It is used mainly to implement
the synchronization protocol. This may contain a pointer to some other
data structure in file objects not derived from a filesystem.
The f_ops
field contains a pointer to a
table of file I/O operations. This has the following structure:
struct CYG_FILEOPS_TAG { int (*fo_read) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); int (*fo_write) (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio); int (*fo_lseek) (struct CYG_FILE_TAG *fp, off_t *pos, int whence ); int (*fo_ioctl) (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data); int (*fo_select) (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info); int (*fo_fsync) (struct CYG_FILE_TAG *fp, int mode ); int (*fo_close) (struct CYG_FILE_TAG *fp); int (*fo_fstat) (struct CYG_FILE_TAG *fp, struct stat *buf ); int (*fo_getinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len ); int (*fo_setinfo) (struct CYG_FILE_TAG *fp, int key, char *buf, int len ); }; |
It should be obvious from the names of most of these functions what
their responsibilities are. The fo_getinfo()
and fo_setinfo()
function pointers, like their
counterparts in the filesystem structure, implement minor control and
info functions such as fpathconf()
.
The second argument to the fo_read()
and
fo_write()
function pointers is a pointer to a
UIO structure:
struct CYG_UIO_TAG { struct CYG_IOVEC_TAG *uio_iov; /* pointer to array of iovecs */ int uio_iovcnt; /* number of iovecs in array */ off_t uio_offset; /* offset into file this uio corresponds to */ ssize_t uio_resid; /* residual i/o count */ enum cyg_uio_seg uio_segflg; /* see above */ enum cyg_uio_rw uio_rw; /* see above */ }; struct CYG_IOVEC_TAG { void *iov_base; /* Base address. */ ssize_t iov_len; /* Length. */ }; |
This structure encapsulates the parameters of any data transfer operation. It provides support for scatter/gather operations and records the progress of any data transfer. It is also compatible with the I/O operations of any BSD-derived network stacks and filesystems.
When a file is opened (or a file object created by some other means,
such as socket()
or accept()
) it is the
responsibility of the filesystem open operation to initialize all the
fields of the object except the f_ucount
,
f_syncmode
and
f_mte
fields. Since the
f_flag
field will already contain bits belonging to the FILEIO
infrastructure, any changes to it must be made with the appropriate
logical operations.