Sample code for handling _IO_WRITE messages
int io_write (resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *ocb)
{
int status;
char *buf;
size_t nbytes;
if ((status = iofunc_write_verify(ctp, msg, ocb, NULL)) != EOK)
return (status);
if ((msg->i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE)
return(ENOSYS);
/* Extract the length of the client's message. */
nbytes = _IO_WRITE_GET_NBYTES(msg);
/* Filter out malicious write requests that attempt to write more
data than they provide in the message. */
if(nbytes > (size_t)ctp->info.srcmsglen - (size_t)ctp->offset - sizeof(io_write_t)) {
return EBADMSG;
}
/* set up the number of bytes (returned by client's write()) */
_IO_SET_WRITE_NBYTES (ctp, nbytes);
buf = (char *) malloc(nbytes + 1);
if (buf == NULL)
return(ENOMEM);
/*
* Read the data from the sender's message.
* We're not assuming that all of the data fit into the
* resource manager library's receive buffer.
*/
resmgr_msgget(ctp, buf, nbytes, sizeof(msg->i));
buf [nbytes] = '\0'; /* just in case the text is not NULL terminated */
printf ("Received %zu bytes = '%s'\n", nbytes, buf);
free(buf);
if (nbytes > 0)
ocb->attr->flags |= IOFUNC_ATTR_MTIME | IOFUNC_ATTR_CTIME;
return (_RESMGR_NPARTS (0));
}
/* initialize functions for handling messages */
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs,
_RESMGR_IO_NFUNCS, &io_funcs);
io_funcs.write = io_write;
int io_write (resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *ocb);
# echo Hello > /dev/sample
Received 6 bytes = 'Hello'
Notice how we passed the last argument to resmgr_msgget() (the offset argument) as the size of the input message buffer. This effectively skips over the header and gets to the data component.
If the buffer you supplied wasn't big enough to contain the entire message from the client
(e.g., you had a 4 KB buffer and the client wanted to write 1 megabyte), you'd have to
read the buffer in stages, using a for
loop, advancing the offset
passed to resmgr_msgget() by the amount read each time.
Unlike the io_read handler sample, this time we didn't do anything with
ocb->offset
.
In this case there's no reason to.
The ocb->offset
would make more sense if we were managing things
that had advancing positions such as a file position.
The reply is simpler than with the io_read handler, since a write() call doesn't expect any data back. Instead, it just wants to know if the write succeeded and if so, how many bytes were written. To tell it how many bytes were written we used the _IO_SET_WRITE_NBYTES() macro. It takes the nbytes that we give it and stores it in the context structure (ctp). Then when we return to the library, the library takes this nbytes and passes it as the second parameter to the MsgReplyv(). The second parameter tells the kernel what the MsgSend() should return. And since the write() function is calling MsgSend(), that's where it finds out how many bytes were written.
Since we're writing to the device, we should also update the modification,
and potentially, the creation time.
For details on updating the modification and change of file status times,
see the section on
Updating the time for reads and writes
below.