2011-06-09 3 views
10

Я хотел бы создать уникальный временный каталог в Windows из некоторого кода C (а не C++ или C#). Я хочу сделать это, чтобы я мог поместить некоторые файлы temp в каталог, а затем легко удалить их, когда я закончил (путем рекурсивного удаления каталога).Создание уникального временного каталога из чистого C в windows

Я по существу ищу эквивалент linux mkdtemp функция. Существует ответ C# here, и ответы на this question предлагают использовать Boost. Но поскольку я использую C, эти решения не работают для меня.

Лучшим, что я смог придумать до сих пор является использование GetTempFileName следует CreateDirectory, но проблема есть в том, что если я попрошу GetTempFileName создать уникальное имя файла, он будет также создайте файл (который мне не нужен, так как я хочу сделать каталог вместо этого).

Relatedly, есть GetTempPath, который возвращает расположение временной папки пользователя из окружения переменных - но так как я хочу, чтобы создать свой собственный каталог, который я могу безопасно удалить позже, мне еще нужно создать каталог внутри любой путь будет возвращен.

Похоже, если я хочу, уникальный каталог будет создан, я должен буду создать временный файл, получить имя, удалить его, а затем создать каталог с таким же именем - что звучит очень грязно , Любые другие идеи?

+3

Идея в вашем последнем абзаце не будет работать - она ​​будет подвержена условиям гонки. –

ответ

8

Вы можете использовать то, что возвращает GetTempPath, связанное с помощью Guid, чтобы обеспечить уникальность каталога. Вы можете создать Guid с использованием UuidCreate или CoCreateGuid Function.

Чтобы удалить рекурсивно каталог, здесь приведен пример в чистом виде C: How to remove directory recursively? на основе FindFirstFile, FindNextFile, DeleteFile и RemoveDirectory.

Существует также SHFileOperation, но он более тяжеловес и основан на функциях Windows Shell, а DLL-файлы Shell не всегда нужны, особенно если вы пишете код сервера.

+0

Я думал об использовании GUID или UUID, но я не мог понять, как преобразовать его в строку. Дальнейшее копание купило меня до ['StringFromGUID2'] (http://msdn.microsoft.com/en-us/library/ms683893 (v = VS.85) .aspx), что могло бы сделать трюк, если оно выиграло 'генерировать символы, которые не могут входить в имена файлов? Похоже, он будет генерировать только шестнадцатеричные строки, и это должно быть хорошо. –

+0

@Timothy - стандартные форматы guid отлично подходят для имен файлов, но в любом случае, поскольку вам не нужны эти директивные форматы, вам не требуется явно StringFromGUIS2, так как вы также можете сгенерировать имя файла «вручную», используя конкатенацию 16 байтов, написанных с использованием шестнадцатеричного формата. –

3

Используйте GetTempPath, затем CreateDirectory со случайным именем под ним, при необходимости повторите попытку, если CreateDirectory не удалось из-за того, что он уже существует. Но если ваше имя генерации достаточно хорошее, вероятность столкновения с существующим именем намного меньше, чем вероятность того, что blackhat угадывает ваш пароль или даже ваш секретный ключ, поэтому вы можете его игнорировать.

+1

Это, по сути, то, что делает 'mkdtemp' (включая повтор, конечно). – andrewdski

2

Используйте _tempnamtmpnam_s, чтобы создать имя файла, которого еще нет, а затем используйте CreateDirectory для создания каталога. Технически это условие гонки, если вы это сделаете, поскольку другой процесс может потенциально создать файл или каталог с таким именем в промежутке между тем, когда вы создаете имя файла и когда вы создаете каталог, но вероятность этого маловероятна. Чтобы защитить от этого, вы можете зацикливаться до тех пор, пока не добьетесь успеха.

Для рекурсивного удаления дерева каталогов можно использовать SHFileOperation. Кроме того, вы можете сделать обход каталога с помощью FindFirstFile/FindNextFile, DeleteFile и RemoveDirectory.

Если вы хотите удалить каталог автоматически после выхода, зарегистрируйте функцию, используя atexit. Это будет работать только для нормального завершения программы (т. Е. Через функцию exit или путем возврата от main/WinMain). Это не будет работать для ненормального завершения программы (например, через abort, нарушение доступа, другое лицо, вызывающее TerminateProcess и т. Д.).