Discussion:
problems with qualifying a user-provided path - are there functions available for it ?
(too old to reply)
R.Wieser
2020-11-26 11:01:06 UTC
Permalink
Hello all,

Using XPsp3 with its standard DLLs (kernel32, shlwapi, etc) :

I'm trying to make sure that a user-provided path is actually usable, and
I've run into a problem: I can't seem to find DLL functions which do that.

As I need an absolute path I've been trying to use GetFullPathName
(kernel32), but it doesn't even bother to check if the result is
syntactically correct - feeding it something like "file: //
d:\folder\file.ext" (spaces not included) makes it return comething like
"d:\currentpath\file:\d:\folder\file.ext", which is absolutily bogus.

I thought that PathSearchAndQualify (shlwapi) would do the trick, but that
internally just calls GetFullPathName (I've disassembled the function), and
thus does not honor its "AndQualify" name in the least. :-(

As a work-around I've been using PathFileExists (shlwapi), but although that
works it accepts relative paths - and I could not find a function which
would check if the path is absolute (starts with a driveletter, network
server, etc.).

To make things even more interresting, I would also like to be able to
qualify things like "%temp%\file.ext" and "D:\%username%\file.ext"

tl;dr:
How do I qualify a path using the standard DLLs functions (read: not trying
to check for all bad cases myself) ?
JJ
2020-11-27 01:38:48 UTC
Permalink
Post by R.Wieser
Hello all,
I'm trying to make sure that a user-provided path is actually usable, and
I've run into a problem: I can't seem to find DLL functions which do that.
As I need an absolute path I've been trying to use GetFullPathName
(kernel32), but it doesn't even bother to check if the result is
syntactically correct - feeding it something like "file: //
d:\folder\file.ext" (spaces not included) makes it return comething like
"d:\currentpath\file:\d:\folder\file.ext", which is absolutily bogus.
I thought that PathSearchAndQualify (shlwapi) would do the trick, but that
internally just calls GetFullPathName (I've disassembled the function), and
thus does not honor its "AndQualify" name in the least. :-(
As a work-around I've been using PathFileExists (shlwapi), but although that
works it accepts relative paths - and I could not find a function which
would check if the path is absolute (starts with a driveletter, network
server, etc.).
To make things even more interresting, I would also like to be able to
qualify things like "%temp%\file.ext" and "D:\%username%\file.ext"
How do I qualify a path using the standard DLLs functions (read: not trying
to check for all bad cases myself) ?
For me, I simply use `GetLongPathName()`. It will fail if the target path is
inaccessible, but if there's other better suited function without actually
checking the physycal file system object, the path will still point to an
inaccessible object anyway.

If the input path may contain environment variables, I'd process it with
`ExpandEnvironmentStrings()` before passing it to `GetLongPathName()`. But
only if `GetLongPathName()` alone fails with an error stating that the
target path is not found.
R.Wieser
2020-11-27 08:39:46 UTC
Permalink
JJ,
Post by JJ
For me, I simply use `GetLongPathName()`.
Thats not really usable I'm afraid, as it only replaces the file/folder
names, and leaves everything else alone. IOW, if you get a non-zero result
the returned path is valid, but can still be relative and/or contain "." and
".." stuff.

Lolz : it returns "C:\Windows\System32\..." (thats three (or more!) dots) as
valid, but "C:\Windows\System32\...\config.sys" as invalid. Go figure.
Post by JJ
If the input path may contain environment variables, I'd process
it with `ExpandEnvironmentStrings()` before passing it
Yup, thats what I'm curently doing. I don't quite like the resulting
code-fumbling though. And I still do not see a way to check if the path is
absolute.

Among others I tried PathIsRelative (shlwapi), but thinks that a path
without a drive but starting with a backslash is absolute ... PathSkipRoot
doesn't want to skip the drive infront of a relative path (like "c:folder").

grumble, grumble, grumble ... :-)

Regards,
Rudy Wieser
JJ
2020-11-28 01:55:58 UTC
Permalink
Post by R.Wieser
Lolz : it returns "C:\Windows\System32\..." (thats three (or more!) dots) as
valid, but "C:\Windows\System32\...\config.sys" as invalid. Go figure.
You're right. It's unreliable. :(
Post by R.Wieser
Among others I tried PathIsRelative (shlwapi), but thinks that a path
without a drive but starting with a backslash is absolute ... PathSkipRoot
doesn't want to skip the drive infront of a relative path (like "c:folder").
I haven't checked, but SHELL32's `PathResolve()` seems worth a try. It's
defined in `shlobj.h`.
R.Wieser
2020-11-28 06:44:44 UTC
Permalink
JJ,
Post by JJ
I haven't checked, but SHELL32's `PathResolve()` seems worth a try.
I had, based on its name, the same idea. Alas, MSDN (docs.microsoft.com)
seems to have thrown all documention about it away. :-(

Regards,
Rudy Wieser
JJ
2020-11-29 06:03:06 UTC
Permalink
Post by R.Wieser
I had, based on its name, the same idea. Alas, MSDN (docs.microsoft.com)
seems to have thrown all documention about it away. :-(
But "PathResolve" is the first entry of Gugle, DuckDuckGo, as well as
docs.microsoft.com search results. (O.o)?
R.Wieser
2020-11-29 09:10:14 UTC
Permalink
JJ,
Post by JJ
But "PathResolve" is the first entry of Gugle, DuckDuckGo, as
well as docs.microsoft.com search results. (O.o)?
And to add insult o injury, I actually saved that docs.microsoft.com page.
:-( My apologies. I must have mixed it up with another similar function.
Ah yes, there it is : PathQualify

It doesn't change anything though, as I discarded the PathResolve function
(which might be why I misremembered it) because it bungles up as well as not
doing its work :

Mind you, the (console, testing) program is ran from a folder on the the D:
drive.
"+" means ok, "-" means fail.
----
Src:'Hello.vbs'
- 'Hello.vbs' ;Fail
----
Src:'.\Hello.vbs'
+ 'C:\Hello.vbs' ;Fail, twice.
----
Src:'\Hello.vbs'
+ 'C:\Hello.vbs' ;Fail
----

Also, remember those triple (or more) dots ? Those do not get the function
to fail either.
----
Src:'files\....'
+ 'C:\files\....'
----
Src:'files\...\file.ext'
+ 'C:\files\...\file.ext'
----

Regards,
Rudy Wieser
JJ
2020-11-29 14:29:10 UTC
Permalink
Post by R.Wieser
drive.
"+" means ok, "-" means fail.
----
Src:'Hello.vbs'
- 'Hello.vbs' ;Fail
----
Src:'.\Hello.vbs'
+ 'C:\Hello.vbs' ;Fail, twice.
----
Src:'\Hello.vbs'
+ 'C:\Hello.vbs' ;Fail
----
Also, remember those triple (or more) dots ? Those do not get the function
to fail either.
----
Src:'files\....'
+ 'C:\files\....'
----
Src:'files\...\file.ext'
+ 'C:\files\...\file.ext'
----
All those seems-to-cover-all PathXXX functions... None of them can do the
most basic thing. How shameful and hilarious.
R.Wieser
2020-11-29 17:15:50 UTC
Permalink
JJ,
Post by JJ
All those seems-to-cover-all PathXXX functions... None of them
can do the most basic thing. How shameful and hilarious.
Including GetFullPathName and GetLongPathName, yes. And mind you, some of
those PathXXX functions have *qualify* in their names ... :-(

Wat I'm currently doing is using ExpandEnvironmentStrings. If that
/doesn't/ expand anything I'm giving it to GetFullPathName (which can make a
mess). After that I use PathSkipRoot (which does seem to do a decent job),
and than check the remainder for certain illegal (combination of) chars.

Though without having documentation on what MS thinks are legal paths I have
to throw testpaths at functions to see how they respond, and take my clues
from there.

And this morning I realised I had almost forgotten about Alternate Data
Streams, the names of which get appended to the filepath using the, normally
forbidden outside of a drive prefix, colon character ...

Somehow I don't think that MS really bothered with actually checking if the
syntax of a filepath is correct. Instead they seem to have just left it up
to functions which actually needed the paths to open files (or devices,
pipes, etc) to error-out on the malformed ones.

Why is it that I always seem to run into these kind of "must be simple, but
isn't" problems ? :-\


By the way: Did you know that there also isn't any function that checks if a
filepath points at a disk/storage-medium file ? I looked for it, but could
not find any either.

Regards,
Rudy Wieser
JJ
2020-11-30 08:33:45 UTC
Permalink
Post by R.Wieser
And this morning I realised I had almost forgotten about Alternate Data
Streams, the names of which get appended to the filepath using the, normally
forbidden outside of a drive prefix, colon character ...
That actually depends on the file system. e.g. file system other than NTFS
and ReFS.

And in terms of NTFS, you've only discovered 66% of it. There's a third
colon usage to separate between stream name, and NTFS attribute (read:
metadata) name. Metadata such as $INDEX_ALLOCATION, $SECURITY_DESCRIPTOR,
$DATA, $REPARSE_POINT, $ATTRIBUTE_LIST, etc. However, they are not commonly
used, and not normally accessible. They can only be used when a
file/directory is opened with FILE_FLAG_BACKUP_SEMANTICS. I actually use it
for my own defragmenter tool. Some example paths would be e.g.

d:\dir\file.ext:stream:$ATTRIBUTE_LIST
d:\dir\subdir::$INDEX_ALLOCATION
Post by R.Wieser
Somehow I don't think that MS really bothered with actually checking if the
syntax of a filepath is correct. Instead they seem to have just left it up
to functions which actually needed the paths to open files (or devices,
pipes, etc) to error-out on the malformed ones.
Why is it that I always seem to run into these kind of "must be simple, but
isn't" problems ? :-\
I could only guess that they think that it's not worth it, considering that
the validity of a file system path depends on the type of the file system -
which can not be retrieved from the path name string alone. Or they're just
being lazy.
Post by R.Wieser
By the way: Did you know that there also isn't any function that checks if a
filepath points at a disk/storage-medium file ? I looked for it, but could
not find any either.
GetDriveType(), QueryDosDevice(), and GetVolumeInformation(); if the input
is a mere path name. But the functions may require that the path is already
valid, and must point to an existing storage; considering that they may have
to check some other things.

There are more options if the input is a file/directory/disk handle.
R.Wieser
2020-11-30 11:54:28 UTC
Permalink
This post might be inappropriate. Click to display it.
Loading...