Почему `rename` не может удалить исходный файл, когда работает` unlink` - PullRequest
1 голос
/ 22 января 2020

У меня есть сценарий PHP, перемещающий файл с помощью функции rename, которая частично завершается ошибкой. Вызов rename выдает предупреждение «Отказано в доступе». Файл, кажется, был скопирован в целевой каталог (я вижу его там все в порядке), но он все еще присутствует в исходном каталоге после rename.

file_exists подтверждает, что старый файл все еще подарок. unlink может затем успешно удалить файл - он возвращает true, а file_exists подтверждает, что файл больше не существует.

Файл получен в результате загрузки по HTTP-запросу в каталог /tmp (и Я использую is_uploaded_file для удовлетворения соображений безопасности - это не проблема здесь). Файл имеет права доступа rw для пользователя веб-службы (www-data). move_uploaded_file также работает без ошибок.

Целевой каталог находится в смонтированном каталоге CIFS.

Linux Ubuntu, PHP версия 7.2.24.

1 Ответ

2 голосов
/ 22 января 2020

( Обновлено: OP говорит, что целевой каталог является монтированием CIFS. Разрешения на монтирование CIFS могут быть сложными для понимания - см. https://linux.die.net/man/8/mount.cifs раздел " Файл и каталог Право собственности и разрешения")

rename - это не одно действие атома c (в PHP). На самом деле он вызывает (в этом порядке для обычных файлов):

  • copy (создать новую копию файла)
  • chown (установить владельца новой копии )
  • chmod (установить разрешения для новой копии)
  • unlink (удалить оригинал)

(Исходный код доступен на GitHub .)

Если какой-либо из этих шагов завершается ошибкой, он прерывается с кодом ошибки и не выполняет откат (что соответствует признакам, которые вы видите).

Примечание: это фактически задокументировано в исходном коде как возможное поведение:

 /*
  * Try to set user and permission info on the target.
  * If we're not root, then some of these may fail.
  * We try chown first, to set proper group info, relying
  * on the system environment to have proper umask to not allow                
  * access to the file in the meantime.
  */

Я ожидаю разрешения для родительского каталога в цели (где вы копируете в ) препятствуют работе chmod или chown.

( NB: это не будет работать для монтирование CIFS ... см. ссылку в верхней части ответа.) Как очень уродливый хак, вы можете попробовать установить права доступа для целевого каталога на 777 (chmod 777 /my/target/directory/), что плохо. но это доказало бы теорию.

...