In my_read_file(), we see much the same code as we saw in the simple read example above. The only strange thing we're doing is we "know" there's only one byte of data being returned, so if nbytes is non-zero, then it must be one (and nothing else). So, we can construct the data to be returned to the client by stuffing the character variable string directly. Notice how we used the inode member of the attribute structure as the basis of which data to return. This is a common trick used in resource managers that must deal with multiple resources. Another trick would be to extend the attributes structure (as discussed above in "Extending the attributes structure") and have either the data stored there directly or a pointer to it.
static int
my_read_file (resmgr_context_t *ctp, io_read_t *msg,
iofunc_ocb_t *ocb)
{
int nbytes;
int nleft;
char string;
// we don't do any xtypes here...
if ((msg -> i.xtype & _IO_XTYPE_MASK) !=
_IO_XTYPE_NONE) {
return (ENOSYS);
}
// figure out how many bytes are left
nleft = ocb -> attr -> nbytes - ocb -> offset;
// and how many we can return to the client
nbytes = min (nleft, msg -> i.nbytes);
if (nbytes) {
// create the output string
string = ocb -> attr -> inode - 1 + 'A';
// return it to the client
MsgReply (ctp -> rcvid, nbytes,
&string + ocb -> offset,
nbytes);
// update flags and offset
ocb -> attr -> flags |= IOFUNC_ATTR_ATIME
| IOFUNC_ATTR_DIRTY_TIME;
ocb -> offset += nbytes;
} else {
// nothing to return, indicate End Of File
MsgReply (ctp -> rcvid, EOK, NULL, 0);
}
// already done the reply ourselves
return (_RESMGR_NOREPLY);
}