Monday, August 31, 2009

PathMatchSpec Problems

Today I was debugging a problem in my application where a wildcard name failed to match. I traced the problem to significant issues with the implementation of PathMatchSpec() in the Windows API.

In short, do not expect this function to work like the command interpreter Cmd.exe. This function does not handle many boundary conditions, nor does it properly handle empty extensions.

The simplest example is this command, which correctly finds the Windows directory on all versions of Windows and MS-DOS 6.x:

dir c:\windows.*

However, this API call returns false on Vista:

BOOL b = ::PathMatchSpec("C:\\Windows", "C:\\Windows.*");

Other inconsistencies are shown in the table below. The "right" answer to these scenarios is unclear because MS-DOS did not support long filenames or spaces in filenames. Although various versions of Windows are themselves inconsistent, PathMatchSpec() does not agree with any of them. I would argue that the correct behavior is what Windows Vista does.

Command::PathMatchSpec("C:\\Windows", xxx);MS-DOSWin 9xWin NT
dir c:\windows.*FalseDisplays directory nameDisplays directory nameDisplays directory name
dir c:\windows.FalseDisplays directory contentsDisplays directory contentsDisplays directory contents
dir c:\windows...FalseDisplays directory nameDisplays directory contentsFail
dir "c:\windows "

(Note the trailing space)
Falsen/aDisplays directory contentsFail
dir "c:\windows ."

(Note the trailing space followed by a period.)
Falsen/aDisplays directory contentsFail

And yes, I did actually install MS-DOS to create this chart :-)

4 comments:

  1. Hello

    I don't understand what is your purpose to find with the strange syntax "c:\windows.*" ?

    But surely you are doing something with the API that it is not made for.

    As the description says and as the examples show this API checks if asterisk characters match letters in the other string.

    I suppose for nothing else it can be used.

    ReplyDelete
  2. The point is that PathMatchSpec() doesn't work properly with an empty extension. The fact that it's the Windows directory in particular is uninteresting. The Windows directory is just a typical example of a path that has no extension. It exists on almost all users' computers, so it's a good sample.

    I think you misunderstand how wildcard matching works. Matching an empty extension is a perfectly reasonable thing to do.

    ReplyDelete
  3. Definitely a matter of interpretation: the dot character is not a wildcard, and there is no dot in "C:\Windows", thus the function works perfectly :-) Trailing spaces are not allowed on Windows file systems, neither trailing dots so most of your input strings are just plain invalid. The only reasonable one is if the pattern "xxx.*" should match a file named 'xxx" without extension and here PathMatchSpec differs from MS-DOS, apparently.

    ReplyDelete
  4. Anonymous,

    I'm really not sure what your point is. My article said that there were inconsistencies. There is no interpretation of "inconsistencies." They either yield identical results, or they don't. Nowhere did I express an opinion of what was right or wrong.

    You are simply incorrect about "no dot in C:\Windows". Windows is not Unix/Linux. The period *always* exists, even if it's not stated. This is a convention that goes back to the very early days of DOS.

    ReplyDelete