0

I'm building a Haskell command-line application in Windows 10, and am trying to debug an issue around the Windows 260-character file path limitation by tracing system calls and seeing which ones fail.

I've used procmon (https://learn.microsoft.com/en-us/sysinternals/downloads/procmon) for this, which seems quite nice, but although it displays many related log entries, I was surprised to find that it doesn't display an entry for the particular CreateFileW call that actually exceeds 260 chars and crashes my application.

I briefly tried Win32 API Monitor (https://www.apimonitor.com) but couldn't make heads or tails of it; it seems better suited to attaching to already-running GUI applications than command-line applications that need to be launched in a particular directory, etc.

Is there a better alternative to these, or a better approach?

arya
  • 946
  • 5
  • 14
  • 3
    "*I was surprised to find that it doesn't display an entry for the particular CreateFileW call that actually exceeds 260 chars and crashes my application*" - because there is nothing for it to log. The call likely gets rejected at the higher level API layer, when the input data is first validated, long before it reaches the file system layer. Procmon logs lower level activity, not higher level APIs. Tools like API Monitor are what you are looking for. If you are having trouble with it, ask a new question about that. – Remy Lebeau Sep 27 '19 at 04:37
  • 1
    Procmon hooks at the kernel level. The kernel, system components, and low-level API library implementations use the native NT API, which uses counted Unicode (UTF-16LE) strings that can have up to 32767 code points. The `MAX_PATH` limit exists due to how user-mode libraries translate paths from DOS to native NT. It was used for compatibility with legacy applications but also enabled unconditional use of relatively small, static (per thread) translation buffers, which was more efficient than dynamic strings back in the early 90s when this mattered. – Eryk Sun Sep 27 '19 at 08:34
  • 1
    For long file paths, your application can manually normalize via `GetFullPathNameW` and convert the result to a device path. The latter begins with the caller's object directory for device junctions. Windows has two prefixes for this object directory -- "\\.\" is normalized and "\\?\" is not normalized for a create/open. You want the non-normalized prefix, e.g. "\\?\C:\Windows". If the path already starts with "\\.\", just replace it with "\\?\". If it's UNC but not a device path, such as "\\server\share", convert it explicitly to the "UNC" device junction -- e.g. "\\?\UNC\server\share". – Eryk Sun Sep 27 '19 at 08:50
  • 1
    @ErykSun note that starting in Windows 10 v1607, the `MAX_PATH` limitation can be avoided without resorting to ```\\?\``` or ```\\?\UNC\``` or device paths, but the [behavior has to manually opted into, see MSDN for details](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation). – Remy Lebeau Sep 27 '19 at 09:41
  • 1
    @RemyLebeau, even if an application opts in, long DOS path support still requires the policy to be enabled at the system level, which is disabled by default, so ultimately we're not at the point where an application can rely on long paths even in Windows 10. It's also not supported for Windows 7 and 8, so applications that require long paths must take this into their own hands by manually normalizing and passing "\\?\" device paths in a create or open context. – Eryk Sun Sep 27 '19 at 11:43
  • 1
    @RemyLebeau, also "\\?\ or \\?\UNC\ or device paths" is unusual wording. "\\?\" is a device path -- as is "\\.\" but it's limited to `MAX_PATH` because it gets normalized in a create or open context to replace slash with backslash and trim trailing spaces and dots from the final component. "\\?\" bypasses normalization in a create or open context. It's the bypassing of normalization and translation of DOS paths that we're depending on when using "\\?\" device paths, because that's what's limited to `MAX_PATH` if long DOS paths aren't supported in the current process. – Eryk Sun Sep 27 '19 at 11:50
  • @RemyLebeau I suppose your original comment is the real answer to my question. Your second comment re. opt-in is also what I want — I had flipped the registry key, but I had misunderstood the part about the application manifest. (I thought it was an OR requirement, not an AND requirement.) I’ll submit a separate question about how to provide an application manifest for my command-line application; although if the answer happened to show up here, I wouldn’t complain. – arya Sep 28 '19 at 19:05

1 Answers1

0

@RemyLebeau's comment was the one I needed:

"I was surprised to find that it doesn't display an entry for the particular CreateFileW call that actually exceeds 260 chars and crashes my application"

Because there is nothing for it to log. The call likely gets rejected at the higher level API layer, when the input data is first validated, long before it reaches the file system layer. Procmon logs lower level activity, not higher level APIs. Tools like API Monitor are what you are looking for. If you are having trouble with it, ask a new question about that.

My eventual solution to the problem that inspired this was to upgrade from base-4.11 to base-4.12 which handles windows paths > 260 chars better.

I don't think I'd even need the registry switch anymore.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
arya
  • 946
  • 5
  • 14