FindFirst on OS X – two small tips

If using FindFirst/FindNext/FindClose when targeting OS X , there’s two things to keep in mind:

  1. To search for items with any name, use a mask of ‘*’ not ‘*.*’.
  2. If enumerating sub-directories and sub-directories of sub-directories, remember to check faSymLink or you may find yourself in an endless loop.

The following code demonstrates getting both things right, assuming you just want to ignore directory links like you would a folder shortcut on Windows (thanks to Primož Gabrijelčič in the comments for making the caveat clear):

procedure DoSearch(const Path, FileSpec: string);
const
  SAnyMask = {$IFDEF MSWINDOWS}'*.*'{$ELSE}'*'{$ENDIF};
var
  Info: TSearchRec;
begin
  //find files in the immediate directory...
  if FindFirst(Path + FileSpec, faAnyFile and not faDirectory,
    Info) = 0 then
  try
    repeat
      //work with found file info...
    until FindNext(Info) <> 0;
  finally
    FindClose(Info);
  end;
  //find sub-directories and recurse
  if FindFirst(Path + SAnyMask, faDirectory, Info) = 0 then
  try
    repeat
      if (Info.Attr and faDirectory <> 0) and
         (Info.Name <> '.') and  (Info.Name <> '..') and
         (Info.Attr and faSymLink = 0) then
        DoSearch(Path + Info.Name + PathDelim, FileSpec);
    until FindNext(Info) <> 0;
  finally
    FindClose(Info);
  end;
end;

As an aside, both these things I previously forgot in the public version of one of my book demos (ahem), but the source is now updated in the SVN.

Advertisements

6 thoughts on “FindFirst on OS X – two small tips

  1. This solution is OK only if you don’t want to traverse symbolic links which is rarely the case. Better solution would be to step into symbolic link but to remember all directories that were visited so far and ignore duplicates. After all, symbolic links cause problems only if they create a cycle at the file system level.

    • You’re quite right about the ‘better solution’. I’m currently in a ‘just get the thing to compile’ mode, alas, for this and many other things!

    • Actually, on second thoughts, I’m not sure it’s necessarily ‘rarely’ the case. Perhaps this is just my Windows-centricism coming through, but I think of symbolic links in a fashion not much different to Windows shortcut files. I realise they are implemented at a level (perhaps two levels!) below, but they look like shortcuts in the Finder UI with that little arrow overlay icon, and I wouldn’t expect a FindXXX loop to follow through .lnk files.

        • Notwithstanding the fact OS X is indeed a Unix, putting a file system subtree on a different partition is far from ‘frequently used’ in Mac-land. On a typical Mac, the vast majority of actually-existing symlinks are for establishing a version non-specific path to the latest version of a given framework. E.g., /System/Library/Frameworks/AppKit.framework/Resources for me is a symlink pointing to /System/Library/Frameworks/AppKit.framework/Versions/C/Resources. The way Finder then treats folder symlinks is pretty much identical to how Windows Explorer treats folder shortcuts. Or, from an historical Mac POV, Finder deliberately blurs the distinction between Unix-style symlinks and classic Mac OS-style aliases.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s