Chapter 6. File descriptor and stream objects


Other miscellaneous file-related function
Linux epoll() implementation
Linux eventfd() implementation
Linux timerfd() implementation
Linux Inotify implementation
The file descriptor transport superclass
Lightweight input and output file descriptor iterators
Automatic file descriptor timeouts
Automatic file descriptor terminator
Read limits
Using sockets
File attributes
Stream objects
String stream objects
File descriptor listeners and servers
POSIX shared memory segments, and memory-mapped files
#include <x/fd.H>

x::fd file(x::fd::base::open("/etc/passwd", O_RDONLY));

x::fdptr fileptr;

x::fdObj is a reference-counted object that represents an open file descriptor. This object provides a somewhat lower-level access to file descriptor than STL's input/output library. An x::fdObj wouldn't be usually instantiated directly, but by using constructors defined in the base class of the x::fd and x::fdptr typedefs for x::fdObj.

The x::fd typedef is a x::ref to an open file descriptor object, while x::fdptr is a typedef for a reference x::ptr. Use null() to check if a x::fdptr points to a file descriptor object, or not.

When the last reference or pointer to the file descriptor object goes out of scope, and the object gets destroyed, the underlying file descriptor gets closed automatically. x::fdObj's methods, generally, throw an exception when an error occurs, instead of returning an error code. However, when x::fdObj's destructor closes the underlying file descriptor, no exceptions gets thrown if the system close() returns an error (as it can, for certain kinds of file descriptors and situations).

x::fd file;

// ...


An explicit call to close() closes the underlying file descriptor, and throws an exception if an error occured. x::fdObj still exists after close() returns, but calling its methods will throw exceptions. Use an explicit close() when it's desirable to verify that the file descriptor gets closed without any errors.

The base class of x::fd and x::fdptr defines several constructors that open new file descriptors.


All of the following constructors are equally accessed via either x::fd::base or x::fdptr::base, for convenience. They are documented with one or the other for clarity only.

Unless otherwise noted, all of these constructors create file descriptors that have their close-on-exec bit set by default:

x::fd regular_file(x::fd::base::open("filename.dat", O_CREAT|O_TRUNC|O_RDWR, 0777);

x::fd create_file_on_close(x::fd::create("filename", 0777));

x::fd duped_filedesc(x::fd::base::dup(0));

std::pair<x::fd, x::fd> pipe(x::fd::base::pipe());

std::pair<x::fd, x::fd> spipe(x::fd::base::socketpair());

x::fd temporary_file(x::fd::base::tmpfile());

x::fd temporary_file(x::fd::base::tmpfile("/var/tmp"));

x::fd sock(x::fd::base::socket(PF_UNIX, SOCK_STREAM));

std::string dirname=x::fd::base::mktempdir(0700);
std::pair<x::fd, std::string> sock(x::fd::base::tmpunixfilesock(dirname + "/sysmon."));

x::fdptr lock_file(x::fdptr::base::lockf("/var/tmp/sysmon.lock", F_TLOCK, 0777);

open() constructs a file descriptor object referring to an open file, using the traditional open(2) parameters. create() is a version of open() that always uses O_CREAT|O_TRUNC|O_RDWR, additionally the file gets actually created as filename.tmp, then renamed to filename when the file gets closed, either automatically when the last pointer or reference to the object goes out of scope and it gets destroyed, or by an explicit close().

dup() dup-es the specified raw file descriptor, and constructs a new file descriptor object, that owns the dup-ed file descriptor. An existing x::fd or x::fdptr may be given instead of a raw file descriptor, referring to another open file descriptor. This essentially clones an existing file descriptor object.

pipe() and spipe() create a regular pipe, and a socketpair pipe, respectively. tmpfile() creates a temporary file in the default, or an explicitly specified directory (which carries only an academic purpose, since, as is the tradition with temporary files, it gets immediately unlinked from the directory, immediately upon creation.

socket() creates a new socket. mktempdir() initializes a temporary subdirectory in /tmp with the specific permissions. mktempdir() tries to use, first, creating it if necessary. If this subdirectory already exists, the process's effective user and group id must match the existing subdirectory's actual ownership. Otherwise, mktempdir() creates a random subdirectory in /tmp. tmpunixfilesock() creates and binds a filesystem domain socket. The socket's name gets created randomly, with the prefix that's specified as the mandatory parameter. Note that "/" must be appended to the return value from mktempdir, so that tmpunixfilesock() gets a pathname into that directory, since tmpunixfilesock() treats its parameter as a simple prefix (it's also recommended to also prepend the application's name, too). tmpunixfilesock() returns the opened socket, and its filename. The socket's filesystem permissions are set to 0777

Combined together, mktempdir() and tmpunixfilesock() provide the means for securely installing filesystem domain sockets in /tmp using filesystem permissions to keep out interlopers, and keeping the pollution in /tmp at a minimum. In a multiuser environment, admins should keep an eye out on impersonators in /tmp. Because mktempdir() verifies any existing subdirectory's permissions, it'll then use a random subdirectory as a fallback plan, meanwhile the pretender's actual userid will identify the culprit.

The first time, though, any application creates the right subdirectory with mktempdir(), it should not remove the subdirectory itself, but rather do any housekeeping inside it. The subdirectory's persistance will keep the troublemakers away, automatically.

See x::fdObj for more information on x::fdObj's available methods, once that object gets constructed.

Other miscellaneous file-related function

x::fd::base and x::fdptr::base also define several miscellaneous file-related functions:

std::string dir=x::fd::base::cwd();

cwd() returns the process's current working directory.

std::string s=x::fd::base::realpath(".");

std::string s=x::fd::base::combinepath("subdir1", "subdir2");

realpath() expands all symbolic links, references to ., .., etc, and translates its parameter to an absolute pathname. combinepath() combines two paths together. The paths may or may not exist. combinepath>() operates on its parameters only. combinepath("/home", "me") returns /home/me, combinepath("/home/user/bin", "..") returns /home/user, and so on.