zfile(3)
========

NAME
----
zfile - provides methods to work with files in a portable fashion.

SYNOPSIS
--------
----
//  Create new file item
CZMQ_EXPORT zfile_t *
    zfile_new (const char *path, const char *name);

//  Destroy a file item
CZMQ_EXPORT void
    zfile_destroy (zfile_t **self_p);

//  Duplicate a file item, returns a newly constructed item
CZMQ_EXPORT zfile_t *
    zfile_dup (zfile_t *self);

//  Return file name, remove path if provided
CZMQ_EXPORT char *
    zfile_filename (zfile_t *self, char *path);

//  Refresh file properties from disk; this is not done automatically
//  on access methods, otherwise it is not possible to compare directory
//  snapshots.
CZMQ_EXPORT void
    zfile_restat (zfile_t *self);

//  Return when the file was last modified. If you want this to reflect the
//  current situation, call zfile_restat before checking this property.
CZMQ_EXPORT time_t
    zfile_modified (zfile_t *self);

//  Return the last-known size of the file. If you want this to reflect the
//  current situation, call zfile_restat before checking this property.
CZMQ_EXPORT off_t
    zfile_cursize (zfile_t *self);

//  Return true if the file is a directory. If you want this to reflect
//  any external changes, call zfile_restat before checking this property.
CZMQ_EXPORT bool
    zfile_is_directory (zfile_t *self);

//  Return true if the file is a regular file. If you want this to reflect
//  any external changes, call zfile_restat before checking this property.
CZMQ_EXPORT bool
    zfile_is_regular (zfile_t *self);

//  Return true if the file is readable by this process. If you want this to
//  reflect any external changes, call zfile_restat before checking this
//  property.
CZMQ_EXPORT bool
    zfile_is_readable (zfile_t *self);

//  Return true if the file is writeable by this process. If you want this
//  to reflect any external changes, call zfile_restat before checking this
//  property.
CZMQ_EXPORT bool
    zfile_is_writeable (zfile_t *self);

//  Check if file has stopped changing and can be safely processed.
//  Updates the file statistics from disk at every call.
CZMQ_EXPORT bool
    zfile_is_stable (zfile_t *self);

//  Remove the file from disk
CZMQ_EXPORT void
    zfile_remove (zfile_t *self);

//  Open file for reading
//  Returns 0 if OK, -1 if not found or not accessible
CZMQ_EXPORT int
    zfile_input (zfile_t *self);

//  Open file for writing, creating directory if needed
//  File is created if necessary; chunks can be written to file at any
//  location. Returns 0 if OK, -1 if error.
CZMQ_EXPORT int
    zfile_output (zfile_t *self);

//  Read chunk from file at specified position. If this was the last chunk,
//  sets self->eof. Returns a null chunk in case of error.
CZMQ_EXPORT zchunk_t *
    zfile_read (zfile_t *self, size_t bytes, off_t offset);

//  Write chunk to file at specified position
//  Return 0 if OK, else -1
CZMQ_EXPORT int
    zfile_write (zfile_t *self, zchunk_t *chunk, off_t offset);

//  Close file, if open
CZMQ_EXPORT void
    zfile_close (zfile_t *self);

//  Return file handle, if opened
CZMQ_EXPORT FILE *
    zfile_handle (zfile_t *self);

//  Self test of this class
CZMQ_EXPORT int
    zfile_test (bool verbose);
//  These methods are deprecated, and now moved to zsys class.
CZMQ_EXPORT bool
    zfile_exists (const char *filename);
CZMQ_EXPORT ssize_t
    zfile_size   (const char *filename);
CZMQ_EXPORT mode_t
    zfile_mode   (const char *filename);
CZMQ_EXPORT int
    zfile_delete (const char *filename);
CZMQ_EXPORT bool
    zfile_stable (const char *filename);
CZMQ_EXPORT int
    zfile_mkdir  (const char *pathname);
CZMQ_EXPORT int
    zfile_rmdir  (const char *pathname);
CZMQ_EXPORT void
    zfile_mode_private (void);
CZMQ_EXPORT void
    zfile_mode_default (void);
----

DESCRIPTION
-----------

The zfile class provides methods to work with disk files. A file object
provides the modified date, current size, and type of the file. You can
create a file object for a filename that does not yet exist. To read or
write data from the file, use the input and output methods, and then
read and write chunks. The output method lets you both read and write
chunks, at any offset. Finally, this class provides portable symbolic
links. If a filename ends in ".ln", the first line of text in the file
is read, and used as the underlying file for read/write operations.
This lets you manipulate (e.g.) copy symbolic links without copying
the perhaps very large files they point to.

This class is a new API, deprecating the old zfile class (which still
exists but is implemented in zsys now).

EXAMPLE
-------
.From zfile_test method
----
    zfile_t *file = zfile_new (".", "bilbo");
    assert (streq (zfile_filename (file, "."), "bilbo"));
    assert (zfile_is_readable (file) == false);
    zfile_destroy (&file);

    //  Create a test file in some random subdirectory
    file = zfile_new ("./this/is/a/test", "bilbo");
    int rc = zfile_output (file);
    assert (rc == 0);
    zchunk_t *chunk = zchunk_new (NULL, 100);
    zchunk_fill (chunk, 0, 100);
    //  Write 100 bytes at position 1,000,000 in the file
    rc = zfile_write (file, chunk, 1000000);
    assert (rc == 0);
    zchunk_destroy (&chunk);
    zfile_close (file);
    assert (zfile_is_readable (file));
    assert (zfile_cursize (file) == 1000100);
    zfile_restat (file);
    assert (!zfile_is_stable (file));
    zclock_sleep (1001);
    assert (!zfile_is_stable (file));
    zfile_restat (file);
    assert (zfile_is_stable (file));

    //  Check we can read from file
    rc = zfile_input (file);
    assert (rc == 0);
    chunk = zfile_read (file, 1000100, 0);
    assert (chunk);
    assert (zchunk_size (chunk) == 1000100);
    zchunk_destroy (&chunk);
    zfile_close (file);

    //  Try some fun with symbolic links
    zfile_t *link = zfile_new ("./this/is/a/test", "bilbo.ln");
    rc = zfile_output (link);
    assert (rc == 0);
    fprintf (zfile_handle (link), "./this/is/a/test/bilbo\n");
    zfile_destroy (&link);

    link = zfile_new ("./this/is/a/test", "bilbo.ln");
    rc = zfile_input (link);
    assert (rc == 0);
    chunk = zfile_read (link, 1000100, 0);
    assert (chunk);
    assert (zchunk_size (chunk) == 1000100);
    zchunk_destroy (&chunk);
    zfile_destroy (&link);

    //  Remove file and directory
    zdir_t *dir = zdir_new ("./this", NULL);
    assert (zdir_cursize (dir) == 2000200);
    zdir_remove (dir, true);
    assert (zdir_cursize (dir) == 0);
    zdir_destroy (&dir);

    //  Check we can no longer read from file
    assert (zfile_is_readable (file));
    zfile_restat (file);
    assert (!zfile_is_readable (file));
    rc = zfile_input (file);
    assert (rc == -1);
    zfile_destroy (&file);
----

SEE ALSO
--------
linkczmq:czmq[7]
