Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2012-09

Function for checking correct file name

32 messages · 14 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Krzysztof

Hi,

Exists any multiplatform function which check if string contains not allowed characters (like < > / \ on windows) for filename?

Regards

Graeme Geldenhuys
to Krzysztof: Exists any multiplatform function which check if string contains not allowed characters…
Krzysztof wrote
Hi, Exists any multiplatform function which check if string contains not allowed characters (like < > / \ on windows) for filename?

Nothing in FPC as far as I know, but once again tiOPF does provide that. Have a look at the tiUtils.pas unit in tiOPF v2. tiOPF is hosted on SourceForge.net. You can browse the repository code online with a web browser if you must.

The function you are looking for is tiIsFileNameValid()

I had a quick look. It can be copied and pasted (with one helper function). There are no other tiOPF dependencies.

Regards,
- Graeme -

Krzysztof
to Graeme Geldenhuys

I just quicky googled not allowed characters and wrote this simple function:

function IsValidFilename(const AFilename: String): Boolean;
var
  c: set of Char = ['<','>',':','"','/','\','|','?','*', '%', '.'];
  i: Integer;
begin
  Result := True;
  for i:=1 to Length(AFilename) do
    if AFilename[i] in c then
      Exit(False);
end;

So, problem solved. Thanks and regards

Mark Morgan Lloyd
to Krzysztof
Krzysztof wrote 14 lines
I just quicky googled not allowed characters and wrote this simple function: function IsValidFilename(const AFilename: String): Boolean; var c: set of Char = ['<','>',':','"','/','\','|','?','*', '%', '.']; i: Integer; begin Result := True; for i:=1 to Length(AFilename) do if AFilename[i] in c then Exit(False); end; So, problem solved. Thanks and regards

But several of those are fine in filenames- just inadvisable since they need special quoting/escaping to get past the shell. As does ' ' which isn't in your list :-)

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]
Mattias Gaertner
to Mark Morgan Lloyd

Mark Morgan Lloyd hat am 14. September 2012
um 15:18 geschrieben:

Show quoted text 19 lines
Krzysztof wrote: > I just quicky googled not allowed characters and wrote this simple function: > > function IsValidFilename(const AFilename: String): Boolean; > var > c: set of Char = ['<','>',':','"','/','\','|','?','*', '%', '.']; > i: Integer; > begin > Result := True; > for i:=1 to Length(AFilename) do > if AFilename[i] in c then > Exit(False); > end; > > So, problem solved. Thanks and regards But several of those are fine in filenames- just inadvisable since they need special quoting/escaping to get past the shell. As does ' ' which isn't in your list :-)

And it does not check for #0..#31, #127.

Mattias

Howard Page-Clark
to Mattias Gaertner
Mattias Gaertner wrote 7 lines
> > c: set of Char = ['<','>',':','"','/','\','|','?','*', '%', '.']; > But several of those are fine in filenames- just inadvisable since they > need special quoting/escaping to get past the shell. As does ' ' which > isn't in your list :-) And it does not check for #0..#31, #127.

As is so often the case, a truly cross-platform solution requires a good deal more care and research (and cross-platform experience) than simply extending a Windows-only solution.

Howard

Jürgen Hestermann
to Krzysztof: Exists any multiplatform function which check if string contains not allowed characters…
Krzysztof wrote
Exists any multiplatform function which check if string contains not allowed characters (like < > / \ on windows) for filename?

The question is: Do you realy need it?

I came to the conclusion that it's very hard to determine what exactly is a valid file name and that it is much easier, safer, platform independend and more future proof to just try creating a file with the name. If it fails, you can check the error result for the reason.

And even if the file name is valid it does not prevent you from error checking because other obstacles like missing rights can also prevent you from using the file(path) name.

Jonas Maebe
to Graeme Geldenhuys
Graeme Geldenhuys wrote 5 lines
On 14/09/12 15:02, Howard Page-Clark wrote: > > As is so often the case, a truly cross-platform solution requires a good... Under linux such a check is easy. Everything is accepted, expect for the NUL character. :-)

And the "/".

Jonas

Vinzent Höfler
to Krzysztof: I just quicky googled not allowed characters and wrote this simple function: function…
Krzysztof wrote
I just quicky googled not allowed characters and wrote this simple function:

Seems, you found one of the many (I'd suspect) wrong search results.

function IsValidFilename(const AFilename: String): Boolean; var c: set of Char = ['<','>',':','"','/','\','|','?','*', '%', '.'];

Really?

|>copy con "a.b.c.%def"
|test
|^Z
| 1 Datei(en) kopiert.
|
|>type "a.b.c.%def"
|test
|
|>dir a.*
|[...]
|
|14.09.2012 18:08 6 a.b.c.%def

And, actually, disallowing the '.' in a filename is really stup^Wshort- sighted. Most files out there in the wild contain at least one.

Vinzent.

The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein
Jorge Aldo G. de F. Junior
to Vinzent Höfler

am i the only one seeing a security risk here ?

2012/9/14 Vinzent Höfler :

Show quoted text 44 lines
On Fri, 14 Sep 2012 14:48:08 +0200, Krzysztof wrote: > I just quicky googled not allowed characters and wrote this simple > function: Seems, you found one of the many (I'd suspect) wrong search results. > function IsValidFilename(const AFilename: String): Boolean; > var > c: set of Char = ['<','>',':','"','/','\','|','?','*', '%', '.']; Really? |>copy con "a.b.c.%def" |test |^Z | 1 Datei(en) kopiert. | |>type "a.b.c.%def" |test | |>dir a.* |[...] | |14.09.2012 18:08 6 a.b.c.%def And, actually, disallowing the '.' in a filename is really stup^Wshort- sighted. Most files out there in the wild contain at least one. Vinzent. -- The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Vinzent Höfler
to Jorge Aldo G. de F. Junior
Jorge Aldo G. de F. Junior wrote
am i the only one seeing a security risk here ?

*scratching head* Which part? Care to elaborate?

I'd presume, you mean another than that I'm using Windows? ;)

I don't see how manually restricting the character set of an application- created file name can be a security risk per se.

Vinzent.

The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein
Vinzent Höfler
to Krzysztof: I need only basic checking, it not need to be 100% compability with OS specification. My…
Krzysztof wrote
I need only basic checking, it not need to be 100% compability with OS specification. My program asking user for playlist name and I'm saving it in local folder with my own extension.

Then for von Neumanns sake simply try to save it where the user asks you to and if any error occurs, tell the user.

I mean, there are hundreds of reasons why a file write may fail, why bother with trying to prevent just one of them? Especially because this hugely differs between different platforms.

You still have to do error handling anyway, and IMO the user is entitled to name his own files any way he likes - as long as the operating system accepts
it. But after all, the choice of operating system was his, so the blame goes
to someone else, not you who prevented the user to create a playlist called "100% Ginuwine" (yes, I googled).

Vinzent.

The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein
Sven Barth
to Graeme Geldenhuys: Also in Windows (as far as I know), file names my not be longer than 255 characters. So…
Graeme Geldenhuys wrote 7 lines
On 14/09/12 13:48, Krzysztof wrote: > I just quicky googled not allowed characters and wrote this simple > function: Also in Windows (as far as I know), file names my not be longer than 255 characters. So you will have to check the length of AFilename parameter too.

It depends. If you use normal "C:\bla\bla" notation you are right, but if you access the NT namespace (which you can do from within the WinAPI) you can use paths with up to 32767 characters. You need to use this notation though: "\\?\C:\bla\bla" (in this case you MUST use "\" though as "/" is not converted here).

For more information see here:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#maxpath

Regards,
Sven

Vinzent Höfler
to Sven Barth
Sven Barth wrote 14 lines
On 14.09.2012 17:44, Graeme Geldenhuys wrote: > On 14/09/12 13:48, Krzysztof wrote: >> I just quicky googled not allowed characters and wrote this simple >> function: > > Also in Windows (as far as I know), file names my not be longer than 255 > characters. So you will have to check the length of AFilename parameter > too. It depends. If you use normal "C:\bla\bla" notation you are right, but if you access the NT namespace (which you can do from within the WinAPI) you can use paths with up to 32767 characters. You need to use this notation though: "\\?\C:\bla\bla" (in this case you MUST use "\" though as "/" is not converted here).

Careful. There's a difference between file/component length and path length.

|This type of path is composed of components separated by backslashes, |each up to the value returned in the lpMaximumComponentLength parameter |of the GetVolumeInformation function (this value is commonly 255 characters).

So, although the path may be up to 32767 characters in length, each component
of the path can no longer than 255 characters. This includes the file name.

Vinzent.

The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein
Sven Barth
to Vinzent Höfler
Vinzent Höfler wrote 33 lines
On Sat, 15 Sep 2012 11:20:53 +0200, Sven Barth wrote: > On 14.09.2012 17:44, Graeme Geldenhuys wrote: >> On 14/09/12 13:48, Krzysztof wrote: >>> I just quicky googled not allowed characters and wrote this simple >>> function: >> >> Also in Windows (as far as I know), file names my not be longer than 255 >> characters. So you will have to check the length of AFilename parameter >> too. > > It depends. If you use normal "C:\bla\bla" notation you are right, but > if you access the NT namespace (which you can do from within the > WinAPI) you can use paths with up to 32767 characters. You need to use > this notation though: "\\?\C:\bla\bla" (in this case you MUST use "\" > though as "/" is not converted here). Careful. There's a difference between file/component length and path length. > For more information see here: > http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#maxpath > |This type of path is composed of components separated by backslashes, |each up to the value returned in the lpMaximumComponentLength parameter |of the GetVolumeInformation function (this value is commonly 255 characters). So, although the path may be up to 32767 characters in length, each component of the path can no longer than 255 characters. This includes the file name.

Right... but 255 characters for a filename is already rather much as well when I compare this with the amount of text I can squash into a SMS ;)

Regards,
Sven

Graeme Geldenhuys
to Sven Barth
Sven Barth wrote
Right... but 255 characters for a filename is already rather much as well when I compare this with the amount of text I can squash into a SMS ;)

Now I can't remember exactly, is that 255 characters, or 255 bytes? Because if it is the latter, then the Unicode character count limit could be significantly less than 255.

Regards,
- Graeme -

Marco van de Voort
to Graeme Geldenhuys

In our previous episode, Graeme Geldenhuys said:

Show quoted text 5 lines
> Right... but 255 characters for a filename is already rather much as > well when I compare this with the amount of text I can squash into a SMS ;) Now I can't remember exactly, is that 255 characters, or 255 bytes? Because if it is the latter, then the Unicode character count limit could be significantly less than 255.

Not really, since on Windows unicode means utf16

Sven Barth
to Graeme Geldenhuys: Now I can't remember exactly, is that 255 characters, or 255 bytes? Because if it is the…
Graeme Geldenhuys wrote 9 lines
On 15/09/12 10:54, Sven Barth wrote: > Right... but 255 characters for a filename is already rather much as > well when I compare this with the amount of text I can squash into a > SMS ;) Now I can't remember exactly, is that 255 characters, or 255 bytes? Because if it is the latter, then the Unicode character count limit could be significantly less than 255.

If you look at the link I gave it says 255 characters. This is because the filename limit on the NTFS filesystem is 255 UTF-16 characters as well (the API seems to be capable of handling larger filenames tough as this is indicated by the point that using the GetVolumeInformation function you can get a value that contains the maximum amount of characters for a file or directory name).

Regards,
Sven

Jorge Aldo G. de F. Junior
to Vinzent Höfler: On Sat, 15 Sep 2012 11:20:53 +0200, Sven Barth Careful. There's a difference between…

Vinzent, i dont know why you need to check the filename - would fileexists() be enough ? - but i suspect that you already know about that function, so, if you need something more complex, i *feel* that it is something related to security.

Supose you wrote a webserver (or whatever thing similar for that matter) and you need to be sure that users can only access files located at c:\htmlpages.

This is a security risk, because, if the function isnt almost perfect, someone could end up reading the passwords file (security.sam on windows ? whatever im not a windows programmer) or rewriting criticial files on a system.

I believe that you already know that, but thats why i asked if others are considering the security risk involved in filenames.

For evidence sake look at this old IIS bug :

http://www.hackingspirits.com/eth-hac/papers/iis_uni.html

Morale : Filenames can be nasty and filename checking functions tend to be complex...

You will need one function for each freepascal target (If you aim at portability).

I believe this can be solved by writing a parser (using a BNF notation of the target filesystem structuring) and a interpreter to expand all the macros possible, without letting the OS even come close to the filename before its sanitized.

That, if i understood your question correctly.

Sorry if i misunderstood.

On a side note : I believe FreePascal should add such filename sanityzing function on future versions (a multiplatform one) to avoid this.

2012/9/15 Vinzent Höfler :

Show quoted text 51 lines
On Sat, 15 Sep 2012 11:20:53 +0200, Sven Barth wrote: > On 14.09.2012 17:44, Graeme Geldenhuys wrote: >> >> On 14/09/12 13:48, Krzysztof wrote: >>> >>> I just quicky googled not allowed characters and wrote this simple >>> function: >> >> >> Also in Windows (as far as I know), file names my not be longer than 255 >> characters. So you will have to check the length of AFilename parameter >> too. > > > It depends. If you use normal "C:\bla\bla" notation you are right, but if > you access the NT namespace (which you can do from within the WinAPI) you > can use paths with up to 32767 characters. You need to use this notation > though: "\\?\C:\bla\bla" (in this case you MUST use "\" though as "/" is not > converted here). Careful. There's a difference between file/component length and path length. > For more information see here: > http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#maxpath |This type of path is composed of components separated by backslashes, |each up to the value returned in the lpMaximumComponentLength parameter |of the GetVolumeInformation function (this value is commonly 255 characters). So, although the path may be up to 32767 characters in length, each component of the path can no longer than 255 characters. This includes the file name. Vinzent. -- The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Mark Morgan Lloyd
to Jorge Aldo G. de F. Junior
Jorge Aldo G. de F. Junior wrote 9 lines
I believe that you already know that, but thats why i asked if others are considering the security risk involved in filenames. For evidence sake look at this old IIS bug : http://www.hackingspirits.com/eth-hac/papers/iis_uni.html Morale : Filenames can be nasty and filename checking functions tend to be complex...

The security risk there isn't in the filename per se, but in what it's passed to. You can safely put most characters in a filename, but the result of that must be checked before being passed to a unix shell, to IIS, to ShellExecuteEx() (or whatever the name of the Windows function is) and so on: that's why Perl has the "tainted" concept that allows anything injected by a user to be tracked and treated as potentially hostile.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]
Jürgen Hestermann
to Jorge Aldo G. de F. Junior: Vinzent, i dont know why you need to check the filename - would fileexists() be enough ?…
Jorge Aldo G. de F. Junior wrote
This is a security risk, because, if the function isnt almost perfect, someone could end up reading the passwords file (security.sam on windows ? whatever im not a windows programmer) or rewriting criticial files on a system.

You mean all programmers in the world need to know all OS security leaks and have to program workarounds for these security leaks? That's completely idiotic because if security is based on this there is no security at all.

Giuliano Colla
to Jorge Aldo G. de F. Junior: Vinzent, i dont know why you need to check the filename - would fileexists() be enough ?…

Il 15/09/2012 23:48, Jorge Aldo G. de F. Junior ha scritto:

This is a security risk, because, if the function isnt almost perfect, someone could end up reading the passwords file (security.sam on windows ? whatever im not a windows programmer) or rewriting criticial files on a system.

IOW you mean that the Open File dialog in Lazarus is a security risk, because it might allows a user to open and read or write a password file? Let's be serious. Security must be a system concern, not an application concern.
If the system gives an application access to sensible data then it's the system which isn't secure.

Giuliano

Jorge Aldo G. de F. Junior
to Jürgen Hestermann: You mean all programmers in the world need to know all OS security leaks and have to…

Like i said earlier, i dont know why he needs to check the filename.

Let me explain :

There are two situations you are describing here :

1 - When the user invokes an application that executes a task on user behalf, using data suplied by the same user.

This first situation is correctly treated by the underlying OS, because it IS on the OS realm to determine who can access what. (It is part of the OS security model).

The problem is, if your application is running using the security permissions of the invoking user, then you dont need to "check correct file name", all you can end up needing to do is to check if some file exists (fileexists()) or if the passed filename is indeed a correct file name (wich can be determined by simply trying to execute the task and checking for errors). In that case theres no need to validate filenames, the user should know better.

2 - When the application is running on behalf of one user but using data supplied by another user. Thats where the security problem happens. In that case the underlying OS security model, usually, have a problem, and thats, usually, why you need to validate filenames. This happens on FTP servers, HTTP servers and in a lot of other cases. This is similar to SQL injection and a lot of other cases of security flaws. The morale is that you should take with a grain of salt everything comming from the user.

If he is validating a filename because of that case, then, a half-baked 10 line function wont cut. THIS IS A SECURITY RISK.

You need a full fledged parser and macro expander.

Thats why i believe such a function should be added to freepascal RTL. A good windows programmer wont know all the caveats of (for one) MacOSX or other platforms.

Oh and thanks for calling me idiotic. IIS developers would think the same about my caution.

2012/9/16 Jürgen Hestermann :

Show quoted text 16 lines
Am 2012-09-15 23:48, schrieb Jorge Aldo G. de F. Junior: > This is a security risk, because, if the function isnt almost perfect, > someone could end up reading the passwords file (security.sam on > windows ? whatever im not a windows programmer) or rewriting criticial > files on a system. You mean all programmers in the world need to know all OS security leaks and have to program workarounds for these security leaks? That's completely idiotic because if security is based on this there is no security at all. _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Peter
to Krzysztof: Exists any multiplatform function which check if string contains not allowed characters…
Krzysztof wrote 10 lines
Hi, Exists any multiplatform function which check if string contains not allowed characters (like< > / \ on windows) for filename? Regards _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

No! File name & path validity are platform specific.

Jurgen's idea of attempting to create a temporary file with the given name, probably best solution.
Also it will check write access to the path, which is useful too. And it is future proof.
Need to run the check on the target of course.

Regards,
PB