Best way to do file change notification on a directory

Hi there,

My problem is this - I need some sort of notification when a file in a given directory is changed, deleted or created. This file can be in a subdirectory, to any arbitrary depth. e.g., if I want to watch /tmp/my_files then if a file /tmp/my_files/level1/new.txt is written, I want some sort of notification. From my research so far, I see that if I was using Linux, inotify would be the way to go. Any ideas on what would work for QNX?

So far, my ideas are:

  • a resource manager. The problem here is, if I attach to an existing directory in the filesystem, the directory is replaced by the new device and the files there are hidden. Is there anyway to note the write calls then “pass through” to the fileystem?

  • ionotify. This seems to be only possible a file by file basis, if I read correctly. Then I would need to keep scanning the directory to add new files, which seems messy. Maybe there is a better way of using this?

  • shell script that runs find periodically to check for timestamp changes. I actually have this working, but it was only really to be used as a prototyping tool, this is far too unwieldy to use.

I would appreciate any suggestions!

Thanks.

Yes this will work. Unfortunately you will have to intercept all calls and implement them as filesystem calls.

Thanks for the reply. If I could do that, it would be ideal. Though when you say “implement them as filesystem calls” I haven’t really got much of an idea where to start with that, can you give me a pointer or two as to how I would go about this? If I am attached to “/tmp/my_files” how I can differentiate between the device of that name, and the filesystem location of that name?

Does that question make sense, or am I getting confused and missing something?

By “implement them as filesystem calls” maschoen meant that your resource manager must “trap” all operations; open, read, write, stats, etc. Then you must “route” them to the proper resource manager.

This will have a significant impact on performance. QNX’s own package manager was build on this concept. It was killed for performance reason ( so I assume ).

I would write a resource manager that you would register to to request files/directory to be monitored. For example that resource manager would mount itself under /dev/fmonitor and if you want to request notification for change the client code could do something like:

f = open ( “/dev/fmonitor/usr/lib”, O_RDONLY );
ionotify ( f, …)

You resource manager would then notice that /usr/lib is a directory and start scanning for changes at a fix rate. When a change is detected , the notification is delivered to the client. Scanning for changes mainly starting from a top level directory such as /usr can use quite a bit of system resources and in my opinion that sucks, but I don’t see any other way.

In the QNX4 days I suggested that such a feature be added in the file system (Fsys) but I was told that was a useless feature and that one just have to poll… I hate the word poll… Imagine if you have to do it over a network, what a waste of resources.

Another solution I’ve use in the past, because polling was not an option, was to include notification at the application level. Of course that means all programs involved needed to have that notification feature added in. That wouldn’t work if you want to watch for new files coming from says ftp or deleted via a command line.

Thanks for the reply Mario. The directory to be monitored won’t need to change once it is set, so in this case it doesn’t even have to be a resource manager at all, which brings me back to my second idea in my original post. I guess this method isn’t looking so messy now I know what is involved in the resource manager solution ;-)

The place to start looking is the documentation for resource managers. Rob Kryten’s QNX 6 book also goes over this. Here’s a shortend picture. When you interact with a file or device you use the system calls: open, close, read, write, and maybe seek and ioctl. A resource manager is a magic program that grabs a piece of the file system tree (called a name space) like / or /dev or /myfiles or anything else you want. Once grabbed, those system calls above get translated into QNX messages to the resource manager. The resource manager then has a routine to implement each one of these calls. There’s a lot more involved, for example there are at least three different types of control blocks you need to deal with in the resource manager. So a typical resource manager has the flow, receive a message, figure out what type of message (open, close, etc.) and implement it. The implementation can be very simple/complex and even useless. The one example source that QNX provides is a /dev/null device, almost completely useless.

So what actually happens? Usually when you read a file you open it and read and/or write to it. Instead of opening the actual file, you open something else that is implemented by your resource manager. But your resource manager in its implementation of open() calls open for the real file. Its implementation for read() calls the real read. So you are just passing the calls along which is where the extra overhead comes in. The performance problem will only be a problem for you if you are expecting very high performance from the accesses.

Now I’ve completely glossed over two issues. First, I think you need to also implement a directory structure layer. The complication here is that you will have to implement more system calls, and put in addition features to others. Implementing a full blown hierarchical structure that mimics the QNX file system would be a real pain, but I think you only need one layer. That is one directory with only files only underneath.

The question you ask about differentiating is a subtle one. What if the actual files are /mydir/files###, and you want to open them with their actual name. You take over “/mydir” from the QNX file system, that’s no problem. But what happens when you want to open the actual file? Won’t the resource manager end up sending messages to itself in an endless loop? QNX anticipated this. More than one resource manager can take over the same “name space”. In fact there is a list and you can choose where in the list to be placed. When you do the open() call from your resource manager, you get the next resource manager down the list.

Of course if you are willing to have the application name for the file be different, then there is no problem at all.

Thanks for the very comprehensive reply, maschoen. I will go away and have a think about this!