/* Use ptrdiff_t for the fd since we're passed a void * and should
* read it as an integer of the same size. */staticvoid do_close_fd(ptrdiff_t fd)
{
int ret;
if (fd < 0) return;
do {
ret = fd_close(fd);
} while ((ret == -1) && (errno == EINTR));
}

/*
* Large reads cause the kernel to validate more memory before
* starting the actual read, and hence cause slowdowns.
* Ideally you read as much as you're going to receive.
* This buffer calculation algorithm tries to optimise the
* read length depending on past read chunksizes.
* For network reads this allows it to follow the packetsizes.
* The initial read will attempt the full buffer. /srb
*/if( i < try_read )
i += SMALL_NETBUF;
else
i += (r-i)>>1;
if (i < SMALL_NETBUF)
i = SMALL_NETBUF;
if(i > r-SMALL_NETBUF)
i = r;

*! the system read function returns. This is mainly useful with
*! stream devices which can return exactly one row or packet at a
*! time. If @[not_all] is used in blocking mode, @[read()] only
*! blocks if there's no data at all available.

*! If something goes wrong and @[not_all] is set, zero is returned.
*! If something goes wrong and @[not_all] is zero or left out, then
*! either zero or a string shorter than @[len] is returned. If the
*! problem persists then a later call to @[read()] fails and returns
*! zero, however.

/* Race: A backend in another thread might have managed to set these
* again for something that arrived after the read above. Not that
* bad - it will get through in a later backend round. */
THIS->box.revents &= ~(PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB);

*! @endint
*!
*! @returns
*! @int
*! @value 1
*! There is data available to @[read()], or @[not_eof] is
*! @expr{0@} (zero) and we're at EOF. A later call to
*! @[read()] will not block.
*!
*! @value 0
*! There is no data available (ie timeout).
*!
*! @value -1
*! Error condition. The error code returned by @[errno()]
*! has been updated.
*! @endint

*! If something goes wrong and @[not_all] is set, zero is returned.
*! If something goes wrong and @[not_all] is zero or left out, then
*! either zero or a string shorter than @[len] is returned. If the
*! problem persists then a later call to @[read_oob()] fails and
*! returns zero, however.

/* Race: A backend in another thread might have managed to set these
* again for something that arrived after the read above. Not that
* bad - it will get through in a later backend round. */
THIS->box.revents &= ~(PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB);

*! @ul
*! @item
*! some data was written successfully and then something went
*! wrong, or
*! @item
*! nonblocking mode is used and not all data could be written
*! without blocking.
*! @endul
*!
*! -1 is returned if something went wrong and no bytes were written.
*! If only some data was written due to an error and that error

/* Race: A backend in another thread might have managed to set these
* again for buffer space available after the write above. Not that
* bad - it will get through in a later backend round. */
THIS->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB);

*! Writes out-of-band data to a stream and returns how many bytes
*! that were actually written. It can be less than the size of the
*! given data if some data was written successfully and then
*! something went wrong.
*!
*! -1 is returned if something went wrong and no bytes were written.
*! If only some data was written due to an error and that error

*! It is not guaranteed that all out-of-band data sent from the
*! other end is received. Most streams only allow for a single byte
*! of out-of-band data at a time. Some streams sends the rest of
*! the data as ordinary data.

/* Race: A backend in another thread might have managed to set these
* again for buffer space available after the write above. Not that
* bad - it will get through in a later backend round. */
THIS->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB);

#ifdef HAVE_PIKE_SEND_FD
/*! @decl void send_fd(Stdio.Fd fd)
*!
*! Queues an open file descriptor for sending to the other end of a stream.
*!
*! @note
*! The actual sending is performed at the next successful call
*! to @[write()], this is due to limitations in the system calls.
*! This means that it isn't possible to send a file descriptor
*! without also sending some in-band data.
*!
*! This operation is only supported on @[pipe()]'s created with
*! @[PROP_SEND_FD].
*!
*! This function is not available on all operating systems, check
*! for @[__HAVE_SEND_FD__].
*!
*! The queue is emptied on successful @[write()] and when the
*! write direction is @[close()]'d.
*!
*! @seealso
*! @[receive_fd()], @[write()], @[pipe()], @[read()], @[__HAVE_SEND_FD__]
*/staticvoid file_send_fd(INT32 args)
{
int other_fd;
struct object *o = NULL;
struct my_file *f = NULL;
int *fd_info = NULL;

*! Open a file, or use an existing fd.
*!
*! If @[filename] is given, attempt to open the named file. If @[fd]
*! is given instead, it should be the file descriptor for an already
*! opened file, which will then be used by this object.
*!

*! This function returns the same information as the function
*! @[file_stat()], but for the file it is called in. If file is not
*! an open file, @expr{0@} (zero) is returned. Zero is also returned
*! if file is a pipe or socket.

#ifdef HAVE_FSTATAT
/*! @decl Stat statat(string path, void|int(0..1) symlink)
*!
*! Get status for a file relative an open directory.
*!
*! This function returns the same information as the function
*! @[file_stat()], but relative to the file it is called in. If file is not
*! an open file, @expr{0@} (zero) is returned. Zero is also returned
*! if file is a pipe or socket.
*!
*! @returns
*! See @[file_stat()] for a description of the return value.
*!
*! @note
*! Not available on all architectures, or in Pike 7.6 and earlier.
*!
*! @seealso

*! The backend keeps a reference to this object only when it is in
*! callback mode. So if this object hasn't got any active callbacks
*! and it runs out of other references, it will still be destructed
*! quickly (after closing, if necessary).
*!
*! Also, this object does not keep a reference to the backend.

*! @note
*! Nonblocking operation is not supported on all Stdio.File objects.
*! Notably it is not guaranteed to be supported on objects returned
*! by @[pipe()] unless @[PROP_NONBLOCK] was specified in the call
*! to @[pipe()].
*!

*! Most methods can't be called for a file descriptor that isn't
*! open. Notable exceptions @[errno], @[mode], and the set and query
*! functions for callbacks and backend.
*/
staticvoid file_is_open (INT32 args)
{

*! Returns the file descriptor number associated with this object, in
*! addition to releasing it so that this object behaves as if closed.
*! Other settings like callbacks and backend remain intact.
*! @[take_fd] can later be used to reinstate the file descriptor so
*! that the state is restored.
*!

*! Rehooks the given file descriptor number to be associated with
*! this object. As opposed to using @[open] with a file descriptor
*! number, it will be closed by this object upon destruct or when
*! @[close] is called.
*!

*!
*! @note
*! It is not guaranteed that this function actually does anything,
*! but it certainly helps to increase data transfer speed when it does.
*!
*! @seealso
*! @[open_socket()], @[accept()]
*/

* socketpair_ultra is 50% more portable than other leading
* brands of socketpair.
* /Hubbe
*/
/* redefine socketpair to something that hopefully won't
* collide with any libs or headers. Also useful when testing
* this code on a system that _has_ socketpair...
*/

*!
*! Duplicate a file over another.
*!
*! This function works similarly to @[assign()], but instead of making
*! the argument a reference to the same file, it creates a new file
*! with the same properties and places it in the argument.
*!

#ifdef SO_REUSEPORT
/* FreeBSD 7.x wants this to reuse portnumbers.
* Linux 2.6.x seems to have reserved a slot for the option, but not
* enabled it. Survive libc's with the option on kernels without.
*/

#ifdef SO_REUSEPORT
/* FreeBSD 7.x wants this to reuse portnumbers.
* Linux 2.6.x seems to have reserved a slot for the option, but not
* enabled it. Survive libc's with the option on kernels without.
*/

*!
*! Open a TCP/IP connection to the specified destination.
*!
*! In nonblocking mode, success is indicated with the write-callback,
*! and failure with the close-callback or the read_oob-callback.
*!
*! @returns

/*! @decl void notify(void|int notification, function(void:void) callback)
*! Receive notification when change occur within the fd.
*! To use, create a Stdio.File object of a directory like
*! Stdio.File(".") and then call notify() with the appropriate
*! parameters.
*!
*! @note
*! When a program registers for some notification, only the first notification

/*! @decl constant NOTE_ATTRIB = 8
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for attribute changes on a file.
*
* @note
* Available on systems that use kqueue.
*//*! @decl constant NOTE_WRITE = 2
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for writes to a file.
*
* @note
* Available on systems that use kqueue.
*//*! @decl constant NOTE_DELETE = 1
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for deletion of a file.
*
* @note
* Available on systems that use kqueue.
*//*! @decl constant NOTE_EXTEND = 4
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for extension events on a file.
*
* @note
* Available on systems that use kqueue.
*//*! @decl constant NOTE_LINK = 16
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for changes to a file's link count.
*
* @note
* Available on systems that use kqueue.
*//*! @decl constant NOTE_RENAME = 32
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for move or rename events on a file.
*
* @note
* Available on systems that use kqueue.
*//*! @decl constant NOTE_REVOKE = 64
*
* Used with @[Stdio.File()->set_fs_event_callback()] to monitor for access revokation (unmount, etc).
*
* @note
* Available on systems that use kqueue.
*/