its quicker to enumerate once than to fopen in each gamedir 7200 times, especially if those files are in a pak/pk3.

Trust me though, linux (utf-8 only) is muuuch faster than windows (utf-16/utf-8/case insensitivity/alternative file names/ntfs... vista...).
This is made even worse when you have id1+qw+fte+$gamedir+home/id1+home/id1+home/fte+home/$gamedir, which I guess is the real difference in our experiences. Hash tables allow FTE to combine all filesystems into a single lookup, regardless of how many paks/pk3s/gamedirs/etc are loaded.
You should probably look into a binary search for pak files - each time you double the number of files in the pak, you only add one extra iteration. See fodquake as an example, but you do need to sort the files inside the pak first, somehow.
sidenote: fte actually loads paks/pk3s within paks/pk3s. This allows embedding paks etc within the .apk of the android port, but you probably don't want to compress those files - the android port uses the apk file as its basedir. I just can't insert pak0/pak1 in there due to copyright issues.
Really though, you ought to be scanning for the filename and ignore the extension, so you find eg: $gamedir/pak0.pak/image.pcx in preference to id1/somepack.pak/image.tga - this is something that pretty much every engine fails at, including my own. Just sayin.

Note that this is especially problematic if you include your own texture package with priority above id1 as it'll take priority over any png/pcx/etc anywhere else, and even tga in id1.
.