-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Deleting a watched
folder in Windows ALWAYS rise an [Error: watch EPERM]
#4337
Comments
Good to mention that the same doesn't happen with 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` |
@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? |
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). |
Well, the behavior of not having an error while deleting a watched folder will be nice. :) I expect at least an usual 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 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 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' } |
@arboleya that'll for sure guarantee your space in heaven |
Is node aimed to be platform independent? |
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? |
@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. |
Those come in two flavors: 'can be worked around' and 'fact of life'. This issue is of the second variety.
Usually, that means we suspect that the fix is worse than the bug, e.g. bad performance, making failure cases more obscure, etc. |
@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) |
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. |
@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). |
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. |
As @bnoordhuis and @piscisaureus point out, this is a Windows rough edge that's with us to stay for now. |
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. |
This issue is still present in the latest versions of node. |
* 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
Tested on Windows 7 (32bits):
Output:
The text was updated successfully, but these errors were encountered: