Существует только два безопасных и относительно переносимых способа изменить каталог без перехода по символической ссылке. В сценариях оболочки это сделать невозможно.
Предположим, ради обсуждения, что мы пытаемся безопасно chdir в "foo". Первый способ - сохранить текущий каталог в дескрипторе открытого файла с open(".", O_RDONLY)
, lstat()
каталогом "foo", записать полученные значения st_dev
и st_ino
, вызвать chdir ("foo"), а затем stat () ".". Сравните полученные значения st_dev
и st_ino
. Если они одинаковы, вы выиграли гонку. Если нет, выдайте сообщение об ошибке, fchdir()
вернувшись назад, используя сохраненный fd, а затем либо прервите работу, либо повторите попытку.
Второй, менее переносимый способ - использовать fd = open("foo", O_RDONLY|O_NOFOLLOW)
, а затем fchdir(fd)
. Вы также можете использовать openat
вместо open
здесь. Проблема переносимости состоит в том, что не все системы имеют O_NOFOLLOW
, и некоторые старые ядра не будут правильно интерпретировать этот флаг (вместо этого они игнорируют его, что является проблемой безопасности).
Для получения дополнительной информации взгляните на исходный код GNU find, в котором я столкнулся с некоторыми трудностями, чтобы избежать подобных проблем, используя метод, очень похожий на описанный выше.
Что касается решения этой проблемы в сценарии оболочки:
Если в вашей системе есть команда stat(1)
или что-то вроде Perl, вы можете использовать ее для выполнения операций статистики; Вы можете записать результат в переменной оболочки. Это означает, что вы можете более или менее реализовать первый метод в сценарии оболочки, за исключением необходимости использовать fchdir
для восстановления. Если можно просто немедленно прервать процесс, когда ваш сценарий оболочки проиграл гонку, вы, безусловно, можете адаптировать первый метод для использования в оболочке. Но в конце концов написать безопасный код в оболочке очень и очень сложно.