Blame docs/src/guide/filesystem.rst

Packit b5b901
Filesystem
Packit b5b901
==========
Packit b5b901
Packit b5b901
Simple filesystem read/write is achieved using the ``uv_fs_*`` functions and the
Packit b5b901
``uv_fs_t`` struct.
Packit b5b901
Packit b5b901
.. note::
Packit b5b901
Packit b5b901
    The libuv filesystem operations are different from :doc:`socket operations
Packit b5b901
    <networking>`. Socket operations use the non-blocking operations provided
Packit b5b901
    by the operating system. Filesystem operations use blocking functions
Packit b5b901
    internally, but invoke these functions in a `thread pool`_ and notify
Packit b5b901
    watchers registered with the event loop when application interaction is
Packit b5b901
    required.
Packit b5b901
Packit b5b901
.. _thread pool: http://docs.libuv.org/en/v1.x/threadpool.html#thread-pool-work-scheduling
Packit b5b901
Packit b5b901
All filesystem functions have two forms - *synchronous* and *asynchronous*.
Packit b5b901
Packit b5b901
The *synchronous* forms automatically get called (and **block**) if the
Packit b5b901
callback is null. The return value of functions is a :ref:`libuv error code
Packit b5b901
<libuv-error-handling>`. This is usually only useful for synchronous calls.
Packit b5b901
The *asynchronous* form is called when a callback is passed and the return
Packit b5b901
value is 0.
Packit b5b901
Packit b5b901
Reading/Writing files
Packit b5b901
---------------------
Packit b5b901
Packit b5b901
A file descriptor is obtained using
Packit b5b901
Packit b5b901
.. code-block:: c
Packit b5b901
Packit b5b901
    int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb)
Packit b5b901
Packit b5b901
``flags`` and ``mode`` are standard
Packit b5b901
`Unix flags <http://man7.org/linux/man-pages/man2/open.2.html>`_.
Packit b5b901
libuv takes care of converting to the appropriate Windows flags.
Packit b5b901
Packit b5b901
File descriptors are closed using
Packit b5b901
Packit b5b901
.. code-block:: c
Packit b5b901
Packit b5b901
    int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
Packit b5b901
Packit b5b901
Packit b5b901
Filesystem operation callbacks have the signature:
Packit b5b901
Packit b5b901
.. code-block:: c
Packit b5b901
Packit b5b901
    void callback(uv_fs_t* req);
Packit b5b901
Packit b5b901
Let's see a simple implementation of ``cat``. We start with registering
Packit b5b901
a callback for when the file is opened:
Packit b5b901
Packit b5b901
.. rubric:: uvcat/main.c - opening a file
Packit b5b901
.. literalinclude:: ../../code/uvcat/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 41-53
Packit b5b901
    :emphasize-lines: 4, 6-7
Packit b5b901
Packit b5b901
The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the
Packit b5b901
``uv_fs_open`` callback. If the file is successfully opened, we start reading it.
Packit b5b901
Packit b5b901
.. rubric:: uvcat/main.c - read callback
Packit b5b901
.. literalinclude:: ../../code/uvcat/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 26-40
Packit b5b901
    :emphasize-lines: 2,8,12
Packit b5b901
Packit b5b901
In the case of a read call, you should pass an *initialized* buffer which will
Packit b5b901
be filled with data before the read callback is triggered. The ``uv_fs_*``
Packit b5b901
operations map almost directly to certain POSIX functions, so EOF is indicated
Packit b5b901
in this case by ``result`` being 0. In the case of streams or pipes, the
Packit b5b901
``UV_EOF`` constant would have been passed as a status instead.
Packit b5b901
Packit b5b901
Here you see a common pattern when writing asynchronous programs. The
Packit b5b901
``uv_fs_close()`` call is performed synchronously. *Usually tasks which are
Packit b5b901
one-off, or are done as part of the startup or shutdown stage are performed
Packit b5b901
synchronously, since we are interested in fast I/O when the program is going
Packit b5b901
about its primary task and dealing with multiple I/O sources*. For solo tasks
Packit b5b901
the performance difference usually is negligible and may lead to simpler code.
Packit b5b901
Packit b5b901
Filesystem writing is similarly simple using ``uv_fs_write()``.  *Your callback
Packit b5b901
will be triggered after the write is complete*.  In our case the callback
Packit b5b901
simply drives the next read. Thus read and write proceed in lockstep via
Packit b5b901
callbacks.
Packit b5b901
Packit b5b901
.. rubric:: uvcat/main.c - write callback
Packit b5b901
.. literalinclude:: ../../code/uvcat/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 16-24
Packit b5b901
    :emphasize-lines: 6
Packit b5b901
Packit b5b901
.. warning::
Packit b5b901
Packit b5b901
    Due to the way filesystems and disk drives are configured for performance,
Packit b5b901
    a write that 'succeeds' may not be committed to disk yet.
Packit b5b901
Packit b5b901
We set the dominos rolling in ``main()``:
Packit b5b901
Packit b5b901
.. rubric:: uvcat/main.c
Packit b5b901
.. literalinclude:: ../../code/uvcat/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 55-
Packit b5b901
    :emphasize-lines: 2
Packit b5b901
Packit b5b901
.. warning::
Packit b5b901
Packit b5b901
    The ``uv_fs_req_cleanup()`` function must always be called on filesystem
Packit b5b901
    requests to free internal memory allocations in libuv.
Packit b5b901
Packit b5b901
Filesystem operations
Packit b5b901
---------------------
Packit b5b901
Packit b5b901
All the standard filesystem operations like ``unlink``, ``rmdir``, ``stat`` are
Packit b5b901
supported asynchronously and have intuitive argument order. They follow the
Packit b5b901
same patterns as the read/write/open calls, returning the result in the
Packit b5b901
``uv_fs_t.result`` field. The full list:
Packit b5b901
Packit b5b901
.. rubric:: Filesystem operations
Packit Service e08953
.. code-block:: c
Packit Service e08953
Packit Service e08953
    int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent);
Packit Service e08953
    int uv_fs_opendir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, uv_dir_t* dir, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_closedir(uv_loop_t* loop, uv_fs_t* req, uv_dir_t* dir, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb);
Packit Service e08953
    int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb);
Packit Service e08953
Packit b5b901
Packit b5b901
.. _buffers-and-streams:
Packit b5b901
Packit b5b901
Buffers and Streams
Packit b5b901
-------------------
Packit b5b901
Packit b5b901
The basic I/O handle in libuv is the stream (``uv_stream_t``). TCP sockets, UDP
Packit b5b901
sockets, and pipes for file I/O and IPC are all treated as stream subclasses.
Packit b5b901
Packit b5b901
Streams are initialized using custom functions for each subclass, then operated
Packit b5b901
upon using
Packit b5b901
Packit b5b901
.. code-block:: c
Packit b5b901
Packit b5b901
    int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb);
Packit b5b901
    int uv_read_stop(uv_stream_t*);
Packit b5b901
    int uv_write(uv_write_t* req, uv_stream_t* handle,
Packit b5b901
                 const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
Packit b5b901
Packit b5b901
The stream based functions are simpler to use than the filesystem ones and
Packit b5b901
libuv will automatically keep reading from a stream when ``uv_read_start()`` is
Packit b5b901
called once, until ``uv_read_stop()`` is called.
Packit b5b901
Packit b5b901
The discrete unit of data is the buffer -- ``uv_buf_t``. This is simply
Packit b5b901
a collection of a pointer to bytes (``uv_buf_t.base``) and the length
Packit b5b901
(``uv_buf_t.len``). The ``uv_buf_t`` is lightweight and passed around by value.
Packit b5b901
What does require management is the actual bytes, which have to be allocated
Packit b5b901
and freed by the application.
Packit b5b901
Packit b5b901
.. ERROR::
Packit b5b901
Packit b5b901
    THIS PROGRAM DOES NOT ALWAYS WORK, NEED SOMETHING BETTER**
Packit b5b901
Packit b5b901
To demonstrate streams we will need to use ``uv_pipe_t``. This allows streaming
Packit b5b901
local files [#]_. Here is a simple tee utility using libuv.  Doing all operations
Packit b5b901
asynchronously shows the power of evented I/O. The two writes won't block each
Packit b5b901
other, but we have to be careful to copy over the buffer data to ensure we don't
Packit b5b901
free a buffer until it has been written.
Packit b5b901
Packit b5b901
The program is to be executed as::
Packit b5b901
Packit b5b901
    ./uvtee <output_file>
Packit b5b901
Packit b5b901
We start off opening pipes on the files we require. libuv pipes to a file are
Packit b5b901
opened as bidirectional by default.
Packit b5b901
Packit b5b901
.. rubric:: uvtee/main.c - read on pipes
Packit b5b901
.. literalinclude:: ../../code/uvtee/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 61-80
Packit b5b901
    :emphasize-lines: 4,5,15
Packit b5b901
Packit b5b901
The third argument of ``uv_pipe_init()`` should be set to 1 for IPC using named
Packit b5b901
pipes. This is covered in :doc:`processes`. The ``uv_pipe_open()`` call
Packit b5b901
associates the pipe with the file descriptor, in this case ``0`` (standard
Packit b5b901
input).
Packit b5b901
Packit b5b901
We start monitoring ``stdin``. The ``alloc_buffer`` callback is invoked as new
Packit b5b901
buffers are required to hold incoming data. ``read_stdin`` will be called with
Packit b5b901
these buffers.
Packit b5b901
Packit b5b901
.. rubric:: uvtee/main.c - reading buffers
Packit b5b901
.. literalinclude:: ../../code/uvtee/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 19-22,44-60
Packit b5b901
Packit b5b901
The standard ``malloc`` is sufficient here, but you can use any memory allocation
Packit b5b901
scheme. For example, node.js uses its own slab allocator which associates
Packit b5b901
buffers with V8 objects.
Packit b5b901
Packit b5b901
The read callback ``nread`` parameter is less than 0 on any error. This error
Packit b5b901
might be EOF, in which case we close all the streams, using the generic close
Packit b5b901
function ``uv_close()`` which deals with the handle based on its internal type.
Packit b5b901
Otherwise ``nread`` is a non-negative number and we can attempt to write that
Packit b5b901
many bytes to the output streams. Finally remember that buffer allocation and
Packit b5b901
deallocation is application responsibility, so we free the data.
Packit b5b901
Packit b5b901
The allocation callback may return a buffer with length zero if it fails to
Packit b5b901
allocate memory. In this case, the read callback is invoked with error
Packit b5b901
UV_ENOBUFS. libuv will continue to attempt to read the stream though, so you
Packit b5b901
must explicitly call ``uv_close()`` if you want to stop when allocation fails.
Packit b5b901
Packit b5b901
The read callback may be called with ``nread = 0``, indicating that at this
Packit b5b901
point there is nothing to be read. Most applications will just ignore this.
Packit b5b901
Packit b5b901
.. rubric:: uvtee/main.c - Write to pipe
Packit b5b901
.. literalinclude:: ../../code/uvtee/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 9-13,23-42
Packit b5b901
Packit b5b901
``write_data()`` makes a copy of the buffer obtained from read. This buffer
Packit b5b901
does not get passed through to the write callback trigged on write completion. To
Packit b5b901
get around this we wrap a write request and a buffer in ``write_req_t`` and
Packit b5b901
unwrap it in the callbacks. We make a copy so we can free the two buffers from
Packit b5b901
the two calls to ``write_data`` independently of each other. While acceptable
Packit b5b901
for a demo program like this, you'll probably want smarter memory management,
Packit b5b901
like reference counted buffers or a pool of buffers in any major application.
Packit b5b901
Packit b5b901
.. WARNING::
Packit b5b901
Packit b5b901
    If your program is meant to be used with other programs it may knowingly or
Packit b5b901
    unknowingly be writing to a pipe. This makes it susceptible to `aborting on
Packit b5b901
    receiving a SIGPIPE`_. It is a good idea to insert::
Packit b5b901
Packit b5b901
        signal(SIGPIPE, SIG_IGN)
Packit b5b901
Packit b5b901
    in the initialization stages of your application.
Packit b5b901
Packit b5b901
.. _aborting on receiving a SIGPIPE: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_SIGPIPE
Packit b5b901
Packit b5b901
File change events
Packit b5b901
------------------
Packit b5b901
Packit b5b901
All modern operating systems provide APIs to put watches on individual files or
Packit b5b901
directories and be informed when the files are modified. libuv wraps common
Packit b5b901
file change notification libraries [#fsnotify]_. This is one of the more
Packit b5b901
inconsistent parts of libuv. File change notification systems are themselves
Packit b5b901
extremely varied across platforms so getting everything working everywhere is
Packit b5b901
difficult. To demonstrate, I'm going to build a simple utility which runs
Packit b5b901
a command whenever any of the watched files change::
Packit b5b901
Packit b5b901
    ./onchange <command> <file1> [file2] ...
Packit b5b901
Packit b5b901
The file change notification is started using ``uv_fs_event_init()``:
Packit b5b901
Packit b5b901
.. rubric:: onchange/main.c - The setup
Packit b5b901
.. literalinclude:: ../../code/onchange/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 26-
Packit b5b901
    :emphasize-lines: 15
Packit b5b901
Packit b5b901
The third argument is the actual file or directory to monitor. The last
Packit b5b901
argument, ``flags``, can be:
Packit b5b901
Packit Service e08953
.. code-block:: c
Packit Service e08953
Packit Service e08953
    /*
Packit Service e08953
    * Flags to be passed to uv_fs_event_start().
Packit Service e08953
    */
Packit Service e08953
    enum uv_fs_event_flags {
Packit Service e08953
        UV_FS_EVENT_WATCH_ENTRY = 1,
Packit Service e08953
        UV_FS_EVENT_STAT = 2,
Packit Service e08953
        UV_FS_EVENT_RECURSIVE = 4
Packit Service e08953
    };
Packit b5b901
Packit b5b901
``UV_FS_EVENT_WATCH_ENTRY`` and ``UV_FS_EVENT_STAT`` don't do anything (yet).
Packit b5b901
``UV_FS_EVENT_RECURSIVE`` will start watching subdirectories as well on
Packit b5b901
supported platforms.
Packit b5b901
Packit b5b901
The callback will receive the following arguments:
Packit b5b901
Packit b5b901
  #. ``uv_fs_event_t *handle`` - The handle. The ``path`` field of the handle
Packit b5b901
     is the file on which the watch was set.
Packit b5b901
  #. ``const char *filename`` - If a directory is being monitored, this is the
Packit b5b901
     file which was changed. Only non-``null`` on Linux and Windows. May be ``null``
Packit b5b901
     even on those platforms.
Packit b5b901
  #. ``int flags`` - one of ``UV_RENAME`` or ``UV_CHANGE``, or a bitwise OR of
Packit b5b901
       both.
Packit b5b901
  #. ``int status`` - Currently 0.
Packit b5b901
Packit b5b901
In our example we simply print the arguments and run the command using
Packit b5b901
``system()``.
Packit b5b901
Packit b5b901
.. rubric:: onchange/main.c - file change notification callback
Packit b5b901
.. literalinclude:: ../../code/onchange/main.c
Packit b5b901
    :linenos:
Packit b5b901
    :lines: 9-24
Packit b5b901
Packit b5b901
----
Packit b5b901
Packit b5b901
.. [#fsnotify] inotify on Linux, FSEvents on Darwin, kqueue on BSDs,
Packit b5b901
               ReadDirectoryChangesW on Windows, event ports on Solaris, unsupported on Cygwin
Packit b5b901
.. [#] see :ref:`pipes`