iNotify 如何检测移出

Posted

技术标签:

【中文标题】iNotify 如何检测移出【英文标题】:iNotify how to detect move-out 【发布时间】:2015-04-18 18:46:05 【问题描述】:

您好,我正在使用 iNotify 来检测目录中的更改。我使用的标志是IN_CLOSE_WRITE | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE

我试图区分重命名时的 IN_MOVED_FROM 和将文件移出文件夹时的 IN_MOVED_FROM

我想在用户移出文件时检查cookie 字段是否不为0。正如我认为cookie 仅用于重命名程序。但是,即使我将文件移出目录,它仍然有一个 cookie。 我还想检查IN_MODIFY,因为我希望它会在重命名时出现,但不会在移动时出现,但两者都不存在。

有没有人知道如何检测它是“移出”还是“重命名的旧文件名”?

谢谢

【问题讨论】:

【参考方案1】:

您需要检查IN_MOVED_FROM 事件和后续IN_MOVED_TO 事件。如果 cookie 相同,则该文件已在同一文件夹中重命名。如果您没有收到带有相同 cookie 的 IN_MOVED_TO 事件,则该文件已移出监视文件夹。

【讨论】:

谢谢@hek2!所以但我的问题是 IN_MOVED_TO 没有进入同一个缓冲区,所以当我得到 IN_MOVED_FROM 时,我应该等待几毫秒,然后如果没有 IN_MOVED_TO 则声明它是一个移动? 基本上重命名文件是一个原子操作,不管它是否发生在同一个文件夹中。我希望IN_MOVED_TO 在那之后立即发生。我需要复制这个给你一些可靠的东西。 谢谢@hek2mgl!因此,如果我收到IN_MOVED_TO,我会检查之前是否发生过具有相同 cookie 的 IN_MOVED_FROM,如果没有,则我声明该项目已移入文件夹。所以这是假设如果重命名,那么IN_MOVED_FROM 总是首先发生。如果IN_MOVED_FROM 首先发生,我不应该立即假设它已移出文件夹,但如果在同一 cookie 之后有一个 IN_MOVED_TO,我应该检查相同的缓冲区,如果它在同一个缓冲区中并且在IN_MOVED_FROM 之后,我可以声明它已从。只是在这里大声思考:)谢谢! 是的,我也是这么想的。如果您的意思是 same 缓冲区,您的意思是与同一 wd? 相关的事件 酷! :) 不要犹豫,发布一个简短的示例作为您自己问题的答案(如果您愿意)。这对其他人(包括我)来说是一个很好的参考:)【参考方案2】:

我应用了@hek2mgl 提到的逻辑,非常感谢他。这是 js-ctypes 代码:

while (true) 
    let length = ostypes.API('read')(fd, buf, count);

    length = parseInt(cutils.jscGetDeepest(length));

    if (length == -1) 
        throw new Error(
            name: 'os-api-error',
            message: 'Failed to read during poll',
            uniEerrno: ctypes.errno
        );
     else if (!length==0) 
        // then its > 0 as its not -1
        // something happend, read struct
        let FSChanges = [];
        var i = 0;
        var numElementsRead = 0;

        length = parseInt(cutils.jscGetDeepest(length));
        var _cache_aRenamed_local = ; // local means per buffer
        do 
            let iHoisted = i;
            numElementsRead++;
            var casted = ctypes.cast(buf.addressOfElement(iHoisted), ostypes.TYPE.inotify_event.ptr).contents;

            var fileName = casted.addressOfField('name').contents.readString();
            var mask = casted.addressOfField('mask').contents;
            var len = casted.addressOfField('len').contents;
            var cookie = cutils.jscGetDeepest(casted.addressOfField('cookie').contents)
            var wd = casted.addressOfField('wd').contents;

            var aEvent = convertFlagsToAEventStr(mask);



            if (aEvent == 'renamed-to') 
                if (cookie in _cache_aRenamed_local)  // assuming that renamed-from must happen before rename-to otherwise its a added
                    if (_cache_aRenamed_local[cookie].aExtra.aOSPath_parentDir_identifier == wd)  // aOSPath_parentDir_identifier is a wd if its different then the current wd then it was added/removed from that watched dir
                        var rezObj = 
                            aFileName: fileName,
                            aEvent: 'renamed',
                            aExtra: 
                                nixInotifyFlags: mask, // i should pass this, as if user did modify the flags, they might want to figure out what exactly changed
                                aOSPath_parentDir_identifier: wd,
                                aOld: 
                                    aFileName: _cache_aRenamed_local[cookie].aFileName,
                                    aExtra: 
                                        nixInotifyFlags: _cache_aRenamed_local[cookie].aExtra.nixInotifyFlags
                                    
                                
                            
                        
                        FSChanges.push(rezObj);
                     else 
                        // the one in cache was removed from its parent folder, this one here was added to parent folder. so this is detect as file moved from one watched dir to another watched dir
                        if (_cache_aRenamed_local[cookie].aFileName != fileName) 
                            console.error('whaaaaa wd\'s are differnt and got renamed-to so names should be same');
                            _cache_aRenamed_local[cookie].aEvent = 'haaa names are different?? im just going to say REMOVED as a guess i have never encoutnered this situation yet and i dont think we ever should';
                            FSChanges.push(_cache_aRenamed_local[cookie]);
                         else 
                            _cache_aRenamed_local[cookie].aEvent = 'removed';
                            FSChanges.push(_cache_aRenamed_local[cookie]);
                        
                    
                    delete _cache_aRenamed_local[cookie];
                 else 
                    var rezObj = 
                        aFileName: fileName,
                        aEvent: 'added',
                        aExtra: 
                            aOSPath_parentDir_identifier: wd
                        
                    
                    FSChanges.push(rezObj);
                
             else if (aEvent == 'renamed-from') 
                var rezObj = 
                    aFileName: fileName,
                    aEvent: aEvent,
                    aExtra: 
                        aOSPath_parentDir_identifier: wd
                    
                
                _cache_aRenamed_local[cookie] = rezObj;
             else 
                var rezObj = 
                    aFileName: fileName,
                    aEvent: aEvent,
                    aExtra: 
                        aOSPath_parentDir_identifier: wd
                    
                
                FSChanges.push(rezObj);
            

            if (len == 0) 
                break;
            ;
            i += nixStuff.sizeField0 + nixStuff.sizeField1 + nixStuff.sizeField2 + nixStuff.sizeField3 + parseInt(len);
         while (i < length);
        for (var cookieLeft in _cache_aRenamed_local) 
            // whatever is left in _cache_aRenamed_local is `removed` things
            _cache_aRenamed_local[cookieLeft].aEvent = 'removed';
            FSChanges.push(rezObj);
        
        console.error('loop ended:', 'numElementsRead:', numElementsRead);

        if (FSChanges.length > 0) 
            return FSChanges;
         // else dont return and continue loop
    

我使用此函数将标志转换为renamed-fromrenamed-to 之类的字符串

function convertFlagsToAEventStr(flags) 
    var default_flags = 
        IN_CLOSE_WRITE: 'contents-modified',
        IN_MOVED_TO: 'renamed-to', // can also be a added
        IN_DELETE: 'removed',
        IN_MOVED_FROM: 'renamed-from', // can also be a removed
        IN_CREATE: 'added'
    ;


    for (var f in default_flags) 
        if (flags & ostypes.CONST[f]) 
            return default_flags[f];
        
    
    return 'UNKNOWN FLAG';

【讨论】:

以上是关于iNotify 如何检测移出的主要内容,如果未能解决你的问题,请参考以下文章

处理多个文件时如何使inotify等待

使用 inotify_read 时,pnctl_signal 不会中断 inotify_read

如果Linux中USB设备中的文件系统有任何更改或如何递归使用inotify,如何获得通知

inotify IN_CLOSE_WRITE 仅检测复制到目录的文件

rsync+inotify实时同步

rsycn+inotify实时网络数据镜像备份