{"id":106201,"date":"2022-01-28T07:00:00","date_gmt":"2022-01-28T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106201"},"modified":"2022-01-28T06:57:05","modified_gmt":"2022-01-28T14:57:05","slug":"20220128-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220128-00\/?p=106201","title":{"rendered":"How can I recognize whether two handles refer to the same underlying file?"},"content":{"rendered":"<p>Last time, we learned <a title=\"How can I recognize file systems that don't support 64-bit unique file identifiers?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220127-00\/?p=106199\"> how to recognize file systems that don&#8217;t support 64-bit unique file identifiers<\/a>. But what do you do want to detect whether two handles refer to the same underlying file, and the file system won&#8217;t give you 64-bit unique file identifiers?<\/p>\n<p>The first step is to compare the volume serial numbers. If they are different, then stop. The files belong to different volumes.<\/p>\n<p>If the volume serial numbers match, then use the <code>Get\u00adFile\u00adInformation\u00adBy\u00adHandle\u00adEx<\/code> function and ask for the <code>File\u00adId\u00adInfo<\/code>. This will give you the 128-bit file identifier. If you can get the 128-bit file identifier, then compare them. (NTFS uses 64-bit file identifiers, but it will return them as a 128-bit value if you ask for one.)<\/p>\n<p>If the volume doesn&#8217;t support 128-bit file identifiers, then maybe it&#8217;s an older file system that doesn&#8217;t understand the &#8220;Please give me the 128-bit file identifier&#8221; function, so try again with the <code>Get\u00adFile\u00adInformation\u00adBy\u00adHandle<\/code> and compare the 64-bit file identifiers, provided they aren&#8217;t zero or <code>0xFFFFFFFF`FFFFFFFF<\/code>.<\/p>\n<p>If the volume doesn&#8217;t support 64-bit identifiers either, then the situation is getting kind of desperate. My colleague Malcolm Smith suggests calling <code>Get\u00adFinal\u00adPath\u00adName\u00adBy\u00adHandle<\/code> with <code>FILE_<wbr \/>NAME_<wbr \/>NORMALIZED<\/code> to try to get the file names into some sort of sane state, and then comparing the names.<\/p>\n<p>This last step isn&#8217;t foolproof, because it will be faked out by hard links, but it&#8217;s probably the best you can do under the circumstances. Let&#8217;s hope that the remote file systems which don&#8217;t support unique identifiers don&#8217;t support hard links either.<\/p>\n<p><b>Bonus chatter<\/b>: The SMB protocol (also known as CIFS) can get into a situation where a single share maps to multiple file systems, which means that the unique identifier is itself just an approximation. If two underlying file systems both use the same unique identifier for different files, then the unique identifier sent over the network via SMB will not actually be unique. But it&#8217;s trying the best it can under the circumstances.\u00b9<\/p>\n<p>\u00b9 This also explains why you might not see the <code>FILE_<wbr \/>SUPPORTS_<wbr \/>OPEN_<wbr \/>BY_<wbr \/>FILE_<wbr \/>ID<\/code> flag on remote volumes. If the underlying volume is multiplexing multiple underlying file systems, then it won&#8217;t be able to redeem those file IDs for files, since it doesn&#8217;t know which file system each ID came from. (I guess it could just try them all, but that would defeat the purpose of striping the storage.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Exploring several avenues, hoping one of them leads somewhere.<\/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":[25],"class_list":["post-106201","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Exploring several avenues, hoping one of them leads somewhere.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106201","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=106201"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106201\/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=106201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}