macOS:文件删除时的断点

时间:2019-07-13 22:35:25

标签: xcode debugging cocoa nsfilemanager unlink

在我用Objective-C编写的旧macOS应用程序中,我正在调试一个可复制的问题,其中在系统框架调用期间过早删除文件包。为了获得线索,我希望每当删除文件时调试器都中断。为此,我在Xcode中的以下符号处设置了符号断点:

unlink
unlinkat
-[NSFileManager removeItemAtPath:error:]
-[NSFileManager removeItemAtURL:error:]

所有这些断点均按预期解析为实际断点,并且在按预期方式删除文件时它们会按预期中断。但是在麻烦的过早删除文件的过程中,没有中断。

macOS中是否还有其他功能可以删除文件,我应该为此添加断点?

背景信息:

在新复制的文件(如 File> Duplicate )中调用[super saveDocument]但从未保存过的文档包时,此问题发生在我的自定义NSDocument子类中。此类文档包位于~/Library/Autosave Information/中,并且当一切正常时,请保留在那里,直到出现“保存”面板并随后将其关闭。但是,在发生错误的情况下,当用户单击File > Save(或发生自动保存)时,包会立即消失,这显然会导致以后出现错误,表明已删除的包无法移至“保存面板”返回的路径。

我也尝试过在该软件包出现后,并且在单击 File> Save 之前,将该软件包的POSIX权限更改为八进制500。我的想法是无法删除它,并且我还打开了它。我所有的异常和错误断点,希望神秘的删除程序会进入调试器控制台。结果:程序包未被删除,并且按照我的假设,保存操作成功。但是什么都没有尖叫。因此,这个神秘的删除器确实是问题所在,但显然既隐秘又宽容:(

编辑,五天后,解决方案:

在找到其他事情要做5天之后,我决定忍痛忍受,并按照肯·托马斯(Ken Thomases)的建议使用DTrace。它起作用了,向我展示了通过libsystem_kernel.dylib__unlink的调用删除了主题文件包中的所有文件,而-[NSFileManager removeItemAtPath:error:]又调用了该文件。

我不知道为什么这些函数的断点没有为这些调用而中断,除非在堆栈跟踪的底部可能有一个线索,提到了“ xpc”。此文件删除是否有可能由XPC帮助程序完成? DTrace是否还会探测正在探测的进程的辅助进程?那真是太神奇了。

以下是简短的DTrace会话记录:

Air2 jk$ sudo dtrace -n 'syscall::unlink*:entry,syscall::rmdir:entry,syscall::rename:entry { printf("time=%d  arg=%s\n", timestamp/1000000000, copyinstr(arg0)); ustack(100); }' -p `pgrep MyApp`
Password:
dtrace: description 'syscall::unlink*:entry,syscall::rmdir:entry,syscall::rename:entry ' matched 4 probes
CPU     ID                    FUNCTION:NAME
  1    178                     unlink:entry time=6562  arg=/Users/jk/Library/Autosave Information/Unsaved MyApp Document.bmco

              libsystem_kernel.dylib`__unlink+0xa
              libremovefile.dylib`__removefile_tree_walker+0x147
              libremovefile.dylib`removefile+0x99
              Foundation`-[NSFilesystemItemRemoveOperation main]+0xba
              Foundation`__NSOPERATION_IS_INVOKING_MAIN__+0x11
              Foundation`-[NSOperation start]+0x2db
              Foundation`-[NSFileManager removeItemAtPath:error:]+0x54
              AppKit`__90-[NSDocumentController(NSInternal) _autoreopenDocumentsFromRecords:withCompletionHandler:]_block_invoke_2+0x90
              AppKit`__89-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_2+0xa6
              AppKit`___NSMainRunLoopPerformBlockInModes_block_invoke+0x19
              CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__+0xc
              CoreFoundation`__CFRunLoopDoBlocks+0x17b
              CoreFoundation`__CFRunLoopRun+0xae8
              CoreFoundation`CFRunLoopRunSpecific+0x1f3
              HIToolbox`RunCurrentEventLoopInMode+0x124
              HIToolbox`ReceiveNextEventCommon+0x164
              HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter+0x40
              AppKit`_DPSNextEvent+0x3de
              AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+0x548
              ViewBridge`-[NSViewServiceApplication nextEventMatchingMask:untilDate:inMode:dequeue:]+0x5f
              AppKit`-[NSApplication run]+0x292
              AppKit`NSApplicationMain+0x309
              libxpc.dylib`_xpc_objc_main.cold.3+0x38
              libxpc.dylib`_xpc_objc_main+0x203
              libxpc.dylib`_xpc_copy_xpcservice_dictionary
              ViewBridge`xpc_connection_handler
              ViewBridge`NSViewServiceApplicationMain+0xbff
              com.apple.appkit.xpc.openAndSavePanelService`main+0xc0
              libdyld.dylib`start+0x1
              com.apple.appkit.xpc.openAndSavePanelService`0x1

(该笔录中的调用显然试图取消文件包的链接,由于该包不为空,我认为这将失败。随后是几个类似的调用,它们遍历包树,删除每个节点,最后是重复该调用以删除软件包,显然是成功的。)

1 个答案:

答案 0 :(得分:1)

重命名操作将使源路径不再引用文件(看起来像源路径处的文件已被删除)。它也可以取消链接/删除目标路径上的文件,尽管它将替换为源路径上的文件。因此,它们将是rename()renameat()renamex_np()renameatx_np()

当然,rmdir()可以删除目录,但前提是该目录为空。

显然,有一个隐藏的delete()系统调用。它被描述为“使用Carbon语义从文件系统中删除名称”。框架可能正在使用它。