{"id":6663,"date":"2012-09-07T07:00:00","date_gmt":"2012-09-07T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/09\/07\/the-case-of-the-asynchronous-copy-and-delete\/"},"modified":"2012-09-07T07:00:00","modified_gmt":"2012-09-07T07:00:00","slug":"the-case-of-the-asynchronous-copy-and-delete","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120907-00\/?p=6663","title":{"rendered":"The case of the asynchronous copy and delete"},"content":{"rendered":"<p>\nA customer reported some strange behavior in the\n<code>Copy&shy;File<\/code> and <code>Delete&shy;File<\/code>\nfunctions.\nThey were able to reduce the problem to a simple test program,\nwhich went like this (pseudocode):\n<\/p>\n<pre>\n\/\/ assume \"a\" is a large file, say, 1MB.\nwhile (true)\n{\n  \/\/ Try twice to copy the file\n  if (!CopyFile(\"a\", \"b\", FALSE)) {\n    Sleep(1000);\n    if (!CopyFile(\"a\", \"b\", FALSE)) {\n      fatalerror\n    }\n  }\n  \/\/ Try twice to delete the file\n  if (!DeleteFile(\"b\")) {\n    Sleep(1000);\n    if (!DeleteFile(\"b\")) {\n      fatalerror\n    }\n  }\n}\n<\/pre>\n<p>\nWhen they ran the program, they found that sometimes the copy\nfailed on the first try with error&nbsp;5\n(<code>ERROR_ACCESS_DENIED<\/code>)\nbut if they waited a second and tried again, it succeeded.\nSimilarly, sometimes the delete failed on the first try,\nbut succeeded on the second try if you waited a bit.\n<\/p>\n<p>\nWhat&#8217;s going on here?\nIt looks like the\n<code>Copy&shy;File<\/code> is returning before the file copy\nis complete, causing the\n<code>Delete&shy;File<\/code>\nto fail because the copy is still in progress.\nConversely, it looks like the\n<code>Delete&shy;File<\/code> returns before the file is deleted,\ncausing the\n<code>Copy&shy;File<\/code> to fail because the destination exists.\n<\/p>\n<p>\nThe operations\n<code>Copy&shy;File<\/code> and\n<code>Delete&shy;File<\/code> are synchronous.\nHowever, the NT model for file deletion is that a file is\ndeleted when the last open handle is closed.&sup1;\nIf <code>Delete&shy;File<\/code> returns and the file still exists,\nthen it means that somebody else still has an open handle to the file.\n<\/p>\n<p>\nSo who has the open handle?\nThe file was freshly created, so there can&#8217;t be any pre-existing\nhandles to the file,\nand we never open it between the copy and the delete.\n<\/p>\n<p>\nMy psychic powers said,\n&#8220;The offending component is your anti-virus software.&#8221;\n<\/p>\n<p>\nI can think of two types of software that goes around snooping\non recently-created files.\nOne of them is an indexing tool,\nbut those tend not to be very aggressive about accessing files\nthe moment they are created.\nThey tend to wait until the computer is idle to do their work.\nAnti-virus software, however, runs in real-time mode,\nwhere they check every file as it is created.\nAnd that&#8217;s more likely to be the software that snuck in and\nopened the file after the copy completes so it can perform a\nscan on it,\nand that open is the extra handle that is preventing the deletion\nfrom completing.\n<\/p>\n<p>\nBut wait, aren&#8217;t anti-virus software supposed to be using\noplocks so that they can close their handle and get out of the way\nif somebody wants to delete the file?\n<\/p>\n<p>\nWell, um, yes, but &#8220;what they should do&#8221; and &#8220;what they actually do&#8221;\nare often not the same.\n<\/p>\n<p>\nWe never did hear back from the customer whether the guess was\ncorrect,\nwhich could mean one of various things:\n<\/p>\n<ol>\n<li>They confirmed the diagnosis and didn&#8217;t feel the need to\n    reply.<\/p>\n<li>They determined that the diagnosis was incorrect but didn&#8217;t\n    bother coming back for more help,\n    because &#8220;those Windows guys don&#8217;t know what they&#8217;re talking about.&#8221;<\/p>\n<li>They didn&#8217;t test the theory at all, so had nothing to report.\n<\/ol>\n<p>\nWe may never know what the answer is.\n<\/p>\n<p>\n<b>Note<\/b>\n<\/p>\n<p>\n&sup1;Every so often, the NT file system folks dream of changing\nthe deletion model to be more Unix-like, but then they wonder if\nthat would end up breaking more things than it fixes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer reported some strange behavior in the Copy&shy;File and Delete&shy;File functions. They were able to reduce the problem to a simple test program, which went like this (pseudocode): \/\/ assume &#8220;a&#8221; is a large file, say, 1MB. while (true) { \/\/ Try twice to copy the file if (!CopyFile(&#8220;a&#8221;, &#8220;b&#8221;, FALSE)) { Sleep(1000); if [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-6663","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>A customer reported some strange behavior in the Copy&shy;File and Delete&shy;File functions. They were able to reduce the problem to a simple test program, which went like this (pseudocode): \/\/ assume &#8220;a&#8221; is a large file, say, 1MB. while (true) { \/\/ Try twice to copy the file if (!CopyFile(&#8220;a&#8221;, &#8220;b&#8221;, FALSE)) { Sleep(1000); if [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6663","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=6663"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6663\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=6663"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6663"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6663"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}