Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Deleting a watched folder in Windows ALWAYS rise an [Error: watch EPERM] #4337

Closed
arboleya opened this issue Nov 30, 2012 · 16 comments
Closed

Comments

@arboleya
Copy link

Tested on Windows 7 (32bits):

fs = require 'fs'

fs.mkdirSync 'test', '0755'

watcher = fs.watch 'test', ->
    unless fs.existsSync 'test'
        console.log 'folder deleted'
        watcher.close() 

watcher.on 'error', (err)->
    console.log err

fs.rmdirSync 'test'

Output:

{ [Error: watch EPERM] code: 'EPERM', errno: 'EPERM', syscall: 'watch' }
@arboleya
Copy link
Author

Good to mention that the same doesn't happen with File, the code bellow works just fine.

fs = require 'fs'

fs.writeFileSync 'test', 'just a test', 'utf-8'

watcher = fs.watch 'test', ->
    unless fs.existsSync 'test'
        console.log 'file deleted'
        watcher.close() 

watcher.on 'error', (args)->
    console.log args

fs.unlinkSync 'test' # outputs `file deleted`

@piscisaureus
Copy link

@arboleya Yes, that's because watching a folder watches the folder's contents and not the directory entry itself. EPERM may be a little unexpected, but what did you expect to happen?

@dougwilson
Copy link
Member

The same case does not throw an error in Linux, but it is probably because the underlying systems are different, in that deleting the folder on Linux (at least Ubuntu) does not actually delete the file descriptor node has on it, so as far as the node watch is concerned, the folder still exists and continues to watch as normal (thus no error is thrown).

@arboleya
Copy link
Author

arboleya commented Dec 4, 2012

Well, the behavior of not having an error while deleting a watched folder will be nice. :) I expect at least an usual change event instead of an error.

I understand the differences between platforms and also the necessary effort to make things works in an transparent way, I'm just trying to show that in Windows (poor users) the fs.watch behaviors strangely. I'm OSX user myself, and I'm going to test all of this in Linux soon (building a vm right now).

But I'm writing a little package that needs to keep track of new files and folders, modified files and folders, and deleted files and folders. Everything is going well under Osx and Linux, but in Windows things are different.

I'm trying some tweaks right now to make it work transparently, but the only solution by now is to not use fs.watch on Windows, so I made a little alternative class that keep checking for stats of files / dirs instead and tells me when something had change. I'm still working on it but I'll paste the code here to give an idea.

class Win32Watcher

    prev: null
    curr: null
    interval: null

    constructor:( @location, @listener, @interval = 30 )->
        @curr = fs.statSync @location
        @interval_id = setInterval @check, @interval

    check:=>
        unless fs.existsSync @location
            @close()
            @listener()
            return

        @prev = @curr
        @curr = fs.statSync @location

        @listener() if (@curr.mtime > @prev.mtime)

    close:->
        clearInterval @interval_id

# win32 comes to say `HI`
if os.platform() is 'win32'
    @_ref = new Win32Watcher location, onchange
else
    options = persistent: true
    @_ref = fs.watch location, options, onchange

I told that everything was working fine with files, but I found another issue. If I delete the parent folder of a file I'm watching the same EPERM error rises again:

fs = require 'fs'
{exec} = require 'child_process'

fs.mkdirSync 'a'
fs.writeFile 'a/file', '1', 'utf-8', ->
  watcher = fs.watch 'a/file', ->
      unless fs.existsSync 'a/file'
        console.log 'file deleted'
  watcher.on 'error', (err)->
    console.log err
  exec 'rm -rf a'

Output:

file deleted
{ [Error: watch EPERM] code: 'EPERM', errno: 'EPERM', syscall: 'watch' }

@hems
Copy link

hems commented Dec 5, 2012

@arboleya that'll for sure guarantee your space in heaven

@vicary
Copy link

vicary commented Dec 6, 2012

Is node aimed to be platform independent?

@piscisaureus
Copy link

Yes, it would be nice to fix this. However node relies on the underlying operating system to notify it when another application changes a file; that means that node can be "platform-independent" insofar the underlying operating system can behave as node expects. The fs.watch case is particularly problematic because all operating systems have their own peculiarities that we can sometimes work around, and sometimes we can't. (you may have noticed that fs.watch isn't perfect on mac os x either, although in 0.10 we do a better job at working around its problems).

In this particular case the problem is that unices have the concept of "inodes", so a directory isn't actually deleted until all programs have "forgotten" about it. On windows this is not the case; if you delete a file/directory the entry actually remains until all programs have forgotten about it; but no further actions are possible until it actually has been deleted. This causes many problems (e.g. sometimes you can't delete a directory after you've deleted all files in it, because some programs may still have one of these deleted files open). It also means that the file watcher cannot continue watching a directory when it has been deleted. We could hide this EPERM error from you and just silently stop the watcher, but I'm not sure that's the right thing to do. (btw, did you notice that after instating a watcher on a directory, you can no longer rename the folder's parent? Another piece of windows weirdness.)

So, @arboleya, for the time being I would suggest you just add an error handler to your directory watchers on windows, and when an error happens just ignore it.

@vicrry I'm sorry if I misunderstood you, but your comment comes about somewhat tendentious. It doesn't really help to suggest we are just being lazy. Besides, this is an open source project: if you have a patch in mind that would improve the situation, why share your ideas?

@vicary
Copy link

vicary commented Dec 6, 2012

@piscisaureus Don't get me wrong, I am just want to clarify things a bit. I've seen issues are left open just because the solution is 'ugly' (so he said). If node is sticking to the underlying things, and are meant to let their dependencies solve this on their own, a patch won't help in any ways and not likely to be accepted.

Not gonna spread negative feelings here, just want to know how you guys think on this kind of not-my-fault issues.

@bnoordhuis
Copy link
Member

just want to know how you guys think on this kind of not-my-fault issues

Those come in two flavors: 'can be worked around' and 'fact of life'. This issue is of the second variety.

I've seen issues are left open just because the solution is 'ugly'

Usually, that means we suspect that the fix is worse than the bug, e.g. bad performance, making failure cases more obscure, etc.

@arboleya
Copy link
Author

arboleya commented Dec 6, 2012

@bnoordhuis Hi, by 'fact of life' you mean 'won't be done because it's impossible to fix without losing performance and this is a master key for implementing it' or 'the time needed to implement this gracefully is considerable and there are other priorities ahead of this'?

As @vicrry said, I'm afraid that even if I could find the time to get my hands into the core in an attempt to workaround this, the patch may be useless according the project standards?

I'm not sure of whats is best, the lack of functionality or the presence of it with a cost of a little performance loss. Can you elaborate your point of view a little more?

(I'll ignore the erros for now event though it sounds weird as well)

@bnoordhuis
Copy link
Member

by 'fact of life' you mean 'won't be done because it's impossible to fix without losing performance and this is a master key for implementing it' or 'the time needed to implement this gracefully is considerable and there are other priorities ahead of this'?

Neither. Node has to work with what the operating system gives it. Sometimes we can paper over platform differences but this area, file notifications, is not one of them; the differences are too fundamental.

@vicary
Copy link

vicary commented Dec 7, 2012

@bnoordhuis clarified the problem a bit, thanks.

This implies some kind of shim in user space for a fully portable code, coz I think this possibly be left open until Windows change its way over this (forever? IDK LOL).

@bnoordhuis
Copy link
Member

You could opt to use fs.watchFile() instead, which behaves mostly the same across platforms. It's not nearly as efficient as fs.watch() but if you're watching a small file set, it's okay.

@sblom
Copy link

sblom commented Jan 23, 2013

As @bnoordhuis and @piscisaureus point out, this is a Windows rough edge that's with us to stay for now.

@sblom sblom closed this as completed Jan 23, 2013
@Mithgol
Copy link

Mithgol commented Jan 24, 2013

If an error is sometimes hard to catch and if a silent death of the watcher is not an option, then maybe that watcher could die while emitting its last and special event with some flag indicating that not only the watched object is “changed”, but its parent is erased.

@Subash
Copy link

Subash commented Sep 3, 2013

This issue is still present in the latest versions of node.

richardlau pushed a commit to ibmruntimes/node that referenced this issue Feb 29, 2016
* buffer:
  - You can now supply an encoding argument when filling a
    Buffer Buffer#fill(string[, start[, end]][, encoding]), supplying
    an existing Buffer will also work with
    Buffer#fill(buffer[, start[, end]]). See the API documentation for
    details on how this works. (Trevor Norris) nodejs#4935
  - Buffer#indexOf() no longer requires a byteOffset argument if you
    also wish to specify an encoding:
    Buffer#indexOf(val[, byteOffset][, encoding]).
    (Trevor Norris) nodejs#4803
* child_process: spawn() and spawnSync() now support a 'shell' option
  to allow for optional execution of the given command inside a shell.
  If set to true, cmd.exe will be used on Windows and /bin/sh
  elsewhere. A path to a custom shell can also be passed to override
  these defaults. On Windows, this option allows .bat. and .cmd files
  to be executed with spawn() and spawnSync(). (Colin Ihrig) nodejs#4598
* http_parser: Update to http-parser 2.6.2 to fix an unintentionally
  strict limitation of allowable header characters.
  (James M Snell) nodejs#5237
* dgram: socket.send() now supports accepts an array of Buffers or
  Strings as the first argument. See the API docs for details on how
  this works. (Matteo Collina) nodejs#4374
* http: Fix a bug where handling headers will mistakenly trigger an
  'upgrade' event where the server is just advertising its protocols.
  This bug can prevent HTTP clients from communicating with HTTP/2
  enabled servers. (Fedor Indutny) nodejs#4337
* net: Added a listening Boolean property to net and http servers to
  indicate whether the server is listening for connections.
  (José Moreira) nodejs#4743
* node: The C++ node::MakeCallback() API is now reentrant and calling
  it from inside another MakeCallback() call no longer causes the
  nextTick queue or Promises microtask queue to be processed out of
  order. (Trevor Norris) nodejs#4507
* tls: Add a new tlsSocket.getProtocol() method to get the negotiated
  TLS protocol version of the current connection. (Brian White) nodejs#4995
* vm: Introduce new 'produceCachedData' and 'cachedData' options to
  new vm.Script() to interact with V8's code cache. When a new
  vm.Script object is created with the 'produceCachedData' set to true
  a Buffer with V8's code cache data will be produced and stored in
  cachedData property of the returned object. This data in turn may be
  supplied back to another vm.Script() object with a 'cachedData'
  option if the supplied source is the same. Successfully executing a
  script from cached data can speed up instantiation time. See the API
  docs for details. (Fedor Indutny) nodejs#4777
* performance: Improvements in:
  - process.nextTick() (Ruben Bridgewater) nodejs#5092
  - path module (Brian White) nodejs#5123
  - querystring module (Brian White) nodejs#5012
  - streams module when processing small chunks (Matteo Collina) nodejs#4354

PR-URL: nodejs/node#5295
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants