{"id":12323,"date":"2010-11-09T07:00:00","date_gmt":"2010-11-09T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/11\/09\/the-curse-of-the-current-directory\/"},"modified":"2010-11-09T07:00:00","modified_gmt":"2010-11-09T07:00:00","slug":"the-curse-of-the-current-directory","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20101109-00\/?p=12323","title":{"rendered":"The curse of the current directory"},"content":{"rendered":"<p>\nThe current directory is both a convenience and a curse.\nIt&#8217;s a convenience because it saves you a lot of typing\nand enables the use of relative paths.\nIt&#8217;s a curse because of everything else.\n<\/p>\n<p>\nThe root cause of this curse is that the Windows&nbsp;NT family\nof operating systems keeps open a handle to the process&#8217;s current\ndirectory.\n(<b>Pre-emptive Yuhong Bao comment<\/b>:\nThe Windows&nbsp;95 series of operating systems, on the other hand,\ndid not keep the current directory open, which had its own\nset of problems not relevant to this discussion.)\n<\/p>\n<p>\nThe primary consequence of this curse is that you can&#8217;t delete\na directory if it is the current directory of a running process.\nI see people stumble upon this all the time without realizing it.\n<\/p>\n<blockquote CLASS=\"q\"><p>\nI am trying to delete a directory&nbsp;X,\nbut when I try, I get the error message\n<code>The process cannot access the file\nbecause it is being used by another process.<\/code>.\nAfter some hunting around, I found that directory&nbsp;X\nis being held open by <code>someapp.exe<\/code>.\nWhy the heck is <code>someapp.exe<\/code> holding my directory open,\nand how do I get it to stop?\n<\/p><\/blockquote>\n<p>\nThe value of <code>someapp.exe<\/code> changes over time,\nbut the underlying problem is the same.\nAnd when this happens, people tend to blame <code>someapp.exe<\/code>\nfor stupidly holding a directory open.\n<\/p>\n<p>\nMost of the time, <code>someapp.exe<\/code> is just a victim of the\ncurse of the current directory.\n<\/p>\n<p>\nFirst, let&#8217;s take the case where <code>someapp.exe<\/code> is\n<code>explorer.exe<\/code>.\nWhy is the current directory of Explore set to this directory?\n<\/p>\n<p>\nWell, one reason might be another curse of the current directory,\nnamely, that the current directory is a process-wide setting.\nIf a shell extension decided to call <code>SetCurrentDirectory<\/code>,\nthen that changes the current directory for all of Explorer.\nAnd if that shell extension doesn&#8217;t bother to call\n<code>SetCurrentDirectory<\/code> a second time to reset the current\ndirectory to what it was,\nthen the current directory gets stuck at the new directory,\nand Explorer has now been conned into changing its current directory\npermanently to your directory.\n<\/p>\n<p>\nMind you, the shell extension might have tried to do the right thing\nby setting the current directory back to its original location,\nbut the attempt might have failed:\n<\/p>\n<pre>\nGetCurrentDirectory(Old) \/\/ returns C:\\Previous\nSetCurrentDirectory(New) \/\/ changes to C:\\Victim\n.. do stuff ..\nSetCurrentDirectory(Old) \/\/ changes to C:\\Previous - fails?\n<\/pre>\n<p>\nThat second call to <code>SetCurrentDirectory<\/code> can fail\nif,\nwhile the shell extension is busy doing stuff,\nthe directory <code>C:\\Previous<\/code> is deleted.\nNow the shell extension can&#8217;t change the directory back,\nso it&#8217;s left stuck at <code>C:\\Victim<\/code>,\nand now you can&#8217;t delete <code>C:\\Victim<\/code> because it\nis Explorer&#8217;s new current directory.\n<\/p>\n<p>\n(The preferred behavior, by the way, is for the shell extension\nnot to call <code>SetCurrentDirectory<\/code> in the first place.\nJust operate on full paths.\nSince the current directory is a process-wide setting, you can&#8217;t\nbe sure that some other thread hasn&#8217;t called <code>SetCurrentDirectory<\/code>\nout from under you.)\n<\/p>\n<p>\nMind you,\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2010\/05\/06\/10008132.aspx#10009183\">\nmaking the current directory a per-thread concept<\/a>\ndoesn&#8217;t solve this problem completely, because the\ncurrent directory for the thread (if such a thing existed)\nwould still have a handle open until the thread exited.\nBut if the current directory had been a per-thread concept,\nand if the thread were associated with an Explorer window,\nthen closing that window would at least encourage that thread\nto exit and let you unstick the directory.\nThat is, unless you did a\n<code>Terminate&shy;Thread<\/code>,\nin which case the handle would be leaked and your attempt to\nrelease the handle only ensures that it never happens.\n(Note to\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2007\/02\/14\/1676656.aspx\">\ntechnology hypochondriacs<\/a>:\nThis paragraph was a hypothetical and consequently\nwill be completely ineffective at solving your problem.)\n<\/p>\n<p>\nThe story isn&#8217;t over yet, but I&#8217;ll need to digress for a bit\nin order to lay the groundwork for the next stage of the curse.\n<\/p>\n<p>\n<b>Bonus chatter<\/b>: Hello, people.\n&#8220;The story isn&#8217;t over yet.&#8221;\nPlease don&#8217;t try to guess the next chapter in the story.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The current directory is both a convenience and a curse. It&#8217;s a convenience because it saves you a lot of typing and enables the use of relative paths. It&#8217;s a curse because of everything else. The root cause of this curse is that the Windows&nbsp;NT family of operating systems keeps open a handle to the [&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-12323","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>The current directory is both a convenience and a curse. It&#8217;s a convenience because it saves you a lot of typing and enables the use of relative paths. It&#8217;s a curse because of everything else. The root cause of this curse is that the Windows&nbsp;NT family of operating systems keeps open a handle to the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/12323","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=12323"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/12323\/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=12323"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=12323"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=12323"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}