Next: , Previous: , Up: Top   [Contents][Index]


4 The C API

4.1 Overview

The C API, whose main header file is libfswatch.h, is a C-compatible lightweight wrapper around the C++ API that provides an easy to use binding to C clients. The central type in the C API is the monitoring session, an opaque type identified by a handle of type FSW_HANDLE that can be manipulated using the C functions of this library.

Session-modifying API calls (such as fsw_add_path) will take effect the next time a monitor is started with fsw_start_monitor. Currently not all monitors supports being stopped, in which case fsw_start_monitor is a non-returning API call.

4.1.1 Translating the C++ API

The conventions used to translate C++ types into C types are rather common:

4.1.2 Thread Safety

If the compiler and the C++ library used to build libfswatch support the thread_local storage specified then this API is thread safe and a different state is maintained on a per-thread basis (see Thread Safety).

Even when thread_local is not available, manipulating different monitoring sessions in different threads concurrently is thread safe, since they share no data.

4.2 Library Initialization

Before calling any library method, the library must be initialized by calling the fsw_init_library() function:

// Initialize the library
FSW_STATUS ret = fsw_init_library();

if (ret != FSW_OK)
{
  exit(1);
}

4.3 Status Codes and Errors

Most API functions return a status code of type FSW_STATUS (error.h header) which can take any value specified in the error.h header. A successful API call returns FSW_OK and the last error can be obtained calling the fsw_last_error() function. Currently, the following status codes are defined:

FSW_OK
0

The operation completed successfully.

FSW_ERR_UNKNOWN_ERROR
(1 << 0)

An error occurred.

FSW_ERR_SESSION_UNKNOWN
(1 << 1)

The session identified by the specified handle does not exist.

FSW_ERR_MONITOR_ALREADY_EXISTS
(1 << 2)

The session already contains a monitor.

FSW_ERR_MEMORY
(1 << 3)

An error occurred while using a memory management routine.

FSW_ERR_UNKNOWN_MONITOR_TYPE
(1 << 4)

The specified monitor type does not exist.

FSW_ERR_CALLBACK_NOT_SET
(1 << 5)

The callback is not set.

FSW_ERR_PATHS_NOT_SET
(1 << 6)

The paths are not set.

FSW_ERR_UNKNOWN_MONITOR
(1 << 7)

Unused.

FSW_ERR_MISSING_CONTEXT
(1 << 8)

The callback context is missing.

FSW_ERR_INVALID_PATH
(1 << 9)

The path is invalid.

FSW_ERR_INVALID_CALLBACK
(1 << 10)

The callback is invalid.

FSW_ERR_INVALID_LATENCY
(1 << 11)

The latency is invalid.

FSW_ERR_INVALID_REGEX
(1 << 12)

The regular expression is invalid.

FSW_ERR_MONITOR_ALREADY_RUNNING
(1 << 13)

A monitor is already running in the specified session.

FSW_ERR_STALE_MONITOR_THREAD
(1 << 14)

Unused.

FSW_ERR_THREAD_FAULT
(1 << 15)

Unused.

FSW_ERR_UNSUPPORTED_OPERATION
(1 << 16)

Unused.

FSW_ERR_UNKNOWN_VALUE
(1 << 17)

Unused.

FSW_ERR_INVALID_PROPERTY
(1 << 18)

The specified property is invalid.

4.4 Functions

The library libfswatch.h header file defines the functions listed in the following table. As seen in See Status Codes and Errors, functions return FSW_OK if they succeed, otherwise they return an error code. Functions that modify an existing monitoring sessions accept the session handle of type FSW_HANDLE.

FSW_STATUS
fsw_init_library()

This function initializes the libfswatch library and must be invoked before any other calls to the C or C++ API. If the function succeeds, it returns FSW_OK, otherwise the initialization routine failed and the library will not be usable.

FSW_HANDLE
fsw_init_session(const fsw_monitor_type type = system_default_monitor_type)

This function creates a new monitor session using the specified monitor and returns an handle to it. This function is the libfswatch API entry point.

FSW_STATUS
fsw_add_path(const FSW_HANDLE handle, const char * path)

Adds a path to watch to the specified session. At least one path must be added to the current session in order for it to be valid.

FSW_STATUS
fsw_add_property(const FSW_HANDLE handle, const char * name, const char * value)

This function adds a new key-value pair (name, value) in the monitor’s property map.

FSW_STATUS
fsw_set_allow_overflow(const FSW_HANDLE handle, const bool allow_overflow)

Sets the allow overflow flag to the specified value. If this flag is set, monitor buffer overflows will be reported as change events of type fsw_event_flag::Overflow.

FSW_STATUS
fsw_set_callback(const FSW_HANDLE handle, const FSW_CEVENT_CALLBACK callback, void * data)

Sets the callback the monitor invokes when some events are received (see Callbacks) and an optional pointer to context data (see Context Data). The callback must be set in the current session in order for it to be valid.

FSW_STATUS
fsw_set_latency(const FSW_HANDLE handle, const double latency);

Sets the latency of the monitor. By default, the latency is set to 1 second.

FSW_STATUS
fsw_set_recursive(const FSW_HANDLE handle, const bool recursive)

Determines whether the monitor recursively scans each watched path or not. Recursive scanning is an optional feature which could not be implemented by all the monitors. By default, recursive scanning is disabled.

FSW_STATUS
fsw_set_directory_only(const FSW_HANDLE handle, const bool directory_only)

Sets the directory only flag to the specified value. If this flag is set, then the monitor will only watch directories during a recursive scan. This functionality is only supported by monitors whose backend fires change events on a directory when one its children is changed. If a monitor backend does not support this functionality, the flag is ignored.

FSW_STATUS
fsw_set_follow_symlinks(const FSW_HANDLE handle, const bool follow_symlinks)

Determines whether a symbolic link is followed or not. By default, symbolic links are not followed.

FSW_STATUS
fsw_add_filter(const FSW_HANDLE handle,const fsw_cmonitor_filter filter)

Adds a filter to the current session. A filter (see Filters) is a regular expression that, depending on whether the filter type is exclusion or not, must or must not be matched for an event path for the event to be accepted.

FSW_STATUS
fsw_add_event_type_filter(const FSW_HANDLE handle, const fsw_event_type_filter event_type)

Adds an event type filter to the current session. A filter (see Event Type Filters) contains the name of the event type to include into the output. A session may contain multiple event type filters.

FSW_STATUS
fsw_start_monitor(const FSW_HANDLE handle)

Starts the monitor if it is properly configured. Depending on the type of monitor this call might return when a monitor is stopped or not.

FSW_STATUS
fsw_destroy_session(const FSW_HANDLE handle)

Destroys an existing session and invalidates its handle.

FSW_STATUS
fsw_last_error()

Gets the last error code.

bool
fsw_is_verbose()

Check whether the verbose mode is active.

4.5 Callbacks

When a monitor receives change events satisfying all the session criteria, a callback provided by the user is invoked and passed a copy of the events; a function pointer of type FSW_CEVENT_CALLBACK is used by the API as a callback:

typedef void (*FSW_CEVENT_CALLBACK)(
  fsw_cevent const * const events,
  const unsigned int event_num,
  void * data);

The callback is passed the following arguments:

The memory used by the fsw_cevent objects will be freed at the end of the callback invocation. A callback should copy such data instead of storing a pointer to it.

4.5.1 Context Data

A context may be passed to the callback when events are received. Context data may be useful to easily associate a ‘state’ to each monitoring session. A monitoring session does not acquire ownership of the context data pointer; therefore, the following are responsibilities of the caller:

4.6 Memory Management Functions

The C API published by the libfswatch library contains some memory management routines. These functions, defined in the libfswatch_mem.h header file, are the following:

void * fsw_alloc(size_t size)

This function allocates a chunk of memory of the specified size and returns a pointer to it. If the memory could not be allocated, nullptr is returned instead.

void fsw_free(void * ptr)

This function frees the memory pointed by ptr.

fsw_free

4.7 Events in the C API

The C API represents events as instances of the fsw_cevent structure (cevent.h) which is an exact translation of the fsw:event type (see Events) where C++ types and collections are represented by C friendly equivalent types:

typedef struct fsw_cevent
{
  char * path;
  time_t evt_time;
  fsw_event_flag * flags;
  unsigned int flags_num;
} fsw_cevent;

4.8 Event Flags

Events flags are enum values shared by both the C++ and the C API and they are defined in the cevent.h header. The values of event flags are power of 2, that is numbers f in the form f = 2^n where n is an integer. This representation makes it easy to combine flags into a bit mask and encode multiple events flags into a single integer. The fsw_event_flag enumeration currently includes the following values:

NoOp
0

This event flag is used as a marker.

PlatformSpecific
1 << 0

This event flag represents a platform-specific flag that is not encoded as any other event flag by the API.

Created
1 << 1

This event flag represents a file creation creation event.

Updated
1 << 2

This event flag represents a file update update event.

Removed
1 << 3

This event flag represents a file removal event.

Renamed
1 << 4

This event flag represents a file rename event.

OwnerModified
1 << 5

This event flag represents a file owner modification event.

AttributeModified
1 << 6

This event flag represents a file attribute modification event.

MovedFrom
1 << 7

This event flag represents a file rename event.

MovedTo
1 << 8

This event flag represents a file rename event.

IsFile
1 << 9

This event flag indicates that the modified object is a regular file.

IsDir
1 << 10

This event flag indicates that the modified object is a directory.

IsSymLink
1 << 11

This event flag indicates that the modified object is a symbolic link.

Link
1 << 12

This event flag represents a file link event.

Overflow
1 << 13

This event flag represents a monitor buffer overflow.

A monitor implementation is required to map implementation-specific flags into API flags. Sometimes, though, a perfect match is not possible and the following situation may arise:

The cevent.h header also defines the following utility functions:

fsw_event_flag fsw_get_event_flag_by_name(const char * name);

This function looks for a fsw_event_flag instace with the specified name. If a matching event type is not found, this function will return a negative number.

char * fsw_get_event_flag_name(const fsw_event_flag flag);

This function returns a char * pointer to the name of the specified event type, flag, or nullptr if an error occurs. The memory pointed by the return value of this function should be freed with a call to fsw_free (see Memory Management Functions).

4.9 Filters in the C API

The C API represents filters (see Filters) as instances of the fsw_cmonitor_filter structure, defined in the cfilter.h header. This structure is a translation of the monitor_filter class using C equivalent types:

enum fsw_filter_type
{
  filter_include,
  filter_exclude
};

typedef struct fsw_cmonitor_filter
{
  char * text;
  fsw_filter_type type;
  bool case_sensitive;
  bool extended;
} fsw_cmonitor_filter;

4.10 Monitor Types

The fsw_monitor_type enumeration, defined in the cmonitor.h header, contains a list of monitor types built into the libfswatch library:

enum fsw_monitor_type
{
  system_default_monitor_type = 0,
  fsevents_monitor_type,
  kqueue_monitor_type,
  inotify_monitor_type,
  windows_monitor_type,
  poll_monitor_type
};

Members of this enumeration may be used with factory methods (see Monitor Discovery provided by the API to request a monitor of a specific type. The members of this enumeration must be known at compile time.

4.11 Logging

The libfswatch library never writes any output to the standard streams, unless the verbose mode is set: in this mode, diagnostic information is written to standard error. The library offers a set of logging functions to ease the task of conditionally writing both literal and formatted messages to the output, when the verbose flag is set.

4.11.1 Logging functions

void fsw_log(const char * msg)

This function prints the specified message msg literally to the standard output.

void fsw_flog(FILE * f, const char * msg)

This function prints the specified message msg literally to the file f.

void fsw_logf(const char * format, ...);

This function prints and formats the specified message format to the standard output.

void fsw_flogf(FILE * f, const char * format, ...)

This function prints and formats the specified message format to the file f.

void fsw_log_perror(const char * msg)

This function prints the specified message msg using perror.

void fsw_logf_perror(const char * format, ...)

This function prints the printf-compatible message using perror.

4.11.2 Logging macros

The libfswatch library provides a set of macros that can be used to print diagnostic messages containing the name of the method where the macro is called from. The format of a message msg printed using one of these macros from inside a function called func will be similar to:

func: msg
FSW_LOG(msg)

This macro prints to standard output the name of the function this macro is called from followed by the message msg.

FSW_ELOG(msg)

This macro prints to standard error the name of the function this macro is called from followed by the message msg.

FSW_LOGF(msg, ...)

This macro prints to standard output the name of the function this macro is called from followed by the message msg, formatted using the specified arguments.

FSW_ELOGF(msg, ...)

This macro prints to standard error the name of the function this macro is called from followed by the message msg, formatted using the specified arguments.

FSW_FLOGF(f, msg, ...)

This macro prints to the specified file the name of the function this macro is called from followed by the message msg, formatted using the specified arguments.

4.12 Example

This is a basic example of how a monitor session can be constructed and run using the C API. To be valid, a session needs at least the following information:

The next code fragment shows how to create and start a basic monitoring session (error checking code was omitted):

// Initialize the library
fsw_init_library();

// Use the default monitor.
const FSW_HANDLE handle = fsw_init_session();
fsw_add_path(handle, "my/path");
fsw_set_callback(handle, my_callback);

fsw_start_monitor(handle);

Next: , Previous: , Up: Top   [Contents][Index]