3/16/2009

03-16-09 - Temp Names

I made the classic error of actually trying to use the APIs you're supposed to use instead of just writing my own code from scratch.

First of all, the stdlib "tmpnam" is just horrifically broken in the MSVC CRT. I don't understand WTF they're thinking, but it's just awful in various ways :

1. It actually puts the files in the ROOT of your damn drive ! WTF.

2. It doesn't work in Vista at all (you can't fopen the name they give you back). Presumably because it's putting the file in the root and the app doesn't have write access to the root (?).

3. The names are awful, like "s38b" , usually with no extension at all. This makes it very hard to delete them safely when you get like 100,000 of them piled up in your fucking root.

Okay, okay, so we're on Windows we can use the Win32 functions. Well, on the plus side, GetTempPath seems to actually work, it gives you the dir specified by the "TMP" environment var (BTW if it can't find a temp setting, it falls back to the Windows directory which is kind of awful, but whatever, it at least finds the temp dir normally).

On the minus side, GetTempFileName is retardedly awfully bad.

If you just glance at the docs is seems like it's pretty reasonable. You stick 0 in for uUnique and rock on.

But then one day your app grinds to a complete halt because of GetTempFileName and you go "WTF?". Well guess what, GetTempFileName only actually makes up to 64k temp file names. And when it actually checks the name for existence and then tries again. This means that if you even get over 10k temp files in your temp dir, it can make names and check existence over and over before it finds an open slot. If you get more than 50k temp files, you app is basically dead.

Now obviously you don't want to have a ton of temp files hanging around, but Windows never cleans up your temp dirs so if you have some bugs at some point or even just other random broken apps, you can easily crud up your temp dir. And the prefix is only 3 characters so you can often run into other people's prefixes!

One improvement would be if they stuck the app's name onto the temp path and made a subdir, so that you at least got your own dir to play in so that one broken app couldn't mess up the whole system.

On the plus side they actually use the extension ".tmp" so you can go delete everything.

Anyhoo, this is all silly because we have this thing called "long file names" and we don't need to be using 4 characters of hex (!? WTF) which makes it so easy to get name collisions.

So I wrote my own; here's my current version of MakeTempFileName :


// stdc tmpnam seems to put files in the fucking root !?
void MakeTempFileName(char * into,int intoSize)
{
    // use better routines on windows

    do
    {
        char tempPath[MAX_PATH];
        GetTempPath(sizeof(tempPath),tempPath);

        static uint32 s_seqNum = 1;
        
        uint32 seqNum = s_seqNum;
        ++s_seqNum; // not thread safe, whatever
        
        // use tsc or something to get a real random int :
        
        Timer::tsc_type tsc = Timer::rdtsc();
        uint32 tscLow = (uint32)tsc;
            
        char tempFile[MAX_PATH];
        sprintf(tempFile,"cb_%d_%08X.tmp",seqNum,tscLow);
        
        CombinePaths(tempPath,tempFile,into);
        into[intoSize-1] = 0;
        
        // retry while this name exists :
        //  (would be very bad luck)
        
    } while( FileExists(into) );
    
}

yes, yes, this calls lots of cblib stuff.

No comments:

old rants