Java WatchService not generating events while watching mapped drives
Asked Answered
C

5

33

I implemented a file watcher but I noticed that java nio file watcher doesn't generate events for files being copied on mapped drives. For instance, I've run the file watcher on Unix to watch a local directory (/sharedfolder) which is mapped on windows (H:\), and then I've put a file in this directory (H:\) but the file watcher hasn't generated any event. Now if I run the file watcher on windows to watcher the mapped drive (H:\) which refers to a unix path (/sharedfolder) and from unix I put a file in this folder, the file watcher identifies the change and generates an event. It looks like a bug, or may be I'm missing some thing, any thoughts?

Cylinder answered 12/12, 2011 at 15:11 Comment(0)
T
30

I have the same issue trying to watch a mounted windows share via CIFS. It seems not possible to get filesystem events for CIFS mounts.

The linux implementation of the Java 7 NIO FileWatcher uses inotify. Inotify is a linux kernel subsystem to notice filesystem changes which works perfect for local directories, but apparently not for CIFS mounts.

At Oracle, it doesn't seem to be high priority to fix this bug. (Is it their responsibility? More of an OS issue...)

JNotify also uses inotify on linux systems, so this is no option either.

So mapped drives monitoring unfortunately seems to be limited to pollers:

  • Apache VFS DefaultFileMonitor to poll directories (mounted share)
  • File Poller based on the standard Java API.
  • Custom File Poller with jCIFS (so the share doesn't need to be mounted on the host)

I'll probably try the Apache VFS Monitor, because it detects file creation, updates and deletes out of the box. It requires to mount the share, but that gives the OS the responsibility of CIFS connections and not my application.

Translocation answered 19/9, 2012 at 12:18 Comment(0)
G
4

File watching functionality in JDK is platform dependent as it uses native libraries so it could behave differently on different platform. I'm surprised it works for network drives at all - Windows must be polling network mapped drives for changes while Linux doesn't (rightfully so I should say).

Usually this sort of monitoring implemented in OS kernel, which obviously has knowledge which files are modified/created/etc locally but there are no easy ways for OS to know what happening on network drive as it doesn't have exclusive control over it.

Gisborne answered 12/12, 2011 at 15:33 Comment(2)
Yeah, but the directory I'm watching is on the same machine on which I'm running my watcher. So either the transfer is made through the network or on the local machine, the os should be aware of that, otherwise how the transfer could be done. It makes sense that windows is polling the mapped drive, but I don't understand how Unix could not be aware of changes made through the network on local folder.Cylinder
@Ramcis: On Linux network shares are mounted via NFS and NFS is by design a state-less protocol. Therefore the server does not know at all how many clients are accessing what file. The design has some advantages (e.g. less overhead) and some drawbacks...Elsi
Q
3

I had the same problem. I have solved it by creating a new thread in de main class and touching the files periodically so a new change event gets fired.

The sample polls the dir for every 10 seconds does a touch.

package com.ardevco.files;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.List;

public class Touch implements Runnable {

    private Path touchPath;

    public Touch(Path touchPath) {
        this.touchPath = touchPath;
        this.checkPath = checkPath;

    }

    public static void touch(Path file) throws IOException {
        long timestamp = System.currentTimeMillis();
        touch(file, timestamp);
    }

    public static void touch(Path file, long timestamp) throws IOException {
        if (Files.exists(file)) {
            FileTime ft = FileTime.fromMillis(timestamp);
            Files.setLastModifiedTime(file, ft);
        }
    }

    List<Path> listFiles(Path path) throws IOException {
        final List<Path> files = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
            for (Path entry : stream) {
                if (Files.isDirectory(entry)) {
                    files.addAll(listFiles(entry));
                }
                files.add(entry);
            }
        }
        return files;
    }

    @Override
    public void run() {
        while (true) {
            try {
                for (Path path : listFiles(touchPath)) {
                    touch(path);
                }
            } catch (IOException e) {
                System.out.println("Exception: " + e);
            }

            try {
                Thread.sleep(10000L);
            } catch (InterruptedException e) {
                System.out.println("Exception: " + e);
            }
        }

    }

}
Quirites answered 1/5, 2015 at 10:24 Comment(0)
I
1

I had similar issues with a Python script watching content of a log file on a remote windows directory.

Here is my answer.

When mapping the remote drive from the Unix, in the /etc/fstab use //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

You can use a credentials file to avoid having the password in plain text.

The command could change depending on the unix version, this was tested under debian. It should work as intended. Can you tell me if it works ? I plan on Implementing the same stuff in Java so the answer might be useful to me as well.

Ingrate answered 19/9, 2012 at 10:29 Comment(1)
This no longer works btw. I think it used to work in a somewhat flaky manner (in ubuntu anyway), but after a recent update it stopped working altogether. I added an answer to describe my awful work-around.Kitti
K
1

I too ran into this and reached the same conclusion as everyone else here (CIFS + inotify = no go).

However, since my workflow happened to depend on both remote mounts and auto-compile tools that rely on inotify, I ended up building a (fairly desperate & hacky) solution which basically just uses polling to watch for changes and then touches the same files again on the mounted side, which does seem to fire off inotify events. It is not my proudest moment.

Having said that, it does work, so, enjoy: http://github.com/rubyruy/watchntouch

Kitti answered 5/5, 2013 at 3:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.