+
+/** Tells if a file is active (i.e., added). **/
+static inline int file_is_active(struct main_file *fi)
+{
+ return clist_is_linked(&fi->n);
+}
+
+/** Show current state of a file. Available only if LibUCW has been compiled with `CONFIG_UCW_DEBUG`. **/
+void file_debug(struct main_file *fi);
+
+/***
+ * [[blockio]]
+ * Asynchronous block I/O
+ * ----------------------
+ *
+ * If you are reading or writing fixed-size blocks of data, you can let the
+ * block I/O interface handle the boring routine of handling partial reads
+ * and writes for you.
+ *
+ * You just create <<struct_main_block_io,`struct main_block_io`>> and call
+ * @block_io_add() on it, which sets up some <<struct_main_file,`main_file`>>s internally.
+ * Then you can just call @block_io_read() or @block_io_write() to ask for
+ * reading or writing of a given block. When the operation is finished,
+ * your handler function is called.
+ *
+ * Additionally, the block I/O is equipped with a timer, which can be used
+ * to detect communication timeouts. The timer is not touched internally
+ * (except that it gets added and deleted at the right places), feel free
+ * to adjust it from your handler functions by @block_io_set_timeout().
+ * When the timer expires, the error handler is automatically called with
+ * <<enum_block_io_err_cause,`BIO_ERR_TIMEOUT`>>.
+ ***/
+
+/** The block I/O structure. **/
+struct main_block_io {
+ struct main_file file;
+ byte *rbuf; /* Read/write pointers for use by file_read/write */
+ uns rpos, rlen;
+ byte *wbuf;
+ uns wpos, wlen;
+ void (*read_done)(struct main_block_io *bio); /* [*] Called when file_read is finished; rpos < rlen if EOF */
+ void (*write_done)(struct main_block_io *bio); /* [*] Called when file_write is finished */
+ void (*error_handler)(struct main_block_io *bio, int cause); /* [*] Handler to call on errors */
+ struct main_timer timer;
+ void *data; /* [*] Data for use by the handlers */
+};
+
+/** Activate a block I/O structure. **/
+void block_io_add(struct main_block_io *bio, int fd);
+
+/** Deactivate a block I/O structure. Calling twice is safe. **/
+void block_io_del(struct main_block_io *bio);
+
+/**
+ * Specifies when or why an error happened. This is passed to the error handler.
+ * `errno` is still set to the original source of error. The only exception
+ * is `BIO_ERR_TIMEOUT`, in which case `errno` is not set and the only possible
+ * cause of it is timeout of the timer associated with the block_io
+ * (see @block_io_set_timeout()).
+ **/
+enum block_io_err_cause {
+ BIO_ERR_READ,
+ BIO_ERR_WRITE,
+ BIO_ERR_TIMEOUT
+};
+