Creating a unique temporary directory from pure C in windows
Asked Answered
G

3

12

I'd like to create a unique temporary directory in Windows from some C code (not C++ or C#). I want to do this so that I can put some temp files in the directory, and then delete them all easily when I'm done (by removing the directory recursively).

I'm essentially looking for an equivalent of the linux mkdtemp function. There is a C# answer here, and responses on this question suggest using Boost. But since I'm using C, those solutions don't work for me.

The best I've been able to come up with so far is to use GetTempFileName followed by CreateDirectory, but the problem there is that if I ask GetTempFileName to create a unique file name, it will also create the file (which I don't want, since I want to make a directory instead).

Relatedly, there's GetTempPath, which returns the location of the user's temp folder from environment variables - but since I want to create my own directory that I can safely delete later, I still need to create a directory inside any path it would return.

It looks like if I want a unique directory to be created, I'll have to create a temp file, get the name, delete it, and then create a directory with the same name - which sounds very messy. Any other ideas?

Gant answered 9/6, 2011 at 2:33 Comment(1)
The idea in your final paragraph would not work - it would be subject to race conditions.Shuster
W
9

You can use what GetTempPath returns concatenated with a Guid to ensure uniqueness of the directory. You can create a Guid using UuidCreate or CoCreateGuid Function.

To delete recursively the directory, there is an example here in pure C: How to remove directory recursively? based on FindFirstFile, FindNextFile, DeleteFile and RemoveDirectory.

There is also SHFileOperation but it's more heavyweight and is based on the Windows Shell functions, and the Shell DLLs are not always wanted, especially if you're writing server code.

Wholism answered 9/6, 2011 at 4:55 Comment(2)
I thought about using a GUID or UUID, but I couldn't see how to convert either to a string. Further digging bought me to StringFromGUID2, which might do the trick, as long as it won't generate characters that can't go in filenames? Looks like it will only generate hex strings, which should be fine.Gant
@Timothy - standard guid formats are fine for file names, but anyway, since you don't need these guid formats, you don't explicitely need StringFromGUIS2, as you can also generate the file name "manually" using a concatenation of the 16 bytes written using hexadecimal format.Wholism
M
4

Use GetTempPath then CreateDirectory with a random name under it, optionally retrying if CreateDirectory fails due to it already existing. But if your name generation is good enough, the likelihood of a collision with an existing name is much smaller than the likelihood of a blackhat guessing your password or even your private key, so you might as well ignore it.

Maupassant answered 9/6, 2011 at 3:9 Comment(2)
This is essentially what mkdtemp does (including the retry, of course).Gauvin
mkdtemp is not available in Windows.Cadell
D
3

Use _tempnam tmpnam_s to create a filename that doesn't exist yet, and then use CreateDirectory to create the directory. There's technically a race condition if you do this, in that another process could potentially create a file or directory with that name in the time in between when you generate the filename and when you create the directory, but the odds of that are rather unlikely. To protect against that, you can loop until you succeed.

For recursively removing a directory tree, you can use SHFileOperation. Alternatively, you can do the directory traversal yourself with FindFirstFile/FindNextFile, DeleteFile, and RemoveDirectory.

If you want to remove the directory automatically upon exiting, register a function using atexit. This will only work for normal program termination (i.e. via the exit function or via returning from main/WinMain). This will not work for abnormal program termination (e.g. via abort, an access violation, someone else calling TerminateProcess, etc.).

Dioxide answered 9/6, 2011 at 4:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.