Monitoring filesystem cannot be done efficiently without support of underlying operating system. This library provides unified interface of the mechanism.
The following simple tail (1)
like script shows how it works:
(import (rnrs) (getopt) (sagittarius filewatch) (prefix (binary io) binary:))
(define (tail file offset)
(define watcher (make-filesystem-watcher))
(define in (open-file-input-port file))
;; dump contents to stdout
(define (dump)
(let loop ()
(let ((line (binary:get-line in)))
(unless (eof-object? line)
(put-bytevector (standard-output-port) line)
(put-bytevector (standard-output-port) #vu8(10))
(loop)))))
(define size (file-size-in-bytes file))
;; move port position if the size if more than offset
(when (> size offset) (set-port-position! in (- size offset)))
;; dump first
(dump)
;; add path to file watcher
(filesystem-watcher-add-path! watcher file '(modify)
(lambda (path event) (dump)))
;; monitor on foreground.
(filesystem-watcher-start-monitoring! watcher :background #f))
;; this tail is not line oriented
;; it shows tail of the file from the given offset.
(define (main args)
(with-args (cdr args)
((offset (#\o "offset") #t "1024")
. rest)
(tail (car rest) (string->number offset))))
Creates and returns filesystem watcher object.
The keyword argument error-handler is specified, which must be a procedure accepts one argument, then it is called with a condition when monitoring handler raised an error.
Releasing the watcher.
Released filesystem watcher can not be reused.
Returns #t if the given o is a filesystem watcher object, otherwise #f.
Adds monitoring targets to the watcher.
The path must be a string and indicating existing path.
The flags must be one of the following symbols or list of the symbols:
access
Checks if the path is accessed.
modify
Checks if the path is modified.
delete
Checks if the path is deleted.
move
Checks if the path is moved.
attribute
Checks if the path's attribute is changed.
NOTE: The flags might not be supported depending on the platform. See implementation limitation section for more details.
The monitoring-handler must be a procedure accepts 2 arguments. The procedure is called if the path gets an event specified flags. When the monitoring-handler is invoked, then the path and a symbol of the invoking event are passed respectively. The possible event symbols are the followings:
accessed
Checks if the path is accessed.
modified
Checks if the path is modified.
deleted
Checks if the path is deleted.
moved
Checks if the path is moved.
attribute
Checks if the path's attribute is changed.
The procedure filesystem-watcher-add-path! returns the watcher.
If the watcher started monitoring, then the procedure raises
&assertion
.
Removes given path from the watcher. And returns watcher,
If the watcher started monitoring, then the procedure raises
&assertion
.
Starts monitoring filesystem on given watcher.
If the keyword argument background is true value, then the procedure
creates a thread and let the thread monitor the filesystem. (So the procedure
returns after the thread invocation.) Otherwise, the procedure blocks and
wait until other thread calls filesystem-watcher-stop-monitoring!
.
Stops monitoring of given watcher.
If the watcher is started on background, then the monitoring thread may not stop immediately.
Even the library provides unified APIs however users still should know the limitations per operating system to avoid unexpected behaviours. The following sections describes the known limitations.
On Linux, the library is constructed on top of inotify (7)
and
poll (2)
. If users add too many paths, then it may reach the
maximum number of watch descriptor.
The IN_MOVED_FROM
and IN_MOVED_TO
flags are passed as
moved
. So it is users responsibility to detect which file is
moved from and which file is moved to.
On BSD Unix, the library is constructed on top of kqueue (2)
. This
implementation contains 3 major issues. Possibility of number of file
descriptor explosion, not access
flag support, and no support of
directory monitoring.
The kqueue
requires file descriptor per monitoring path. Thus if
the number of paths is large, then it reaches the maxinum number of file
descriptors. (NB: kern.maxfiles
on FreeBSD).
kqueue
doesn't support path access monitoring (e.g. IN_ACCESS
on inotify
). So it is impossible to monitor file access.
Current implementation of (sagittarius filewatch)
using kqueue
doesn't allow users to monitor directory. This is because by default,
kqueue
doesn't provide facility to detect which file is added.
To do it, we need manual management. To keep our code as simple as possible,
we decided not to do it for now. This decision may be changed if there's
enough demands.
On OS X, the library is constructed on top of kqueue
, thus the
same limitation as BSD Unix is applied.
Staring Windows Vista, Microsoft decided not to change timestamp just accessing
the file or directory by default. So access
flag may or may not work on
Windows depending on the configuration of the platform.
Due to the lack of deletion detect, delete
and move
work the
same. Thus the monitoring handler may get both deleted
and moved
even though it's only specified delete
or move
.