The Hackerlab at regexps.com

Buffered File Descriptors

up: libhackerlab
next: Reserved File Descriptors and Pseudo-Descriptors
prev: A VU Handler for the URL Socket Scheme

These functions allow you to perform buffered I/O on descriptors using the VU functions. (See A Virtual Unix File-System Interface.)

Each buffered file is associated with these values:

     t_uchar * buffer;
             Storage for buffered characters.
             The location of the buffer in memory
             may change over time.

     long bufsize
             The size of the buffer.

     t_uchar * read_write_position;
             The read/write position, within the buffer.
             This corresponds to the file offset returned
             by:
                     vu_lseek (&errn, fd, 0, SEEK_CUR)

     long buffered;
             The number of buffered characters relative
             to the read/write position.

             All bytes between `buffer' and 
             `read_write_position + buffered' are
             buffered.

             Note that `buffered' may be negative if the
             `read_write_position' is beyond the current
             end of the file.

Normal I/O functions like vu_read and vu_write operate in the expected way: they buffer characters or read characters from the buffer, flushing or refilling it as needed.

For high-performance I/O, there is assistance for performing buffered I/O without copying characters to and from the buffer:

             vfdbuf_getbuf
             vfdbuf_takebuf
             vfdbuf_set_buffer
             vfdbuf_more
             vfdbuf_advance

which are documented later in this chapter.

Buffers can be designated dont_flush -- which means that the buffer grows rather than writing to an underlying file. In combination with pseudo-descriptors (see reserv_pseudo), dont_flush buffers can be used to implement in-core files (files which are actually strings).

Buffers can be designated zero_byte -- which means that an extra byte is added to the buffer (at buffer + bufsize ) and that byte is initialized to 0 .


Establishing Buffers

up: Buffered File Descriptors
next: Controlling Buffer Flushing

Function vfdbuf_buffer_fd

int vfdbuf_buffer_fd (int * errn,
                      int fd,
                      long bufsize,
                      int flags,
                      int buffer_flags);

Arrange to buffer I/O on descriptor fd .

fd is the descriptor to buffer.

bufsize is the initial size of the buffer or 0 to use a buffer of the default size.

flags indicates whether to buffer for input (O_RDONLY ), output (O_WRONLY ) or both (O_RDWR ).

WARNING: I am fairly sure that there are bugs in the buffering code, especially for O_RDWR files. Some comprehensive unit tests are needed for this module.

buffer_flags is a combination (| ) of any of the bits:

     vfdbuf_add_zero_byte
     vfdbuf_auto_shift

If vfdbuf_add_zero_byte is set, the actual buffer size for this descriptor is one byte larger than bufsize (even if the buffer is reallocated). The extra byte is initialized to 0 .

If vfdbuf_auto_shift is set, the behavior of vfdbuf_more is modified. See vfdbuf_more.

If fd is already buffered, this function attempts to reset the buffer size, flags, and buffer flags. If more than bufsize characters are already buffered, the resulting buffer will be larger than bufsize .

Return 0 on success, -1 (and set *errn ) on error.



Function vfdbuf_set_buffer

int
vfdbuf_set_buffer (int * errn,
                   int fd,
                   t_uchar * buffer,
                   long bufsize,
                   long read_write_pos,
                   long buffered,
                   int add_zero_byte,
                   void (*free_buffer)(t_uchar * buf, void * closure),
                   void * free_buffer_closure)

Establish a specific region of memory as the buffer for fd .

See Buffered File Descriptors and vfdbuf_buffer_fd.



Function vfdbuf_is_buffered

int vfdbuf_is_buffered (int fd);

Return 1 if fd has a (vfdbuf) buffer, 0 otherwise.




Controlling Buffer Flushing

up: Buffered File Descriptors
next: Controlling Buffer Auto-shift
prev: Establishing Buffers

Function vfdbuf_set_dont_flush

int vfdbuf_set_dont_flush (int * errn, int fd, int setting);

Activate or deactivate buffer flushing for descriptor fd .

setting is 0 to deactivate and any other value to activate flushing.

If flushing is deactivated, writes may cause the size of the buffer to be increased and calls to vfdbuf_flush have no effect.

Return -1 and EINVAL if fd is not buffered, 0 otherwise.

See also vfdbuf_is_dont_flush.



Function vfdbuf_is_dont_flush

int vfdbuf_is_dont_flush (int * errn, int fd);

Return 0 if fd is buffered and flushing is enabled, a positive value if fd is buffered and flushing is disabled.

Return -1 and EINVAL if fd is not buffered.




Controlling Buffer Auto-shift

up: Buffered File Descriptors
next: Access to Buffers
prev: Controlling Buffer Flushing

Function vfdbuf_set_auto_shift

int vfdbuf_set_auto_shift (int * errn, int fd, int setting);

Activate or deactivate buffer auto-shift for descriptor fd .

setting is 0 to deactivate and any other value to activate auto-shift.

See vfdbuf_more.

Return -1 and EINVAL if fd is not buffered, 0 otherwise.

See also vfdbuf_is_auto_shift.



Function vfdbuf_is_auto_shift

int vfdbuf_is_auto_shift (int * errn, int fd);

Return 0 if fd is buffered and auto-shift is disabled, a positive value if fd is buffered and auto-shift is enabled.

Return -1 and EINVAL if fd is not buffered.




Access to Buffers

up: Buffered File Descriptors
next: Controlling What is Buffered
prev: Controlling Buffer Auto-shift

Function vfdbuf_getbuf

int vfdbuf_getbuf (int * errn,
                   t_uchar ** buffer,
                   long * bufsize,
                   t_uchar ** read_write_position,
                   long * buffered,
                   int fd);

Return the address and size of the buffer and the address (within that buffer) and number of buffered characters beyond the read/write position for descriptor fd .

Upon return, *buf is the read/write position and *buffered is the number of buffered characters beyond that position. If *buffered is less than 0 , then the characters between *buffer and *buffer - *buffered are not yet part of the file (the read/write position is beyond the end of the file).

Any of buffer , bufsize , read_write_pos or buffered may be 0 .

Return -1 and EINVAL if fd is not buffered, 0 otherwise.



Function vfdbuf_takebuf

int vfdbuf_takebuf (int * errn,
                    t_uchar ** bufbase,
                    long * bufsize,
                    t_uchar ** read_write_pos,
                    long * buffered,
                    int fd,
                    void (*free_buffer)(t_uchar * buf, void * closure),
                    void * free_buffer_closure);

Return the address of and size of the buffer for fd . Also return the address of and number of buffered characters beyond the read/write position. (See vfdbuf_getbuf .)

Responsibility for freeing the buffer returned (allocated by must_malloc ) rests with the caller. vfdbuf functions will continue to use the buffer. When the vfdbuf functions no longer require the buffer, they call free_buffer :

             free_buffer (buffer, free_buffer_closure)

Subsequent calls to vfdbuf_takebuf , made before free_buffer is called will return the same buffer if the same values are passed for free_buffer and free_buffer_closure and a newly allocated buffer otherwise.




Controlling What is Buffered

up: Buffered File Descriptors
next: The End-of-File
prev: Access to Buffers

Function vfdbuf_shift

int vfdbuf_shift (int * errn, int fd, long amt);

WARNING: there is a note in the code that says documentation for this function is out of date.

Discard amt leading characters from a buffer, shifting any remaining characters to make room at the end of the buffer.

If the don't flush flag is set for this buffer, this call will increase the size of the buffer by amt characters and leave existing characters untouched.

If amt is larger than the number of buffered characters that preceed the read/write position, or if amt is -1 , the effect is the same as if amt were exactly the number of buffered characters that preceed the read/write position.

If the buffer is being used for output, this call will first flush shifted characters that are currently part of the file. If there are characters in the buffer beyond the end of the file, however, they are not flushed by this function. The effect is that this function will not make a file larger. (See vfdbuf_buffer_to_position .)

Return 0 upon success, -1 upon error. This function can fail for a descriptor opened for writing if it was necessary to flush characters from the buffer, but the flush operation failed.

One useful post-condition of this function is that there is room for amt more characters beyond the read/write position after a call to this function than were available before.

Another useful post-condition is that the read/write position within the file is not changed by this function. (See vfdbuf_advance .)



Function vfdbuf_advance

int vfdbuf_advance (int * errn, int fd, long amt);

Advance the read/write position of a buffered descriptor.

If amt is larger than the number of buffered characters beyond the read/write position, the size of the buffer is increased, and the new characters initialized to 0 , but no new characters are read from the descriptor.

One or more calls this function are commonly followed by a call to vfdbuf_shift to discard the advanced-over characters from the buffer. A good time to make such a call is before a call to vfdbuf_more , if it is safe to discard characters from the buffer at that time.

Return -1 and EINVAL if fd is not buffered, 0 otherwise.



Function vfdbuf_flush

int vfdbuf_flush (int * errn, int fd);

Write buffered characters prior to the read/write position to disk. This function has no effect if descriptor fd is not buffered, or if the don't flush flag is set for this descriptor. (See vfdbuf_set_dont_flush .)

Flushed characters are removed from the buffer.

The read/write position may be past the last character of the file. In that case, only the characters in the file are flushed to disk. (See vfdbuf_buffer_to_position .)

Return 0 upon success, -1 upon error.



Function vfdbuf_return

int vfdbuf_return (int * errn, int fd, t_uchar * str, long len);

Add characters to the buffer for descriptor fd .

Characters are inserted immediately after the read/write position so that subsequent reads on this descriptor return those characters first and subsequent writes overwrite them. Subsequent flushes of a writable descriptor will ignore these characters unless the read/write position is first advanced by a write or by vfdbuf_advance .

If fd is a read-only descriptor, buffered characters prior to the read/write position may be overwritten.

The read/write position of the descriptor is unchanged relative to the beginning of the file by calls to this function.



Function vfdbuf_more

int vfdbuf_more (int * errn,
                 t_uchar ** buffer,
                 long * bufsize,
                 t_uchar ** read_write_pos,
                 long * buffered,
                 int fd,
                 long opt_amt);

Buffer (by reading) additional characters for descriptor fd . Return the address of and number of buffered unread characters (including previously buffered but unread characters).

opt_amt is the number of additional characters to read or 0 to read a default number of additional characters.

Ordinarily, no characters are discarded from the buffer by this function. (See vfdbuf_advance and vfdbuf_shift .)

If the buffer was created with the flag vfdbuf_auto_shift , opt_amt is 0 , and the last buffered character is more than 3/4 of the way through the buffer's allocated memory, then vfdbuf_more will call vfdbuf_shift before doing anything else. This is the only circumstance under which vfdbuf_more will discard characters from a buffer.

The read/write position is not changed by this function.

Return -1 upon error, the number of characters read upon success.




The End-of-File

up: Buffered File Descriptors
prev: Controlling What is Buffered

Function vfdbuf_is_eof

int vfdbuf_is_eof (int * errn, int fd);

Return 1 value if the end of file has been reached while reading from buffered descriptor fd , 0 otherwise.

Return -1 and EINVAL if fd is not a buffered descriptor.



Function vfdbuf_clear_eof

void vfdbuf_clear_eof (int * errn, int fd);

Clear the eof flag for buffered file descriptor fd .

Return -1 and EINVAL if fd is not a buffered descriptor.



libhackerlab: The Hackerlab C Library
The Hackerlab at regexps.com