ИМЯ
rename, renameat, renameat2 -
изменяет
имя или
расположение
файла
ОБЗОР
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
#include <fcntl.h> /* определения констант AT_* */
#include <stdio.h>
int renameat(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath);
int renameat2(int olddirfd, const char *oldpath,
int newdirfd, const char *newpath, unsigned int flags);
Требования
макроса
тестирования
свойств
для glibc (см.
feature_test_macros(7)):
renameat():
- Начиная с glibc
2.10:
- _POSIX_C_SOURCE >= 200809L
- До glibc 2.10:
- _ATFILE_SOURCE
renameat2():
ОПИСАНИЕ
Вызов rename()
переименовывает
файл и, если
требуется,
перемещает
его из
одного
каталога в
другой. Все
прочие
жёсткие
ссылки на
файл
(созданные
с помощью
link(2)), не
изменяются.
Открытые
файловые
дескрипторы
на oldpath также
не
изменяются.
На
успешность
выполнения
операции
переименования
влияют
различные
ограничения:
смотрите
ОШИБКИ
далее.
Если newpath
уже
существует,
то он будет
атомарно
перезаписан
так, что
другой
процесс,
пытающийся
в этот
момент
обратиться
к newpath, не
сможет
определить
его
временное
отсутствие.
Однако
будет
промежуток
времени,
когда oldpath и
newpath
указывают
на один
файл.
Если oldpath и
newpath
являются
жёсткими
ссылками
на один и
тот же файл,
то rename()
ничего не
делает и
возвращает
код
успешного
выполнения.
Если newpath
существует,
но
операция
завершается
ошибкой, то
rename()
гарантирует,
что newpath
останется
нетронутым.
В oldpath может
быть
указан
каталог. В
этом
случае
каталог в
newpath должен
или не
существовать,
или должен
быть пуст.
Если oldpath
является
символьной
ссылкой, то
она
переименовывается;
если newpath
является
символьной
ссылкой, то
будет
вновь
записан
файл, на
который
она
указывает.
Системный
вызов renameat()
работает
также как
системный
вызов rename(), за
исключением
случаев,
описанных
далее.
Если в oldpath
указан
относительный
путь, то он
считается
относительно
каталога,
на который
ссылается
файловый
дескриптор
olddirfd (а не
относительно
текущего
рабочего
каталога
вызывающего
процесса,
как это
делается в
rename()).
Если в oldpath
указан
относительный
путь и olddirfd
равно
специальному
значению
AT_FDCWD, то oldpath
рассматривается
относительно
текущего
рабочего
каталога
вызывающего
процесса
(как rename()).
Если в oldpath
указан
абсолютный
путь, то olddirfd
игнорируется.
Значение
newpath
интерпретируется
как oldpath, за
исключением
того, что
относительный
путь
интерпретируется
относительно
каталога,
на который
ссылается
файловый
дескриптор
newdirfd.
Смотрите
в openat(2)
объяснение
необходимости
renameat().
Вызов renameat2()
имеет
дополнительный
аргумент
flags. Если
значение
flags равно
нулю, то renameat2()
эквивалентен
renameat().
Аргумент
flags
является
битовой
маской,
состоящей
из нуля или
более
следующих
флагов:
- RENAME_EXCHANGE
- Атомарно
обменять
oldpath и newpath. Оба
пути
должны
существовать,
но могут
быть
различных
типов
(например,
один может
быть
непустым
каталогом,
а другой
символической
ссылкой).
- RENAME_NOREPLACE
- Не
перезаписывать
newpath.
Возвращать
ошибку,
если newpath уже
существует.
- RENAME_NOREPLACE не
может быть
применен
вместе с
RENAME_EXCHANGE.
- Для RENAME_NOREPLACE
требуется
поддержка
в файловой
системе;
она есть
только у
нескольких
файловых
систем:
- ext4 (начиная
с Linux 3.15);
- btrfs, shmem, и cifs
(начиная
с Linux 3.17);
- xfs (начиная
с Linux 4.0);
- Поддержка
для других
файловых
систем
была
добавлена
в Linux 4.9: etx2, minix, reiserfs, jfs, vfat и bpf.
- RENAME_WHITEOUT
(начиная с Linux
3.18)
- Эта
операция
применима
только для
реализаций
оверлейных/объединённых
файловых
систем.
- При
указании
RENAME_WHITEOUT для
источника
переименования
одновременно
с
выполнением
переименования
создаётся
«замазанный»
объект (whiteout object).
Вся
операция
атомарна, и
при
успешном
выполнении
переименования
создаётся
и замазка.
- «Замазка»
— это
объект,
имеющий
специальное
предназначение
в
оверлейных/объединённых
файловых
системах. В
них
существует
несколько
слоёв, и
для
изменения
доступен
только
верхний.
Замазка на
верхнем
слое
эффективно
скрывает
файл из
нижнего
слоя, и
кажется,
что файл не
существует.
- Когда
переименовывается
файл,
существующий
в нижнем
слое, то
первым
действием
он
переписывается
(если его
уже нет в
верхнем
слое) и
переименовывается
в верхнем,
доступном
на
чтение-запись
слое.
Одновременно
с этим,
исходный
файл
требуется
«замазать»
(что
исходный
файл в
нижнем
слое
отражался
невидимым).
Вся
операция
должна
выполняться
атомарно.
- При
отсутствии
объединения/оверлея
замазка
появляется
в виде
символьного
устройства
с номером
устройства
{0,0} (заметим,
что в
других
реализациях
объединения/оверлея
могут
использоваться
другие
методы
хранения
элементов
замазки; в
частности,
в BSD для
объединения
монтирования
используется
специальный
тип иноды,
DT_WHT, который,
хотя и
поддерживается
некоторыми
файловыми
системами,
доступными
в Linux,
например CODA
и XFS, но
игнорируется
кодом
поддержки
замазки в
ядре, по
крайней
мере, в Linux 4.19).
- Для RENAME_WHITEOUT
требуются
те же
права, что
и для
создания
узла
устройства
(т. е.,
мандата
CAP_MKNOD).
- RENAME_WHITEOUT не
может быть
применён
вместе с
RENAME_EXCHANGE.
- Для RENAME_WHITEOUT
требуется
поддержка
в файловой
системе.
Такая
поддержка
имеется в tmpfs
(начиная с Linux
3.18), ext4 (начиная
с Linux 3.18), XFS
(начиная с Linux
4.1), f2fs (начиная
с Linux 4.2), btrfs
(начиная с Linux
4.7) и ubifs
(начиная с Linux
4.9).
ВОЗВРАЩАЕМОЕ
ЗНАЧЕНИЕ
При
успешном
выполнении
возвращается
0. В случае
ошибки
возвращается
-1, а errno
устанавливается
в
соответствующее
значение.
ОШИБКИ
- EACCES
- Запись в
каталог,
содержащий
oldpath или newpath,
запрещена,
или в одном
из
каталогов
пути oldpath или
newpath нельзя
производить
поиск, или
oldpath
является
каталогом,
в который
запрещена
запись
(требует
обновления
элемента
..);
смотрите
также path_resolution(7)).
- EBUSY
- Переименование
завершилось
неудачно,
так как oldpath
или newpath
является
каталогом,
который
используется
другим
процессом
(возможно в
качестве
текущего
рабочего
каталога
или в
качестве
корневого
каталога,
или он
открыт на
чтение),
или
используется
системой
(например,
в качестве
точки
монтирования),
и система
считает
это
ошибкой
(заметим,
что нет
требования
возвращать
EBUSY в таких
случаях —
нет ничего
неправильного
в таком
переименовании
— но
разрешается
возвращать
EBUSY, если
система не
может
иначе
обработать
такие
ситуации).
- EDQUOT
- Исчерпана
пользовательская
квота на
дисковые
блоки
файловой
системы.
- EFAULT
- Значения
oldpath и newpath
указывают
за пределы
доступного
адресного
пространства.
- EINVAL
- Новый путь
содержит
префикс
старого
пути или, в
более
общем
смысле,
выполняется
попытка
сделать
каталог
подкаталогом
самого
себя.
- EISDIR
- Каталог newpath
уже
существует,
но oldpath не
является
каталогом.
- ELOOP
- Во время
определения
oldpath или newpath
встретилось
слишком
много
символьных
ссылок.
- EMLINK
- В oldpath уже
имеется
максимальное
количество
ссылок, или
каталог,
содержащий
newpath, уже
имеет
максимальное
количество
ссылок.
- ENAMETOOLONG
- Слишком
длинное
значение
аргумента
oldpath или newpath.
- ENOENT
- Ссылка, на
которую
ссылается
oldpath, не
существует;
компонент
каталога в
newpath не
существует;
в oldpath или newpath
указана
пустая
строка.
- ENOMEM
- Недостаточное
количество
памяти
ядра.
- ENOSPC
- На
устройстве,
содержащем
файл, нет
места для
создания
нового
элемента
каталога.
- ENOTDIR
- Компонент,
используемый
как
каталог в
oldpath или newpath, в
действительности
не
является
каталогом.
Или oldpath
является
каталогом
и
существует
newpath, который
не
является
каталогом.
- ENOTEMPTY
или EEXIST
- Значение
newpath
является
непустым
каталогом,
то есть
содержит
элементы,
отличные
от «.» и «..».
- EPERM
или EACCES
- Каталог,
содержащийся
в oldpath, имеет
закрепляющий
бит (S_ISVTX) и
эффективный
идентификатор
процесса
не
совпадает
с
идентификатором
пользователя
удаляемого
файла или
каталога,
его
содержащего,
и процесс
не имеет
прав (Linux: нет
мандата
CAP_FOWNER); или newpath
является
существующим
файлом и
каталог,
содержащий
его, имеет
закрепляющий
бит и
эффективный
идентификатор
процесса
не
совпадает
с
идентификатором
пользователя
замещаемого
файла или
каталога,
его
содержащего,
и процесс
не имеет
прав (Linux: нет
мандата
CAP_FOWNER); или
файловая
система,
содержащая
pathname, не
поддерживает
переименования
запрашиваемого
типа.
- EROFS
- Файл
расположен
в файловой
системе,
доступной
только для
чтения.
- EXDEV
- Элементы
oldpath и newpath
находятся
не в одной
смонтированной
файловой
системе (Linux
позволяет
монтировать
файловую
систему в
несколько
точек, но rename()
не
работает с
различающимися
точками
монтирования,
даже если в
них
смонтирована
идентичная
файловая
система).
В renameat() и renameat2()
дополнительно
могут
возникнуть
следующие
ошибки:
- EBADF
- Значение
olddirfd или newdirfd не
является
правильным
файловым
дескриптором.
- ENOTDIR
- Значение
oldpath
содержит
относительный
путь и olddirfd
содержит
файловый
дескриптор,
указывающий
на файл, а
не на
каталог;
или
произошло
тоже самое
с newpath и newdirfd.
В renameat2()
дополнительно
могут
возникнуть
следующие
ошибки:
- EEXIST
- Значение
flags
содержит
RENAME_NOREPLACE, а newpath уже
существует.
- EINVAL
- В flags указан
неверный
флаг.
- EINVAL
- В flags
указаны
оба флага,
RENAME_NOREPLACE и RENAME_EXCHANGE.
- EINVAL
- В flags
указаны
оба флага,
RENAME_WHITEOUT и RENAME_EXCHANGE.
- EINVAL
- Файловая
система не
поддерживает
один из
флагов в
flags.
- ENOENT
- В flags
содержится
RENAME_EXCHANGE, но newpath не
существует.
- EPERM
- В flags указан
флаг RENAME_WHITEOUT , но
вызывающий
не имеет
мандата
CAP_MKNOD.
ВЕРСИИ
Системный
вызов renameat()
был
добавлен в
ядро Linux
версии 2.6.16;
поддержка
в glibc
доступна с
версии 2.4.
Вызов renameat2()
был
добавлен в
Linux 3.15;
поддержка
в glibc
доступна с
версии 2.28.
СООТВЕТСТВИЕ
СТАНДАРТАМ
rename(): 4.3BSD, C89, C99, POSIX.1-2001, POSIX.1-2008.
renameat(): POSIX.1-2008.
Вызов renameat2()
есть
только в Linux.
ЗАМЕЧАНИЯ
Замечания
по glibc
В старых
ядрах, где
renameat()
отсутствует,
обёрточная
функция glibc
использует
rename(). Если oldpath и
newpath
являются
относительными
путями, то glibc
собирает
пути
относительно
символической
ссылки в
/proc/self/fd,
которая
соответствует
аргументам
olddirfd и newdirfd.
ДЕФЕКТЫ
При
работе с
файловыми
системами NFS
нельзя
считать,
что если
операция
завершилась
неудачно,
то имя
файла не
изменилось.
Если
сервер
производит
операцию
переименования,
а затем
аварийно
останавливает
свою
работу, то
перепосланный
пакет RPC
будет
вновь
обработан
при
восстановлении
работы
сервера,
что
вызовет
сообщение
об ошибке.
Приложение
в этой
ситуации
должно
работать
корректно.
Смотрите
link(2), где
описывается
подобная
проблема.