2017-01-08 8 views
2

Существует ли не-платформенный способ выполнения атомарного «переименования File1 в File2, если File2 не существует, иначе дайте ошибку»? Я знаю, что могу просто проверить, существует ли File2, а затем переименовать файл, если это не так, но это приводит к потенциальному состоянию гонки, когда какой-либо другой процесс создает File2 между проверкой и rename().C кросс-платформенная функция renameat2() rename-if-not-exist

Под Linux есть функция renameat2(), которая выполняет именно это с установленным флагом RENAME_NOREPLACE. К сожалению, manpage говорит

renameat2() предназначен для Linux.

Я даже не знаю, поддерживают ли все реализации libc этот вызов или только glibc.

Для моего использования, переименования внутри одного и того же каталога достаточно, мне не нужно иметь поддержку для перехода на совершенно другой путь.

Это потенциально связано с https://stackoverflow.com/a/230581/5562035 и Atomically swap contents of two files on Linux

+0

Атомный в каком смысле? Обратите внимание, в частности, что документы Linux для 'rename()' и 'renameat()' специально отмечают, что «там, вероятно, будет окно, в котором оба« oldpath »и« newpath »относятся к переименоваемому файлу». –

+0

Используйте здравый смысл. –

+0

Между проверкой наличия целевого файла и переименования, в котором другой процесс мог создать целевой файл, не должно быть временного окна. Без этого условия вы могли бы просто «if (! File_exists (path_2)) {rename (path_1, path_2)}' – buggy3

ответ

2

Есть без конкретной платформы способ сделать атомный «переименовать file1 в Файл2 если File2 не существует, в противном случае выдаст ошибку»?

Стандартная библиотека C обеспечивает только rename() для изменения имен файлов и стандарт говорит это о том, что функции: «Если файл с именем строки, на которую указывает new существует до вызова функции rename, то поведение определяется реализацией ». Поэтому, если «не-платформенно-специфический» интерпретируется как «заданный стандартом C», то нет, такого механизма нет.

Если расширить сферу «не специфичен для каждой платформы», чтобы объекты, указанные в POSIX, однако, вы можете рассчитывать на link(), которые

должны атомарно создать новую ссылку для существующего файла и количество ссылок на файл должно быть увеличено на единицу. [и] не работает, если [... второй аргумент] разрешает существующую запись каталога или ссылается на символическую ссылку.

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

Самой известной платформой, отличной от POSIX, в которой может быть интересно, будет Windows. Я не уверен, что вообще можно делать то, что вы просите в Windows, но если есть, вы можете подумать о создании функции-обертки, которая использует условную компиляцию для выбора реализации POSIX или Windows.